require 'thor' module LicenseFinder module CLI class Base < Thor def self.subcommand(namespace, klass, namespace_description) description = "#{namespace} [#{(klass.tasks.keys - ["help"]).join("|")}]" desc description, "#{namespace_description} - see `license_finder #{namespace} help` for more information" super namespace, klass end private def sync_with_package_managers options={} die_on_error { logger = LicenseFinder::Logger.new options DependencyManager.new(logger: logger).sync_with_package_managers } end def die_on_error yield rescue LicenseFinder::Error => e say e.message, :red exit 1 end end # Thor fix for `license_finder <subcommand> help <action>` class Subcommand < Base # Hack to override the help message produced by Thor. # https://github.com/wycats/thor/issues/261#issuecomment-16880836 def self.banner(command, namespace = nil, subcommand = nil) "#{basename} #{underscore_name(name)} #{command.usage}" end protected def self.underscore_name(name) underscored = name.split("::").last underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') underscored.tr!("-", "_") underscored.downcase end end class Dependencies < Subcommand method_option :approve, type: :boolean, desc: "Approve the added dependency" method_option :approver, desc: "The person granting the approval" method_option :message, desc: "The reason for the approval" desc "add LICENSE DEPENDENCY_NAME [VERSION] [--approve] [--approver APPROVER_NAME] [--message APPROVAL_MESSAGE]", "Add a dependency that is not managed by a package manager, optionally storing who approved the dependency and why" def add(license, name, version = nil) die_on_error { DependencyManager.new.tap do |dependency_manager| dependency_manager.manually_add(license, name, version) dependency_manager.approve!(name, options[:approver], options[:message]) if options[:approve] end } if options[:approve] say "The #{name} dependency has been added and approved!", :green else say "The #{name} dependency has been added!", :green end end desc "remove DEPENDENCY_NAME", "Remove a dependency that is not managed by a package manager" def remove(name) die_on_error { DependencyManager.new.manually_remove(name) } say "The #{name} dependency has been removed.", :green end end class ConfigSubcommand < Subcommand private def modifying die_on_error { yield LicenseFinder.config.save sync_with_package_managers } end end class Whitelist < ConfigSubcommand desc "list", "List all the whitelisted licenses" def list whitelist = LicenseFinder.config.whitelist say "Whitelisted Licenses:", :blue whitelist.each do |license| say license end end desc "add LICENSE...", "Add one or more licenses to the whitelist" def add(license, *other_licenses) licenses = other_licenses.unshift license modifying { licenses.each do |license| LicenseFinder.config.whitelist.push(license) end } say "Added #{licenses.join(", ")} to the license whitelist" end desc "remove LICENSE...", "Remove one or more licenses from the whitelist" def remove(license, *other_licenses) licenses = other_licenses.unshift license modifying { licenses.each do |license| LicenseFinder.config.whitelist.delete(license) end } say "Removed #{licenses.join(", ")} from the license whitelist" end end class ProjectName < ConfigSubcommand desc "set NAME", "Set the project name" def set(name) modifying { LicenseFinder.config.project_name = name } say "Set the project name to #{name}", :green end end class IgnoredBundlerGroups < ConfigSubcommand desc "list", "List all the ignored bundler groups" def list ignored = LicenseFinder.config.ignore_groups say "Ignored Bundler Groups:", :blue ignored.each do |group| say group end end desc "add GROUP", "Add a bundler group to be ignored" def add(group) modifying { LicenseFinder.config.ignore_groups.push(group) } say "Added #{group} to the ignored bundler groups" end desc "remove GROUP", "Remove a bundler group from the ignored bundler groups" def remove(group) modifying { LicenseFinder.config.ignore_groups.delete(group) } say "Removed #{group} from the ignored bundler groups" end end class IgnoredDependencies < ConfigSubcommand desc "list", "List all the ignored dependencies" def list ignored = LicenseFinder.config.ignore_dependencies say "Ignored Dependencies:", :blue if ignored.any? ignored.each do |group| say group end else say '(none)' end end desc "add DEPENDENCY", "Add a dependency to be ignored" def add(group) modifying { LicenseFinder.config.ignore_dependencies.push(group) } say "Added #{group} to the ignored dependencies" end desc "remove DEPENDENCY", "Remove a dependency from the ignored dependencies" def remove(group) modifying { LicenseFinder.config.ignore_dependencies.delete(group) } say "Removed #{group} from the ignored dependencies" end end class Main < Base method_option :quiet, type: :boolean, desc: "silences loading output" method_option :debug, type: :boolean, desc: "emit detailed info about what LicenseFinder is doing" desc "rescan", "Find new dependencies. (Default action)" def rescan sync_with_package_managers options show_results end desc "show_results", "Display ignored dependencies and action items" def show_results IgnoredDependencies.new.list action_items end default_task :rescan method_option :approver, desc: "The person granting the approval" method_option :message, desc: "The reason for the approval" desc "approve DEPENDENCY_NAME... [--approver APPROVER_NAME] [--message APPROVAL_MESSAGE]", "Approve one or more dependencies by name, optionally storing who approved the dependency and why" def approve(name, *other_names) names = other_names.unshift name die_on_error { names.each { |name| DependencyManager.new.approve!(name, options[:approver], options[:message]) } } say "The #{names.join(", ")} dependency has been approved!", :green end desc "license LICENSE DEPENDENCY_NAME", "Update a dependency's license" def license(license, name) die_on_error { DependencyManager.new.license!(name, license) } say "The #{name} dependency has been marked as using #{license} license!", :green end desc "move", "Move dependency.* files from root directory to doc/" def move Configuration.move! say "Congratulations, you have cleaned up your root directory!'", :green end desc "action_items", "List unapproved dependencies" def action_items unapproved = Dependency.unapproved if unapproved.empty? say "All dependencies are approved for use", :green else say "Dependencies that need approval:", :red say TextReport.new(unapproved) exit 1 end end subcommand "dependencies", Dependencies, "Manually manage dependencies that your package managers are not aware of" subcommand "ignored_bundler_groups", IgnoredBundlerGroups, "Manage ignored Bundler groups" subcommand "ignored_dependencies", IgnoredDependencies, "Manage ignored dependencies" subcommand "whitelist", Whitelist, "Manage whitelisted licenses" subcommand "project_name", ProjectName, "Manage the project name" end end end