class Nucop::Cli

Public Instance Methods

diff() click to toggle source
# File lib/nucop/cli.rb, line 25
def diff
  puts "Running on files changed relative to '#{options[:"commit-spec"]}' (specify using the 'commit-spec' option)"
  diff_filter = options[:"added-only"] ? "A" : "d"
  diff_base = capture_std_out("git merge-base HEAD #{options[:"commit-spec"]}").chomp

  files, diff_status = Open3.capture2("git diff #{diff_base} --diff-filter=#{diff_filter} --name-only | grep \"\\.rb$\"")

  if diff_status != 0
    if options[:exit]
      puts "There are no rb files present in diff. Exiting."
      exit 0
    else
      puts "There are no rb files present in diff."
      return true
    end
  end

  if options[:ignore] && File.exist?(options[:diffignore_file]) && !File.zero?(options[:diffignore_file])
    files, non_ignored_diff_status = Open3.capture2("grep -v -f #{options[:diffignore_file]}", stdin_data: files)

    if non_ignored_diff_status != 0
      if options[:exit]
        puts "There are no non-ignored rb files present in diff. Exiting."
        exit 0
      else
        puts "There are no non-ignored rb files present in diff."
        return true
      end
    end
  end

  no_violations_detected = invoke :rubocop, [multi_line_to_single_line(files)], options

  exit 1 unless no_violations_detected
  return true unless options[:exit]
  exit 0
end
diff_enforced() click to toggle source
# File lib/nucop/cli.rb, line 14
def diff_enforced
  invoke :diff, nil, options.merge(only: cops_to_enforce.join(","))
end
modified_lines() click to toggle source
# File lib/nucop/cli.rb, line 110
def modified_lines
  diff_files, diff_status = Open3.capture2("git diff #{options[:'commit-spec']} --diff-filter=d --name-only | grep \"\\.rb$\"")

  exit 1 unless diff_status.exitstatus.zero?

  command = [
    "bundle exec rubocop",
    "--parallel",
    "--format Nucop::Formatters::GitDiffFormatter",
    "--config #{options[:rubocop_todo_config_file]}",
    multi_line_to_single_line(diff_files).to_s
  ].join(" ")

  # HACK: use ENVVAR to parameterize GitDiffFormatter
  system({ "RUBOCOP_COMMIT_SPEC" => options[:"commit-spec"] }, command)
end
ready_for_promotion() click to toggle source
# File lib/nucop/cli.rb, line 129
def ready_for_promotion
  finder = Helpers::NextCopForPromotion.new(options[:rubocop_todo_file])
  todo_config = YAML.load_file(options[:rubocop_todo_file])

  puts "The following cop(s) are ready to be promoted to enforced. Good luck!"
  puts "Remember to run `nucop:regen_backlog` to capture your hard work."
  puts
  finder.find(options["n"].to_i).each do |todo|
    puts "#{todo.name} with #{todo.offenses} offenses:"
    puts

    files = todo_config.fetch(todo.name, {}).fetch("Exclude", [])

    system("bundle exec rubocop --parallel --config #{options[:rubocop_todo_config_file]} --only #{todo.name} #{files.join(' ')}")
    puts("*" * 100) if options["n"] > 1
    puts
  end
end
regen_backlog() click to toggle source
# File lib/nucop/cli.rb, line 98
def regen_backlog
  regenerate_rubocop_todos
  update_enforced_cops
end
rubocop(files = nil) click to toggle source
# File lib/nucop/cli.rb, line 67
def rubocop(files = nil)
  print_cops_being_run(options[:only])
  config_file = options[:"exclude-backlog"] ? RUBOCOP_DEFAULT_CONFIG_FILE : options[:rubocop_todo_config_file]
  rubocop_requires = [
    "--require rubocop-rspec",
    "--require rubocop-performance",
    "--require rubocop-rails"
  ]

  formatters = []
  formatters << "--format Nucop::Formatters::JUnitFormatter --out #{options[:junit_report]}" if options[:junit_report]
  formatters << "--format json --out #{options[:json]}" if options[:json]
  formatters << "--format progress" if formatters.any?

  command = [
    "bundle exec rubocop",
    "--parallel",
    rubocop_requires.join(" "),
    formatters.join(" "),
    "--force-exclusion",
    "--config", config_file,
    pass_through_option(options, "auto-correct"),
    pass_through_flag(options, "only"),
    files
  ].join(" ")

  system(command)
end
update_enforced() click to toggle source
# File lib/nucop/cli.rb, line 104
def update_enforced
  update_enforced_cops
end

Private Instance Methods

capture_std_out(command, error_message = nil, stdin_data = nil) click to toggle source
# File lib/nucop/cli.rb, line 164
def capture_std_out(command, error_message = nil, stdin_data = nil)
  std_out, std_error, status = Open3.capture3(command, stdin_data: stdin_data)
  print_errors_and_exit(std_error, error_message) unless status.success?

  std_out
end
configuration_options() click to toggle source
# File lib/nucop/cli.rb, line 268
def configuration_options
  if File.exist?(CONFIGURATION_FILEPATH)
    default_configuration.merge(YAML.load_file(CONFIGURATION_FILEPATH))
  else
    default_configuration
  end
end
cops_to_enforce() click to toggle source

some cops cannot be used with the –only option and will raise an error this filters them out

# File lib/nucop/cli.rb, line 152
def cops_to_enforce
  cops = enforced_cops

  cops.delete("Lint/UnneededCopDisableDirective")

  cops
end
cops_without_violations() click to toggle source
# File lib/nucop/cli.rb, line 246
def cops_without_violations
  cops_with_violations = YAML.load_file(options[:rubocop_todo_file]).map(&:first)

  enabled_cops - cops_with_violations
end
default_configuration() click to toggle source
# File lib/nucop/cli.rb, line 276
def default_configuration
  {
    enforced_cops_file: ".rubocop.enforced.yml",
    rubocop_todo_file: ".rubocop_todo.yml",
    rubocop_todo_config_file: ".rubocop.backlog.yml",
    diffignore_file: ".nucop_diffignore"
  }
end
enabled_cops() click to toggle source
# File lib/nucop/cli.rb, line 252
def enabled_cops
  YAML.load(`bundle exec rubocop --parallel --show-cops`) # rubocop:disable Security/YAMLLoad
    .select { |_, config| config["Enabled"] }
    .map(&:first)
end
enforced_cops() click to toggle source
# File lib/nucop/cli.rb, line 160
def enforced_cops
  @_enforced_cops ||= YAML.load_file(options[:enforced_cops_file])
end
files_changed_since(commit_spec) click to toggle source
# File lib/nucop/cli.rb, line 200
def files_changed_since(commit_spec)
  `git diff #{commit_spec} HEAD --name-only`
    .split("\n")
    .select { |e| e.end_with?(".rb") }
end
multi_line_to_single_line(str) click to toggle source
# File lib/nucop/cli.rb, line 187
def multi_line_to_single_line(str)
  str.split(/\n+/).join(" ")
end
options() click to toggle source

Override Thor's options method to include Nucop's options

Calls superclass method
# File lib/nucop/cli.rb, line 259
def options
  return @_options if defined?(@_options)

  original_options = super
  @_options = Thor::CoreExt::HashWithIndifferentAccess.new(
    configuration_options.merge(original_options)
  )
end
pass_through_flag(options, option) click to toggle source
# File lib/nucop/cli.rb, line 191
def pass_through_flag(options, option)
  pass_through_option(options, option, true)
end
pass_through_option(options, option, is_flag_option = false) click to toggle source
# File lib/nucop/cli.rb, line 195
def pass_through_option(options, option, is_flag_option = false)
  return nil unless options[option]
  "--#{option} #{options[option] if is_flag_option}"
end
print_cops_being_run(only_option) click to toggle source
print_errors_and_exit(std_error, message = "An error has occurred") click to toggle source
regenerate_rubocop_todos() click to toggle source
# File lib/nucop/cli.rb, line 206
def regenerate_rubocop_todos
  puts "Regenerating '#{options[:rubocop_todo_file]}'. Please be patient..."

  rubocop_options = [
    "--auto-gen-config",
    "--config #{options[:rubocop_todo_config_file]}",
    "--exclude-limit #{options[:'exclude-limit']}",
    "--require rubocop-rspec",
    "--require rubocop-performance",
    "--require rubocop-rails"
  ]

  rubocop_command = "DISABLE_SPRING=1 bundle exec rubocop #{rubocop_options.join(' ')}"

  system(rubocop_command)

  # RuboCop wants to inherit from our todos (options[:rubocop_todo_file]) in our backlog configuration file (options[:rubocop_todo_config_file])
  # However, that means the next time we try to update our backlog, it will NOT include the violations recorded as todo
  # For now, we ignore any changes in our backlog config
  system("git checkout #{options[:rubocop_todo_config_file]}")
end
update_enforced_cops() click to toggle source
# File lib/nucop/cli.rb, line 228
def update_enforced_cops
  puts "Updating enforced cops list..."

  current_enforced_cops = Helpers::CopSet.new(enforced_cops)
  cops_without_violations.each do |cop|
    current_enforced_cops.add_cop(cop)
  end

  if current_enforced_cops.cop_added?
    File.open(options[:enforced_cops_file], "w+") do |f|
      f.write(current_enforced_cops.to_a.sort.to_yaml)
    end
    puts "Updated '#{options[:enforced_cops_file]}'!"
  else
    puts "No new cops are clear of violations"
  end
end