From 084f63ef222a5a51856d77cc276431f3de925420 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Thu, 21 Mar 2024 22:16:13 -0700 Subject: [PATCH] Port Homebrew::DevCmd::UpdateTest --- Library/Homebrew/dev-cmd/update-test.rb | 283 +++++++++--------- .../extend/os/linux/dev-cmd/update-test.rb | 18 +- .../Homebrew/test/dev-cmd/update-test_spec.rb | 8 + 3 files changed, 164 insertions(+), 145 deletions(-) create mode 100644 Library/Homebrew/test/dev-cmd/update-test_spec.rb diff --git a/Library/Homebrew/dev-cmd/update-test.rb b/Library/Homebrew/dev-cmd/update-test.rb index c9e66b55d3..0c2c42a131 100644 --- a/Library/Homebrew/dev-cmd/update-test.rb +++ b/Library/Homebrew/dev-cmd/update-test.rb @@ -1,151 +1,158 @@ # typed: true # frozen_string_literal: true +require "abstract_command" require "cli/parser" +require "fileutils" + module Homebrew - sig { returns(CLI::Parser) } - def self.update_test_args - Homebrew::CLI::Parser.new do - description <<~EOS - Run a test of `brew update` with a new repository clone. - If no options are passed, use `origin/master` as the start commit. - EOS - switch "--to-tag", - description: "Set `HOMEBREW_UPDATE_TO_TAG` to test updating between tags." - switch "--keep-tmp", - description: "Retain the temporary directory containing the new repository clone." - flag "--commit=", - description: "Use the specified as the start commit." - flag "--before=", - description: "Use the commit at the specified as the start commit." + module DevCmd + class UpdateTest < AbstractCommand + include FileUtils - named_args :none - end - end - - def self.update_test - args = update_test_args.parse - - # Avoid `update-report.rb` tapping Homebrew/homebrew-core - ENV["HOMEBREW_UPDATE_TEST"] = "1" - - # Avoid accidentally updating when we don't expect it. - ENV["HOMEBREW_NO_AUTO_UPDATE"] = "1" - - # Use default behaviours - ENV["HOMEBREW_AUTO_UPDATE_SECS"] = nil - ENV["HOMEBREW_DEVELOPER"] = nil - ENV["HOMEBREW_DEV_CMD_RUN"] = nil - ENV["HOMEBREW_MERGE"] = nil - ENV["HOMEBREW_NO_UPDATE_CLEANUP"] = nil - - branch = if args.to_tag? - ENV["HOMEBREW_UPDATE_TO_TAG"] = "1" - "stable" - else - ENV["HOMEBREW_UPDATE_TO_TAG"] = nil - "master" - end - - # Utils.popen_read returns a String without a block argument, but that isn't easily typed. We thus label this - # as untyped for now. - start_commit = T.let("", T.untyped) - end_commit = "HEAD" - cd HOMEBREW_REPOSITORY do - start_commit = if (commit = args.commit) - commit - elsif (date = args.before) - Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp - elsif args.to_tag? - tags = git_tags - current_tag, previous_tag, = tags.lines - current_tag = current_tag.to_s.chomp - odie "Could not find current tag in:\n#{tags}" if current_tag.empty? - # ^0 ensures this points to the commit rather than the tag object. - end_commit = "#{current_tag}^0" - - previous_tag = previous_tag.to_s.chomp - odie "Could not find previous tag in:\n#{tags}" if previous_tag.empty? - # ^0 ensures this points to the commit rather than the tag object. - "#{previous_tag}^0" - else - Utils.popen_read("git", "merge-base", "origin/master", end_commit).chomp - end - odie "Could not find start commit!" if start_commit.empty? - - start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp - odie "Could not find start commit!" if start_commit.empty? - - end_commit = T.cast(Utils.popen_read("git", "rev-parse", end_commit).chomp, String) - odie "Could not find end commit!" if end_commit.empty? - - if Utils.popen_read("git", "branch", "--list", "master").blank? - safe_system "git", "branch", "master", "origin/master" - end - end - - puts <<~EOS - Start commit: #{start_commit} - End commit: #{end_commit} - EOS - - mkdir "update-test" - chdir "update-test" do - curdir = Pathname.new(Dir.pwd) - - oh1 "Preparing test environment..." - # copy Homebrew installation - safe_system "git", "clone", "#{HOMEBREW_REPOSITORY}/.git", ".", - "--branch", "master", "--single-branch" - - # set git origin to another copy - safe_system "git", "clone", "#{HOMEBREW_REPOSITORY}/.git", "remote.git", - "--bare", "--branch", "master", "--single-branch" - safe_system "git", "config", "remote.origin.url", "#{curdir}/remote.git" - ENV["HOMEBREW_BREW_GIT_REMOTE"] = "#{curdir}/remote.git" - - # force push origin to end_commit - safe_system "git", "checkout", "-B", "master", end_commit - safe_system "git", "push", "--force", "origin", "master" - - # set test copy to start_commit - safe_system "git", "reset", "--hard", start_commit - - # update ENV["PATH"] - ENV["PATH"] = PATH.new(ENV.fetch("PATH")).prepend(curdir/"bin").to_s - - # run brew help to install portable-ruby (if needed) - quiet_system "brew", "help" - - # run brew update - oh1 "Running `brew update`..." - safe_system "brew", "update", "--verbose", "--debug" - actual_end_commit = Utils.popen_read("git", "rev-parse", branch).chomp - if actual_end_commit != end_commit - start_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", start_commit).chomp - end_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", end_commit).chomp - actual_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", actual_end_commit).chomp - odie <<~EOS - `brew update` didn't update #{branch}! - Start commit: #{start_log} - Expected end commit: #{end_log} - Actual end commit: #{actual_log} + cmd_args do + description <<~EOS + Run a test of `brew update` with a new repository clone. + If no options are passed, use `origin/master` as the start commit. EOS - end - end - ensure - FileUtils.rm_rf "update-test" unless args.keep_tmp? - end + switch "--to-tag", + description: "Set `HOMEBREW_UPDATE_TO_TAG` to test updating between tags." + switch "--keep-tmp", + description: "Retain the temporary directory containing the new repository clone." + flag "--commit=", + description: "Use the specified as the start commit." + flag "--before=", + description: "Use the commit at the specified as the start commit." - def self.git_tags - tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname") - if tags.blank? - tags = if (HOMEBREW_REPOSITORY/".git/shallow").exist? - safe_system "git", "fetch", "--tags", "--depth=1" - Utils.popen_read("git", "tag", "--list", "--sort=-version:refname") + named_args :none + end + + sig { override.void } + def run + # Avoid `update-report.rb` tapping Homebrew/homebrew-core + ENV["HOMEBREW_UPDATE_TEST"] = "1" + + # Avoid accidentally updating when we don't expect it. + ENV["HOMEBREW_NO_AUTO_UPDATE"] = "1" + + # Use default behaviours + ENV["HOMEBREW_AUTO_UPDATE_SECS"] = nil + ENV["HOMEBREW_DEVELOPER"] = nil + ENV["HOMEBREW_DEV_CMD_RUN"] = nil + ENV["HOMEBREW_MERGE"] = nil + ENV["HOMEBREW_NO_UPDATE_CLEANUP"] = nil + + branch = if args.to_tag? + ENV["HOMEBREW_UPDATE_TO_TAG"] = "1" + "stable" + else + ENV["HOMEBREW_UPDATE_TO_TAG"] = nil + "master" + end + + # Utils.popen_read returns a String without a block argument, but that isn't easily typed. We thus label this + # as untyped for now. + start_commit = T.let("", T.untyped) + end_commit = "HEAD" + cd HOMEBREW_REPOSITORY do + start_commit = if (commit = args.commit) + commit + elsif (date = args.before) + Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp + elsif args.to_tag? + tags = git_tags + current_tag, previous_tag, = tags.lines + current_tag = current_tag.to_s.chomp + odie "Could not find current tag in:\n#{tags}" if current_tag.empty? + # ^0 ensures this points to the commit rather than the tag object. + end_commit = "#{current_tag}^0" + + previous_tag = previous_tag.to_s.chomp + odie "Could not find previous tag in:\n#{tags}" if previous_tag.empty? + # ^0 ensures this points to the commit rather than the tag object. + "#{previous_tag}^0" + else + Utils.popen_read("git", "merge-base", "origin/master", end_commit).chomp + end + odie "Could not find start commit!" if start_commit.empty? + + start_commit = Utils.popen_read("git", "rev-parse", start_commit).chomp + odie "Could not find start commit!" if start_commit.empty? + + end_commit = T.cast(Utils.popen_read("git", "rev-parse", end_commit).chomp, String) + odie "Could not find end commit!" if end_commit.empty? + + if Utils.popen_read("git", "branch", "--list", "master").blank? + safe_system "git", "branch", "master", "origin/master" + end + end + + puts <<~EOS + Start commit: #{start_commit} + End commit: #{end_commit} + EOS + + mkdir "update-test" + chdir "update-test" do + curdir = Pathname.new(Dir.pwd) + + oh1 "Preparing test environment..." + # copy Homebrew installation + safe_system "git", "clone", "#{HOMEBREW_REPOSITORY}/.git", ".", + "--branch", "master", "--single-branch" + + # set git origin to another copy + safe_system "git", "clone", "#{HOMEBREW_REPOSITORY}/.git", "remote.git", + "--bare", "--branch", "master", "--single-branch" + safe_system "git", "config", "remote.origin.url", "#{curdir}/remote.git" + ENV["HOMEBREW_BREW_GIT_REMOTE"] = "#{curdir}/remote.git" + + # force push origin to end_commit + safe_system "git", "checkout", "-B", "master", end_commit + safe_system "git", "push", "--force", "origin", "master" + + # set test copy to start_commit + safe_system "git", "reset", "--hard", start_commit + + # update ENV["PATH"] + ENV["PATH"] = PATH.new(ENV.fetch("PATH")).prepend(curdir/"bin").to_s + + # run brew help to install portable-ruby (if needed) + quiet_system "brew", "help" + + # run brew update + oh1 "Running `brew update`..." + safe_system "brew", "update", "--verbose", "--debug" + actual_end_commit = Utils.popen_read("git", "rev-parse", branch).chomp + if actual_end_commit != end_commit + start_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", start_commit).chomp + end_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", end_commit).chomp + actual_log = Utils.popen_read("git", "log", "-1", "--decorate", "--oneline", actual_end_commit).chomp + odie <<~EOS + `brew update` didn't update #{branch}! + Start commit: #{start_log} + Expected end commit: #{end_log} + Actual end commit: #{actual_log} + EOS + end + end + ensure + FileUtils.rm_rf "update-test" unless args.keep_tmp? + end + + private + + def git_tags + tags = Utils.popen_read("git", "tag", "--list", "--sort=-version:refname") + if tags.blank? + tags = if (HOMEBREW_REPOSITORY/".git/shallow").exist? + safe_system "git", "fetch", "--tags", "--depth=1" + Utils.popen_read("git", "tag", "--list", "--sort=-version:refname") + end + end + tags end end - tags end end diff --git a/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb b/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb index 792e3458a1..836a80c702 100644 --- a/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb +++ b/Library/Homebrew/extend/os/linux/dev-cmd/update-test.rb @@ -2,14 +2,18 @@ # frozen_string_literal: true module Homebrew - class << self - alias generic_git_tags git_tags + module DevCmd + class UpdateTest < AbstractCommand + alias generic_git_tags git_tags - sig { returns(String) } - def git_tags - tags = generic_git_tags - tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank? - tags + private + + sig { returns(String) } + def git_tags + tags = generic_git_tags + tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank? + tags + end end end end diff --git a/Library/Homebrew/test/dev-cmd/update-test_spec.rb b/Library/Homebrew/test/dev-cmd/update-test_spec.rb new file mode 100644 index 0000000000..2ac5b8fd60 --- /dev/null +++ b/Library/Homebrew/test/dev-cmd/update-test_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "cmd/shared_examples/args_parse" +require "dev-cmd/update-test" + +RSpec.describe Homebrew::DevCmd::UpdateTest do + it_behaves_like "parseable arguments" +end