プライベートなツールをGitHub Releaseにおいてbrewで配布していたのがエラーになった件の対処メモ


GitHubのプライベートリポジトリのReleaseにおいてHomebrewのtapをつかってインストールできるようにしていたところ、以下がエラーが出るようになった。

```
==> Installing XXXX from xxxx/xxxx
Error: An exception occurred within a child process:
  MethodDeprecatedError: Calling GitHubPrivateRepositoryReleaseDownloadStrategy is disabled! Use a vendored GitHubPrivateRepositoryReleaseDownloadStrategy in your own formula or tap (using require_relative) instead.
```


`GitHubPrivateRepositoryReleaseDownloadStrategy`は使えなくなったのでえ、自分のtapで読みこんで使って、と書かれている気がする。


# 対処した内容

## download_strategy.rbの配置

自前のtapの `lib/download_strategy.rb` を配置

```lib/download_strategy.rb
# GitHubPrivateRepositoryDownloadStrategy downloads contents from GitHub
# Private Repository. To use it, add
# `:using => :github_private_repo` 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:)
    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 => :github_private_release` 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:)
    # 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.open_api(release_url)
  end
end
```

## Formulaの修正

各Formulaの先頭に以下を追加

```
require_relative '../lib/download_strategy'
```

## 作業メモ

以下の変更で、非推奨になって、コードの位置が移動した。
https://github.com/Homebrew/brew/pull/5112

以下の変更で、コードが消えた。
https://github.com/Homebrew/brew/pull/5598

消えたファイルの中身
https://github.com/Homebrew/brew/blob/193af1442f6b9a19fa71325160d0ee2889a1b6c9/Library/Homebrew/compat/download_strategy.rb

## 修正方法

1. 使いたいストラテジーをコピーしてもってくる。
2. `odisable`の呼び出しを削除する
3. もってきたものを各Formulaで読み込む

消えたストラテジー

* S3DownloadStrategy
* GitHubPrivateRepositoryDownloadStrategy
* GitHubPrivateRepositoryReleaseDownloadStrategy
* ScpDownloadStrategy

マージするまえに、特定のブランチの作業を確認してもらう方法

```
brew tap [リポジトリ名]/[tap名]
cd /usr/local/Homebrew/Library/Taps/[リポジトリ名]/homebrew-[tap名]
git fetch origin [作業ブランチ名]
git checkout FETCH_HEAD
brew install [確認するformula名]
```