Update Homebrew Tap #58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Homebrew Tap | |
| # Triggered by release.yml via `gh workflow run` after the release is | |
| # published (not by the release event directly, to avoid racing with | |
| # asset uploads). Can also be invoked manually with a version input | |
| # if the automation ever misses. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to publish (e.g. 0.0.2 — no leading v)' | |
| required: true | |
| env: | |
| # Opt every JavaScript-based action into Node 24 ahead of GitHub's | |
| # June 2026 forced switch. See ci.yml for the full rationale. | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| permissions: | |
| contents: read | |
| jobs: | |
| update-tap: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| VERSION: ${{ github.event.inputs.version }} | |
| REPO: xiaolai/claudepot-app | |
| steps: | |
| # Homebrew serves the stable channel only. release.yml gates | |
| # its dispatch on non-beta tags; this guard catches a manual | |
| # dispatch with a prerelease version — shipping a `-beta.N` to | |
| # the tap would hand it to every stable `brew upgrade` user. | |
| - name: Validate version shape (stable only) | |
| run: | | |
| set -eu | |
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "::error::Version '$VERSION' is not a bare X.Y.Z stable version." | |
| echo "::error::Prerelease versions must never reach the Homebrew tap." | |
| exit 1 | |
| fi | |
| echo "OK: $VERSION is a stable version" | |
| - name: Wait for release assets to be available | |
| run: | | |
| set -eu | |
| BASE="https://github.com/${REPO}/releases/download/v${VERSION}" | |
| # macOS users get the CLI bundled inside the .app (via the | |
| # cask's binary stanza), so the Homebrew workflow only needs | |
| # the two DMGs and the two Linux CLI tarballs. | |
| ASSETS=( | |
| "claudepot-aarch64-linux.tar.gz" | |
| "claudepot-x86_64-linux.tar.gz" | |
| "Claudepot-aarch64.dmg" | |
| "Claudepot-x86_64.dmg" | |
| ) | |
| for attempt in $(seq 1 30); do | |
| all_ok=1 | |
| for asset in "${ASSETS[@]}"; do | |
| code=$(curl -sI -o /dev/null -w "%{http_code}" -L "$BASE/$asset") | |
| case "$code" in | |
| 200|302) ;; | |
| *) all_ok=0; echo " $asset: HTTP $code" ;; | |
| esac | |
| done | |
| if [ "$all_ok" -eq 1 ]; then | |
| echo "All four assets available." | |
| exit 0 | |
| fi | |
| echo "Attempt ${attempt}/30 — waiting 30s…" | |
| sleep 30 | |
| done | |
| echo "Assets not available after 15 minutes" >&2 | |
| exit 1 | |
| - name: Download assets and compute sha256 | |
| id: sha256 | |
| run: | | |
| set -eu | |
| BASE="https://github.com/${REPO}/releases/download/v${VERSION}" | |
| compute() { | |
| local name="$1" outvar="$2" | |
| curl -sL -o "/tmp/$name" "$BASE/$name" | |
| local sum | |
| sum=$(sha256sum "/tmp/$name" | cut -d ' ' -f 1) | |
| echo " $name → $sum" | |
| echo "${outvar}=${sum}" >> "$GITHUB_OUTPUT" | |
| rm "/tmp/$name" | |
| } | |
| compute "claudepot-aarch64-linux.tar.gz" cli_linux_arm | |
| compute "claudepot-x86_64-linux.tar.gz" cli_linux_intel | |
| compute "Claudepot-aarch64.dmg" dmg_arm | |
| compute "Claudepot-x86_64.dmg" dmg_intel | |
| - name: Checkout homebrew-tap | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: xiaolai/homebrew-tap | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| path: homebrew-tap | |
| # The formula is Linux-only: macOS users get the CLI bundled | |
| # inside the GUI cask (see below), so `brew install claudepot` | |
| # is the right install on Linux and `brew install --cask claudepot` | |
| # is the right install on macOS. | |
| - name: Generate Formula/claudepot.rb | |
| env: | |
| CLI_LINUX_ARM: ${{ steps.sha256.outputs.cli_linux_arm }} | |
| CLI_LINUX_INTEL: ${{ steps.sha256.outputs.cli_linux_intel }} | |
| run: | | |
| cat > homebrew-tap/Formula/claudepot.rb <<RUBY | |
| class Claudepot < Formula | |
| desc "Multi-account Claude Code / Claude Desktop switcher (CLI)" | |
| homepage "https://claudepot.com/app/" | |
| version "${VERSION}" | |
| license "MIT" | |
| depends_on :linux | |
| on_linux do | |
| if Hardware::CPU.arm? | |
| url "https://github.com/${REPO}/releases/download/v#{version}/claudepot-aarch64-linux.tar.gz" | |
| sha256 "${CLI_LINUX_ARM}" | |
| else | |
| url "https://github.com/${REPO}/releases/download/v#{version}/claudepot-x86_64-linux.tar.gz" | |
| sha256 "${CLI_LINUX_INTEL}" | |
| end | |
| end | |
| def install | |
| bin.install "claudepot" | |
| end | |
| test do | |
| assert_match "Multi-account Claude Code", shell_output("#{bin}/claudepot --help") | |
| end | |
| end | |
| RUBY | |
| echo "Generated Formula/claudepot.rb:" | |
| cat homebrew-tap/Formula/claudepot.rb | |
| # The cask ships the GUI **and** the CLI. Tauri 2 takes the | |
| # `binaries/claudepot-cli` `externalBin` entry, picks the | |
| # matching `claudepot-cli-<triple>` source file from | |
| # `src-tauri/binaries/`, signs it as part of the bundle, and | |
| # writes it into `Contents/MacOS/` under the BARE basename | |
| # (no triple suffix in the bundled name — the suffix is just a | |
| # source-side disambiguator). The `binary` stanza symlinks | |
| # that bundled file as /opt/homebrew/bin/claudepot so a single | |
| # `brew install --cask claudepot` gives users both. The | |
| # bundled path is identical on both arches; only the URL + | |
| # sha256 differ. | |
| - name: Generate Casks/claudepot.rb | |
| env: | |
| DMG_ARM: ${{ steps.sha256.outputs.dmg_arm }} | |
| DMG_INTEL: ${{ steps.sha256.outputs.dmg_intel }} | |
| run: | | |
| cat > homebrew-tap/Casks/claudepot.rb <<RUBY | |
| cask "claudepot" do | |
| version "${VERSION}" | |
| on_arm do | |
| sha256 "${DMG_ARM}" | |
| url "https://github.com/${REPO}/releases/download/v#{version}/Claudepot-aarch64.dmg" | |
| end | |
| on_intel do | |
| sha256 "${DMG_INTEL}" | |
| url "https://github.com/${REPO}/releases/download/v#{version}/Claudepot-x86_64.dmg" | |
| end | |
| binary "#{appdir}/Claudepot.app/Contents/MacOS/claudepot-cli", | |
| target: "claudepot" | |
| name "Claudepot" | |
| desc "Multi-account Claude Code / Claude Desktop switcher" | |
| homepage "https://claudepot.com/app/" | |
| # The app self-updates in place (Settings → About), so the | |
| # Caskroom version goes stale by design. auto_updates makes | |
| # plain 'brew upgrade' skip the cask (only --greedy | |
| # reinstalls), so brew can't downgrade a self-updated app | |
| # when the tap lags a release. | |
| auto_updates true | |
| livecheck do | |
| url "https://github.com/${REPO}" | |
| strategy :github_latest | |
| end | |
| depends_on macos: ">= :catalina" | |
| app "Claudepot.app" | |
| zap trash: [ | |
| "~/.claudepot", | |
| "~/Library/Caches/com.claudepot.app", | |
| "~/Library/Preferences/com.claudepot.app.plist", | |
| "~/Library/Saved Application State/com.claudepot.app.savedState", | |
| "~/Library/WebKit/com.claudepot.app", | |
| ] | |
| end | |
| RUBY | |
| echo "Generated Casks/claudepot.rb:" | |
| cat homebrew-tap/Casks/claudepot.rb | |
| - name: Commit and push | |
| run: | | |
| set -eu | |
| cd homebrew-tap | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/claudepot.rb Casks/claudepot.rb | |
| if git diff --staged --quiet; then | |
| echo "No changes to publish." | |
| exit 0 | |
| fi | |
| git commit -m "Update claudepot to ${VERSION}" | |
| git push |