diff --git a/.rubocop.yml b/.rubocop.yml index 96b245937..5f6b84634 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,6 +10,7 @@ AllCops: TargetRubyVersion: 2.4 Exclude: - 'vendor/**/*' + - "spec/support/repo/bin/tapioca" Style/CaseEquality: Enabled: false diff --git a/lib/tapioca/cli.rb b/lib/tapioca/cli.rb index 247202023..dc340d5d9 100644 --- a/lib/tapioca/cli.rb +++ b/lib/tapioca/cli.rb @@ -38,20 +38,9 @@ class Cli < Thor desc "init", "initializes folder structure" def init - create_file(Config::SORBET_CONFIG, skip: true) do - <<~CONTENT - --dir - . - CONTENT - end - create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do - <<~CONTENT - # typed: false - # frozen_string_literal: true - - # Add your extra requires here - CONTENT - end + create_config + create_post_require + generate_binstub end desc "require", "generate the list of files to be required by tapioca" @@ -103,6 +92,34 @@ def __print_version puts "Tapioca v#{Tapioca::VERSION}" end + private + + def create_config + create_file(Config::SORBET_CONFIG, skip: true) do + <<~CONTENT + --dir + . + CONTENT + end + end + + def create_post_require + create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do + <<~CONTENT + # typed: false + # frozen_string_literal: true + + # Add your extra requires here + CONTENT + end + end + + def generate_binstub + installer = Bundler::Installer.new(Bundler.root, Bundler.definition) + spec = Bundler.definition.specs.find { |s| s.name == "tapioca" } + installer.generate_bundler_executable_stubs(spec, { force: true }) + end + no_commands do def self.exit_on_failure? true diff --git a/lib/tapioca/config.rb b/lib/tapioca/config.rb index 277831fa5..a842007aa 100644 --- a/lib/tapioca/config.rb +++ b/lib/tapioca/config.rb @@ -8,7 +8,6 @@ class Config < T::Struct const(:outdir, String) const(:prerequire, T.nilable(String)) const(:postrequire, String) - const(:generate_command, String) const(:exclude, T::Array[String]) const(:typed_overrides, T::Hash[String, String]) const(:todos_path, String) @@ -27,6 +26,7 @@ def outpath TAPIOCA_PATH = T.let("#{SORBET_PATH}/tapioca", String) TAPIOCA_CONFIG = T.let("#{TAPIOCA_PATH}/config.yml", String) + DEFAULT_COMMAND = T.let("bin/tapioca", String) DEFAULT_POSTREQUIRE = T.let("#{TAPIOCA_PATH}/require.rb", String) DEFAULT_RBIDIR = T.let("#{SORBET_PATH}/rbi", String) DEFAULT_DSLDIR = T.let("#{DEFAULT_RBIDIR}/dsl", String) diff --git a/lib/tapioca/config_builder.rb b/lib/tapioca/config_builder.rb index 0d37b78d7..471b7e513 100644 --- a/lib/tapioca/config_builder.rb +++ b/lib/tapioca/config_builder.rb @@ -10,9 +10,13 @@ class << self sig { params(command: Symbol, options: T::Hash[String, T.untyped]).returns(Config) } def from_options(command, options) - Config.from_hash( - merge_options(default_options(command), config_options, options) - ) + merged_options = merge_options(default_options(command), config_options, options) + + puts(<<~MSG) if merged_options.include?("generate_command") + DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release. + MSG + + Config.from_hash(merged_options) end private @@ -40,15 +44,6 @@ def default_options(command) DEFAULT_OPTIONS.merge("outdir" => default_outdir) end - sig { returns(String) } - def default_command - command = File.basename($PROGRAM_NAME) - # Hack to avoid flags ending up in the header of the RBIs - args = ARGV.grep_v(/^-/).join(" ") - - "#{command} #{args}".strip - end - sig { params(options: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) } def merge_options(*options) options.each_with_object({}) do |option, result| @@ -66,7 +61,6 @@ def merge_options(*options) DEFAULT_OPTIONS = T.let({ "postrequire" => Config::DEFAULT_POSTREQUIRE, "outdir" => nil, - "generate_command" => default_command, "exclude" => [], "typed_overrides" => Config::DEFAULT_OVERRIDES, "todos_path" => Config::DEFAULT_TODOSPATH, diff --git a/lib/tapioca/generator.rb b/lib/tapioca/generator.rb index f5e75e123..9a1ae7b9f 100644 --- a/lib/tapioca/generator.rb +++ b/lib/tapioca/generator.rb @@ -63,7 +63,7 @@ def build_requires content = String.new content << rbi_header( - config.generate_command, + "#{Config::DEFAULT_COMMAND} require", reason: "explicit gem requires", strictness: "false" ) @@ -76,8 +76,8 @@ def build_requires say("Done", :green) say("All requires from this application have been written to #{name}.", [:green, :bold]) - cmd = set_color("tapioca sync", :yellow, :bold) - say("Please review changes and commit them, then run #{cmd}.", [:green, :bold]) + cmd = set_color("#{Config::DEFAULT_COMMAND} sync", :yellow, :bold) + say("Please review changes and commit them, then run `#{cmd}`.", [:green, :bold]) end sig { void } @@ -99,7 +99,7 @@ def build_todos content = String.new content << rbi_header( - config.generate_command, + "#{Config::DEFAULT_COMMAND} todo", reason: "unresolved constants", strictness: "false" ) @@ -225,7 +225,7 @@ def explain_failed_require(file, error) say_error("If you populated ", :yellow) say_error("#{file} ", :bold, :blue) say_error("with ", :yellow) - say_error("tapioca require", :bold, :blue) + say_error("`#{Config::DEFAULT_COMMAND} require`", :bold, :blue) say_error("you should probably review it and remove the faulty line.", :yellow) end @@ -484,7 +484,7 @@ def compile_gem_rbi(gem) rbi_body_content = compiler.compile(gem) content = String.new content << rbi_header( - config.generate_command, + "#{Config::DEFAULT_COMMAND} sync", reason: "types exported from the `#{gem.name}` gem", strictness: strictness ) @@ -510,14 +510,13 @@ def compile_gem_rbi(gem) def compile_dsl_rbi(constant, contents, outpath: config.outpath) return if contents.nil? - command = format(config.generate_command, constant.name) constant_name = Module.instance_method(:name).bind(constant).call rbi_name = constant_name.underscore + ".rbi" filename = outpath / rbi_name out = String.new out << rbi_header( - command, + "#{Config::DEFAULT_COMMAND} dsl #{constant_name}", reason: "dynamic methods in `#{constant.name}`" ) out << contents @@ -555,7 +554,7 @@ def verify_dsl_rbi(tmp_dir:) sig { params(dir: String).void } def perform_dsl_verification(dir) if (error = verify_dsl_rbi(tmp_dir: Pathname.new(dir))) - say("RBI files are out-of-date, please run `#{config.generate_command}` to update.") + say("RBI files are out-of-date, please run `#{Config::DEFAULT_COMMAND} dsl` to update.") say("Reason: ", [:red]) say(error) exit(1) diff --git a/spec/support/repo/bin/tapioca b/spec/support/repo/bin/tapioca index e13303f95..32290dee5 100755 --- a/spec/support/repo/bin/tapioca +++ b/spec/support/repo/bin/tapioca @@ -26,4 +26,4 @@ end require "rubygems" require "bundler/setup" -load(Gem.bin_path("tapioca", "tapioca")) +load Gem.bin_path("tapioca", "tapioca") diff --git a/spec/tapioca/cli_spec.rb b/spec/tapioca/cli_spec.rb index a8e6d22f6..9c56243e3 100644 --- a/spec/tapioca/cli_spec.rb +++ b/spec/tapioca/cli_spec.rb @@ -9,7 +9,7 @@ module Contents FOO_RBI = <<~CONTENTS # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `foo` gem. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca sync`. # typed: true @@ -25,7 +25,7 @@ def bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end BAR_RBI = <<~CONTENTS # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `bar` gem. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca sync`. # typed: true @@ -41,7 +41,7 @@ def bar(a = T.unsafe(nil), b: T.unsafe(nil), **opts); end BAZ_RBI = <<~CONTENTS # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `baz` gem. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca sync`. # typed: true @@ -68,7 +68,6 @@ class Tapioca::CliSpec < Minitest::HooksSpec def execute(command, args = [], flags = {}) flags = { outdir: outdir, - generate_command: "'generate command'", }.merge(flags).flat_map { |k, v| ["--#{k}", v.to_s] } exec_command = [ @@ -142,6 +141,8 @@ def execute(command, args = [], flags = {}) # Add your extra requires here CONTENTS + + assert_path_exists(repo_path / "bin/tapioca") end it 'must not overwrite files' do @@ -204,7 +205,7 @@ def foo assert_equal(<<~CONTENTS, File.read(repo_path / "sorbet/rbi/todo.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for unresolved constants. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca todo`. # typed: false @@ -220,7 +221,7 @@ module Foo::Undef2; end File.write(repo_path / "sorbet/rbi/todo.rbi", <<-RBI) # DO NOT EDIT MANUALLY # This is an autogenerated file for unresolved constants. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca todo`. # typed: false @@ -274,14 +275,14 @@ module Foo::Undef2; end assert_equal(<<~OUTPUT, output) Compiling sorbet/tapioca/require.rb, this may take a few seconds... Done All requires from this application have been written to sorbet/tapioca/require.rb. - Please review changes and commit them, then run tapioca sync. + Please review changes and commit them, then run `bin/tapioca sync`. OUTPUT assert_path_exists(repo_path / "sorbet/tapioca/require.rb") assert_equal(<<~CONTENTS, File.read(repo_path / "sorbet/tapioca/require.rb")) # DO NOT EDIT MANUALLY # This is an autogenerated file for explicit gem requires. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca require`. # typed: false @@ -305,14 +306,14 @@ module Foo::Undef2; end assert_equal(<<~OUTPUT, output) Compiling sorbet/tapioca/require.rb, this may take a few seconds... Done All requires from this application have been written to sorbet/tapioca/require.rb. - Please review changes and commit them, then run tapioca sync. + Please review changes and commit them, then run `bin/tapioca sync`. OUTPUT assert_path_exists(repo_path / "sorbet/tapioca/require.rb") assert_equal(<<~CONTENTS, File.read(repo_path / "sorbet/tapioca/require.rb")) # DO NOT EDIT MANUALLY # This is an autogenerated file for explicit gem requires. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca require`. # typed: false @@ -363,7 +364,7 @@ module Foo::Undef2; end assert_equal(<<~CONTENTS.chomp, File.read("#{outdir}/post.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for dynamic methods in `Post`. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca dsl Post`. # typed: true class Post @@ -448,7 +449,7 @@ def title=(title); end assert_equal(<<~CONTENTS.chomp, File.read("#{outdir}/baz/role.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for dynamic methods in `Baz::Role`. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca dsl Baz::Role`. # typed: true module Baz @@ -465,7 +466,7 @@ def title=(title); end assert_equal(<<~CONTENTS.chomp, File.read("#{outdir}/post.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for dynamic methods in `Post`. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca dsl Post`. # typed: true class Post @@ -480,7 +481,7 @@ def title=(title); end assert_equal(<<~CONTENTS.chomp, File.read("#{outdir}/namespace/comment.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for dynamic methods in `Namespace::Comment`. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca dsl Namespace::Comment`. # typed: true module Namespace @@ -612,7 +613,7 @@ class Image output = execute("dsl", "--verify") assert_includes(output, <<~OUTPUT) - RBI files are out-of-date, please run `generate command` to update. + RBI files are out-of-date, please run `bin/tapioca dsl` to update. Reason: New file(s) introduced. OUTPUT assert_includes($?.to_s, "exit 1") # rubocop:disable Style/SpecialGlobalVars @@ -653,7 +654,7 @@ class Image output = execute("dsl", "--verify") assert_includes(output, <<~OUTPUT) - RBI files are out-of-date, please run `generate command` to update. + RBI files are out-of-date, please run `bin/tapioca dsl` to update. Reason: File(s) updated: - sorbet/rbi/dsl/image.rbi OUTPUT @@ -717,7 +718,7 @@ class Foo::Secret LoadError: cannot load such file -- foo/will_fail Tapioca could not load all the gems required by your application. - If you populated /postrequire_faulty.rb with tapioca require + If you populated /postrequire_faulty.rb with `bin/tapioca require` you should probably review it and remove the faulty line. OUTPUT end @@ -879,7 +880,7 @@ class Foo::Secret assert_equal(<<~CONTENTS.chomp, File.read("#{outdir}/qux@0.5.0.rbi")) # DO NOT EDIT MANUALLY # This is an autogenerated file for types exported from the `qux` gem. - # Please instead update this file by running `generate command`. + # Please instead update this file by running `bin/tapioca sync`. # typed: true @@ -994,4 +995,21 @@ class Foo::Secret refute_path_exists("#{outdir}/baz@0.0.1.rbi") end end + + describe("deprecations") do + it "prints the correct deprecation message with -c" do + output = execute("dsl", ["-c", "foo"]) + assert_includes(output, "DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release.") + end + + it "prints the correct deprecation message with --cmd" do + output = execute("dsl", ["--cmd", "foo"]) + assert_includes(output, "DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release.") + end + + it "doesn't print the correct deprecation message with no flag" do + output = execute("dsl") + refute_includes(output, "DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release.") + end + end end