lib/tapioca/cli.rb in tapioca-0.8.3 vs lib/tapioca/cli.rb in tapioca-0.9.0
- old
+ new
@@ -3,12 +3,11 @@
module Tapioca
class Cli < Thor
include CliHelper
include ConfigHelper
- include SorbetHelper
- include ShimsHelper
+ include EnvHelper
FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
class_option :config,
aliases: ["-c"],
@@ -20,16 +19,27 @@
aliases: ["-V"],
type: :boolean,
desc: "Verbose output for debugging purposes",
default: false
- desc "init", "initializes folder structure"
+ desc "init", "get project ready for type checking"
def init
- command = Commands::Init.new(
+ invoke(:configure)
+ invoke(:annotations)
+ invoke(:gem)
+ invoke(:todo)
+
+ print_init_next_steps
+ end
+
+ desc "configure", "initialize folder structure and type checking configuration"
+ option :postrequire, type: :string, default: DEFAULT_POSTREQUIRE_FILE
+ def configure
+ command = Commands::Configure.new(
sorbet_config: SORBET_CONFIG_FILE,
- tapioca_config: TAPIOCA_CONFIG_FILE,
- default_postrequire: DEFAULT_POSTREQUIRE_FILE
+ tapioca_config: options[:config],
+ default_postrequire: options[:postrequire]
)
command.execute
end
desc "require", "generate the list of files to be required by tapioca"
@@ -98,12 +108,19 @@
desc: "EXPERIMENTAL: Number of parallel workers to use when generating RBIs",
default: 1
option :rbi_max_line_length,
type: :numeric,
desc: "Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped",
- default: 120
+ default: DEFAULT_RBI_MAX_LINE_LENGTH
+ option :environment,
+ aliases: ["-e"],
+ type: :string,
+ desc: "The Rack/Rails environment to use when generating RBIs",
+ default: DEFAULT_ENVIRONMENT
def dsl(*constants)
+ set_environment(options)
+
command = Commands::Dsl.new(
requested_constants: constants,
outpath: Pathname.new(options[:outdir]),
only: options[:only],
exclude: options[:exclude],
@@ -192,13 +209,20 @@
desc: "The DSL directory used to correct gems strictnesses",
default: DEFAULT_DSL_DIR
option :rbi_max_line_length,
type: :numeric,
desc: "Set the max line length of generated RBIs. Signatures longer than the max line length will be wrapped",
- default: 120
+ default: DEFAULT_RBI_MAX_LINE_LENGTH
+ option :environment,
+ aliases: ["-e"],
+ type: :string,
+ desc: "The Rack/Rails environment to use when generating RBIs",
+ default: DEFAULT_ENVIRONMENT
def gem(*gems)
Tapioca.silence_warnings do
+ set_environment(options)
+
all = options[:all]
verify = options[:verify]
command = Commands::Gem.new(
gem_names: all ? [] : gems,
@@ -206,11 +230,11 @@
prerequire: options[:prerequire],
postrequire: options[:postrequire],
typed_overrides: options[:typed_overrides],
outpath: Pathname.new(options[:outdir]),
file_header: options[:file_header],
- doc: options[:doc],
+ include_doc: options[:doc],
include_exported_rbis: options[:exported_gem_rbis],
number_of_workers: options[:workers],
auto_strictness: options[:auto_strictness],
dsl_dir: options[:dsl_dir],
rbi_formatter: rbi_formatter(options)
@@ -241,72 +265,49 @@
desc "check-shims", "check duplicated definitions in shim RBIs"
option :gem_rbi_dir, type: :string, desc: "Path to gem RBIs", default: DEFAULT_GEM_DIR
option :dsl_rbi_dir, type: :string, desc: "Path to DSL RBIs", default: DEFAULT_DSL_DIR
option :shim_rbi_dir, type: :string, desc: "Path to shim RBIs", default: DEFAULT_SHIM_DIR
+ option :annotations_rbi_dir, type: :string, desc: "Path to annotations RBIs", default: DEFAULT_ANNOTATIONS_DIR
+ option :todo_rbi_file, type: :string, desc: "Path to the generated todo RBI file", default: DEFAULT_TODO_FILE
option :payload, type: :boolean, desc: "Check shims against Sorbet's payload", default: true
def check_shims
- index = RBI::Index.new
+ command = Commands::CheckShims.new(
+ gem_rbi_dir: options[:gem_rbi_dir],
+ dsl_rbi_dir: options[:dsl_rbi_dir],
+ shim_rbi_dir: options[:shim_rbi_dir],
+ annotations_rbi_dir: options[:annotations_rbi_dir],
+ todo_rbi_file: options[:todo_rbi_file],
+ payload: options[:payload]
+ )
+ command.execute
+ end
- shim_rbi_dir = options[:shim_rbi_dir]
- if !Dir.exist?(shim_rbi_dir) || Dir.empty?(shim_rbi_dir)
- say("No shim RBIs to check", :green)
- exit(0)
- end
-
- payload_path = T.let(nil, T.nilable(String))
-
- if options[:payload]
- if sorbet_supports?(:print_payload_sources)
- Dir.mktmpdir do |dir|
- payload_path = dir
- result = sorbet("--no-config --print=payload-sources:#{payload_path}")
-
- unless result.status
- say_error("Sorbet failed to dump payload")
- say_error(result.err)
- exit(1)
- end
-
- index_payload(index, payload_path)
- end
- else
- say_error("The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`")
- say_error("Current: v#{SORBET_GEM_SPEC.version}")
- say_error("Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}")
- exit(1)
- end
- end
-
- index_rbis(index, "shim", shim_rbi_dir)
- index_rbis(index, "gem", options[:gem_rbi_dir])
- index_rbis(index, "dsl", options[:dsl_rbi_dir])
-
- duplicates = duplicated_nodes_from_index(index, shim_rbi_dir)
- unless duplicates.empty?
- duplicates.each do |key, nodes|
- say_error("\nDuplicated RBI for #{key}:", :red)
- nodes.each do |node|
- node_loc = node.loc
- next unless node_loc
-
- loc_string = location_to_payload_url(node_loc, path_prefix: payload_path)
- say_error(" * #{loc_string}", :red)
- end
- end
- say_error("\nPlease remove the duplicated definitions from the #{shim_rbi_dir} directory.", :red)
+ desc "annotations", "Pull gem RBI annotations from remote sources"
+ option :sources, type: :array, default: [CENTRAL_REPO_ROOT_URI],
+ desc: "URIs of the sources to pull gem RBI annotations from"
+ option :netrc, type: :boolean, default: true, desc: "Use .netrc to authenticate to private sources"
+ option :netrc_file, type: :string, desc: "Path to .netrc file"
+ option :auth, type: :string, default: nil, desc: "HTTP authorization header for private sources"
+ option :typed_overrides,
+ aliases: ["--typed", "-t"],
+ type: :hash,
+ banner: "gem:level [gem:level ...]",
+ desc: "Override for typed sigils for pulled annotations",
+ default: {}
+ def annotations
+ if !options[:netrc] && options[:netrc_file]
+ say_error("Options `--no-netrc` and `--netrc-file` can't be used together", :bold, :red)
exit(1)
end
- say("\nNo duplicates found in shim RBIs", :green)
- exit(0)
- end
-
- desc "annotations", "Pull gem annotations from a central RBI repository"
- option :repo_uri, type: :string, desc: "Repository URI to pull annotations from", default: CENTRAL_REPO_ROOT_URI
- def annotations
- command = Commands::Annotations.new(central_repo_root_uri: options[:repo_uri])
+ command = Commands::Annotations.new(
+ central_repo_root_uris: options[:sources],
+ auth: options[:auth],
+ netrc_file: netrc_file(options),
+ typed_overrides: options[:typed_overrides]
+ )
command.execute
end
map ["--version", "-v"] => :__print_version
@@ -317,8 +318,64 @@
no_commands do
def self.exit_on_failure?
true
end
+ end
+
+ private
+
+ def print_init_next_steps
+ say(<<~OUTPUT)
+ #{set_color("This project is now set up for use with Sorbet and Tapioca", :bold)}
+
+ The sorbet/ folder should exist and look something like this:
+
+ ├── config # Default options to be passed to Sorbet on every run
+ └── rbi/
+ ├── annotations/ # Type definitions pulled from the rbi-central repository
+ ├── gems/ # Autogenerated type definitions for your gems
+ └── todo.rbi # Constants which were still missing after RBI generation
+ └── tapioca/
+ ├── config.yml # Default options to be passed to Tapioca
+ └── require.rb # A file where you can make requires from gems that might be needed for gem RBI generation
+
+ Please check this folder into version control.
+
+ #{set_color("🤔 What's next", :bold)}
+
+ 1. Many Ruby applications use metaprogramming DSLs to dynamically generate constants and methods.
+ To generate type definitions for any DSLs in your application, run:
+
+ #{set_color("bin/tapioca dsl", :cyan)}
+
+ 2. Check whether the constants in the #{set_color("sorbet/rbi/todo.rbi", :cyan)} file actually exist in your project.
+ It is possible that some of these constants are typos, and leaving them in #{set_color("todo.rbi", :cyan)} will
+ hide errors in your application. Ideally, you should be able to remove all definitions
+ from this file and delete it.
+
+ 3. Typecheck your project:
+
+ #{set_color("bundle exec srb tc", :cyan)}
+
+ There should not be any typechecking errors.
+
+ 4. Upgrade a file marked "#{set_color("# typed: false", :cyan)}" to "#{set_color("# typed: true", :cyan)}".
+ Then, run: #{set_color("bundle exec srb tc", :cyan)} and try to fix any errors.
+
+ You can use Spoom to bump files for you:
+
+ #{set_color("spoom bump --from false --to true", :cyan)}
+
+ To learn more about Spoom, visit: #{set_color("https://github.com/Shopify/spoom", :cyan)}
+
+ 5. Add signatures to your methods with #{set_color("sig", :cyan)}. To learn how, read: #{set_color("https://sorbet.org/docs/sigs", :cyan)}
+
+ #{set_color("Documentation", :bold)}
+ We recommend skimming these docs to get a feel for how to use Sorbet:
+ - Gradual Type Checking: #{set_color("https://sorbet.org/docs/gradual", :cyan)}
+ - Enabling Static Checks: #{set_color("https://sorbet.org/docs/static", :cyan)}
+ - RBI Files: #{set_color("https://sorbet.org/docs/rbi", :cyan)}
+ OUTPUT
end
end
end