feat(ci): auto-update Homebrew tap formula on release

Add a release follow-up job that updates the Homebrew tap from the checksum manifest when a tap token is configured.

The job now skips before checkout/download/update when neither HOMEBREW_TAP_PAT nor RELEASE_TAG_PAT is configured, so missing tap credentials do not fail an otherwise successful release.

Closes #1602.

Co-authored-by: Zhiping <2716057626@qq.com>
Co-authored-by: Oliver-ZPLiu <47081637+Oliver-ZPLiu@users.noreply.github.com>
This commit is contained in:
ZzzPL
2026-05-15 03:10:25 +08:00
committed by GitHub
parent cc67454f1f
commit 9f3a1ec951
3 changed files with 179 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# Update the Homebrew tap at Hmbown/homebrew-deepseek-tui after a release.
#
# Expected environment:
# TAG git tag, e.g. "v0.8.31"
# MANIFEST path to deepseek-artifacts-sha256.txt
# TAP_REPO owner/repo of the Homebrew tap
# TOKEN PAT with contents:write on TAP_REPO (optional; skips if unset)
set -euo pipefail
: "${TAG:?}"
: "${MANIFEST:?}"
: "${TAP_REPO:?}"
if [ -z "${TOKEN:-}" ]; then
echo "No Homebrew tap token configured; skipping."
exit 0
fi
VERSION="${TAG#v}"
die() { echo "::error::${1}" >&2; exit 1; }
sha() {
local file="${1:?}"
local val
val="$(awk -v f="${file}" '$2 == f {print $1; exit}' "${MANIFEST}")"
if [ -z "${val}" ]; then
die "Missing binary in checksum manifest: ${file}"
fi
echo "${val}"
}
# --- read checksums ---------------------------------------------------
readonly SHA_DISP_MACOS_ARM="$(sha deepseek-macos-arm64)"
readonly SHA_TUI_MACOS_ARM="$(sha deepseek-tui-macos-arm64)"
readonly SHA_DISP_MACOS_X64="$(sha deepseek-macos-x64)"
readonly SHA_TUI_MACOS_X64="$(sha deepseek-tui-macos-x64)"
readonly SHA_DISP_LINUX_ARM="$(sha deepseek-linux-arm64)"
readonly SHA_TUI_LINUX_ARM="$(sha deepseek-tui-linux-arm64)"
readonly SHA_DISP_LINUX_X64="$(sha deepseek-linux-x64)"
readonly SHA_TUI_LINUX_X64="$(sha deepseek-tui-linux-x64)"
# --- temp dirs --------------------------------------------------------
FORMULA_FILE="$(mktemp)"
TAP_DIR="$(mktemp -d)"
trap 'rm -rf "${TAP_DIR}" "${FORMULA_FILE}"' EXIT
# --- generate formula --------------------------------------------------
readonly BASE_URL="https://github.com/Hmbown/DeepSeek-TUI/releases/download/${TAG}"
cat > "${FORMULA_FILE}" << EOF
class DeepseekTui < Formula
desc "Terminal-native coding agent for DeepSeek V4"
homepage "https://github.com/Hmbown/DeepSeek-TUI"
version "${VERSION}"
license "MIT"
on_macos do
if Hardware::CPU.arm?
url "${BASE_URL}/deepseek-macos-arm64", using: :nounzip
sha256 "${SHA_DISP_MACOS_ARM}"
resource "tui" do
url "${BASE_URL}/deepseek-tui-macos-arm64", using: :nounzip
sha256 "${SHA_TUI_MACOS_ARM}"
end
else
url "${BASE_URL}/deepseek-macos-x64", using: :nounzip
sha256 "${SHA_DISP_MACOS_X64}"
resource "tui" do
url "${BASE_URL}/deepseek-tui-macos-x64", using: :nounzip
sha256 "${SHA_TUI_MACOS_X64}"
end
end
end
on_linux do
if Hardware::CPU.arm?
url "${BASE_URL}/deepseek-linux-arm64", using: :nounzip
sha256 "${SHA_DISP_LINUX_ARM}"
resource "tui" do
url "${BASE_URL}/deepseek-tui-linux-arm64", using: :nounzip
sha256 "${SHA_TUI_LINUX_ARM}"
end
else
url "${BASE_URL}/deepseek-linux-x64", using: :nounzip
sha256 "${SHA_DISP_LINUX_X64}"
resource "tui" do
url "${BASE_URL}/deepseek-tui-linux-x64", using: :nounzip
sha256 "${SHA_TUI_LINUX_X64}"
end
end
end
def install
bin.install Dir["*"].first => "deepseek"
resource("tui").stage { bin.install Dir["*"].first => "deepseek-tui" }
end
test do
system "#{bin}/deepseek", "--version"
end
end
EOF
# --- push to tap repo --------------------------------------------------
ENCODED_TOKEN="$(printf '%s' "${TOKEN}" | python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read(),safe=""))')"
TAP_URL="https://x-access-token:${ENCODED_TOKEN}@github.com/${TAP_REPO}.git"
git clone --depth 1 "${TAP_URL}" "${TAP_DIR}"
mkdir -p "${TAP_DIR}/Formula"
cp "${FORMULA_FILE}" "${TAP_DIR}/Formula/deepseek-tui.rb"
cd "${TAP_DIR}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/deepseek-tui.rb
if git diff --cached --quiet; then
echo "Formula unchanged (already at ${VERSION}); nothing to push."
exit 0
fi
git commit -m "chore: bump formula to ${VERSION}
Automated update from the release workflow."
git push origin HEAD:main
echo "Pushed formula update to ${TAP_REPO} (v${VERSION})"
+42
View File
@@ -333,6 +333,48 @@ jobs:
See [CHANGELOG.md](https://github.com/Hmbown/DeepSeek-TUI/blob/main/CHANGELOG.md) for the full notes for this release.
homebrew:
needs: [release, resolve]
if: ${{ !cancelled() && needs.release.result == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check Homebrew tap token
id: homebrew-token
env:
TOKEN: ${{ secrets.HOMEBREW_TAP_PAT || secrets.RELEASE_TAG_PAT }}
run: |
if [ -z "${TOKEN:-}" ]; then
echo "No Homebrew tap token configured; skipping tap update."
echo "available=false" >> "${GITHUB_OUTPUT}"
else
echo "available=true" >> "${GITHUB_OUTPUT}"
fi
# Checkout main (not the tag) so the release-infra script is always
# available, even for tags created before this workflow was added.
- uses: actions/checkout@v4
if: steps.homebrew-token.outputs.available == 'true'
with:
ref: main
- name: Download checksum manifest
if: steps.homebrew-token.outputs.available == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release download ${{ needs.resolve.outputs.tag }} \
--repo ${{ github.repository }} \
--pattern 'deepseek-artifacts-sha256.txt' \
--dir /tmp
- name: Update Homebrew tap
if: steps.homebrew-token.outputs.available == 'true'
env:
TAG: ${{ needs.resolve.outputs.tag }}
MANIFEST: /tmp/deepseek-artifacts-sha256.txt
TAP_REPO: Hmbown/homebrew-deepseek-tui
TOKEN: ${{ secrets.HOMEBREW_TAP_PAT || secrets.RELEASE_TAG_PAT }}
run: bash .github/scripts/update-homebrew-tap.sh
# npm publish is intentionally not automated. The npm account requires 2FA OTP
# on every publish, and a granular automation token that bypasses 2FA has not
# been provisioned. Release the npm wrapper manually from a developer machine
+1
View File
@@ -49,6 +49,7 @@ docs/*.pdf
# Local dev scripts and temp files
*.sh
!scripts/**
!.github/scripts/**
test.txt
TODO*.md
todo*.md