lib/packwerk/cli.rb in packwerk-3.0.1 vs lib/packwerk/cli.rb in packwerk-3.1.0

- old
+ new

@@ -1,10 +1,8 @@ # typed: strict # frozen_string_literal: true -require "optparse" - module Packwerk # A command-line interface to Packwerk. class Cli extend T::Sig @@ -44,186 +42,25 @@ exit(success) end sig { params(args: T::Array[String]).returns(T::Boolean) } def execute_command(args) - subcommand = args.shift - case subcommand - when "init" - init - when "check" - output_result(parse_run(args).check) - when "update-todo", "update" - output_result(parse_run(args).update_todo) - when "validate" - validate(args) - when "version" - @out.puts(Packwerk::VERSION) - true - when nil, "help" - usage - else - @err_out.puts( - "'#{subcommand}' is not a packwerk command. See `packwerk help`." - ) - false - end - end + command = args.shift || "help" + command_class = Commands.for(command) - private - - sig { returns(T::Boolean) } - def init - @out.puts("📦 Initializing Packwerk...") - - generate_configs - end - - sig { returns(T::Boolean) } - def generate_configs - configuration_file = Generators::ConfigurationFile.generate( - root: @configuration.root_path, - out: @out - ) - - root_package = Generators::RootPackage.generate(root: @configuration.root_path, out: @out) - - success = configuration_file && root_package - - result = if success - <<~EOS - - 🎉 Packwerk is ready to be used. You can start defining packages and run `bin/packwerk check`. - For more information on how to use Packwerk, see: https://github.com/Shopify/packwerk/blob/main/USAGE.md - EOS + if command_class + command_class.new( + args, + configuration: @configuration, + out: @out, + err_out: @err_out, + progress_formatter: @progress_formatter, + offenses_formatter: @offenses_formatter, + ).run else - <<~EOS + @err_out.puts("'#{command}' is not a packwerk command. See `packwerk help`.",) - ⚠️ Packwerk is not ready to be used. - Please check output and refer to https://github.com/Shopify/packwerk/blob/main/USAGE.md for more information. - EOS + false end - - @out.puts(result) - success - end - - sig { returns(T::Boolean) } - def usage - @err_out.puts(<<~USAGE) - Usage: #{$PROGRAM_NAME} <subcommand> - - Subcommands: - init - set up packwerk - check - run all checks - update-todo - update package_todo.yml files - validate - verify integrity of packwerk and package configuration - version - output packwerk version - help - display help information about packwerk - USAGE - true - end - - sig { params(result: Result).returns(T::Boolean) } - def output_result(result) - @out.puts - @out.puts(result.message) - result.status - end - - sig do - params( - relative_file_paths: T::Array[String], - ignore_nested_packages: T::Boolean - ).returns(FilesForProcessing) - end - def fetch_files_to_process(relative_file_paths, ignore_nested_packages) - files_for_processing = FilesForProcessing.fetch( - relative_file_paths: relative_file_paths, - ignore_nested_packages: ignore_nested_packages, - configuration: @configuration - ) - @out.puts(<<~MSG.squish) if files_for_processing.files.empty? - No files found or given. - Specify files or check the include and exclude glob in the config file. - MSG - - files_for_processing - end - - sig { params(_paths: T::Array[String]).returns(T::Boolean) } - def validate(_paths) - result = T.let(nil, T.nilable(Validator::Result)) - - @progress_formatter.started_validation do - result = validator.check_all(package_set, @configuration) - - list_validation_errors(result) - end - - T.must(result).ok? - end - - sig { returns(ApplicationValidator) } - def validator - ApplicationValidator.new - end - - sig { returns(PackageSet) } - def package_set - PackageSet.load_all_from( - @configuration.root_path, - package_pathspec: @configuration.package_paths - ) - end - - sig { params(result: Validator::Result).void } - def list_validation_errors(result) - @out.puts - if result.ok? - @out.puts("Validation successful 🎉") - else - @out.puts("Validation failed ❗") - @out.puts - @out.puts(result.error_value) - end - end - - sig { params(args: T::Array[String]).returns(ParseRun) } - def parse_run(args) - relative_file_paths = T.let([], T::Array[String]) - ignore_nested_packages = nil - formatter = @offenses_formatter - - if args.any? { |arg| arg.include?("--packages") } - OptionParser.new do |parser| - parser.on("--packages=PACKAGESLIST", Array, "package names, comma separated") do |p| - relative_file_paths = p - end - end.parse!(args) - ignore_nested_packages = true - else - relative_file_paths = args - ignore_nested_packages = false - end - - if args.any? { |arg| arg.include?("--offenses-formatter") } - OptionParser.new do |parser| - parser.on("--offenses-formatter=FORMATTER", String, - "identifier of offenses formatter to use") do |formatter_identifier| - formatter = OffensesFormatter.find(formatter_identifier) - end - end.parse!(args) - end - - files_for_processing = fetch_files_to_process(relative_file_paths, ignore_nested_packages) - - ParseRun.new( - relative_file_set: files_for_processing.files, - file_set_specified: files_for_processing.files_specified?, - configuration: @configuration, - progress_formatter: @progress_formatter, - offenses_formatter: formatter - ) end end end