| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "cli/parser" | 
					
						
							|  |  |  | require "utils/github" | 
					
						
							| 
									
										
										
										
											2023-05-17 23:48:58 +08:00
										 |  |  | require "utils/github/artifacts" | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | require "tmpdir" | 
					
						
							| 
									
										
										
										
											2020-08-22 14:21:02 +10:00
										 |  |  | require "formula" | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |   sig { returns(CLI::Parser) } | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.pr_pull_args | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     Homebrew::CLI::Parser.new do | 
					
						
							| 
									
										
										
										
											2021-01-15 15:04:02 -05:00
										 |  |  |       description <<~EOS | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |         Download and publish bottles, and apply the bottle commit from a | 
					
						
							| 
									
										
										
										
											2020-04-18 12:13:43 -04:00
										 |  |  |         pull request with artifacts generated by GitHub Actions. | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |         Requires write access to the repository. | 
					
						
							|  |  |  |       EOS | 
					
						
							|  |  |  |       switch "--no-upload", | 
					
						
							| 
									
										
										
										
											2021-06-07 15:13:29 +05:30
										 |  |  |              description: "Download the bottles but don't upload them." | 
					
						
							| 
									
										
										
										
											2021-04-02 16:47:56 +01:00
										 |  |  |       switch "--no-commit", | 
					
						
							|  |  |  |              description: "Do not generate a new commit before uploading." | 
					
						
							| 
									
										
										
										
											2023-03-19 23:44:44 +08:00
										 |  |  |       switch "--no-cherry-pick", | 
					
						
							|  |  |  |              description: "Do not cherry-pick commits from the pull request branch." | 
					
						
							| 
									
										
										
										
											2020-04-18 12:13:43 -04:00
										 |  |  |       switch "-n", "--dry-run", | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |              description: "Print what would be done rather than doing it." | 
					
						
							|  |  |  |       switch "--clean", | 
					
						
							|  |  |  |              description: "Do not amend the commits from pull requests." | 
					
						
							| 
									
										
										
										
											2020-08-14 13:40:21 +02:00
										 |  |  |       switch "--keep-old", | 
					
						
							|  |  |  |              description: "If the formula specifies a rebuild version, " \ | 
					
						
							|  |  |  |                           "attempt to preserve its value in the generated DSL." | 
					
						
							| 
									
										
										
										
											2023-03-28 21:51:01 +08:00
										 |  |  |       switch "--autosquash", | 
					
						
							|  |  |  |              description: "Automatically reformat and reword commits in the pull request to our " \ | 
					
						
							|  |  |  |                           "preferred format." | 
					
						
							| 
									
										
										
										
											2022-02-08 20:02:21 +08:00
										 |  |  |       switch "--no-autosquash", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "Skip automatically reformatting and rewording commits in the pull request to our " \ | 
					
						
							| 
									
										
										
										
											2023-12-07 22:58:54 +00:00
										 |  |  |                           "preferred format.", | 
					
						
							|  |  |  |              disable:     true, # odisabled: remove this switch with 4.3.0 | 
					
						
							|  |  |  |              hidden:      true | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       switch "--branch-okay", | 
					
						
							| 
									
										
										
										
											2020-09-17 16:22:36 +10:00
										 |  |  |              description: "Do not warn if pulling to a branch besides the repository default (useful for testing)." | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       switch "--resolve", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "When a patch fails to apply, leave in progress and allow user to resolve, " \ | 
					
						
							| 
									
										
										
										
											2020-04-18 12:13:43 -04:00
										 |  |  |                           "instead of aborting." | 
					
						
							| 
									
										
										
										
											2020-07-02 00:11:55 +10:00
										 |  |  |       switch "--warn-on-upload-failure", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "Warn instead of raising an error if the bottle upload fails. " \ | 
					
						
							| 
									
										
										
										
											2020-07-02 00:11:55 +10:00
										 |  |  |                           "Useful for repairing bottle uploads that previously failed." | 
					
						
							| 
									
										
										
										
											2024-01-25 10:31:22 -05:00
										 |  |  |       switch "--retain-bottle-dir", | 
					
						
							|  |  |  |              description: "Does not clean up the tmp directory for the bottle so it can be used later." | 
					
						
							| 
									
										
										
										
											2021-04-01 16:23:39 +05:30
										 |  |  |       flag   "--committer=", | 
					
						
							|  |  |  |              description: "Specify a committer name and email in `git`'s standard author format." | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |       flag   "--message=", | 
					
						
							| 
									
										
										
										
											2023-03-28 21:51:01 +08:00
										 |  |  |              depends_on:  "--autosquash", | 
					
						
							| 
									
										
										
										
											2024-03-10 03:56:25 +00:00
										 |  |  |              description: "Message to include when autosquashing revision bumps, deletions and rebuilds." | 
					
						
							| 
									
										
										
										
											2020-04-18 12:13:43 -04:00
										 |  |  |       flag   "--artifact=", | 
					
						
							| 
									
										
										
										
											2020-06-25 12:01:52 -04:00
										 |  |  |              description: "Download artifacts with the specified name (default: `bottles`)." | 
					
						
							| 
									
										
										
										
											2020-04-18 12:13:43 -04:00
										 |  |  |       flag   "--tap=", | 
					
						
							| 
									
										
										
										
											2020-06-25 12:01:52 -04:00
										 |  |  |              description: "Target tap repository (default: `homebrew/core`)." | 
					
						
							| 
									
										
										
										
											2020-06-20 21:55:49 +10:00
										 |  |  |       flag   "--root-url=", | 
					
						
							|  |  |  |              description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default." | 
					
						
							| 
									
										
										
										
											2021-04-28 14:57:41 -04:00
										 |  |  |       flag   "--root-url-using=", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "Use the specified download strategy class for downloading the bottle's URL instead of " \ | 
					
						
							| 
									
										
										
										
											2021-04-29 12:51:15 -04:00
										 |  |  |                           "Homebrew's default." | 
					
						
							| 
									
										
										
										
											2023-02-10 23:15:40 -05:00
										 |  |  |       comma_array "--workflows", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |                   description: "Retrieve artifacts from the specified workflow (default: `tests.yml`). " \ | 
					
						
							| 
									
										
										
										
											2020-12-18 10:09:23 -05:00
										 |  |  |                                "Can be a comma-separated list to include multiple workflows." | 
					
						
							| 
									
										
										
										
											2023-02-10 23:15:40 -05:00
										 |  |  |       comma_array "--ignore-missing-artifacts", | 
					
						
							| 
									
										
										
										
											2020-11-22 15:14:42 +01:00
										 |  |  |                   description: "Comma-separated list of workflows which can be ignored if they have not been run." | 
					
						
							| 
									
										
										
										
											2020-11-12 10:40:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 21:51:01 +08:00
										 |  |  |       conflicts "--clean", "--autosquash" | 
					
						
							| 
									
										
										
										
											2021-01-10 14:26:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 15:04:02 -05:00
										 |  |  |       named_args :pull_request, min: 1
 | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |   # Separates a commit message into subject, body, and trailers. | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.separate_commit_message(message) | 
					
						
							| 
									
										
										
										
											2020-06-10 19:27:05 +10:00
										 |  |  |     subject = message.lines.first.strip | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by") | 
					
						
							|  |  |  |     # from lines that look like regular body text. | 
					
						
							|  |  |  |     trailers, body = message.lines.drop(1).partition { |s| s.match?(/^[a-z-]+-by:/i) } | 
					
						
							| 
									
										
										
										
											2020-06-27 23:00:05 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 19:27:05 +10:00
										 |  |  |     trailers = trailers.uniq.join.strip | 
					
						
							|  |  |  |     body = body.join.strip.gsub(/\n{3,}/, "\n\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     [subject, body, trailers] | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |   def self.signoff!(git_repo, pull_request: nil, dry_run: false) | 
					
						
							|  |  |  |     subject, body, trailers = separate_commit_message(git_repo.commit_message) | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |     if pull_request | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |       # This is a tap pull request and approving reviewers should also sign-off. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |       tap = Tap.from_path(git_repo.pathname) | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |       review_trailers = GitHub.approved_reviews(tap.user, tap.full_name.split("/").last, pull_request).map do |r| | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |         "Signed-off-by: #{r["name"]} <#{r["email"]}>" | 
					
						
							| 
									
										
										
										
											2020-10-12 21:31:12 +11:00
										 |  |  |       end | 
					
						
							|  |  |  |       trailers = trailers.lines.concat(review_trailers).map(&:strip).uniq.join("\n") | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |       # Append the close message as well, unless the commit body already includes it. | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |       close_message = "Closes ##{pull_request}." | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |       body += "\n\n#{close_message}" unless body.include? close_message | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     git_args = Utils::Git.git, "-C", git_repo.pathname, "commit", "--amend", "--signoff", "--allow-empty", "--quiet", | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |                "--message", subject, "--message", body, "--message", trailers | 
					
						
							| 
									
										
										
										
											2020-06-10 19:27:05 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |     if dry_run | 
					
						
							|  |  |  |       puts(*git_args) | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2020-09-19 17:14:06 +10:00
										 |  |  |       safe_system(*git_args) | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.get_package(tap, subject_name, subject_path, content) | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |     if subject_path.to_s.start_with?("#{tap.cask_dir}/") | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |       cask = begin | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |         Cask::CaskLoader.load(content.dup) | 
					
						
							|  |  |  |       rescue Cask::CaskUnavailableError | 
					
						
							|  |  |  |         nil | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |       return cask | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     begin | 
					
						
							|  |  |  |       Formulary.from_contents(subject_name, subject_path, content, :stable) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     rescue FormulaUnavailableError | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  |       nil | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.determine_bump_subject(old_contents, new_contents, subject_path, reason: nil) | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     subject_path = Pathname(subject_path) | 
					
						
							|  |  |  |     tap          = Tap.from_path(subject_path) | 
					
						
							|  |  |  |     subject_name = subject_path.basename.to_s.chomp(".rb") | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |     is_cask      = subject_path.to_s.start_with?("#{tap.cask_dir}/") | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |     name         = is_cask ? "cask" : "formula" | 
					
						
							| 
									
										
										
										
											2020-11-10 00:11:22 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     new_package = get_package(tap, subject_name, subject_path, new_contents) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return "#{subject_name}: delete #{reason}".strip if new_package.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     old_package = get_package(tap, subject_name, subject_path, old_contents) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |     if old_package.blank? | 
					
						
							| 
									
										
										
										
											2022-04-04 14:14:00 +02:00
										 |  |  |       "#{subject_name} #{new_package.version} (new #{name})" | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |     elsif old_package.version != new_package.version | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       "#{subject_name} #{new_package.version}" | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |     elsif !is_cask && old_package.revision != new_package.revision | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       "#{subject_name}: revision #{reason}".strip | 
					
						
							| 
									
										
										
										
											2022-04-26 08:57:29 +02:00
										 |  |  |     elsif is_cask && old_package.sha256 != new_package.sha256 | 
					
						
							|  |  |  |       "#{subject_name}: checksum update #{reason}".strip | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       "#{subject_name}: #{reason || "rebuild"}".strip | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Cherry picks a single commit that modifies a single file. | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Potentially rewords this commit using {determine_bump_subject}. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:35:43 -07:00
										 |  |  |   def self.reword_package_commit(commit, file, git_repo:, reason: "", verbose: false, resolve: false) | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     package_file = git_repo.pathname / file | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     package_name = package_file.basename.to_s.chomp(".rb") | 
					
						
							| 
									
										
										
										
											2020-09-19 15:22:02 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     odebug "Cherry-picking #{package_file}: #{commit}" | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |     Utils::Git.cherry_pick!(git_repo.to_s, commit, verbose:, resolve:) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-24 22:34:09 +08:00
										 |  |  |     old_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD^") | 
					
						
							|  |  |  |     new_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD") | 
					
						
							| 
									
										
										
										
											2020-09-19 15:22:02 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |     bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:).strip | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     subject, body, trailers = separate_commit_message(git_repo.commit_message) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     if subject != bump_subject && !subject.start_with?("#{package_name}:") | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |       safe_system("git", "-C", git_repo.pathname, "commit", "--amend", "-q", | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |                   "-m", bump_subject, "-m", subject, "-m", body, "-m", trailers) | 
					
						
							|  |  |  |       ohai bump_subject | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       ohai subject | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Cherry picks multiple commits that each modify a single file. | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Words the commit according to {determine_bump_subject} with the body | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |   # corresponding to all the original commit messages combined. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:35:43 -07:00
										 |  |  |   def self.squash_package_commits(commits, file, git_repo:, reason: "", verbose: false, resolve: false) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     odebug "Squashing #{file}: #{commits.join " "}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Format commit messages into something similar to `git fmt-merge-message`. | 
					
						
							|  |  |  |     # * subject 1 | 
					
						
							|  |  |  |     # * subject 2 | 
					
						
							|  |  |  |     #   optional body | 
					
						
							|  |  |  |     # * subject 3 | 
					
						
							|  |  |  |     messages = [] | 
					
						
							|  |  |  |     trailers = [] | 
					
						
							|  |  |  |     commits.each do |commit| | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |       subject, body, trailer = separate_commit_message(git_repo.commit_message(commit)) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |       body = body.lines.map { |line| "  #{line.strip}" }.join("\n") | 
					
						
							|  |  |  |       messages << "* #{subject}\n#{body}".strip | 
					
						
							|  |  |  |       trailers << trailer | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the set of authors in this series. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     authors = Utils.safe_popen_read("git", "-C", git_repo.pathname, "show", | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |                                     "--no-patch", "--pretty=%an <%ae>", *commits).lines.map(&:strip).uniq.compact | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the author and date of the first commit of this series, which we use for the squashed commit. | 
					
						
							|  |  |  |     original_author = authors.shift | 
					
						
							| 
									
										
										
										
											2023-04-15 18:35:43 -07:00
										 |  |  |     original_date = Utils.safe_popen_read "git", "-C", git_repo.pathname, "show", "--no-patch", "--pretty=%ad", | 
					
						
							|  |  |  |                                           commits.first | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Generate trailers for coauthors and combine them with the existing trailers. | 
					
						
							|  |  |  |     co_author_trailers = authors.map { |au| "Co-authored-by: #{au}" } | 
					
						
							|  |  |  |     trailers = [trailers + co_author_trailers].flatten.uniq.compact | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Apply the patch series but don't commit anything yet. | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |     Utils::Git.cherry_pick!(git_repo.pathname, "--no-commit", *commits, verbose:, resolve:) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Determine the bump subject by comparing the original state of the tree to its current state. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     package_file = git_repo.pathname / file | 
					
						
							| 
									
										
										
										
											2023-04-15 19:35:00 -07:00
										 |  |  |     old_package = Utils::Git.file_at_commit(git_repo.pathname, file, "#{commits.first}^") | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |     new_package = package_file.read | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |     bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Commit with the new subject, body, and trailers. | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |     safe_system("git", "-C", git_repo.pathname, "commit", "--quiet", | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |                 "-m", bump_subject, "-m", messages.join("\n"), "-m", trailers.join("\n"), | 
					
						
							|  |  |  |                 "--author", original_author, "--date", original_date, "--", file) | 
					
						
							|  |  |  |     ohai bump_subject | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-29 17:11:51 +08:00
										 |  |  |   # TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`. | 
					
						
							|  |  |  |   def self.autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true) | 
					
						
							| 
									
										
										
										
											2023-04-15 19:35:00 -07:00
										 |  |  |     git_repo = tap.git_repo | 
					
						
							|  |  |  |     original_head = git_repo.head_ref | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-01 16:11:50 +00:00
										 |  |  |     commits = Utils.safe_popen_read("git", "-C", tap.path, "rev-list", | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |                                     "--reverse", "#{original_commit}..HEAD").lines.map(&:strip) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     # Generate a bidirectional mapping of commits <=> formula/cask files. | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     files_to_commits = {} | 
					
						
							| 
									
										
										
										
											2021-12-23 14:49:05 -05:00
										 |  |  |     commits_to_files = commits.to_h do |commit| | 
					
						
							| 
									
										
										
										
											2022-03-01 16:11:50 +00:00
										 |  |  |       files = Utils.safe_popen_read("git", "-C", tap.path, "diff-tree", "--diff-filter=AMD", | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |                                     "-r", "--name-only", "#{commit}^", commit).lines.map(&:strip) | 
					
						
							|  |  |  |       files.each do |file| | 
					
						
							|  |  |  |         files_to_commits[file] ||= [] | 
					
						
							|  |  |  |         files_to_commits[file] << commit | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |         tap_file = (tap.path/file).to_s | 
					
						
							|  |  |  |         if (tap_file.start_with?("#{tap.formula_dir}/") || tap_file.start_with?("#{tap.cask_dir}/")) && | 
					
						
							| 
									
										
										
										
											2022-04-04 13:24:05 +02:00
										 |  |  |            File.extname(file) == ".rb" | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |           next | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |         odie <<~EOS | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |           Autosquash can only squash commits that modify formula or cask files. | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |             File:   #{file} | 
					
						
							|  |  |  |             Commit: #{commit} | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       [commit, files] | 
					
						
							| 
									
										
										
										
											2021-12-23 14:49:05 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Reset to state before cherry-picking. | 
					
						
							| 
									
										
										
										
											2022-03-01 16:11:50 +00:00
										 |  |  |     safe_system "git", "-C", tap.path, "reset", "--hard", original_commit | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Iterate over every commit in the pull request series, but if we have to squash | 
					
						
							|  |  |  |     # multiple commits into one, ensure that we skip over commits we've already squashed. | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |     processed_commits = T.let([], T::Array[String]) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     commits.each do |commit| | 
					
						
							|  |  |  |       next if processed_commits.include? commit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       files = commits_to_files[commit] | 
					
						
							|  |  |  |       if files.length == 1 && files_to_commits[files.first].length == 1
 | 
					
						
							|  |  |  |         # If there's a 1:1 mapping of commits to files, just cherry pick and (maybe) reword. | 
					
						
							| 
									
										
										
										
											2023-04-15 19:35:00 -07:00
										 |  |  |         reword_package_commit( | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |           commit, files.first, git_repo:, reason:, verbose:, resolve: | 
					
						
							| 
									
										
										
										
											2023-04-15 19:35:00 -07:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |         processed_commits << commit | 
					
						
							|  |  |  |       elsif files.length == 1 && files_to_commits[files.first].length > 1
 | 
					
						
							|  |  |  |         # If multiple commits modify a single file, squash them down into a single commit. | 
					
						
							|  |  |  |         file = files.first | 
					
						
							|  |  |  |         commits = files_to_commits[file] | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         squash_package_commits(commits, file, git_repo:, reason:, verbose:, resolve:) | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |         processed_commits += commits | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         # We can't split commits (yet) so just raise an error. | 
					
						
							|  |  |  |         odie <<~EOS | 
					
						
							|  |  |  |           Autosquash can't split commits that modify multiple files. | 
					
						
							|  |  |  |             Commit: #{commit} | 
					
						
							|  |  |  |             Files:  #{files.join " "} | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   rescue | 
					
						
							| 
									
										
										
										
											2023-03-29 17:11:51 +08:00
										 |  |  |     opoo "Autosquash encountered an error; resetting to original state at #{original_head}" | 
					
						
							| 
									
										
										
										
											2022-03-01 16:11:50 +00:00
										 |  |  |     system "git", "-C", tap.path, "reset", "--hard", original_head | 
					
						
							| 
									
										
										
										
											2023-03-29 17:11:51 +08:00
										 |  |  |     system "git", "-C", tap.path, "cherry-pick", "--abort" if cherry_picked | 
					
						
							| 
									
										
										
										
											2020-06-28 18:27:45 +10:00
										 |  |  |     raise | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |   def self.cherry_pick_pr!(user, repo, pull_request, args:, path: ".") | 
					
						
							| 
									
										
										
										
											2020-07-25 04:27:40 +02:00
										 |  |  |     if args.dry_run? | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       puts <<~EOS | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |         git fetch --force origin +refs/pull/#{pull_request}/head | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |         git merge-base HEAD FETCH_HEAD | 
					
						
							|  |  |  |         git cherry-pick --ff --allow-empty $merge_base..FETCH_HEAD | 
					
						
							|  |  |  |       EOS | 
					
						
							| 
									
										
										
										
											2020-09-17 16:06:41 +10:00
										 |  |  |       return | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-09-17 16:06:41 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |     commits = GitHub.pull_request_commits(user, repo, pull_request) | 
					
						
							| 
									
										
										
										
											2020-09-17 16:06:41 +10:00
										 |  |  |     safe_system "git", "-C", path, "fetch", "--quiet", "--force", "origin", commits.last | 
					
						
							| 
									
										
										
										
											2023-04-18 15:06:50 -07:00
										 |  |  |     ohai "Using #{commits.count} commit#{"s" if commits.count != 1} from ##{pull_request}" | 
					
						
							| 
									
										
										
										
											2020-09-17 16:06:41 +10:00
										 |  |  |     Utils::Git.cherry_pick!(path, "--ff", "--allow-empty", *commits, verbose: args.verbose?, resolve: args.resolve?) | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 21:59:53 +08:00
										 |  |  |   def self.formulae_need_bottles?(tap, original_commit, labels, args:) | 
					
						
							| 
									
										
										
										
											2023-12-14 02:52:30 +00:00
										 |  |  |     return false if args.dry_run? | 
					
						
							| 
									
										
										
										
											2021-07-08 13:43:43 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |     return false if labels.include?("CI-syntax-only") || labels.include?("CI-no-bottles") | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     changed_packages(tap, original_commit).any? do |f| | 
					
						
							| 
									
										
										
										
											2022-05-30 14:59:14 +01:00
										 |  |  |       !f.instance_of?(Cask::Cask) | 
					
						
							| 
									
										
										
										
											2020-06-20 21:55:49 +10:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.changed_packages(tap, original_commit) | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     formulae = Utils.popen_read("git", "-C", tap.path, "diff-tree", | 
					
						
							|  |  |  |                                 "-r", "--name-only", "--diff-filter=AM", | 
					
						
							|  |  |  |                                 original_commit, "HEAD", "--", tap.formula_dir) | 
					
						
							|  |  |  |                     .lines | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |                     .filter_map do |line| | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       next unless line.end_with? ".rb\n" | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       name = "#{tap.name}/#{File.basename(line.chomp, ".rb")}" | 
					
						
							|  |  |  |       if Homebrew::EnvConfig.disable_load_formula? | 
					
						
							|  |  |  |         opoo "Can't check if updated bottles are necessary as HOMEBREW_DISABLE_LOAD_FORMULA is set!" | 
					
						
							|  |  |  |         break | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       begin | 
					
						
							|  |  |  |         Formulary.resolve(name) | 
					
						
							|  |  |  |       rescue FormulaUnavailableError | 
					
						
							|  |  |  |         nil | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     casks = Utils.popen_read("git", "-C", tap.path, "diff-tree", | 
					
						
							|  |  |  |                              "-r", "--name-only", "--diff-filter=AM", | 
					
						
							|  |  |  |                              original_commit, "HEAD", "--", tap.cask_dir) | 
					
						
							|  |  |  |                  .lines | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |                  .filter_map do |line| | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  |       next unless line.end_with? ".rb\n" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       name = "#{tap.name}/#{File.basename(line.chomp, ".rb")}" | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |       begin | 
					
						
							|  |  |  |         Cask::CaskLoader.load(name) | 
					
						
							|  |  |  |       rescue Cask::CaskUnavailableError | 
					
						
							|  |  |  |         nil | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-02-22 23:29:55 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2022-01-10 18:57:56 +02:00
										 |  |  |     formulae + casks | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |   def self.pr_check_conflicts(repo, pull_request) | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |     long_build_pr_files = GitHub.issues( | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       repo:, state: "open", labels: "no long build conflict", | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |     ).each_with_object({}) do |long_build_pr, hash| | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |       next unless long_build_pr.key?("pull_request") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |       number = long_build_pr["number"] | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |       next if number == pull_request.to_i | 
					
						
							| 
									
										
										
										
											2022-08-05 21:41:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |       GitHub.get_pull_request_changed_files(repo, number).each do |file| | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |         key = file["filename"] | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |         hash[key] ||= [] | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |         hash[key] << number | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |     return if long_build_pr_files.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-23 23:41:44 +00:00
										 |  |  |     this_pr_files = GitHub.get_pull_request_changed_files(repo, pull_request) | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |     conflicts = this_pr_files.each_with_object({}) do |file, hash| | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |       filename = file["filename"] | 
					
						
							|  |  |  |       next unless long_build_pr_files.key?(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       long_build_pr_files[filename].each do |pr_number| | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |         key = "#{repo}/pull/#{pr_number}" | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |         hash[key] ||= [] | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |         hash[key] << filename | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |     return if conflicts.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Raise an error, display the conflicting PR. For example: | 
					
						
							|  |  |  |     # Error: You are trying to merge a pull request that conflicts with a long running build in: | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |     # { | 
					
						
							|  |  |  |     #   "homebrew-core/pull/98809": [ | 
					
						
							|  |  |  |     #    "Formula/icu4c.rb", | 
					
						
							|  |  |  |     #    "Formula/node@10.rb" | 
					
						
							|  |  |  |     #   ] | 
					
						
							|  |  |  |     # } | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |     odie <<~EOS | 
					
						
							|  |  |  |       You are trying to merge a pull request that conflicts with a long running build in: | 
					
						
							| 
									
										
										
										
											2022-08-04 23:18:19 +02:00
										 |  |  |       #{JSON.pretty_generate(conflicts)} | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  |     EOS | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 18:31:26 -07:00
										 |  |  |   def self.pr_pull | 
					
						
							| 
									
										
										
										
											2020-07-25 04:27:40 +02:00
										 |  |  |     args = pr_pull_args.parse | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-02 05:19:41 +00:00
										 |  |  |     # Needed when extracting the CI artifact. | 
					
						
							|  |  |  |     ensure_executable!("unzip", reason: "extracting CI artifacts") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-25 09:18:10 +00:00
										 |  |  |     workflows = args.workflows.presence || ["tests.yml"] | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |     artifact = args.artifact || "bottles" | 
					
						
							| 
									
										
										
										
											2020-04-14 00:10:02 +10:00
										 |  |  |     tap = Tap.fetch(args.tap || CoreTap.instance.name) | 
					
						
							| 
									
										
										
										
											2023-06-22 16:53:46 +01:00
										 |  |  |     raise TapUnavailableError, tap.name unless tap.installed? | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:23:39 +05:30
										 |  |  |     Utils::Git.set_name_email!(committer: args.committer.blank?) | 
					
						
							| 
									
										
										
										
											2020-11-02 12:21:18 +00:00
										 |  |  |     Utils::Git.setup_gpg! | 
					
						
							| 
									
										
										
										
											2020-03-31 22:11:30 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:23:39 +05:30
										 |  |  |     if (committer = args.committer) | 
					
						
							|  |  |  |       committer = Utils.parse_author!(committer) | 
					
						
							|  |  |  |       ENV["GIT_COMMITTER_NAME"] = committer[:name] | 
					
						
							|  |  |  |       ENV["GIT_COMMITTER_EMAIL"] = committer[:email] | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 12:05:50 +02:00
										 |  |  |     args.named.uniq.each do |arg| | 
					
						
							| 
									
										
										
										
											2020-03-31 11:24:10 +02:00
										 |  |  |       arg = "#{tap.default_remote}/pull/#{arg}" if arg.to_i.positive? | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       url_match = arg.match HOMEBREW_PULL_OR_COMMIT_URL_REGEX | 
					
						
							|  |  |  |       _, user, repo, pr = *url_match | 
					
						
							|  |  |  |       odie "Not a GitHub pull request: #{arg}" unless pr | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |       git_repo = tap.git_repo | 
					
						
							| 
									
										
										
										
											2023-07-22 22:41:51 +01:00
										 |  |  |       if !git_repo.default_origin_branch? && !args.branch_okay? && !args.no_commit? && !args.no_cherry_pick? | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |         opoo "Current branch is #{git_repo.branch_name}: do you need to pull inside #{git_repo.origin_branch_name}?" | 
					
						
							| 
									
										
										
										
											2020-09-17 16:22:36 +10:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-28 21:59:53 +08:00
										 |  |  |       pr_labels = GitHub.pull_request_labels(user, repo, pr) | 
					
						
							|  |  |  |       if pr_labels.include?("autosquash") && !args.autosquash? | 
					
						
							|  |  |  |         opoo "Pull request is labelled `autosquash`: do you need to pass `--autosquash`?" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-03 20:54:09 +01:00
										 |  |  |       pr_check_conflicts("#{user}/#{repo}", pr) | 
					
						
							| 
									
										
										
										
											2022-07-04 19:34:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       ohai "Fetching #{tap} pull request ##{pr}" | 
					
						
							| 
									
										
										
										
											2024-02-26 16:58:39 +00:00
										 |  |  |       dir = Dir.mktmpdir("pr-pull-#{pr}-", HOMEBREW_TEMP) | 
					
						
							| 
									
										
										
										
											2024-01-25 10:31:22 -05:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |         cd dir do | 
					
						
							| 
									
										
										
										
											2023-04-15 18:13:38 -07:00
										 |  |  |           current_branch_head = ENV["GITHUB_SHA"] || tap.git_head | 
					
						
							| 
									
										
										
										
											2023-03-20 00:55:20 +08:00
										 |  |  |           original_commit = if args.no_cherry_pick? | 
					
						
							|  |  |  |             # TODO: Handle the case where `merge-base` returns multiple commits. | 
					
						
							|  |  |  |             Utils.safe_popen_read("git", "-C", tap.path, "merge-base", "origin/HEAD", current_branch_head).strip | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             current_branch_head | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2023-03-29 17:56:05 +08:00
										 |  |  |           odebug "Pull request merge-base: #{original_commit}" | 
					
						
							| 
									
										
										
										
											2021-04-06 13:30:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |           unless args.no_commit? | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |             cherry_pick_pr!(user, repo, pr, path: tap.path, args:) unless args.no_cherry_pick? | 
					
						
							| 
									
										
										
										
											2023-03-28 21:51:01 +08:00
										 |  |  |             if args.autosquash? && !args.dry_run? | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |               autosquash!(original_commit, tap:, cherry_picked: !args.no_cherry_pick?, | 
					
						
							| 
									
										
										
										
											2021-04-06 13:30:07 +01:00
										 |  |  |                           verbose: args.verbose?, resolve: args.resolve?, reason: args.message) | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2023-04-15 19:35:00 -07:00
										 |  |  |             signoff!(git_repo, pull_request: pr, dry_run: args.dry_run?) unless args.clean? | 
					
						
							| 
									
										
										
										
											2020-06-20 21:55:49 +10:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |           unless formulae_need_bottles?(tap, original_commit, pr_labels, args:) | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  |             ohai "Skipping artifacts for ##{pr} as the formulae don't need bottles" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:14:42 +01:00
										 |  |  |           workflows.each do |workflow| | 
					
						
							|  |  |  |             workflow_run = GitHub.get_workflow_run( | 
					
						
							|  |  |  |               user, repo, pr, workflow_id: workflow, artifact_name: artifact | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if args.ignore_missing_artifacts.present? && | 
					
						
							|  |  |  |                args.ignore_missing_artifacts.include?(workflow) && | 
					
						
							| 
									
										
										
										
											2020-11-24 23:06:46 +01:00
										 |  |  |                workflow_run.first.blank? | 
					
						
							| 
									
										
										
										
											2020-11-22 15:14:42 +01:00
										 |  |  |               # Ignore that workflow as it was not executed and we specified | 
					
						
							|  |  |  |               # that we could skip it. | 
					
						
							| 
									
										
										
										
											2021-01-24 21:40:41 -05:00
										 |  |  |               ohai "Ignoring workflow #{workflow} as requested by `--ignore-missing-artifacts`" | 
					
						
							| 
									
										
										
										
											2020-11-22 15:14:42 +01:00
										 |  |  |               next | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ohai "Downloading bottles for workflow: #{workflow}" | 
					
						
							|  |  |  |             url = GitHub.get_artifact_url(workflow_run) | 
					
						
							| 
									
										
										
										
											2023-05-17 11:39:40 +08:00
										 |  |  |             GitHub.download_artifact(url, pr) | 
					
						
							| 
									
										
										
										
											2020-11-22 15:14:42 +01:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-04-11 19:27:34 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |           next if args.no_upload? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 21:55:49 +10:00
										 |  |  |           upload_args = ["pr-upload"] | 
					
						
							| 
									
										
										
										
											2020-07-31 19:42:31 +02:00
										 |  |  |           upload_args << "--debug" if args.debug? | 
					
						
							|  |  |  |           upload_args << "--verbose" if args.verbose? | 
					
						
							| 
									
										
										
										
											2021-04-02 16:47:56 +01:00
										 |  |  |           upload_args << "--no-commit" if args.no_commit? | 
					
						
							| 
									
										
										
										
											2020-06-20 21:55:49 +10:00
										 |  |  |           upload_args << "--dry-run" if args.dry_run? | 
					
						
							| 
									
										
										
										
											2020-08-14 13:40:21 +02:00
										 |  |  |           upload_args << "--keep-old" if args.keep_old? | 
					
						
							| 
									
										
										
										
											2020-07-02 00:11:55 +10:00
										 |  |  |           upload_args << "--warn-on-upload-failure" if args.warn_on_upload_failure? | 
					
						
							| 
									
										
										
										
											2021-04-02 00:17:43 +02:00
										 |  |  |           upload_args << "--committer=#{args.committer}" if args.committer | 
					
						
							| 
									
										
										
										
											2020-08-14 13:40:21 +02:00
										 |  |  |           upload_args << "--root-url=#{args.root_url}" if args.root_url | 
					
						
							| 
									
										
										
										
											2021-04-28 14:57:41 -04:00
										 |  |  |           upload_args << "--root-url-using=#{args.root_url_using}" if args.root_url_using | 
					
						
							| 
									
										
										
										
											2020-07-01 23:59:07 +10:00
										 |  |  |           safe_system HOMEBREW_BREW_FILE, *upload_args | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-01-25 10:31:22 -05:00
										 |  |  |       ensure | 
					
						
							| 
									
										
										
										
											2024-01-25 11:50:19 -05:00
										 |  |  |         if args.retain_bottle_dir? && ENV["GITHUB_ACTIONS"] | 
					
						
							| 
									
										
										
										
											2024-01-25 11:45:20 -05:00
										 |  |  |           ohai "Bottle files retained at:", dir | 
					
						
							|  |  |  |           File.open(ENV.fetch("GITHUB_OUTPUT"), "a") do |f| | 
					
						
							|  |  |  |             f.puts "bottle_path=#{dir}" | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2024-01-25 10:31:22 -05:00
										 |  |  |         else | 
					
						
							|  |  |  |           FileUtils.remove_entry dir | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-03-30 00:47:38 +11:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |