From 3ae261136524d58fb7f153dbfacc03528151a03e Mon Sep 17 00:00:00 2001
From: Seeker <meaningseeking@protonmail.com>
Date: Wed, 15 Jul 2020 08:16:33 -0700
Subject: [PATCH] bump-formula-pr: determine url/tag from version

---
 Library/Homebrew/dev-cmd/bump-formula-pr.rb | 129 ++++++++++++--------
 docs/Manpage.md                             |   7 +-
 manpages/brew.1                             |   5 +-
 3 files changed, 87 insertions(+), 54 deletions(-)

diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
index 4418d66d15..116d192665 100644
--- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb
+++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
@@ -18,7 +18,11 @@ module Homebrew
         be made if either or both values are not supplied by the user.
 
         If a <tag> is specified, the Git commit <revision> corresponding to that tag
-        must also be specified.
+        should also be specified. A best effort to determine the <revision> will be made
+        if the value is not supplied by the user.
+
+        If a <version> is specified, a best effort to determine the <URL> and <SHA-256> or
+        the <tag> and <revision> will be made if both values are not supplied by the user.
 
         *Note:* this command cannot be used to transition a formula from a
         URL-and-SHA-256 style specification into a tag-and-revision style specification,
@@ -58,8 +62,8 @@ module Homebrew
       flag   "--tag=",
              description: "Specify the new git commit <tag> for the formula."
       flag   "--revision=",
-             required_for: "--tag=",
-             description:  "Specify the new git commit <revision> corresponding to the specified <tag>."
+             depends_on:  "--tag=",
+             description: "Specify the new git commit <revision> corresponding to the specified <tag>."
       switch :force
       switch :quiet
       switch :verbose
@@ -119,31 +123,7 @@ module Homebrew
     formula = args.formulae.first
 
     new_url = args.url
-    if new_url && !formula
-      # Split the new URL on / and find any formulae that have the same URL
-      # except for the last component, but don't try to match any more than the
-      # first five components since sometimes the last component isn't the only
-      # one to change.
-      new_url_split = new_url.split("/")
-      maximum_url_components_to_match = 5
-      components_to_match = [new_url_split.count - 1, maximum_url_components_to_match].min
-      base_url = new_url_split.first(components_to_match).join("/")
-      base_url = /#{Regexp.escape(base_url)}/
-      is_devel = args.devel?
-      guesses = []
-      Formula.each do |f|
-        if is_devel && f.devel && f.devel.url && f.devel.url.match(base_url)
-          guesses << f
-        elsif f.stable&.url && f.stable.url.match(base_url)
-          guesses << f
-        end
-      end
-      if guesses.count == 1
-        formula = guesses.shift
-      elsif guesses.count > 1
-        odie "Couldn't guess formula for sure; could be one of these:\n#{guesses.map(&:name).join(", ")}"
-      end
-    end
+    formula ||= determine_formula_from_url(new_url, args.devel?) if new_url
     raise FormulaUnspecifiedError unless formula
 
     tap_full_name, origin_branch, previous_branch = use_correct_linux_tap(formula)
@@ -175,28 +155,41 @@ module Homebrew
       new_url.sub "mirrors.ocf.berkeley.edu/debian", "mirrorservice.org/sites/ftp.debian.org/debian"
     end
     new_mirrors ||= [new_mirror] unless new_mirror.nil?
-    forced_version = args.version
+    new_version = args.version
+    old_url = formula_spec.url
+    old_tag = formula_spec.specs[:tag]
+    old_formula_version = formula_version(formula, requested_spec)
+    old_version = old_formula_version.to_s
+    forced_version = false
     new_url_hash = if new_url && new_hash
       true
     elsif new_tag && new_revision
       false
     elsif !hash_type
-      odie "#{formula}: no --tag=/--revision= arguments specified!"
-    elsif !new_url
-      odie "#{formula}: no --url= argument specified!"
+      odie "#{formula}: no --tag= or --version= argument specified!" if !new_tag && !new_version
+      new_tag ||= old_tag.gsub(old_version, new_version)
+      if new_tag == old_tag
+        odie <<~EOS
+          You probably need to bump this formula manually since the new tag
+          and old tag are both #{new_tag}.
+        EOS
+      end
+      resource_path, forced_version = fetch_resource(formula, new_version, old_url, tag: new_tag)
+      new_revision = Utils.popen_read("git -C \"#{resource_path}\" rev-parse -q --verify HEAD")
+      new_revision = new_revision.strip
+      false
+    elsif !new_url && !new_version
+      odie "#{formula}: no --url= or --version= argument specified!"
     else
-      resource = Resource.new { @url = new_url }
-      resource.download_strategy = DownloadStrategyDetector.detect_from_url(new_url)
-      resource.owner = Resource.new(formula.name)
-      if forced_version
-        if forced_version == resource.version
-          forced_version = nil
-        else
-          resource.version = forced_version
-        end
+      new_url ||= old_url.gsub(old_version, new_version)
+      if new_url == old_url
+        odie <<~EOS
+          You probably need to bump this formula manually since the new URL
+          and old URL are both:
+            #{new_url}
+        EOS
       end
-      odie "No --version= argument specified!" unless resource.version
-      resource_path = resource.fetch
+      resource_path, forced_version = fetch_resource(formula, new_version, new_url)
       tar_file_extensions = %w[.tar .tb2 .tbz .tbz2 .tgz .tlz .txz .tZ]
       if tar_file_extensions.any? { |extension| new_url.include? extension }
         gnu_tar_gtar_path = HOMEBREW_PREFIX/"opt/gnu-tar/bin/gtar"
@@ -212,8 +205,6 @@ module Homebrew
       end
     end
 
-    old_formula_version = formula_version(formula, requested_spec)
-
     replacement_pairs = []
     if requested_spec == :stable && formula.revision.nonzero?
       replacement_pairs << [
@@ -273,32 +264,32 @@ module Homebrew
       ]
     end
 
-    if forced_version && forced_version != "0"
+    if forced_version && new_version != "0"
       case requested_spec
       when :stable
         replacement_pairs << if File.read(formula.path).include?("version \"#{old_formula_version}\"")
           [
             old_formula_version.to_s,
-            forced_version,
+            new_version,
           ]
         elsif new_mirrors
           [
             /^( +)(mirror "#{Regexp.escape(new_mirrors.last)}"\n)/m,
-            "\\1\\2\\1version \"#{forced_version}\"\n",
+            "\\1\\2\\1version \"#{new_version}\"\n",
           ]
         else
           [
             /^( +)(url "#{Regexp.escape(new_url)}"\n)/m,
-            "\\1\\2\\1version \"#{forced_version}\"\n",
+            "\\1\\2\\1version \"#{new_version}\"\n",
           ]
         end
       when :devel
         replacement_pairs << [
           /(  devel do.+?version ")#{old_formula_version}("\n.+?end\n)/m,
-          "\\1#{forced_version}\\2",
+          "\\1#{new_version}\\2",
         ]
       end
-    elsif forced_version && forced_version == "0"
+    elsif forced_version && new_version == "0"
       case requested_spec
       when :stable
         replacement_pairs << [
@@ -312,7 +303,7 @@ module Homebrew
         ]
       end
     end
-    new_contents = inreplace_pairs(formula.path, replacement_pairs)
+    new_contents = inreplace_pairs(formula.path, replacement_pairs.uniq)
 
     new_formula_version = formula_version(formula, requested_spec, new_contents)
 
@@ -413,6 +404,40 @@ module Homebrew
     end
   end
 
+  def determine_formula_from_url(url, is_devel)
+    # Split the new URL on / and find any formulae that have the same URL
+    # except for the last component, but don't try to match any more than the
+    # first five components since sometimes the last component isn't the only
+    # one to change.
+    url_split = url.split("/")
+    maximum_url_components_to_match = 5
+    components_to_match = [url_split.count - 1, maximum_url_components_to_match].min
+    base_url = url_split.first(components_to_match).join("/")
+    base_url = /#{Regexp.escape(base_url)}/
+    guesses = []
+    Formula.each do |f|
+      if is_devel && f.devel && f.devel.url && f.devel.url.match(base_url)
+        guesses << f
+      elsif f.stable&.url && f.stable.url.match(base_url)
+        guesses << f
+      end
+    end
+    return guesses.shift if guesses.count == 1
+    return unless guesses.count > 1
+
+    odie "Couldn't guess formula for sure; could be one of these:\n#{guesses.map(&:name).join(", ")}"
+  end
+
+  def fetch_resource(formula, new_version, url, **specs)
+    resource = Resource.new
+    resource.url(url, specs)
+    resource.owner = Resource.new(formula.name)
+    forced_version = new_version && new_version != resource.version
+    resource.version = new_version if forced_version
+    odie "No --version= argument specified!" unless resource.version
+    [resource.fetch, forced_version]
+  end
+
   def forked_repo_info(formula, tap_full_name, backup_file)
     response = GitHub.create_fork(tap_full_name)
   rescue GitHub::AuthenticationFailedError, *GitHub.api_errors => e
diff --git a/docs/Manpage.md b/docs/Manpage.md
index 9400e96410..64cf84e86a 100644
--- a/docs/Manpage.md
+++ b/docs/Manpage.md
@@ -707,7 +707,12 @@ be specified. A best effort to determine the *`SHA-256`* and *`formula`* name wi
 be made if either or both values are not supplied by the user.
 
 If a *`tag`* is specified, the Git commit *`revision`* corresponding to that tag
-must also be specified.
+should also be specified. A best effort to determine the *`revision`* will be made
+if the value is not supplied by the user.
+
+If a *`version`* is specified, a best effort to determine the *`URL`* and *`SHA-256`*
+or the *`tag`* and *`revision`* will be made if both values are not supplied by the
+user.
 
 *Note:* this command cannot be used to transition a formula from a
 URL-and-SHA-256 style specification into a tag-and-revision style specification,
diff --git a/manpages/brew.1 b/manpages/brew.1
index 0442395eed..8cb2c10c71 100644
--- a/manpages/brew.1
+++ b/manpages/brew.1
@@ -917,7 +917,10 @@ Create a pull request to update \fIformula\fR with a new URL or a new tag\.
 If a \fIURL\fR is specified, the \fISHA\-256\fR checksum of the new download should also be specified\. A best effort to determine the \fISHA\-256\fR and \fIformula\fR name will be made if either or both values are not supplied by the user\.
 .
 .P
-If a \fItag\fR is specified, the Git commit \fIrevision\fR corresponding to that tag must also be specified\.
+If a \fItag\fR is specified, the Git commit \fIrevision\fR corresponding to that tag should also be specified\. A best effort to determine the \fIrevision\fR will be made if the value is not supplied by the user\.
+.
+.P
+If a \fIversion\fR is specified, a best effort to determine the \fIURL\fR and \fISHA\-256\fR or the \fItag\fR and \fIrevision\fR will be made if both values are not supplied by the user\.
 .
 .P
 \fINote:\fR this command cannot be used to transition a formula from a URL\-and\-SHA\-256 style specification into a tag\-and\-revision style specification, nor vice versa\. It must use whichever style specification the formula already uses\.
-- 
GitLab