Merge pull request #8410 from dawidd6/github-releases
Support bottle uploads to GitHub Releases
This commit is contained in:
		
						commit
						14741e3681
					
				@ -148,11 +148,7 @@ class Bintray
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def upload_bottle_json(json_files, publish_package: false, warn_on_error: false)
 | 
			
		||||
    bottles_hash = json_files.reduce({}) do |hash, json_file|
 | 
			
		||||
      hash.deep_merge(JSON.parse(IO.read(json_file)))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  def upload_bottles(bottles_hash, publish_package: false, warn_on_error: false)
 | 
			
		||||
    formula_packaged = {}
 | 
			
		||||
 | 
			
		||||
    bottles_hash.each do |formula_name, bottle_hash|
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ module Homebrew
 | 
			
		||||
      usage_banner <<~EOS
 | 
			
		||||
        `pr-upload` [<options>]
 | 
			
		||||
 | 
			
		||||
        Apply the bottle commit and publish bottles to Bintray.
 | 
			
		||||
        Apply the bottle commit and publish bottles to Bintray or GitHub Releases.
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "--no-publish",
 | 
			
		||||
             description: "Apply the bottle commit and upload the bottles, but don't publish them."
 | 
			
		||||
@ -30,30 +30,37 @@ module Homebrew
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def check_bottled_formulae(json_files)
 | 
			
		||||
    hashes = json_files.reduce({}) do |hash, json|
 | 
			
		||||
      hash.deep_merge(JSON.parse(IO.read(json)))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    hashes.each do |name, hash|
 | 
			
		||||
      formula_path = HOMEBREW_REPOSITORY/hash["formula"]["path"]
 | 
			
		||||
  def check_bottled_formulae(bottles_hash)
 | 
			
		||||
    bottles_hash.each do |name, bottle_hash|
 | 
			
		||||
      formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]
 | 
			
		||||
      formula_version = Formulary.factory(formula_path).pkg_version
 | 
			
		||||
      bottle_version = PkgVersion.parse hash["formula"]["pkg_version"]
 | 
			
		||||
      bottle_version = PkgVersion.parse bottle_hash["formula"]["pkg_version"]
 | 
			
		||||
      next if formula_version == bottle_version
 | 
			
		||||
 | 
			
		||||
      odie "Bottles are for #{name} #{bottle_version} but formula is version #{formula_version}!"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def github_releases?(bottles_hash)
 | 
			
		||||
    @github_releases ||= bottles_hash.values.all? do |bottle_hash|
 | 
			
		||||
      root_url = bottle_hash["bottle"]["root_url"]
 | 
			
		||||
      url_match = root_url.match HOMEBREW_RELEASES_URL_REGEX
 | 
			
		||||
      _, _, _, tag = *url_match
 | 
			
		||||
 | 
			
		||||
      tag
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pr_upload
 | 
			
		||||
    args = pr_upload_args.parse
 | 
			
		||||
 | 
			
		||||
    bintray_org = args.bintray_org || "homebrew"
 | 
			
		||||
    bintray = Bintray.new(org: bintray_org)
 | 
			
		||||
 | 
			
		||||
    json_files = Dir["*.json"]
 | 
			
		||||
    odie "No JSON files found in the current working directory" if json_files.empty?
 | 
			
		||||
 | 
			
		||||
    bottles_hash = json_files.reduce({}) do |hash, json_file|
 | 
			
		||||
      hash.deep_merge(JSON.parse(IO.read(json_file)))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    bottle_args = ["bottle", "--merge", "--write"]
 | 
			
		||||
    bottle_args << "--verbose" if args.verbose?
 | 
			
		||||
    bottle_args << "--debug" if args.debug?
 | 
			
		||||
@ -62,14 +69,51 @@ module Homebrew
 | 
			
		||||
    bottle_args += json_files
 | 
			
		||||
 | 
			
		||||
    if args.dry_run?
 | 
			
		||||
      service = if github_releases?(bottles_hash)
 | 
			
		||||
        "GitHub Releases"
 | 
			
		||||
      else
 | 
			
		||||
        "Bintray"
 | 
			
		||||
      end
 | 
			
		||||
      puts "brew #{bottle_args.join " "}"
 | 
			
		||||
      puts "Upload bottles described by these JSON files to Bintray:\n  #{json_files.join("\n  ")}"
 | 
			
		||||
      puts "Upload bottles described by these JSON files to #{service}:\n  #{json_files.join("\n  ")}"
 | 
			
		||||
      return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    check_bottled_formulae(bottles_hash)
 | 
			
		||||
 | 
			
		||||
    safe_system HOMEBREW_BREW_FILE, *bottle_args
 | 
			
		||||
 | 
			
		||||
    if github_releases?(bottles_hash)
 | 
			
		||||
      # Handle uploading to GitHub Releases.
 | 
			
		||||
      bottles_hash.each_value do |bottle_hash|
 | 
			
		||||
        root_url = bottle_hash["bottle"]["root_url"]
 | 
			
		||||
        url_match = root_url.match HOMEBREW_RELEASES_URL_REGEX
 | 
			
		||||
        _, user, repo, tag = *url_match
 | 
			
		||||
 | 
			
		||||
        # Ensure a release is created.
 | 
			
		||||
        release = begin
 | 
			
		||||
          GitHub.get_release user, repo, tag
 | 
			
		||||
          odebug "Existing GitHub release \"#{tag}\" found"
 | 
			
		||||
        rescue GitHub::HTTPNotFoundError
 | 
			
		||||
          odebug "Creating new GitHub release \"#{tag}\""
 | 
			
		||||
          GitHub.create_or_update_release user, repo, tag
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        # Upload bottles as release assets.
 | 
			
		||||
        bottle_hash["bottle"]["tags"].each_value do |tag_hash|
 | 
			
		||||
          remote_file = tag_hash["filename"]
 | 
			
		||||
          local_file = tag_hash["local_filename"]
 | 
			
		||||
          odebug "Uploading #{remote_file}"
 | 
			
		||||
          GitHub.upload_release_asset user, repo, release["id"], local_file: local_file, remote_file: remote_file
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      check_bottled_formulae(json_files)
 | 
			
		||||
      safe_system HOMEBREW_BREW_FILE, *bottle_args
 | 
			
		||||
      bintray.upload_bottle_json(json_files,
 | 
			
		||||
                                 publish_package: !args.no_publish?,
 | 
			
		||||
                                 warn_on_error:   args.warn_on_upload_failure?)
 | 
			
		||||
      # Handle uploading to Bintray.
 | 
			
		||||
      bintray_org = args.bintray_org || "homebrew"
 | 
			
		||||
      bintray = Bintray.new(org: bintray_org)
 | 
			
		||||
      bintray.upload_bottles(bottles_hash,
 | 
			
		||||
                             publish_package: !args.no_publish?,
 | 
			
		||||
                             warn_on_error:   args.warn_on_upload_failure?)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -112,6 +112,8 @@ HOMEBREW_PULL_API_REGEX =
 | 
			
		||||
  %r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
 | 
			
		||||
HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
 | 
			
		||||
  %r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})].freeze
 | 
			
		||||
HOMEBREW_RELEASES_URL_REGEX =
 | 
			
		||||
  %r{https://github\.com/([\w-]+)/([\w-]+)?/releases/download/(.+)}.freeze
 | 
			
		||||
 | 
			
		||||
require "PATH"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -175,7 +175,7 @@ module GitHub
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def open_api(url, data: nil, request_method: nil, scopes: [].freeze, parse_json: true)
 | 
			
		||||
  def open_api(url, data: nil, data_binary_path: nil, request_method: nil, scopes: [].freeze, parse_json: true)
 | 
			
		||||
    # This is a no-op if the user is opting out of using the GitHub API.
 | 
			
		||||
    return block_given? ? yield({}) : {} if Homebrew::EnvConfig.no_github_api?
 | 
			
		||||
 | 
			
		||||
@ -200,6 +200,11 @@ module GitHub
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if data_binary_path.present?
 | 
			
		||||
      args += ["--data-binary", "@#{data_binary_path}"]
 | 
			
		||||
      args += ["--header", "Content-Type: application/gzip"]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    headers_tmpfile = Tempfile.new("github_api_headers", HOMEBREW_TEMP)
 | 
			
		||||
    begin
 | 
			
		||||
      if data
 | 
			
		||||
@ -468,6 +473,33 @@ module GitHub
 | 
			
		||||
                  scopes:         CREATE_ISSUE_FORK_OR_PR_SCOPES)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def get_release(user, repo, tag)
 | 
			
		||||
    url = "#{API_URL}/repos/#{user}/#{repo}/releases/tags/#{tag}"
 | 
			
		||||
    open_api(url, request_method: :GET)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create_or_update_release(user, repo, tag, id: nil, name: nil, draft: false)
 | 
			
		||||
    url = "#{API_URL}/repos/#{user}/#{repo}/releases"
 | 
			
		||||
    method = if id
 | 
			
		||||
      url += "/#{id}"
 | 
			
		||||
      :PATCH
 | 
			
		||||
    else
 | 
			
		||||
      :POST
 | 
			
		||||
    end
 | 
			
		||||
    data = {
 | 
			
		||||
      tag_name: tag,
 | 
			
		||||
      name:     name || tag,
 | 
			
		||||
      draft:    draft,
 | 
			
		||||
    }
 | 
			
		||||
    open_api(url, data: data, request_method: method, scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def upload_release_asset(user, repo, id, local_file: nil, remote_file: nil)
 | 
			
		||||
    url = "https://uploads.github.com/repos/#{user}/#{repo}/releases/#{id}/assets"
 | 
			
		||||
    url += "?name=#{remote_file}" if remote_file
 | 
			
		||||
    open_api(url, data_binary_path: local_file, request_method: :POST, scopes: CREATE_ISSUE_FORK_OR_PR_SCOPES)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def get_artifact_url(user, repo, pr, workflow_id: "tests.yml", artifact_name: "bottles")
 | 
			
		||||
    scopes = CREATE_ISSUE_FORK_OR_PR_SCOPES
 | 
			
		||||
    base_url = "#{API_URL}/repos/#{user}/#{repo}"
 | 
			
		||||
 | 
			
		||||
@ -1113,7 +1113,7 @@ Requires write access to the repository.
 | 
			
		||||
 | 
			
		||||
### `pr-upload` [*`options`*]
 | 
			
		||||
 | 
			
		||||
Apply the bottle commit and publish bottles to Bintray.
 | 
			
		||||
Apply the bottle commit and publish bottles to Bintray or GitHub Releases.
 | 
			
		||||
 | 
			
		||||
* `--no-publish`:
 | 
			
		||||
  Apply the bottle commit and upload the bottles, but don't publish them.
 | 
			
		||||
 | 
			
		||||
@ -1547,7 +1547,7 @@ Use the specified \fIURL\fR as the root of the bottle\'s URL instead of Homebrew
 | 
			
		||||
Use the specified Bintray repository to automatically mirror stable URLs defined in the formulae (default: \fBmirror\fR)\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBpr\-upload\fR [\fIoptions\fR]"
 | 
			
		||||
Apply the bottle commit and publish bottles to Bintray\.
 | 
			
		||||
Apply the bottle commit and publish bottles to Bintray or GitHub Releases\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-no\-publish\fR
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user