Skip to content

Instantly share code, notes, and snippets.

@Earlopain
Last active August 18, 2024 08:33
Show Gist options
  • Save Earlopain/b307c9d8b243023c90045adde75ef87a to your computer and use it in GitHub Desktop.
Save Earlopain/b307c9d8b243023c90045adde75ef87a to your computer and use it in GitHub Desktop.
Run each commit of a repo against current rubocop to check for cop errors
# frozen_string_literal: true
require "bundler/inline"
extensions = {
"rubocop-rails" => "2.25.1",
"rubocop-rspec" => "3.0.4",
"rubocop-rspec_rails" => "2.30.0",
"rubocop-minitest" => "0.35.1",
"rubocop-performance" => "1.21.1",
"rubocop-capybara" => "2.21.0",
"rubocop-factory_bot" => "2.26.1",
"rubocop-rake" => "0.6.0",
"rubocop-thread_safety" => "0.5.1",
"rubocop-erb" => "0.5.2",
}
gemfile do
source "https://rubygems.org"
gem "rubocop", path: "./rubocop"
extensions.each { |name, version| gem name, version }
end
require "tempfile"
RubyVM::YJIT.enable
# Supress whatever warnings may occur (wrong department, regexp, etc.)
def Warning.warn(...)
end
# Doesn't work if there is no .rubocop.yml
class RuboCop::TargetRuby::GemspecFile
def gemspec_filepath
"#{Dir.pwd}/#{gemspec_filename}"
end
end
# `rubocop:disable Rspec/PredicateMatcher` raises
class RuboCop::CommentConfig
def cop_disabled_line_ranges
{}
end
end
# source buffer must be valid utf-8
class RuboCop::CachedData
def deserialize_offenses(offenses)
[]
end
end
def runner(extensions)
config_path = RuboCop::ConfigLoader.configuration_file_for("./")
other_yml = begin
RuboCop::ConfigLoader.load_yaml_configuration(config_path)
rescue Psych::SyntaxError
{}
end
other_all_cops = (other_yml.dig("AllCops") || {}).slice("TargetRubyVersion", "TargetRailsVersion")
other_config = RuboCop::Config.create({ "AllCops" => other_all_cops }, ".rubocop.yml", check: false)
target_ruby = RuboCop::TargetRuby.new(other_config).version
target_rails = other_config.target_rails_version
without = ENV.fetch("WITHOUT", "").split(",").map do |cop|
<<~YML
#{cop}:
Enabled: false
YML
end.join("\n")
config = Tempfile.new
config << <<~YML
require: #{extensions.keys.inspect}
AllCops:
EnabledByDefault: true
TargetRubyVersion: #{target_ruby}
TargetRailsVersion: #{target_rails}
MaxFilesInCache: 100000
Style/Copyright:
Enabled: false
#{without}
YML
config.close
options = RuboCop::Options.new.parse([
"--stderr",
"--format",
"RuboCop::Formatter::BaseFormatter",
]).first
config_store = RuboCop::ConfigStore.new
config_store.options_config = config.path
r = RuboCop::Runner.new(options, config_store)
def r.run(...)
super
raise Interrupt if aborting?
end
[r, target_ruby, target_rails]
end
Dir.chdir(ENV.fetch("FOLDER")) do
start = ENV.fetch("START") do
`git branch`.split("\n")[1].strip
end
system("git checkout #{start}", exception: true)
remaining_commits = `git rev-list HEAD --count`.to_i
loop do
current_commit = `git rev-parse HEAD`.strip
raise StandardError, "rev-parse failed" if current_commit == ""
r, target_ruby, target_rails = runner(extensions)
puts "Commit #{current_commit} (#{remaining_commits}), #{target_ruby}/#{target_rails}"
r.run(["./"])
if r.errors.any?
puts "-" * 20
pp r.errors
break
end
previous_commit = `git log --pretty=format:"%H" -2`.split("\n").last
break if previous_commit == current_commit
remaining_commits -= 1
system("git checkout #{previous_commit}", exception: true, out: File::NULL, err: File::NULL)
end
end
puts "DONE!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment