| 
									
										
										
										
											2023-07-21 11:45:34 -04:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  | require "abstract_command" | 
					
						
							| 
									
										
										
										
											2023-07-25 06:38:00 -04:00
										 |  |  | require "bump_version_parser" | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | require "cask" | 
					
						
							| 
									
										
										
										
											2021-08-24 18:15:04 -07:00
										 |  |  | require "cask/download" | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | require "utils/tar" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |   module DevCmd | 
					
						
							|  |  |  |     class BumpCaskPr < AbstractCommand | 
					
						
							|  |  |  |       cmd_args do | 
					
						
							|  |  |  |         description <<~EOS | 
					
						
							|  |  |  |           Create a pull request to update <cask> with a new version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           A best effort to determine the <SHA-256> will be made if the value is not | 
					
						
							|  |  |  |           supplied by the user. | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         switch "-n", "--dry-run", | 
					
						
							|  |  |  |                description: "Print what would be done rather than doing it." | 
					
						
							|  |  |  |         switch "--write-only", | 
					
						
							|  |  |  |                description: "Make the expected file modifications without taking any Git actions." | 
					
						
							|  |  |  |         switch "--commit", | 
					
						
							|  |  |  |                depends_on:  "--write-only", | 
					
						
							|  |  |  |                description: "When passed with `--write-only`, generate a new commit after writing changes " \ | 
					
						
							|  |  |  |                             "to the cask file." | 
					
						
							|  |  |  |         switch "--no-audit", | 
					
						
							|  |  |  |                description: "Don't run `brew audit` before opening the PR." | 
					
						
							|  |  |  |         switch "--no-style", | 
					
						
							|  |  |  |                description: "Don't run `brew style --fix` before opening the PR." | 
					
						
							|  |  |  |         switch "--no-browse", | 
					
						
							|  |  |  |                description: "Print the pull request URL instead of opening in a browser." | 
					
						
							|  |  |  |         switch "--no-fork", | 
					
						
							|  |  |  |                description: "Don't try to fork the repository." | 
					
						
							|  |  |  |         flag   "--version=", | 
					
						
							|  |  |  |                description: "Specify the new <version> for the cask." | 
					
						
							|  |  |  |         flag   "--version-arm=", | 
					
						
							|  |  |  |                description: "Specify the new cask <version> for the ARM architecture." | 
					
						
							|  |  |  |         flag   "--version-intel=", | 
					
						
							|  |  |  |                description: "Specify the new cask <version> for the Intel architecture." | 
					
						
							|  |  |  |         flag   "--message=", | 
					
						
							|  |  |  |                description: "Prepend <message> to the default pull request message." | 
					
						
							|  |  |  |         flag   "--url=", | 
					
						
							|  |  |  |                description: "Specify the <URL> for the new download." | 
					
						
							|  |  |  |         flag   "--sha256=", | 
					
						
							|  |  |  |                description: "Specify the <SHA-256> checksum of the new download." | 
					
						
							|  |  |  |         flag   "--fork-org=", | 
					
						
							|  |  |  |                description: "Use the specified GitHub organization for forking." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts "--dry-run", "--write" | 
					
						
							|  |  |  |         conflicts "--version=", "--version-arm=" | 
					
						
							|  |  |  |         conflicts "--version=", "--version-intel=" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         named_args :cask, number: 1, without_api: true | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |       sig { override.void } | 
					
						
							|  |  |  |       def run | 
					
						
							|  |  |  |         # This will be run by `brew audit` or `brew style` later so run it first to | 
					
						
							|  |  |  |         # not start spamming during normal output. | 
					
						
							|  |  |  |         gem_groups = [] | 
					
						
							|  |  |  |         gem_groups << "style" if !args.no_audit? || !args.no_style? | 
					
						
							|  |  |  |         gem_groups << "audit" unless args.no_audit? | 
					
						
							|  |  |  |         Homebrew.install_bundler_gems!(groups: gem_groups) unless gem_groups.empty? | 
					
						
							| 
									
										
										
										
											2021-04-30 12:00:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         # As this command is simplifying user-run commands then let's just use a | 
					
						
							|  |  |  |         # user path, too. | 
					
						
							|  |  |  |         ENV["PATH"] = PATH.new(ORIGINAL_PATHS).to_s | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         # Use the user's browser, too. | 
					
						
							|  |  |  |         ENV["BROWSER"] = EnvConfig.browser | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-03 17:43:22 -08:00
										 |  |  |         cask = args.named.to_casks.fetch(0) | 
					
						
							| 
									
										
										
										
											2021-01-08 11:42:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         odie "This cask is not in a tap!" if cask.tap.blank? | 
					
						
							|  |  |  |         odie "This cask's tap is not a Git repository!" unless cask.tap.git? | 
					
						
							| 
									
										
										
										
											2021-01-08 11:42:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         odie <<~EOS unless cask.tap.allow_bump?(cask.token) | 
					
						
							|  |  |  |           Whoops, the #{cask.token} cask has its version update | 
					
						
							| 
									
										
										
										
											2024-05-31 10:23:13 +01:00
										 |  |  |           pull requests automatically opened by BrewTestBot every ~3 hours! | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           We'd still love your contributions, though, so try another one | 
					
						
							| 
									
										
										
										
											2025-04-26 16:43:48 +02:00
										 |  |  |           that is excluded from autobump list (i.e. it has 'no_autobump!' | 
					
						
							|  |  |  |           method or 'livecheck' block with 'skip'.) | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         EOS | 
					
						
							| 
									
										
										
										
											2024-03-01 09:15:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-23 16:47:06 +01:00
										 |  |  |         if !args.write_only? && GitHub.too_many_open_prs?(cask.tap) | 
					
						
							|  |  |  |           odie "You have too many PRs open: close or merge some first!" | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-03-28 11:56:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         new_version = BumpVersionParser.new( | 
					
						
							|  |  |  |           general: args.version, | 
					
						
							|  |  |  |           intel:   args.version_intel, | 
					
						
							|  |  |  |           arm:     args.version_arm, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         new_hash = unless (new_hash = args.sha256).nil? | 
					
						
							|  |  |  |           raise UsageError, "`--sha256` must not be empty." if new_hash.blank? | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           ["no_check", ":no_check"].include?(new_hash) ? :no_check : new_hash | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         new_base_url = unless (new_base_url = args.url).nil? | 
					
						
							|  |  |  |           raise UsageError, "`--url` must not be empty." if new_base_url.blank? | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           begin | 
					
						
							|  |  |  |             URI(new_base_url) | 
					
						
							|  |  |  |           rescue URI::InvalidURIError | 
					
						
							|  |  |  |             raise UsageError, "`--url` is not valid." | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-12-08 12:42:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         if new_version.blank? && new_base_url.nil? && new_hash.nil? | 
					
						
							|  |  |  |           raise UsageError, "No `--version`, `--url` or `--sha256` argument specified!" | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-23 16:47:06 +01:00
										 |  |  |         check_pull_requests(cask, new_version:) unless args.write_only? | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         replacement_pairs ||= [] | 
					
						
							|  |  |  |         branch_name = "bump-#{cask.token}" | 
					
						
							|  |  |  |         commit_message = nil | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         old_contents = File.read(cask.sourcefile_path) | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         if new_base_url | 
					
						
							|  |  |  |           commit_message ||= "#{cask.token}: update URL" | 
					
						
							| 
									
										
										
										
											2023-03-30 04:11:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           m = /^ +url "(.+?)"\n/m.match(old_contents) | 
					
						
							|  |  |  |           odie "Could not find old URL in cask!" if m.nil? | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           old_base_url = m.captures.fetch(0) | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           replacement_pairs << [ | 
					
						
							|  |  |  |             /#{Regexp.escape(old_base_url)}/, | 
					
						
							|  |  |  |             new_base_url.to_s, | 
					
						
							|  |  |  |           ] | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         if new_version.present? | 
					
						
							| 
									
										
										
										
											2025-05-23 16:47:06 +01:00
										 |  |  |           # For simplicity, our naming defers to the arm version if multiple architectures are specified | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           branch_version = new_version.arm || new_version.general | 
					
						
							|  |  |  |           if branch_version.is_a?(Cask::DSL::Version) | 
					
						
							|  |  |  |             commit_version = shortened_version(branch_version, cask:) | 
					
						
							|  |  |  |             branch_name = "bump-#{cask.token}-#{branch_version.tr(",:", "-")}" | 
					
						
							|  |  |  |             commit_message ||= "#{cask.token} #{commit_version}" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           replacement_pairs = replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         # Now that we have all replacement pairs, we will replace them further down | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         commit_message ||= "#{cask.token}: update checksum" if new_hash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Remove nested arrays where elements are identical | 
					
						
							|  |  |  |         replacement_pairs = replacement_pairs.reject { |pair| pair[0] == pair[1] }.uniq.compact | 
					
						
							|  |  |  |         Utils::Inreplace.inreplace_pairs(cask.sourcefile_path, | 
					
						
							|  |  |  |                                          replacement_pairs, | 
					
						
							|  |  |  |                                          read_only_run: args.dry_run?, | 
					
						
							|  |  |  |                                          silent:        args.quiet?) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         run_cask_audit(cask, old_contents) | 
					
						
							|  |  |  |         run_cask_style(cask, old_contents) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pr_info = { | 
					
						
							| 
									
										
										
										
											2025-04-09 22:55:56 +10:00
										 |  |  |           commits:     [{ | 
					
						
							|  |  |  |             commit_message:, | 
					
						
							|  |  |  |             old_contents:, | 
					
						
							|  |  |  |             sourcefile_path: cask.sourcefile_path, | 
					
						
							|  |  |  |           }], | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |           branch_name:, | 
					
						
							| 
									
										
										
										
											2025-04-09 22:55:56 +10:00
										 |  |  |           pr_message:  "Created with `brew bump-cask-pr`.", | 
					
						
							|  |  |  |           tap:         cask.tap, | 
					
						
							|  |  |  |           pr_title:    commit_message, | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-04-09 22:55:56 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-23 16:47:06 +01:00
										 |  |  |         GitHub.create_bump_pr(pr_info, args:) unless args.write_only? | 
					
						
							| 
									
										
										
										
											2023-10-23 19:17:35 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |       private | 
					
						
							| 
									
										
										
										
											2023-11-30 02:49:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |       sig { params(version: Cask::DSL::Version, cask: Cask::Cask).returns(Cask::DSL::Version) } | 
					
						
							|  |  |  |       def shortened_version(version, cask:) | 
					
						
							|  |  |  |         if version.before_comma == cask.version.before_comma | 
					
						
							|  |  |  |           version | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           version.before_comma | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-07-21 11:45:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 12:21:04 -04:00
										 |  |  |       sig { params(cask: Cask::Cask).returns(T::Array[[Symbol, Symbol]]) } | 
					
						
							|  |  |  |       def generate_system_options(cask) | 
					
						
							| 
									
										
										
										
											2025-04-06 08:44:33 -04:00
										 |  |  |         current_os = Homebrew::SimulateSystem.current_os | 
					
						
							|  |  |  |         current_os_is_macos = MacOSVersion::SYMBOLS.include?(current_os) | 
					
						
							| 
									
										
										
										
											2025-06-13 18:36:30 -04:00
										 |  |  |         newest_macos = MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym | 
					
						
							| 
									
										
											  
											
												bump-cask-pr: fix macOS host handling
`bump-cask-pr` was recently updated to add Linux support but the
change to the `replace_version_and_checksum` logic has broken the
command for casks that have on_system blocks that reference specific
macOS versions (e.g., `on_monterey :or_newer` in `logi-options+`).
The previous logic only simulated the arch, so the `current_os` value
on macOS was a specific version like `:sequoia`. The current logic
uses generic `:macos` values, which work for `on_macos` blocks but
don't work for blocks like `on_sequoia`, etc. This leads to an
`undefined method 'latest?' for nil` error, as `old_cask.version` is
`nil` in this scenario (i.e., none of the on_system blocks apply to
`:macos`, so `version` is never set).
This updates the method to only specify the OS in `system_options` if
the value doesn't align with the host (e.g., `:linux` on macOS),
which restores the previous behavior.
This also replaces `:macos` values with the newest macOS version
(e.g., `:sequoia`), so that `bump-cask-pr` on Linux can update casks
with on_system blocks that reference specific macOS versions. A
generic `:macos` value doesn't work with those on_system blocks, so
`version` is never called on Linux in that scenario but it works as
expected if we use the newest macOS value instead. This may not be
perfect but it brings `bump-cask-pr` a little closer to parity with
macOS on Linux.
Lastly, this skips `system_options` values where `old_cask` has no
version, as this means the cask doesn't apply to that OS/arch. We've
been seeing a related error on homebrew/cask autobump CI and this
guard should help to avoid it.
											
										 
											2025-04-03 00:23:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |         depends_on_archs = cask.depends_on.arch&.filter_map { |arch| arch[:type] }&.uniq | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												bump-cask-pr: fix macOS host handling
`bump-cask-pr` was recently updated to add Linux support but the
change to the `replace_version_and_checksum` logic has broken the
command for casks that have on_system blocks that reference specific
macOS versions (e.g., `on_monterey :or_newer` in `logi-options+`).
The previous logic only simulated the arch, so the `current_os` value
on macOS was a specific version like `:sequoia`. The current logic
uses generic `:macos` values, which work for `on_macos` blocks but
don't work for blocks like `on_sequoia`, etc. This leads to an
`undefined method 'latest?' for nil` error, as `old_cask.version` is
`nil` in this scenario (i.e., none of the on_system blocks apply to
`:macos`, so `version` is never set).
This updates the method to only specify the OS in `system_options` if
the value doesn't align with the host (e.g., `:linux` on macOS),
which restores the previous behavior.
This also replaces `:macos` values with the newest macOS version
(e.g., `:sequoia`), so that `bump-cask-pr` on Linux can update casks
with on_system blocks that reference specific macOS versions. A
generic `:macos` value doesn't work with those on_system blocks, so
`version` is never called on Linux in that scenario but it works as
expected if we use the newest macOS value instead. This may not be
perfect but it brings `bump-cask-pr` a little closer to parity with
macOS on Linux.
Lastly, this skips `system_options` values where `old_cask` has no
version, as this means the cask doesn't apply to that OS/arch. We've
been seeing a related error on homebrew/cask autobump CI and this
guard should help to avoid it.
											
										 
											2025-04-03 00:23:27 -04:00
										 |  |  |         # NOTE: We substitute the newest macOS (e.g. `:sequoia`) in place of | 
					
						
							|  |  |  |         # `:macos` values (when used), as a generic `:macos` value won't apply | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |         # to on_system blocks referencing macOS versions. | 
					
						
							|  |  |  |         os_values = [] | 
					
						
							|  |  |  |         arch_values = depends_on_archs.presence || [] | 
					
						
							|  |  |  |         if cask.on_system_blocks_exist? | 
					
						
							|  |  |  |           OnSystem::BASE_OS_OPTIONS.each do |os| | 
					
						
							|  |  |  |             os_values << if os == :macos | 
					
						
							| 
									
										
										
										
											2025-04-06 08:44:33 -04:00
										 |  |  |               (current_os_is_macos ? current_os : newest_macos) | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |             else | 
					
						
							|  |  |  |               os | 
					
						
							| 
									
										
											  
											
												bump-cask-pr: fix macOS host handling
`bump-cask-pr` was recently updated to add Linux support but the
change to the `replace_version_and_checksum` logic has broken the
command for casks that have on_system blocks that reference specific
macOS versions (e.g., `on_monterey :or_newer` in `logi-options+`).
The previous logic only simulated the arch, so the `current_os` value
on macOS was a specific version like `:sequoia`. The current logic
uses generic `:macos` values, which work for `on_macos` blocks but
don't work for blocks like `on_sequoia`, etc. This leads to an
`undefined method 'latest?' for nil` error, as `old_cask.version` is
`nil` in this scenario (i.e., none of the on_system blocks apply to
`:macos`, so `version` is never set).
This updates the method to only specify the OS in `system_options` if
the value doesn't align with the host (e.g., `:linux` on macOS),
which restores the previous behavior.
This also replaces `:macos` values with the newest macOS version
(e.g., `:sequoia`), so that `bump-cask-pr` on Linux can update casks
with on_system blocks that reference specific macOS versions. A
generic `:macos` value doesn't work with those on_system blocks, so
`version` is never called on Linux in that scenario but it works as
expected if we use the newest macOS value instead. This may not be
perfect but it brings `bump-cask-pr` a little closer to parity with
macOS on Linux.
Lastly, this skips `system_options` values where `old_cask` has no
version, as this means the cask doesn't apply to that OS/arch. We've
been seeing a related error on homebrew/cask autobump CI and this
guard should help to avoid it.
											
										 
											2025-04-03 00:23:27 -04:00
										 |  |  |             end | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           arch_values = OnSystem::ARCH_OPTIONS if arch_values.empty? | 
					
						
							| 
									
										
										
										
											2025-04-01 12:07:16 +01:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |           # Architecture is only relevant if on_system blocks are present or | 
					
						
							|  |  |  |           # the cask uses `depends_on arch`, otherwise we default to ARM for | 
					
						
							|  |  |  |           # consistency. | 
					
						
							| 
									
										
										
										
											2025-04-06 08:44:33 -04:00
										 |  |  |           os_values << (current_os_is_macos ? current_os : newest_macos) | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |           arch_values << :arm if arch_values.empty? | 
					
						
							| 
									
										
										
										
											2025-03-17 11:58:00 +01:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-05 12:21:04 -04:00
										 |  |  |         os_values.product(arch_values) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { | 
					
						
							|  |  |  |         params( | 
					
						
							|  |  |  |           cask:              Cask::Cask, | 
					
						
							|  |  |  |           new_hash:          T.any(NilClass, String, Symbol), | 
					
						
							|  |  |  |           new_version:       BumpVersionParser, | 
					
						
							|  |  |  |           replacement_pairs: T::Array[[T.any(Regexp, String), T.any(Pathname, String)]], | 
					
						
							|  |  |  |         ).returns(T::Array[[T.any(Regexp, String), T.any(Pathname, String)]]) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs) | 
					
						
							|  |  |  |         generate_system_options(cask).each do |os, arch| | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |           SimulateSystem.with(os:, arch:) do | 
					
						
							| 
									
										
										
										
											2025-04-01 12:07:16 +01:00
										 |  |  |             # Handle the cask being invalid for specific os/arch combinations | 
					
						
							|  |  |  |             old_cask = begin | 
					
						
							|  |  |  |               Cask::CaskLoader.load(cask.sourcefile_path) | 
					
						
							| 
									
										
										
										
											2025-04-03 17:35:26 -04:00
										 |  |  |             rescue Cask::CaskInvalidError, Cask::CaskUnreadableError | 
					
						
							| 
									
										
										
										
											2025-04-01 12:07:16 +01:00
										 |  |  |               raise unless cask.on_system_blocks_exist? | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             next if old_cask.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												bump-cask-pr: fix macOS host handling
`bump-cask-pr` was recently updated to add Linux support but the
change to the `replace_version_and_checksum` logic has broken the
command for casks that have on_system blocks that reference specific
macOS versions (e.g., `on_monterey :or_newer` in `logi-options+`).
The previous logic only simulated the arch, so the `current_os` value
on macOS was a specific version like `:sequoia`. The current logic
uses generic `:macos` values, which work for `on_macos` blocks but
don't work for blocks like `on_sequoia`, etc. This leads to an
`undefined method 'latest?' for nil` error, as `old_cask.version` is
`nil` in this scenario (i.e., none of the on_system blocks apply to
`:macos`, so `version` is never set).
This updates the method to only specify the OS in `system_options` if
the value doesn't align with the host (e.g., `:linux` on macOS),
which restores the previous behavior.
This also replaces `:macos` values with the newest macOS version
(e.g., `:sequoia`), so that `bump-cask-pr` on Linux can update casks
with on_system blocks that reference specific macOS versions. A
generic `:macos` value doesn't work with those on_system blocks, so
`version` is never called on Linux in that scenario but it works as
expected if we use the newest macOS value instead. This may not be
perfect but it brings `bump-cask-pr` a little closer to parity with
macOS on Linux.
Lastly, this skips `system_options` values where `old_cask` has no
version, as this means the cask doesn't apply to that OS/arch. We've
been seeing a related error on homebrew/cask autobump CI and this
guard should help to avoid it.
											
										 
											2025-04-03 00:23:27 -04:00
										 |  |  |             old_version = old_cask.version | 
					
						
							|  |  |  |             next unless old_version | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 12:07:53 -04:00
										 |  |  |             bump_version = new_version.send(arch) || new_version.general | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             old_version_regex = old_version.latest? ? ":latest" : %Q(["']#{Regexp.escape(old_version.to_s)}["']) | 
					
						
							|  |  |  |             replacement_pairs << [/version\s+#{old_version_regex}/m, | 
					
						
							|  |  |  |                                   "version #{bump_version.latest? ? ":latest" : %Q("#{bump_version}")}"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # We are replacing our version here so we can get the new hash | 
					
						
							|  |  |  |             tmp_contents = Utils::Inreplace.inreplace_pairs(cask.sourcefile_path, | 
					
						
							|  |  |  |                                                             replacement_pairs.uniq.compact, | 
					
						
							|  |  |  |                                                             read_only_run: true, | 
					
						
							|  |  |  |                                                             silent:        true) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 13:25:59 +01:00
										 |  |  |             tmp_cask = Cask::CaskLoader::FromContentLoader.new(tmp_contents) | 
					
						
							|  |  |  |                                                           .load(config: nil) | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |             old_hash = tmp_cask.sha256 | 
					
						
							|  |  |  |             if tmp_cask.version.latest? || new_hash == :no_check | 
					
						
							|  |  |  |               opoo "Ignoring specified `--sha256=` argument." if new_hash.is_a?(String) | 
					
						
							|  |  |  |               replacement_pairs << [/"#{old_hash}"/, ":no_check"] if old_hash != :no_check | 
					
						
							|  |  |  |             elsif old_hash == :no_check && new_hash != :no_check | 
					
						
							|  |  |  |               replacement_pairs << [":no_check", "\"#{new_hash}\""] if new_hash.is_a?(String) | 
					
						
							|  |  |  |             elsif new_hash && !cask.on_system_blocks_exist? && cask.languages.empty? | 
					
						
							|  |  |  |               replacement_pairs << [old_hash.to_s, new_hash.to_s] | 
					
						
							|  |  |  |             elsif old_hash != :no_check | 
					
						
							|  |  |  |               opoo "Multiple checksum replacements required; ignoring specified `--sha256` argument." if new_hash | 
					
						
							|  |  |  |               languages = if cask.languages.empty? | 
					
						
							|  |  |  |                 [nil] | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 cask.languages | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |               languages.each do |language| | 
					
						
							|  |  |  |                 new_cask        = Cask::CaskLoader.load(tmp_contents) | 
					
						
							|  |  |  |                 new_cask.config = if language.blank? | 
					
						
							|  |  |  |                   tmp_cask.config | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                   tmp_cask.config.merge(Cask::Config.new(explicit: { languages: [language] })) | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |                 download = Cask::Download.new(new_cask, quarantine: true).fetch(verify_download_integrity: false) | 
					
						
							|  |  |  |                 Utils::Tar.validate_file(download) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if new_cask.sha256.to_s != download.sha256 | 
					
						
							|  |  |  |                   replacement_pairs << [new_cask.sha256.to_s, | 
					
						
							|  |  |  |                                         download.sha256] | 
					
						
							|  |  |  |                 end | 
					
						
							|  |  |  |               end | 
					
						
							| 
									
										
										
										
											2023-07-21 11:45:34 -04:00
										 |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         replacement_pairs | 
					
						
							| 
									
										
										
										
											2023-07-21 11:45:34 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |       sig { params(cask: Cask::Cask, new_version: BumpVersionParser).void } | 
					
						
							|  |  |  |       def check_pull_requests(cask, new_version:) | 
					
						
							| 
									
										
										
										
											2024-09-25 09:52:28 -04:00
										 |  |  |         tap_remote_repo = cask.tap.full_name || cask.tap.remote_repository | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-30 08:55:13 +01:00
										 |  |  |         file = cask.sourcefile_path.relative_path_from(cask.tap.path).to_s | 
					
						
							|  |  |  |         quiet = args.quiet? | 
					
						
							| 
									
										
										
										
											2025-04-01 11:01:17 +01:00
										 |  |  |         official_tap = cask.tap.official? | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo, | 
					
						
							| 
									
										
										
										
											2025-04-01 11:01:17 +01:00
										 |  |  |                                                  state: "open", file:, quiet:, official_tap:) | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-30 08:55:13 +01:00
										 |  |  |         # if we haven't already found open requests, try for an exact match across all pull requests | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         new_version.instance_variables.each do |version_type| | 
					
						
							| 
									
										
										
										
											2024-08-30 08:55:13 +01:00
										 |  |  |           version_type_version = new_version.instance_variable_get(version_type) | 
					
						
							|  |  |  |           next if version_type_version.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           version = shortened_version(version_type_version, cask:) | 
					
						
							| 
									
										
										
										
											2025-04-01 11:01:17 +01:00
										 |  |  |           GitHub.check_for_duplicate_pull_requests(cask.token, tap_remote_repo, version:, | 
					
						
							|  |  |  |                                                    file:, quiet:, official_tap:) | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { params(cask: Cask::Cask, old_contents: String).void } | 
					
						
							|  |  |  |       def run_cask_audit(cask, old_contents) | 
					
						
							|  |  |  |         if args.dry_run? | 
					
						
							|  |  |  |           if args.no_audit? | 
					
						
							|  |  |  |             ohai "Skipping `brew audit`" | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             ohai "brew audit --cask --online #{cask.full_name}" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         failed_audit = false | 
					
						
							|  |  |  |         if args.no_audit? | 
					
						
							|  |  |  |           ohai "Skipping `brew audit`" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           system HOMEBREW_BREW_FILE, "audit", "--cask", "--online", cask.full_name | 
					
						
							|  |  |  |           failed_audit = !$CHILD_STATUS.success? | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         return unless failed_audit | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         cask.sourcefile_path.atomic_write(old_contents) | 
					
						
							|  |  |  |         odie "`brew audit` failed!" | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |       sig { params(cask: Cask::Cask, old_contents: String).void } | 
					
						
							|  |  |  |       def run_cask_style(cask, old_contents) | 
					
						
							|  |  |  |         if args.dry_run? | 
					
						
							|  |  |  |           if args.no_style? | 
					
						
							|  |  |  |             ohai "Skipping `brew style --fix`" | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             ohai "brew style --fix #{cask.sourcefile_path.basename}" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         failed_style = false | 
					
						
							|  |  |  |         if args.no_style? | 
					
						
							|  |  |  |           ohai "Skipping `brew style --fix`" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           system HOMEBREW_BREW_FILE, "style", "--fix", cask.sourcefile_path | 
					
						
							|  |  |  |           failed_style = !$CHILD_STATUS.success? | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         return unless failed_style | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 15:56:38 -07:00
										 |  |  |         cask.sourcefile_path.atomic_write(old_contents) | 
					
						
							|  |  |  |         odie "`brew style --fix` failed!" | 
					
						
							| 
									
										
										
										
											2020-09-04 16:58:31 -07:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |