Skip to content

Instantly share code, notes, and snippets.

@arika
Last active November 19, 2020 16:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arika/9c945d9a452aed3eebff0bcd6f2b7f3d to your computer and use it in GitHub Desktop.
Save arika/9c945d9a452aed3eebff0bcd6f2b7f3d to your computer and use it in GitHub Desktop.
require "yaml"
require "json"
require "tempfile"
module RuboCopAutoCollrect
class << self
def run_all!(targets, *cop_names, commit_log_format:, fixup_commit_log_format:)
plan(targets, *cop_names).each do |cop_name|
run!(targets, cop_name, commit_log_format: commit_log_format)
end
run!(targets, *cop_names, commit_log_format: fixup_commit_log_format)
end
def run!(targets, *cop_names, commit_log_format:)
cop_list = cop_names.join(",") unless cop_names.empty?
print "\n*** auto-correct by #{cop_list || 'AllCops'}...\n\n"
only_cops = cop_list ? ["--only", cop_list] : []
begin
rubocop_auto_correct("--format", "autogenconf", *only_cops, *targets)
rescue
print "\n** try to detect errors...\n\n"
rubocop_check(*only_cops, *targets)
abort
end
return unless git_diff?
git("add", ".")
git("commit", "-q", "-m", format(commit_log_format, cop_list: cop_list))
print "\n** commit changes\n\n"
end
def plan(targets, *cop_names)
print "*** calculate auto-correct plan...\n\n"
only_cops = cop_names.empty? ? [] : ["--only", cop_names.join(",")]
begin
output = Tempfile.open("auto_correct_plan") do |tf|
rubocop_auto_correct(
*only_cops,
"--display-cop-names",
"--format", "fuubar",
"--format", "json",
"--out", tf.path,
*targets,
)
tf.read
end
rescue
print "\n** try to detect errors...\n\n"
rubocop_check(*only_cops, *targets)
abort
end
git("restore", ".")
categories = cop_names.map {|cop_name| cop_name[%r{\A[^/]*}] }.uniq
corrected_cops = corrected_cops(JSON.parse(output))
corrected_cops.keys.sort_by do |cop_name|
count = corrected_cops[cop_name]
idx = categories.index {|category| cop_name.start_with?(category) }
[idx || categories.size, -count]
end
end
private
def corrected_cops(rubocop_output)
rubocop_output["files"]
.map {|f| f["offenses"].select {|o| o["corrected"] } }
.flatten
.group_by {|o| o["cop_name"] }
.transform_values(&:size)
end
def rubocop(*args, on_failure: :raise)
command("rubocop", "--safe", *args)
rescue => e
warn "\n#{e}"
abort if on_failure == :abort
raise
end
def rubocop_auto_correct(*args)
rubocop(
"--fail-level", "E",
"--safe-auto-correct",
*args,
)
end
def rubocop_check(*args)
rubocop(
"--fail-level", "E",
"--display-only-fail-level-offenses",
*args,
on_failure: :abort,
)
end
def git(*args)
command("git", *args)
rescue => e
warn e
abort
end
def git_diff?
command("git", "diff", "--quiet")
false
rescue
true
end
def command(*cmd)
system(*cmd)
raise "failed: #{cmd.join(' ')}" unless $?.success?
end
end
end
sep_idx = ARGV.index("--") || 0
targets = ARGV[(sep_idx + 1)..-1]
commit_log_prefix, = ARGV[0, sep_idx]
commit_log_format = "#{commit_log_prefix}auto-correct by RuboCop %<cop_list>s"
cop_names = %w(Layout Style)
RuboCopAutoCollrect.run_all!(
targets, *cop_names,
commit_log_format: commit_log_format,
fixup_commit_log_format: "#{commit_log_format} (fix-up)",
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment