Class: Homebrew::DevCmd::BumpCaskPr Private
- Inherits:
-
AbstractCommand
- Object
- AbstractCommand
- Homebrew::DevCmd::BumpCaskPr
- Defined in:
- dev-cmd/bump-cask-pr.rb,
sorbet/rbi/dsl/homebrew/dev_cmd/bump_cask_pr.rbi
This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.
Defined Under Namespace
Classes: Args
Instance Method Summary collapse
- #args ⇒ Homebrew::DevCmd::BumpCaskPr::Args private
- #check_throttle(cask, new_version:) ⇒ void private
- #generate_system_options(cask, new_version) ⇒ Array<Array<(Symbol, Symbol)>> private
- #replace_cask_stanza_value(contents, name, old_value, new_value, within: nil) ⇒ String private
- #replace_version_and_checksum(cask, new_hash, new_version, contents) ⇒ String private
- #run ⇒ void private
Methods inherited from AbstractCommand
command, command_name, dev_cmd?, #initialize, parser, ruby_cmd?
Methods included from Utils::Output::Mixin
#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning
Constructor Details
This class inherits a constructor from Homebrew::AbstractCommand
Instance Method Details
#args ⇒ Homebrew::DevCmd::BumpCaskPr::Args
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
10 |
# File 'sorbet/rbi/dsl/homebrew/dev_cmd/bump_cask_pr.rbi', line 10 def args; end |
#check_throttle(cask, new_version:) ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
# File 'dev-cmd/bump-cask-pr.rb', line 394 def check_throttle(cask, new_version:) return unless cask.tap throttle_rate = cask.livecheck.throttle throttle_days = cask.livecheck.throttle_days return if throttle_rate.nil? && throttle_days.nil? version = new_version.arm || new_version.intel || new_version.general return unless version.is_a?(Cask::DSL::Version) return if Livecheck.throttle_allows_bump?(cask, version.to_s, throttle_rate:, throttle_days:) throttle_items = [] throttle_items << "#{throttle_rate} releases on multiples of #{throttle_rate}" if throttle_rate throttle_items << "#{throttle_days} #{Utils.pluralize("day", throttle_days)}" if throttle_days odie "#{cask.token} should only be updated every #{throttle_items.join(" or ")}" end |
#generate_system_options(cask, new_version) ⇒ Array<Array<(Symbol, Symbol)>>
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'dev-cmd/bump-cask-pr.rb', line 220 def (cask, new_version) current_os = Homebrew::SimulateSystem.current_os current_os_is_macos = MacOSVersion::SYMBOLS.include?(current_os) newest_macos = MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym # NOTE: We substitute the newest macOS (e.g. `:sequoia`) in place of # `:macos` values (when used), as a generic `:macos` value won't apply # to on_system blocks referencing macOS versions. os_values = [] arch_values = [] if new_version.arm || new_version.intel arch_values << :arm if new_version.arm arch_values << :intel if new_version.intel end if cask.on_system_blocks_exist? OnSystem::BASE_OS_OPTIONS.each do |os| os_values << if os == :macos (current_os_is_macos ? current_os : newest_macos) else os end end # `depends_on arch:` may be scoped to an `on_os` block, so arch # filtering is deferred to `replace_version_and_checksum`. arch_values = OnSystem::ARCH_OPTIONS.dup if arch_values.empty? else # Architecture is only relevant if on_system blocks are present or # the cask uses `depends_on arch`, otherwise we default to ARM for # consistency. os_values << (current_os_is_macos ? current_os : newest_macos) if arch_values.empty? depends_on_archs = cask.depends_on.arch&.filter_map { |arch| arch[:type] }&.uniq arch_values = depends_on_archs.presence || [:arm] end end if arch_values.length > 1 && !new_version.general # We sort arch values in descending order by version to mitigate the # issue where updating multiple arch-specific versions can lead to # incorrect version changes in the cask (e.g. ARM is version 1.2.3, # Intel is updated to 1.2.3, ARM is updated to 1.2.4 and this # incorrectly replaces the 1.2.3 version for both archs). This is # something that should be handled by better version replacement logic # but this is a workaround for now. arch_values = arch_values.sort_by do |type| new_version_value = Version.new(new_version.send(type) || "0") Livecheck::LivecheckVersion.create(cask, new_version_value) end.reverse end os_values.product(arch_values) end |
#replace_cask_stanza_value(contents, name, old_value, new_value, within: nil) ⇒ String
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'dev-cmd/bump-cask-pr.rb', line 376 def replace_cask_stanza_value(contents, name, old_value, new_value, within: nil) return contents if old_value == new_value cask_ast = Utils::AST::CaskAST.new(contents) replacement_count = cask_ast.replace_stanza_value(name, old_value, new_value, within:) if replacement_count.zero? # Treat an already-applied replacement as a successful no-op so the # per-(os, arch) loop in `replace_version_and_checksum` can yield the # same general version more than once without raising. return contents if cask_ast.replace_stanza_value(name, new_value, new_value, within:).positive? raise "Could not find '#{name}' stanza with value #{old_value.inspect}!" end cask_ast.process end |
#replace_version_and_checksum(cask, new_hash, new_version, contents) ⇒ String
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'dev-cmd/bump-cask-pr.rb', line 284 def replace_version_and_checksum(cask, new_hash, new_version, contents) cask_sourcefile_path = cask.sourcefile_path raise "unexpected nil cask.sourcefile_path" unless cask_sourcefile_path contents = split_root_version_and_checksum(new_version, contents) old_cask = Homebrew::SimulateSystem.with(os: default_cask_os, arch: :arm) do Cask::CaskLoader.load(cask_sourcefile_path) end (cask, new_version).each do |os, arch| tag = Utils::Bottles::Tag.new(system: os, arch:) old_cask.refresh_for_tag(tag) do # Skip archs excluded by the cask's `depends_on arch:`. reloaded_archs = old_cask.depends_on.arch&.filter_map { |a| a[:type] }&.uniq next if reloaded_archs.present? && reloaded_archs.exclude?(arch) old_version = old_cask.version next unless old_version next if unsupported_nested_arch_stanza?(contents, :version, arch) || unsupported_nested_arch_stanza?(contents, :sha256, arch) bump_version = new_version.send(arch) || new_version.general next unless bump_version version_scope = cask_stanza_scope(contents, :version, arch) contents = replace_cask_stanza_value( contents, :version, old_version.latest? ? :latest : old_version.to_s, bump_version.latest? ? :latest : bump_version.to_s, within: version_scope ) tmp_cask = Cask::CaskLoader::FromContentLoader.new(contents) .load(config: nil) old_hash = tmp_cask.sha256 next if new_hash.is_a?(String) && old_hash.to_s == new_hash checksum_scope = cask_stanza_scope(contents, :sha256, arch) if tmp_cask.version.latest? || new_hash == :no_check opoo "Ignoring specified `--sha256=` argument." if new_hash.is_a?(String) if old_hash != :no_check contents = replace_cask_stanza_value(contents, :sha256, old_hash.to_s, :no_check, within: checksum_scope) end elsif old_hash == :no_check && new_hash != :no_check if new_hash.is_a?(String) && (!arch_specific_version_bump?(new_version) || checksum_scope) contents = replace_cask_stanza_value(contents, :sha256, :no_check, new_hash, within: checksum_scope) end elsif new_hash && cask.languages.empty? && (!cask.on_system_blocks_exist? || checksum_scope || arch_specific_version_bump?(new_version)) contents = replace_cask_stanza_value(contents, :sha256, old_hash.to_s, new_hash.to_s, within: checksum_scope) 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(contents) next unless new_cask.url 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).fetch(verify_download_integrity: false) Utils::Tar.validate_file(download) if new_cask.sha256.to_s != download.sha256 contents = replace_cask_stanza_value(contents, :sha256, new_cask.sha256.to_s, download.sha256, within: checksum_scope) end end end end end contents end |
#run ⇒ void
This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.
This method returns an undefined value.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'dev-cmd/bump-cask-pr.rb', line 62 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 = ["ast"] gem_groups << "style" if !args.no_audit? || !args.no_style? gem_groups << "audit" unless args.no_audit? Homebrew.install_bundler_gems!(groups: gem_groups) require "utils/ast" # 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 # Use the user's browser, too. ENV["BROWSER"] = EnvConfig.browser @cask_retried = T.let(false, T.nilable(T::Boolean)) cask = begin args.named.to_casks.fetch(0) rescue Cask::CaskUnavailableError raise if @cask_retried CoreCaskTap.instance.install(force: true) @cask_retried = true retry end tap = cask.tap odie "This cask is not in a tap!" if tap.nil? odie "This cask's tap is not a Git repository!" unless tap.git? odie <<~EOS unless tap.allow_bump?(cask.token) Whoops, the #{cask.token} cask has its version update pull requests automatically opened by BrewTestBot every ~3 hours! We'd still love your contributions, though, so try another one that is excluded from autobump list (i.e. it has 'no_autobump!' method or 'livecheck' block with 'skip'.) EOS if !args.write_only? && GitHub.too_many_open_prs?(cask.tap) odie "You have too many PRs open: close or merge some first!" end new_version = BumpVersionParser.new( general: args.version, intel: args.version_intel, arm: args.version_arm, ) new_hash = unless (new_hash = args.sha256).nil? raise UsageError, "`--sha256` must not be empty." if new_hash.blank? ["no_check", ":no_check"].include?(new_hash) ? :no_check : new_hash end new_base_url = unless (new_base_url = args.url).nil? raise UsageError, "`--url` must not be empty." if new_base_url.blank? begin URI(new_base_url) rescue URI::InvalidURIError raise UsageError, "`--url` is not valid." end end if new_version.blank? && new_base_url.nil? && new_hash.nil? raise UsageError, "No `--version`, `--url` or `--sha256` argument specified!" end check_throttle(cask, new_version:) check_pull_requests(cask, new_version:) unless args.write_only? branch_name = "bump-#{cask.token}" = nil sourcefile_path = cask.sourcefile_path raise "unexpected nil cask.sourcefile_path" unless sourcefile_path old_contents = sourcefile_path.read new_contents = old_contents if new_base_url ||= "#{cask.token}: update URL" cask_ast = Utils::AST::CaskAST.new(new_contents) cask_ast.replace_first_stanza_value(:url, new_base_url.to_s) new_contents = cask_ast.process end if new_version.present? # For simplicity, our naming defers to the arm version if multiple architectures are specified branch_version = new_version.arm || new_version.intel || 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(",:", "-")}" ||= "#{cask.token} #{commit_version}" # Append an arch-only suffix to the branch name and parenthetical to # the commit title if the cask is multi-arch but only one arch is # being updated if new_version.arm && !new_version.intel branch_name += "-arm-only" += " (arm only)" elsif new_version.intel && !new_version.arm branch_name += "-intel-only" += " (intel only)" end end before_contents = new_contents new_contents = replace_version_and_checksum(cask, new_hash, new_version, new_contents) raise "Unable to update cask" if new_contents == before_contents end ||= "#{cask.token}: update checksum" if new_hash # We should have already thrown UsageError above if there's nothing to update raise "Expected to have a commit message" if .nil? sourcefile_path.atomic_write(new_contents) unless args.dry_run? audit_exceptions = [] audit_exceptions << ["min_os", "rosetta", "signing"] if ENV["HOMEBREW_TEST_BOT_AUTOBUMP"].present? run_cask_audit(cask, old_contents, audit_exceptions) run_cask_style(cask, old_contents) return if args.write_only? && !args.commit? url = Homebrew::Bump.create_pr( Homebrew::Bump::BumpInfo.new( package_tap: cask.tap, branch_name:, pr_title: , pr_message: Homebrew::Bump.("bump-cask-pr", user_message: args.), commits: [ Homebrew::Bump::Commit.new( sourcefile_path:, old_contents:, commit_message:, ), ], ), dry_run: args.dry_run?, no_fork: args.no_fork? || args.write_only?, fork_org: args.fork_org, commit: args.commit?, ) return if url.blank? if args.no_browse? puts url else exec_browser url end end |