Bump Homebrew Formula #5
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: Bump Homebrew Formula | |
| # 触发:作为 reusable workflow 被 release.yml 在发版(tag 推送)后链式调用(workflow_call)。 | |
| # —— 不靠 release:published 事件:由默认 GITHUB_TOKEN 创建的 Release 不会触发其它 workflow(GitHub 防递归), | |
| # 同一 run 内链式调用可绕开该限制,且无需 PAT。 | |
| # 备份:手动触发,可显式指定版本号(用于补救 / dry-run)。 | |
| on: | |
| workflow_call: | |
| inputs: | |
| version: | |
| description: 'Version to bump (e.g. 1.6.278)' | |
| required: true | |
| type: string | |
| # 最小权限:只显式接收跨仓写 tap 所需的 HOMEBREW_TAP_TOKEN,不用 secrets: inherit | |
| # 把 caller 的全部 secrets(CSC_*/APPLE_* 等)都灌进来。GITHUB_TOKEN 由平台自动提供。 | |
| secrets: | |
| HOMEBREW_TAP_TOKEN: | |
| required: true | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| # required:true 让 UI 在派发前强制填写(本 workflow 无 latest-tag 回落,空值会直接报错)。 | |
| description: 'Version to bump (e.g., 1.6.225)' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: read | |
| jobs: | |
| bump: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Resolve version | |
| id: ver | |
| # SECURITY: ${{ inputs.version }} 必须经 env: 注入,不得直接拼进 run: 脚本——后者会让恶意输入 | |
| # (仅 collaborator 可触发,但仍是标准 antipattern)在 semver 校验前就被 shell 解释。 | |
| # 版本来源统一为 inputs.version(workflow_call 与 workflow_dispatch 共用 inputs 上下文)。 | |
| env: | |
| INPUT_VERSION: ${{ inputs.version }} | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "$INPUT_VERSION" ]]; then | |
| echo "Cannot resolve version: inputs.version is empty" >&2 | |
| exit 1 | |
| fi | |
| VER="${INPUT_VERSION#v}" # caller 传 github.ref_name=vX.Y.Z 时剥前导 v | |
| # 校验版本号严格 semver patch 格式(再次防御:确保所有后续步骤拿到的 VER 是干净的) | |
| if ! [[ "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "Invalid version: $VER" >&2 | |
| exit 1 | |
| fi | |
| echo "version=$VER" >> "$GITHUB_OUTPUT" | |
| echo "Resolved version: $VER" | |
| - name: Wait for npm registry to publish | |
| env: | |
| VER: ${{ steps.ver.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| # CDN 传播最长 ~5min;每 30s 重试,共 10 次 = 5min | |
| for i in $(seq 1 10); do | |
| if curl -fsSL "https://registry.npmjs.org/cc-viewer/${VER}" >/dev/null 2>&1; then | |
| echo "✓ npm has cc-viewer@${VER}" | |
| exit 0 | |
| fi | |
| echo "[$i/10] npm not yet showing cc-viewer@${VER}, sleeping 30s..." | |
| sleep 30 | |
| done | |
| echo "✗ Timed out waiting for npm to publish cc-viewer@${VER}" >&2 | |
| exit 1 | |
| - name: Compute tarball sha256 | |
| id: hash | |
| env: | |
| VER: ${{ steps.ver.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| URL="https://registry.npmjs.org/cc-viewer/-/cc-viewer-${VER}.tgz" | |
| curl -fsSL "$URL" -o /tmp/pkg.tgz | |
| SHA=$(sha256sum /tmp/pkg.tgz | cut -d' ' -f1) | |
| echo "sha256=$SHA" >> "$GITHUB_OUTPUT" | |
| echo "url=$URL" >> "$GITHUB_OUTPUT" | |
| echo "✓ sha256=$SHA" | |
| - name: Checkout tap repo | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: weiesky/homebrew-cc-viewer | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| path: tap | |
| - name: Update formula | |
| env: | |
| URL: ${{ steps.hash.outputs.url }} | |
| SHA: ${{ steps.hash.outputs.sha256 }} | |
| run: | | |
| set -euo pipefail | |
| FORMULA=tap/Formula/cc-viewer.rb | |
| if [[ ! -f "$FORMULA" ]]; then | |
| echo "$FORMULA not found in tap repo" >&2 | |
| exit 1 | |
| fi | |
| # 仅替换 url 与 sha256 行;其它内容(depends_on / install / test 块)由维护者管理。 | |
| # python 通过 sys.argv 拿 env 注入的 URL/SHA,不让 Action 表达式直接拼进 shell 行。 | |
| python3 - "$FORMULA" "$URL" "$SHA" <<'PY' | |
| import re, sys | |
| path, url, sha = sys.argv[1], sys.argv[2], sys.argv[3] | |
| with open(path, 'r', encoding='utf-8') as f: | |
| src = f.read() | |
| src = re.sub(r'url\s+"[^"]+"', f'url "{url}"', src, count=1) | |
| src = re.sub(r'sha256\s+"[^"]+"', f'sha256 "{sha}"', src, count=1) | |
| with open(path, 'w', encoding='utf-8') as f: | |
| f.write(src) | |
| PY | |
| echo "--- Updated formula ---" | |
| grep -E '(url|sha256) ' "$FORMULA" | |
| - name: Create PR | |
| id: cpr | |
| uses: peter-evans/create-pull-request@v6 | |
| with: | |
| path: tap | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| commit-message: "cc-viewer ${{ steps.ver.outputs.version }}" | |
| title: "cc-viewer ${{ steps.ver.outputs.version }}" | |
| body: | | |
| Automated bump from [cc-viewer release `v${{ steps.ver.outputs.version }}`](https://github.com/weiesky/cc-viewer/releases/tag/v${{ steps.ver.outputs.version }}). | |
| - npm tarball: <${{ steps.hash.outputs.url }}> | |
| - sha256: `${{ steps.hash.outputs.sha256 }}` | |
| Generated by `.github/workflows/bump-homebrew.yml` in `weiesky/cc-viewer`. | |
| branch: bump-${{ steps.ver.outputs.version }} | |
| delete-branch: true | |
| - name: Auto-merge PR | |
| # 只在 created / updated 分支跑(none / closed 时跳过,避免对错误 PR 号操作)。 | |
| # 跨仓 token 用 HOMEBREW_TAP_TOKEN(与 Create PR 同源),需在 tap 仓 settings → | |
| # general → Pull Requests 启用 Allow merge commits(已是默认)。 | |
| if: steps.cpr.outputs.pull-request-operation == 'created' || steps.cpr.outputs.pull-request-operation == 'updated' | |
| env: | |
| GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| PR_NUM: ${{ steps.cpr.outputs.pull-request-number }} | |
| run: | | |
| set -euo pipefail | |
| # 数字校验防注入(peter-evans action 输出可信,但本仓 hardening 风格一致) | |
| if ! [[ "$PR_NUM" =~ ^[0-9]+$ ]]; then | |
| echo "Invalid PR number: $PR_NUM" >&2 | |
| exit 1 | |
| fi | |
| gh pr merge "$PR_NUM" \ | |
| --repo weiesky/homebrew-cc-viewer \ | |
| --merge \ | |
| --delete-branch | |
| echo "✓ Merged PR #$PR_NUM into tap main" |