Skip to content

Instantly share code, notes, and snippets.

@ZPascal
Forked from minamijoyo/hoge.rb
Last active August 18, 2023 14:06
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save ZPascal/b21c652b811872b3f56db9d54d61d6c6 to your computer and use it in GitHub Desktop.
Save ZPascal/b21c652b811872b3f56db9d54d61d6c6 to your computer and use it in GitHub Desktop.
Using GitHubPrivateRepositoryReleaseDownloadStrategy removed in brew v2
require "formula"
require_relative "lib/private_strategy"
class Hoge < Formula
homepage "https://github.com/yourcompany/hoge"
url "https://github.com/yourcompany/hoge/releases/download/v0.1.0/hoge_v0.1.0_darwin_amd64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
sha256 "6de411ff3e4b1658a413dd6181fcXXXXXXXXXXXXXXXXXXXX"
head "https://github.com/yourcompany/hoge.git"
version "0.1.0"
def install
bin.install "hoge"
end
end
brew tap yourcompany/tap git@github.com:yourcompany/homebrew-tap.git
export HOMEBREW_GITHUB_API_TOKEN=xxx
brew install hoge
# Save this file as `lib/private_strategy.rb`
# Add `require_relative "lib/private_strategy"` to your formula.
#
# This is based on the following, with minor fixes.
# https://github.com/Homebrew/brew/blob/193af1442f6b9a19fa71325160d0ee2889a1b6c9/Library/Homebrew/compat/download_strategy.rb#L48-L157
# BSD 2-Clause License
#
# Copyright (c) 2009-present, Homebrew contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# GitHubPrivateRepositoryDownloadStrategy downloads contents from GitHub
# Private Repository. To use it, add
# `:using => GitHubPrivateRepositoryDownloadStrategy` to the URL section of
# your formula. This download strategy uses GitHub access tokens (in the
# environment variables `HOMEBREW_GITHUB_API_TOKEN`) to sign the request. This
# strategy is suitable for corporate use just like S3DownloadStrategy, because
# it lets you use a private GitHub repository for internal distribution. It
# works with public one, but in that case simply use CurlDownloadStrategy.
class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy
require "utils/formatter"
require "utils/github"
def initialize(url, name, version, **meta)
super
parse_url_pattern
set_github_token
end
def parse_url_pattern
unless match = url.match(%r{https://github.com/([^/]+)/([^/]+)/(\S+)})
raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Repository."
end
_, @owner, @repo, @filepath = *match
end
def download_url
"https://#{@github_token}@github.com/#{@owner}/#{@repo}/#{@filepath}"
end
private
def _fetch(url:, resolved_url:, timeout:)
curl_download download_url, to: temporary_path
end
def set_github_token
@github_token = ENV["HOMEBREW_GITHUB_API_TOKEN"]
unless @github_token
raise CurlDownloadStrategyError, "Environmental variable HOMEBREW_GITHUB_API_TOKEN is required."
end
validate_github_repository_access!
end
def validate_github_repository_access!
# Test access to the repository
GitHub.repository(@owner, @repo)
rescue GitHub::API::HTTPNotFoundError
# We switched to GitHub::API::HTTPNotFoundError,
# because we can now handle bad credentials messages
message = <<~EOS
HOMEBREW_GITHUB_API_TOKEN can not access the repository: #{@owner}/#{@repo}
This token may not have permission to access the repository or the url of formula may be incorrect.
EOS
raise CurlDownloadStrategyError, message
end
end
# GitHubPrivateRepositoryReleaseDownloadStrategy downloads tarballs from GitHub
# Release assets. To use it, add
# `:using => GitHubPrivateRepositoryReleaseDownloadStrategy` to the URL section of
# your formula. This download strategy uses GitHub access tokens (in the
# environment variables HOMEBREW_GITHUB_API_TOKEN) to sign the request.
class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDownloadStrategy
def initialize(url, name, version, **meta)
super
end
def parse_url_pattern
url_pattern = %r{https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\S+)}
unless @url =~ url_pattern
raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Release."
end
_, @owner, @repo, @tag, @filename = *@url.match(url_pattern)
end
def download_url
"https://#{@github_token}@api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}"
end
private
def _fetch(url:, resolved_url:, timeout:)
# HTTP request header `Accept: application/octet-stream` is required.
# Without this, the GitHub API will respond with metadata, not binary.
curl_download download_url, "--header", "Accept: application/octet-stream", to: temporary_path
end
def asset_id
@asset_id ||= resolve_asset_id
end
def resolve_asset_id
release_metadata = fetch_release_metadata
assets = release_metadata["assets"].select { |a| a["name"] == @filename }
raise CurlDownloadStrategyError, "Asset file not found." if assets.empty?
assets.first["id"]
end
def fetch_release_metadata
#release_url = "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}"
#GitHub::API.open_rest(release_url)
GitHub.get_release(@owner, @repo, @tag)
end
end
@joemiller
Copy link

joemiller commented Jul 20, 2021

Greetings. Thanks all for helping maintain this. It's a huge timesaver to have this as a resource to keep our internal homebrew formulas working when upstream brew makes changes.

we recently discovered a small bug. If you try to use a GH token that does not have access to your private repo you'll get this exception:

Error: uninitialized constant GitHub::HTTPNotFoundError
Please report this issue:
  https://docs.brew.sh/Troubleshooting
/usr/local/Homebrew/Library/Taps/foo/homebrew-internal/lib/download_strategy.rb:81:in `rescue in validate_github_repository_access!'
/usr/local/Homebrew/Library/Taps/foo/homebrew-internal/lib/download_strategy.rb:78:in `validate_github_repository_access!'
/usr/local/Homebrew/Library/Taps/foo/homebrew-internal/lib/download_strategy.rb:75:in `set_github_token'
/usr/local/Homebrew/Library/Taps/foo/homebrew-internal/lib/download_strategy.rb:48:in `initialize'
/usr/local/Homebrew/Library/Taps/foo/homebrew-internal/lib/download_strategy.rb:99:in `initialize'
/usr/local/Homebrew/Library/Homebrew/resource.rb:48:in `new'
/usr/local/Homebrew/Library/Homebrew/resource.rb:48:in `downloader'
/usr/local/Homebrew/Library/Homebrew/resource.rb:142:in `fetch'
/usr/local/Homebrew/Library/Homebrew/vendor/portable-ruby/2.6.3_2/lib/ruby/2.6.0/forwardable.rb:230:in `fetch'
/usr/local/Homebrew/Library/Homebrew/formula.rb:2016:in `fetch'
/usr/local/Homebrew/Library/Homebrew/formula_installer.rb:1133:in `fetch'
/usr/local/Homebrew/Library/Homebrew/reinstall.rb:58:in `reinstall_formula'
/usr/local/Homebrew/Library/Homebrew/cmd/reinstall.rb:116:in `block in reinstall'
/usr/local/Homebrew/Library/Homebrew/cmd/reinstall.rb:110:in `each'
/usr/local/Homebrew/Library/Homebrew/cmd/reinstall.rb:110:in `reinstall'
/usr/local/Homebrew/Library/Homebrew/brew.rb:122:in `<main>'

The fix is simple. On line 81 change rescue GitHub::HTTPNotFoundError to rescue GitHub::API::HTTPNotFoundError and the user gets the intended error message:

Error: GitHub API Error: Bad credentials
HOMEBREW_GITHUB_API_TOKEN may be invalid or expired; check:
  https://github.com/settings/tokens

@ZPascal
Copy link
Author

ZPascal commented Jul 22, 2021

@joemiller Thank you for the hint. I've updated the corresponding line.

@robinjhector
Copy link

This is very much appreciated! Can't believe they deleted this from the official Homebrew...

@edbighead
Copy link

thanks! I was getting Unknown keyword: timeout on my 2 years old brew tap

@vallieres
Copy link

Getting the same error, brand new tap, and formula.

@ZPascal
Copy link
Author

ZPascal commented Dec 13, 2021

@vallieres Do you want to share your tap? Maybe we identify the issue, together.

@vallieres
Copy link

@ZPascal hi! Sorry I can't share it, internal business soft, but I can past the error here:

❯ brew update && brew install yyyyyyyyy --debug
Already up-to-date.
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaLoader): loading /opt/homebrew/Library/Taps/xxxxxxxxxx/homebrew-tap/Formula/yyyyyyyyy.rb
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.3.8\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.0.1\)\ curl/7.77.0 --header Accept-Language:\ en --retry 3 --location https://api.github.com/repos/xxxxxxxxxx/yyyyyyyyy --header Accept:\ application/vnd.github.v3\+json --write-out '
'\%\{http_code\} --header Accept:\ application/vnd.github.antiope-preview\+json --header Authorization:\ token\ ****** --dump-header /private/tmp/github_api_headers20211213-59509-568f5x
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.3.8\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.0.1\)\ curl/7.77.0 --header Accept-Language:\ en --retry 3 --location --silent --head --request GET https://github.com/xxxxxxxxxx/yyyyyyyyy/releases/download/v1.0.10/yyyyyyyyy_1.0.10_Darwin_arm64.tar.gz
==> Downloading https://github.com/xxxxxxxxxx/yyyyyyyyy/releases/download/v1.0.10/yyyyyyyyy_1.0.10_Darwin_arm64.tar.gz
Error: unknown keyword: timeout
Please report this issue:
  https://docs.brew.sh/Troubleshooting
/opt/homebrew/Library/Taps/xxxxxxxxxx/homebrew-tap/Formula/lib/private_strategy.rb:117:in `_fetch'
/opt/homebrew/Library/Homebrew/download_strategy.rb:408:in `fetch'
/opt/homebrew/Library/Homebrew/resource.rb:147:in `fetch'
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/forwardable.rb:230:in `fetch'
/opt/homebrew/Library/Homebrew/formula.rb:2073:in `fetch'
/opt/homebrew/Library/Homebrew/formula_installer.rb:1185:in `fetch'
/opt/homebrew/Library/Homebrew/install.rb:301:in `block in install_formulae'
/opt/homebrew/Library/Homebrew/install.rb:275:in `map'
/opt/homebrew/Library/Homebrew/install.rb:275:in `install_formulae'
/opt/homebrew/Library/Homebrew/cmd/install.rb:214:in `install'
/opt/homebrew/Library/Homebrew/brew.rb:110:in `<main>'

This is the binary my Mac is trying to download:

    if Hardware::CPU.arm?
      url "https://github.com/xxxxxxxxx/yyyyyyyyy/releases/download/v1.0.10/yyyyyyyyy_1.0.10_Darwin_arm64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
      sha256 "f5753753191e78e75dac2b7a1c06bfc2eb01d1209e697c6aba3d8b5095e29e1f"

      def install
        bin.install "yyyyyyyyy"
      end
    end

The tap is brand new, created yesterday with brew tap-new and the Formula is also brand new. It's Go executable so most of the build and release was made with Goreleaser. I only have this one formula.

Gorelease is able to compile and push a new release without any issue.

@ZPascal
Copy link
Author

ZPascal commented Dec 14, 2021

@vallieres Could you please also post your used Homebrew version?

@vallieres
Copy link

Sure!

❯ brew --version
Homebrew 3.3.8-15-gd448121
Homebrew/homebrew-core (git revision 43865460f66; last commit 2021-12-14)
Homebrew/homebrew-cask (git revision 9e847b02f5; last commit 2021-12-14)

I have since tried many things, but I'm at a loss to understand why, but it finally worked. The best thing I could point to is my Terminal window had a bad environment variable set or something. Not sure, at all.

Goreleaser is defined as such:

url_template: "https://github.com/xxxxxxxx/yyyyyyyy/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
download_strategy: GitHubPrivateRepositoryReleaseDownloadStrategy
custom_require: "lib/private_strategy"

Formula:

on_macos do
  if Hardware::CPU.arm?
    url "https://github.com/xxxxxxxx/yyyyyyyy/releases/download/v1.1.2/yyyyyyyyy_1.1.2_Darwin_arm64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
    sha256 "1e1d8c1956280cb2ded2d34c12f57ee843bdcb47721b1da19174096fae4c7373"
  
    def install
      bin.install "yyyyyyyyy"
    end
  end

And if I do a diff between your private_strategy and mine, they are identical...
Sorry to have wasted your time!

I have this Makefile command I added to my project so I figured I might share it with you 🙂

Basically, you just do make release when on the main branch, and give it the next SEMVER version, and it does everything for you with Goreleaser. Then a simple brew update && brew upgrade yyyyyy updates your app.

release: ## Builds the binary release of the app

ifeq ($(BRANCH), $(MAIN))
	@echo "[-] This is the latest tag on the repo:"
	@git describe --abbrev=0
	@echo " "
	@read -p "[-] Enter New Tag: " TAG; git tag -s -a v$$TAG -m "Version $$TAG"; git push origin v$$TAG
	@echo " "
	@echo "[-] Launching Go Releaser..."
	@goreleaser release --rm-dist
	@echo "[-] Done!"
else
	@echo $(BRANCH)$(MAIN)$(BRANCH)
	@echo ""
	@echo "⚠️ You must be on the main branch! ⚠️"
	@echo ""
endif

@ZPascal
Copy link
Author

ZPascal commented Feb 26, 2022

Hi @vallieres, thanks for sharing the Makefile command, and I am glad that it now works for you.

I have since tried many things, but I'm at a loss to understand why, but it finally worked. The best thing I could point to is my Terminal window had a bad environment variable set or something. Not sure, at all.

In general, the functionality just overwrite/ replace the already existing functionality inside Homebrew itself. Maybe, you missed resetting an env variable, or you used an old token from Mac OS X keychain.

@gaarutyunov
Copy link

gaarutyunov commented Mar 21, 2022

Hello! Had same problem with timeout, resolved by adding timeout argument to _fetch methods.
Then I realised that GitHub module changed and open_api method was removed, so I used get_release method.

Now everything works like a charm!

# Save this file as `lib/private_strategy.rb`
# Add `require_relative "lib/private_strategy"` to your formula.
# 
# This is based on the following, with minor fixes.
# https://github.com/Homebrew/brew/blob/193af1442f6b9a19fa71325160d0ee2889a1b6c9/Library/Homebrew/compat/download_strategy.rb#L48-L157

# BSD 2-Clause License
#
# Copyright (c) 2009-present, Homebrew contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# GitHubPrivateRepositoryDownloadStrategy downloads contents from GitHub
# Private Repository. To use it, add
# `:using => GitHubPrivateRepositoryDownloadStrategy` to the URL section of
# your formula. This download strategy uses GitHub access tokens (in the
# environment variables `HOMEBREW_GITHUB_API_TOKEN`) to sign the request.  This
# strategy is suitable for corporate use just like S3DownloadStrategy, because
# it lets you use a private GitHub repository for internal distribution.  It
# works with public one, but in that case simply use CurlDownloadStrategy.
class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy
  require "utils/formatter"
  require "utils/github"

  def initialize(url, name, version, **meta)
    super
    parse_url_pattern
    set_github_token
  end

  def parse_url_pattern
    unless match = url.match(%r{https://github.com/([^/]+)/([^/]+)/(\S+)})
      raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Repository."
    end

    _, @owner, @repo, @filepath = *match
  end

  def download_url
    "https://#{@github_token}@github.com/#{@owner}/#{@repo}/#{@filepath}"
  end

  private

  def _fetch(url:, resolved_url:, timeout:)
    curl_download download_url, to: temporary_path
  end

  def set_github_token
    @github_token = ENV["HOMEBREW_GITHUB_API_TOKEN"]
    unless @github_token
      raise CurlDownloadStrategyError, "Environmental variable HOMEBREW_GITHUB_API_TOKEN is required."
    end

    validate_github_repository_access!
  end

  def validate_github_repository_access!
    # Test access to the repository
    GitHub.repository(@owner, @repo)
  rescue GitHub::HTTPNotFoundError
    # We only handle HTTPNotFoundError here,
    # becase AuthenticationFailedError is handled within util/github.
    message = <<~EOS
      HOMEBREW_GITHUB_API_TOKEN can not access the repository: #{@owner}/#{@repo}
      This token may not have permission to access the repository or the url of formula may be incorrect.
    EOS
    raise CurlDownloadStrategyError, message
  end
end

# GitHubPrivateRepositoryReleaseDownloadStrategy downloads tarballs from GitHub
# Release assets. To use it, add
# `:using => GitHubPrivateRepositoryReleaseDownloadStrategy` to the URL section of
# your formula. This download strategy uses GitHub access tokens (in the
# environment variables HOMEBREW_GITHUB_API_TOKEN) to sign the request.
class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDownloadStrategy
  def initialize(url, name, version, **meta)
    super
  end

  def parse_url_pattern
    url_pattern = %r{https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\S+)}
    unless @url =~ url_pattern
      raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Release."
    end

    _, @owner, @repo, @tag, @filename = *@url.match(url_pattern)
  end

  def download_url
    "https://#{@github_token}@api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}"
  end

  private

  def _fetch(url:, resolved_url:, timeout:)
    # HTTP request header `Accept: application/octet-stream` is required.
    # Without this, the GitHub API will respond with metadata, not binary.
    curl_download download_url, "--header", "Accept: application/octet-stream", to: temporary_path
  end

  def asset_id
    @asset_id ||= resolve_asset_id
  end

  def resolve_asset_id
    release_metadata = fetch_release_metadata
    assets = release_metadata["assets"].select { |a| a["name"] == @filename }
    raise CurlDownloadStrategyError, "Asset file not found." if assets.empty?

    assets.first["id"]
  end

  def fetch_release_metadata
    GitHub.get_release(@owner, @repo, @tag)
  end
end

@ZPascal
Copy link
Author

ZPascal commented Mar 21, 2022

@gaarutyunov Thanks for the hint. I think both methods used, at the end, the same/ a similar call to get the expected result. I'll update that because, I think, it's better to use the central wrapper method to extract the release version.

@alejakun
Copy link

Hello! I don't even know if it's possible, but I want to do something of this sort with a Font Cask, by hiding my fonts behind a private repository, however I don't know where to start, since the font-cask requires to only create the cask, and the cask will not let me import the private_strategy.rb. Any idea of how can I make this work?

@ZPascal
Copy link
Author

ZPascal commented May 12, 2022

Hi @alejakun, I'm not so familiar with the Homebrew Cask, but could you please post a dummy example of your cask and the corresponding error message. Maybe it's also possible to use the "dirty way" and inject the Token directly inside the URL.

@alejakun
Copy link

Hi, I think it should be possible to do it "the dirty way", just trying to find a "clean way" to do it, I've been trying several approaches and I have come up with some solutions but all of them seem a bit odd or quirky:

First what's working right now:

FAMILY: Some Name
cask 'FIXME' do
  version "?"
  sha256 "51481a4ac783bb8cf21cd202f3d7eb27437bc29eb49874b1ab58301234567890"

  url "file://#{ENV['HOMEBREW_PREFIX']}/Homebrew/Library/Taps/<user>/homebrew-cask-fonts/Fonts/some-font.zip"
  name "Some Font"
  homepage ""

  font "SOME_FONT.TTF"
end

I've been looking around for a while now and there are two options which seem more clean, the first is with your approach which involves importing a file, however this is not working because I have no access to the Formula (this is handled by the cask-font, and meddling with it seems a little bit too much) and when I try to import it to the cask it says something in the line of "invalid file format".

The other option I've been trying as explained here is to add an authorization token like this:

cask 'XXXX' do
...
  url "https://raw.githubusercontent.com/....",
      header : "Authorization: token #{ENV['HOMEBREW_GITHUB_API_TOKEN']}"
...
end

However I feel like this is outdated because the variable HOMEBREW_GITHUB_API_TOKEN is set in the environment correctly (I've tested this concatenating this to the URL as the URL is displayed in the command line when homebrew works its magic.

FAMILY: Some Name
cask 'FIXME' do
  version "?"
  sha256 "51481a4ac783bb8cf21cd202f3d7eb27437bc29eb49874b1ab58301234567890"

  url "https://github.com/<user>/homebrew-cask-fonts/raw/master/Fonts/<some-font>.zip"
  name "Some Font"
  homepage ""

  font "SOME_FONT.TTF"
end

Now that I'm writing all this I believe I have to use the second approach but changing the URL from what I have to something more like in your code like this "https://#{ENV['HOMEBREW_GITHUB_API_TOKEN']}@github.com/<user>/<repo>/<file_path>"

I'll be testing this approach and let you know.

@alejakun
Copy link

I've tested my proposed strategy, but it is not working ☹️ , error displayed:

==> Downloading https://<api-token>@github.com/alej
curl: (22) The requested URL returned error: 404

hope someone has a clue.

@ZPascal
Copy link
Author

ZPascal commented May 12, 2022

@alejakun Could you please test if it's possible to download the artifact without the cask? Maybe, an access problem.

@alejakun
Copy link

I've tried with several formats:

https://#{ENV['HOMEBREW_GITHUB_API_TOKEN']}@github.com/<user>/<repo>/Fonts/<file_name>.zip
https://#{ENV['HOMEBREW_GITHUB_API_TOKEN']}@github.com/<user>/<repo>/raw/master/Fonts/<file_name>.zip

The first one fails in the browser, the second one is successful in the browser as long as I'm logged in GH, otherwise it returns a HTTP 404.

@ZPascal
Copy link
Author

ZPascal commented May 12, 2022

Could you please try curl or wget and the corresponding TOKEN directly? If the file is located inside the repository, please use the raw mode.

@alejakun
Copy link

You are correct, using just curl it returns the 404 page. Any suggestions of what might be wrong with my environment?

@ZPascal
Copy link
Author

ZPascal commented May 13, 2022

Are you sure, that your access token got the correct access rights? Could you please validate that?

@alejakun
Copy link

Tests were performed with a token with the following permissions granted:

  • Repo (and all sub permissions)
  • Workflow
  • Gist

@ZPascal
Copy link
Author

ZPascal commented May 13, 2022

I've started a test on my side to download a file from a private repository directly via curl. I've used the following command curl https://<TOKEN>@raw.githubusercontent.com/<OWNER>/<REPO>/<BRANCH>/<PATH TO FILE> --output <NAME OF THE FILE>. Could you please try it out? I think it should be possible, to use the URL at the end directly inside the cask.

@alejakun
Copy link

alejakun commented May 16, 2022

Hi, sorry for the late reply, the curl command with the suggested format is working, however I don't know how to translate that to the URL in my cask definition.

Edit: Finally made it work, it seems I was so into it that I missed some parts of the url. Anyways you nailed it, thanks for the support!

@ZPascal
Copy link
Author

ZPascal commented May 17, 2022

Hi @alejakun, great to hear that now everything works as aspected.

@mtintes
Copy link

mtintes commented Oct 5, 2022

I am not sure this is the exact place for it but has anyone using this seen an error Error: can't modify frozen class while using these scripts? I am running a brew install for a private github repo when I get this error. My google-fu is weak so taking a shot in the dark in case it is more widespread.

@ZPascal
Copy link
Author

ZPascal commented Oct 5, 2022

Hi @mtintes, could you please post the output of the --debug flag of the installation command?

@mtintes
Copy link

mtintes commented Oct 5, 2022

One of coworkers ended up finding an answer (sort of). This was the original error. konductor is a cli written in go in this case.

➜  brew install konductor --debug --verbose             
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaLoader): loading /opt/homebrew/Library/Taps/<org>/homebrew-konductor/formula/konductor.rb
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location https://api.github.com/repos/<org>/konductor --header Accept:\ application/vnd.github\+json --write-out '
'\%\{http_code\} --header Authorization:\ token\ ****** --dump-header /private/tmp/github_api_headers20221005-47324-1n0405m
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location --silent --head --request GET https://github.com/<org>/konductor/releases/download/v1.17.9/konductor-osx-amd64.tar.gz
==> Downloading https://github.com/<org>/konductor/releases/download/v1.17.9/konductor-osx-amd64.tar.gz
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --retry 3 --location https://api.github.com/repos/<org>/konductor/releases/tags/v1.17.9 --header Accept:\ application/vnd.github\+json --write-out '
'\%\{http_code\} --header Authorization:\ token\ ****** --dump-header /private/tmp/github_api_headers20221005-47324-f7o4v1
/opt/homebrew/Library/Homebrew/shims/shared/curl --disable --cookie /dev/null --globoff --show-error --user-agent Homebrew/3.6.4\ \(Macintosh\;\ arm64\ Mac\ OS\ X\ 12.5.1\)\ curl/7.79.1 --header Accept-Language:\ en --fail --retry 3 --location --remote-time --output /Users/miketintes/Library/Caches/Homebrew/downloads/e21e5b9112fcd59c4caec2c40316e0fe0c08cab973ba491d5ccd1460569812b8--konductor-osx-amd64.tar.gz.incomplete https://******@api.github.com/repos/<org>/konductor/releases/assets/79035814 --header Accept:\ application/octet-stream
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 30.6M  100 30.6M    0     0  13.2M      0  0:00:02  0:00:02 --:--:-- 16.4M
==> Verifying checksum for 'e21e5b9112fcd59c4caec2c40316e0fe0c08cab973ba491d5ccd1460569812b8--konductor-osx-amd64.tar.gz'
==> Installing konductor from <org>/konductor
/opt/homebrew/Library/Homebrew/brew.rb (Formulary::TapLoader): loading /opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb
Error: can't modify frozen class
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/lib/private_strategy.rb:98:in `<class:GitHubPrivateRepositoryReleaseDownloadStrategy>'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/lib/private_strategy.rb:97:in `<top (required)>'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb:2:in `require_relative'
/opt/homebrew/Library/Taps/<org>/homebrew-konductor/Formula/konductor.rb:2:in `block in load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:90:in `module_eval'
/opt/homebrew/Library/Homebrew/formulary.rb:90:in `block in load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:102:in `load_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:122:in `load_formula_from_path'
/opt/homebrew/Library/Homebrew/formulary.rb:321:in `load_file'
/opt/homebrew/Library/Homebrew/formulary.rb:478:in `load_file'
/opt/homebrew/Library/Homebrew/formulary.rb:311:in `klass'
/opt/homebrew/Library/Homebrew/formulary.rb:306:in `get_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:468:in `get_formula'
/opt/homebrew/Library/Homebrew/formulary.rb:560:in `factory'
/opt/homebrew/Library/Homebrew/formula_installer.rb:374:in `install'
/opt/homebrew/Library/Homebrew/upgrade.rb:212:in `install_formula'
/opt/homebrew/Library/Homebrew/install.rb:333:in `install_formula'
/opt/homebrew/Library/Homebrew/install.rb:323:in `block in install_formulae'
/opt/homebrew/Library/Homebrew/install.rb:322:in `each'
/opt/homebrew/Library/Homebrew/install.rb:322:in `install_formulae'
/opt/homebrew/Library/Homebrew/cmd/install.rb:226:in `install'
/opt/homebrew/Library/Homebrew/brew.rb:95:in `<main>'

We had to copy a bunch of old code from homebrew that looks like it got deprecated and put that in the private strategy. This is a copy of that. No idea if that is the best path since neither of us does anything with ruby.

@stevenpitts
Copy link

For anyone recently having issues with this, see Homebrew/brew#15169. CurlDownloadStrategy changed a bit.

This fix worked for me.

@roeeyn
Copy link

roeeyn commented Jul 4, 2023

For anyone recently having issues with this, see Homebrew/brew#15169. CurlDownloadStrategy changed a bit.

This fix worked for me.

It worked for me too. Thanks for sharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment