diff options
Diffstat (limited to 'spec/mspec/tool/sync')
| -rw-r--r-- | spec/mspec/tool/sync/sync-rubyspec.rb | 120 |
1 files changed, 67 insertions, 53 deletions
diff --git a/spec/mspec/tool/sync/sync-rubyspec.rb b/spec/mspec/tool/sync/sync-rubyspec.rb index fbd37fe95b..86c43d0dc8 100644 --- a/spec/mspec/tool/sync/sync-rubyspec.rb +++ b/spec/mspec/tool/sync/sync-rubyspec.rb @@ -1,6 +1,9 @@ +# This script is based on commands from the wiki: +# https://github.com/ruby/spec/wiki/Merging-specs-from-JRuby-and-other-sources + IMPLS = { truffleruby: { - git: "https://github.com/graalvm/truffleruby.git", + git: "https://github.com/truffleruby/truffleruby.git", from_commit: "f10ab6988d", }, jruby: { @@ -12,13 +15,16 @@ IMPLS = { }, mri: { git: "https://github.com/ruby/ruby.git", - master: "trunk", - merge_message: "Update to ruby/spec@", }, } MSPEC = ARGV.delete('--mspec') +CHECK_LAST_MERGE = !MSPEC && ENV['CHECK_LAST_MERGE'] != 'false' +TEST_MASTER = ENV['TEST_MASTER'] != 'false' + +ONLY_FILTER = ENV['ONLY_FILTER'] == 'true' + MSPEC_REPO = File.expand_path("../../..", __FILE__) raise MSPEC_REPO if !Dir.exist?(MSPEC_REPO) or !Dir.exist?("#{MSPEC_REPO}/.git") @@ -28,12 +34,22 @@ raise RUBYSPEC_REPO unless Dir.exist?(RUBYSPEC_REPO) SOURCE_REPO = MSPEC ? MSPEC_REPO : RUBYSPEC_REPO +# LAST_MERGE is a commit of ruby/spec or ruby/mspec +# which is the spec/mspec commit that was last imported in the Ruby implementation +# (i.e. the commit in "Update to ruby/spec@commit"). +# It is normally automatically computed, but can be manually set when +# e.g. the last update of specs wasn't merged in the Ruby implementation. +LAST_MERGE = ENV["LAST_MERGE"] + NOW = Time.now BRIGHT_RED = "\e[31;1m" BRIGHT_YELLOW = "\e[33;1m" RESET = "\e[0m" +# git filter-branch --subdirectory-filter works fine for our use case +ENV['FILTER_BRANCH_SQUELCH_WARNING'] = '1' + class RubyImplementation attr_reader :name @@ -46,14 +62,14 @@ class RubyImplementation @data[:git] end - def default_branch - @data[:master] || "master" - end - def repo_name File.basename(git_url, ".git") end + def repo_path + "#{__dir__}/#{repo_name}" + end + def repo_org File.basename(File.dirname(git_url)) end @@ -64,7 +80,7 @@ class RubyImplementation end def last_merge_message - message = @data[:merge_message] || "Merge ruby/spec commit" + message = @data[:merge_message] || "Update to ruby/spec@" message.gsub!("ruby/spec", "ruby/mspec") if MSPEC message end @@ -97,7 +113,7 @@ def update_repo(impl) Dir.chdir(impl.repo_name) do puts Dir.pwd - sh "git", "checkout", impl.default_branch + sh "git", "checkout", "master" sh "git", "pull" end end @@ -133,22 +149,27 @@ def rebase_commits(impl) else sh "git", "checkout", impl.name - if ENV["LAST_MERGE"] - last_merge = `git log -n 1 --format='%H %ct' #{ENV["LAST_MERGE"]}` + if LAST_MERGE + last_merge = `git log -n 1 --format='%H %ct' #{LAST_MERGE}` else last_merge = `git log --grep='^#{impl.last_merge_message}' -n 1 --format='%H %ct'` end - last_merge, commit_timestamp = last_merge.chomp.split(' ') + last_merge, commit_timestamp = last_merge.split(' ') raise "Could not find last merge" unless last_merge puts "Last merge is #{last_merge}" commit_date = Time.at(Integer(commit_timestamp)) days_since_last_merge = (NOW-commit_date) / 86400 - if days_since_last_merge > 60 + if CHECK_LAST_MERGE and days_since_last_merge > 60 raise "#{days_since_last_merge.floor} days since last merge, probably wrong commit" end + puts "Checking if the last merge is consistent with upstream files" + rubyspec_commit = `git log -n 1 --format='%s' #{last_merge}`.chomp.split('@', 2)[-1] + sh "git", "checkout", last_merge + sh "git", "diff", "--exit-code", rubyspec_commit, "--", ":!.github" + puts "Rebasing..." sh "git", "branch", "-D", rebased if branch?(rebased) sh "git", "checkout", "-b", rebased, impl.name @@ -157,53 +178,40 @@ def rebase_commits(impl) end end -def test_new_specs - require "yaml" +def new_commits?(impl) Dir.chdir(SOURCE_REPO) do - if MSPEC - sh "bundle", "exec", "rspec" - else - versions = YAML.load_file(".travis.yml") - versions = versions["matrix"]["include"].map { |job| job["rvm"] } - versions.delete "ruby-head" - min_version, max_version = versions.minmax - - run_rubyspec = -> version { - command = "chruby #{version} && ../mspec/bin/mspec -j" - sh ENV["SHELL"], "-c", command - } - run_rubyspec[min_version] - run_rubyspec[max_version] - run_rubyspec["trunk"] - end + diff = `git diff master #{impl.rebased_branch}` + !diff.empty? end end -def verify_commits(impl) - puts +def test_new_specs + require "yaml" Dir.chdir(SOURCE_REPO) do - history = `git log master...` - history.lines.slice_before(/^commit \h{40}$/).each do |commit, *message| - commit = commit.chomp.split.last - message = message.join - if /\W(#\d+)/ === message - puts "Commit #{commit} contains an unqualified issue number: #{$1}" - puts "Replace it with #{impl.repo_org}/#{impl.repo_name}#{$1}" - sh "git", "rebase", "-i", "#{commit}^" - end - end + workflow = YAML.load_file(".github/workflows/ci.yml") + job_name = MSPEC ? "test" : "specs" + versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby").map(&:to_s) + versions = versions.grep(/^\d+\./) # Test on MRI + min_version, max_version = versions.minmax + + test_command = MSPEC ? "bundle install && bundle exec rspec" : "../mspec/bin/mspec -j" + + run_test = -> version { + command = "chruby ruby-#{version} && #{test_command}" + sh ENV["SHELL"], "-c", command + } - puts "Manually check commit messages:" - print "Press enter >" - STDIN.gets - sh "git", "log", "master..." + run_test[min_version] + run_test[max_version] + run_test["master"] if TEST_MASTER end end def fast_forward_master(impl) Dir.chdir(SOURCE_REPO) do sh "git", "checkout", "master" - sh "git", "merge", "--ff-only", "#{impl.name}-rebased" + sh "git", "merge", "--ff-only", impl.rebased_branch + sh "git", "branch", "--delete", impl.rebased_branch end end @@ -221,11 +229,17 @@ def main(impls) impl = RubyImplementation.new(impl, data) update_repo(impl) filter_commits(impl) - rebase_commits(impl) - test_new_specs - verify_commits(impl) - fast_forward_master(impl) - check_ci + unless ONLY_FILTER + rebase_commits(impl) + if new_commits?(impl) + test_new_specs + fast_forward_master(impl) + check_ci + else + STDERR.puts "#{BRIGHT_YELLOW}No new commits#{RESET}" + fast_forward_master(impl) + end + end end end |
