diff --git a/README.md b/README.md index d76969e81..8c64e50ae 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ Options: # Default: development [--halt-upon-load-error], [--no-halt-upon-load-error], [--skip-halt-upon-load-error] # Halt upon a load error while loading the Rails application # Default: true + [--default-command-override=DEFAULT_COMMAND_OVERRIDE] # Override the default command printed on failure -c, [--config=] # Path to the Tapioca configuration file # Default: sorbet/tapioca/config.yml -V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes @@ -367,17 +368,18 @@ Usage: tapioca annotations Options: - [--sources=one two three] # URIs of the sources to pull gem RBI annotations from - # Default: "https://raw.githubusercontent.com/Shopify/rbi-central/main" - [--netrc], [--no-netrc], [--skip-netrc] # Use .netrc to authenticate to private sources - # Default: true - [--netrc-file=NETRC_FILE] # Path to .netrc file - [--auth=AUTH] # HTTP authorization header for private sources - --typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Override for typed sigils for pulled annotations - -c, [--config=] # Path to the Tapioca configuration file - # Default: sorbet/tapioca/config.yml - -V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes - # Default: false + [--sources=one two three] # URIs of the sources to pull gem RBI annotations from + # Default: "https://raw.githubusercontent.com/Shopify/rbi-central/main" + [--netrc], [--no-netrc], [--skip-netrc] # Use .netrc to authenticate to private sources + # Default: true + [--netrc-file=NETRC_FILE] # Path to .netrc file + [--auth=AUTH] # HTTP authorization header for private sources + --typed, -t, [--typed-overrides=gem:level [gem:level ...]] # Override for typed sigils for pulled annotations + [--default-command-override=DEFAULT_COMMAND_OVERRIDE] # Override the default command printed on failure + -c, [--config=] # Path to the Tapioca configuration file + # Default: sorbet/tapioca/config.yml + -V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes + # Default: false Pull gem RBI annotations from remote sources ``` @@ -503,6 +505,7 @@ Options: # Default: true [--skip-constant=constant [constant ...]] # Do not generate RBI definitions for the given application constant(s) [--compiler-options=key:value] # Options to pass to the DSL compilers + [--default-command-override=DEFAULT_COMMAND_OVERRIDE] # Override the default command printed on failure -c, [--config=] # Path to the Tapioca configuration file # Default: sorbet/tapioca/config.yml -V, [--verbose], [--no-verbose], [--skip-verbose] # Verbose output for debugging purposes @@ -939,9 +942,11 @@ The full configuration file, with each option and its default value, would look --- require: postrequire: sorbet/tapioca/require.rb + default_command_override: '' todo: todo_file: sorbet/rbi/todo.rbi file_header: true + default_command_override: '' dsl: outdir: sorbet/rbi/dsl file_header: true @@ -957,6 +962,7 @@ dsl: halt_upon_load_error: true skip_constant: [] compiler_options: {} + default_command_override: '' gem: outdir: sorbet/rbi/gems file_header: true @@ -977,6 +983,7 @@ gem: rbi_max_line_length: 120 environment: development halt_upon_load_error: true + default_command_override: '' check_shims: gem_rbi_dir: sorbet/rbi/gems dsl_rbi_dir: sorbet/rbi/dsl @@ -991,6 +998,7 @@ annotations: netrc: true netrc_file: '' typed_overrides: {} + default_command_override: '' ``` diff --git a/lib/tapioca/cli.rb b/lib/tapioca/cli.rb index cadddf6c7..a45702379 100644 --- a/lib/tapioca/cli.rb +++ b/lib/tapioca/cli.rb @@ -36,6 +36,7 @@ def init Commands::Todo.new( todo_file: DEFAULT_TODO_FILE, file_header: true, + default_command_override: nil, ).run print_init_next_steps @@ -43,21 +44,25 @@ def init desc "configure", "Initialize folder structure and type checking configuration" option :postrequire, type: :string, default: DEFAULT_POSTREQUIRE_FILE + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def configure command = Commands::Configure.new( sorbet_config: SORBET_CONFIG_FILE, tapioca_config: options[:config], default_postrequire: options[:postrequire], + default_command_override: options[:default_command_override], ) command.run end desc "require", "Generate the list of files to be required by tapioca" option :postrequire, type: :string, default: DEFAULT_POSTREQUIRE_FILE + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def require command = Commands::Require.new( requires_path: options[:postrequire], sorbet_config_path: SORBET_CONFIG_FILE, + default_command_override: options[:default_command_override], ) command.run end @@ -71,10 +76,12 @@ def require type: :boolean, desc: FILE_HEADER_OPTION_DESC, default: true + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def todo command = Commands::Todo.new( todo_file: options[:todo_file], file_header: options[:file_header], + default_command_override: options[:default_command_override], ) command.run_with_deprecation end @@ -144,6 +151,7 @@ def todo type: :hash, desc: "Options to pass to the DSL compilers", default: {} + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def dsl(*constant_or_paths) set_environment(options) @@ -166,6 +174,7 @@ def dsl(*constant_or_paths) app_root: options[:app_root], halt_upon_load_error: options[:halt_upon_load_error], compiler_options: options[:compiler_options], + default_command_override: options[:default_command_override], } command = if options[:verify] @@ -261,6 +270,7 @@ def dsl(*constant_or_paths) type: :boolean, desc: "Halt upon a load error while loading the Rails application", default: true + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def gem(*gems) set_environment(options) @@ -295,6 +305,7 @@ def gem(*gems) dsl_dir: options[:dsl_dir], rbi_formatter: rbi_formatter(options), halt_upon_load_error: options[:halt_upon_load_error], + default_command_override: options[:default_command_override], } command = if verify @@ -326,6 +337,7 @@ def check_shims todo_rbi_file: options[:todo_rbi_file], payload: options[:payload], number_of_workers: options[:workers], + default_command_override: nil, ) command.run @@ -345,6 +357,7 @@ def check_shims banner: "gem:level [gem:level ...]", desc: "Override for typed sigils for pulled annotations", default: {} + option :default_command_override, type: :string, desc: "Override the default command printed on failure" def annotations if !options[:netrc] && options[:netrc_file] raise Thor::Error, set_color("Options `--no-netrc` and `--netrc-file` can't be used together", :bold, :red) @@ -355,6 +368,7 @@ def annotations auth: options[:auth], netrc_file: netrc_file(options), typed_overrides: options[:typed_overrides], + default_command_override: options[:default_command_override], ) command.run diff --git a/lib/tapioca/commands/abstract_dsl.rb b/lib/tapioca/commands/abstract_dsl.rb index 3395afd53..97548c789 100644 --- a/lib/tapioca/commands/abstract_dsl.rb +++ b/lib/tapioca/commands/abstract_dsl.rb @@ -18,6 +18,7 @@ class AbstractDsl < CommandWithoutTracker exclude: T::Array[String], file_header: T::Boolean, tapioca_path: String, + default_command_override: T.nilable(String), skip_constant: T::Array[String], quiet: T::Boolean, verbose: T::Boolean, @@ -38,6 +39,7 @@ def initialize( exclude:, file_header:, tapioca_path:, + default_command_override: nil, skip_constant: [], quiet: false, verbose: false, @@ -67,7 +69,7 @@ def initialize( @skip_constant = skip_constant @compiler_options = compiler_options - super() + super(default_command_override: default_command_override) end private diff --git a/lib/tapioca/commands/abstract_gem.rb b/lib/tapioca/commands/abstract_gem.rb index c4b66916b..5431a4af0 100644 --- a/lib/tapioca/commands/abstract_gem.rb +++ b/lib/tapioca/commands/abstract_gem.rb @@ -22,6 +22,7 @@ class AbstractGem < Command include_doc: T::Boolean, include_loc: T::Boolean, include_exported_rbis: T::Boolean, + default_command_override: T.nilable(String), number_of_workers: T.nilable(Integer), auto_strictness: T::Boolean, dsl_dir: String, @@ -41,6 +42,7 @@ def initialize( include_doc:, include_loc:, include_exported_rbis:, + default_command_override: nil, number_of_workers: nil, auto_strictness: true, dsl_dir: DEFAULT_DSL_DIR, @@ -60,7 +62,7 @@ def initialize( @dsl_dir = dsl_dir @rbi_formatter = rbi_formatter - super() + super(default_command_override: default_command_override) @bundle = T.let(Gemfile.new(exclude), Gemfile) @existing_rbis = T.let(nil, T.nilable(T::Hash[String, String])) diff --git a/lib/tapioca/commands/annotations.rb b/lib/tapioca/commands/annotations.rb index 9da9d4c9d..0a4c43f68 100644 --- a/lib/tapioca/commands/annotations.rb +++ b/lib/tapioca/commands/annotations.rb @@ -9,6 +9,7 @@ class Annotations < CommandWithoutTracker sig do params( central_repo_root_uris: T::Array[String], + default_command_override: T.nilable(String), auth: T.nilable(String), netrc_file: T.nilable(String), central_repo_index_path: String, @@ -17,12 +18,13 @@ class Annotations < CommandWithoutTracker end def initialize( central_repo_root_uris:, + default_command_override: nil, auth: nil, netrc_file: nil, central_repo_index_path: CENTRAL_REPO_INDEX_PATH, typed_overrides: {} ) - super() + super(default_command_override: default_command_override) @outpath = T.let(Pathname.new(DEFAULT_ANNOTATIONS_DIR), Pathname) @central_repo_root_uris = central_repo_root_uris @auth = auth diff --git a/lib/tapioca/commands/check_shims.rb b/lib/tapioca/commands/check_shims.rb index 43416bfdd..5f1144941 100644 --- a/lib/tapioca/commands/check_shims.rb +++ b/lib/tapioca/commands/check_shims.rb @@ -17,6 +17,7 @@ class CheckShims < CommandWithoutTracker todo_rbi_file: String, payload: T::Boolean, number_of_workers: T.nilable(Integer), + default_command_override: T.nilable(String), ).void end def initialize( @@ -26,9 +27,10 @@ def initialize( shim_rbi_dir:, todo_rbi_file:, payload:, - number_of_workers: + number_of_workers:, + default_command_override: nil ) - super() + super(default_command_override: default_command_override) @gem_rbi_dir = gem_rbi_dir @dsl_rbi_dir = dsl_rbi_dir @annotations_rbi_dir = annotations_rbi_dir diff --git a/lib/tapioca/commands/command.rb b/lib/tapioca/commands/command.rb index d9cd5eb96..0816adc9f 100644 --- a/lib/tapioca/commands/command.rb +++ b/lib/tapioca/commands/command.rb @@ -16,8 +16,9 @@ class FileWriter < Thor abstract! - sig { void } - def initialize + sig { params(default_command_override: T.nilable(String)).void } + def initialize(default_command_override: nil) + @default_command_override = default_command_override @file_writer = T.let(FileWriter.new, Thor::Actions) end @@ -35,7 +36,7 @@ def execute; end sig { params(command: Symbol, args: String).returns(String) } def default_command(command, *args) - [Tapioca::BINARY_FILE, command.to_s, *args].join(" ") + @default_command_override || [Tapioca::BINARY_FILE, command.to_s, *args].join(" ") end sig { returns(Thor::Actions) } diff --git a/lib/tapioca/commands/command_without_tracker.rb b/lib/tapioca/commands/command_without_tracker.rb index 67b3820a9..753401cf0 100644 --- a/lib/tapioca/commands/command_without_tracker.rb +++ b/lib/tapioca/commands/command_without_tracker.rb @@ -8,10 +8,10 @@ class CommandWithoutTracker < Command abstract! - sig { void } - def initialize + sig { params(default_command_override: T.nilable(String)).void } + def initialize(default_command_override: nil) Tapioca::Runtime::Trackers.disable_all! - super + super(default_command_override: default_command_override) end end end diff --git a/lib/tapioca/commands/configure.rb b/lib/tapioca/commands/configure.rb index 29fbff786..16893dc14 100644 --- a/lib/tapioca/commands/configure.rb +++ b/lib/tapioca/commands/configure.rb @@ -9,18 +9,20 @@ class Configure < CommandWithoutTracker sorbet_config: String, tapioca_config: String, default_postrequire: String, + default_command_override: T.nilable(String), ).void end def initialize( sorbet_config:, tapioca_config:, - default_postrequire: + default_postrequire:, + default_command_override: nil ) @sorbet_config = sorbet_config @tapioca_config = tapioca_config @default_postrequire = default_postrequire - super() + super(default_command_override: default_command_override) @installer = T.let(nil, T.nilable(Bundler::Installer)) @spec = T.let(nil, T.nilable(Bundler::StubSpecification)) diff --git a/lib/tapioca/commands/require.rb b/lib/tapioca/commands/require.rb index f5cb9e3f3..cab0ee292 100644 --- a/lib/tapioca/commands/require.rb +++ b/lib/tapioca/commands/require.rb @@ -8,13 +8,14 @@ class Require < CommandWithoutTracker params( requires_path: String, sorbet_config_path: String, + default_command_override: T.nilable(String), ).void end - def initialize(requires_path:, sorbet_config_path:) + def initialize(requires_path:, sorbet_config_path:, default_command_override: nil) @requires_path = requires_path @sorbet_config_path = sorbet_config_path - super() + super(default_command_override: default_command_override) end private diff --git a/lib/tapioca/commands/todo.rb b/lib/tapioca/commands/todo.rb index a77788edd..d0f14b9f7 100644 --- a/lib/tapioca/commands/todo.rb +++ b/lib/tapioca/commands/todo.rb @@ -21,13 +21,14 @@ class Todo < CommandWithoutTracker params( todo_file: String, file_header: T::Boolean, + default_command_override: T.nilable(String), ).void end - def initialize(todo_file:, file_header:) + def initialize(todo_file:, file_header:, default_command_override: nil) @todo_file = todo_file @file_header = file_header - super() + super(default_command_override: default_command_override) end sig { void } diff --git a/spec/tapioca/cli/dsl_spec.rb b/spec/tapioca/cli/dsl_spec.rb index b421f194b..a205892c4 100644 --- a/spec/tapioca/cli/dsl_spec.rb +++ b/spec/tapioca/cli/dsl_spec.rb @@ -1949,6 +1949,49 @@ class Image @project.remove!("lib/image.rb") end + it "advises of changes with the overridden default_command_override in the output" do + @project.tapioca("dsl --default-command-override='ENV_VAR=something bin/my_command --with=options'") + + @project.write!("lib/image.rb", <<~RB) + require "smart_properties" + + class Image + include(SmartProperties) + + property :title, accepts: String + end + RB + + result = @project.tapioca( + "dsl --verify --default-command-override='ENV_VAR=something bin/my_command --with=options'", + ) + + assert_stdout_equals(<<~OUT, result) + Loading DSL extension classes... Done + Loading Rails application... Done + Loading DSL compiler classes... Done + Checking for out-of-date RBIs... + + + OUT + + assert_stderr_equals(<<~ERROR, result) + RBI files are out-of-date. In your development environment, please run: + `ENV_VAR=something bin/my_command --with=options` + Once it is complete, be sure to commit and push any changes + If you don't observe any changes after running the command locally, ensure your database is in a good + state e.g. run `bin/rails db:reset` + + Reason: + File(s) added: + - sorbet/rbi/dsl/image.rbi + ERROR + + refute_success_status(result) + + @project.remove!("lib/image.rb") + end + it "advises of modified file(s) and returns exit status 1 with modified file" do @project.write!("lib/post.rb", <<~RB) require "smart_properties"