summaryrefslogtreecommitdiff
path: root/spec/mspec/tool/sync/sync-rubyspec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/mspec/tool/sync/sync-rubyspec.rb')
-rw-r--r--spec/mspec/tool/sync/sync-rubyspec.rb120
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