From e7659ec59b985265c70459084c1113d28aced246 Mon Sep 17 00:00:00 2001 From: Eric Rodriguez Date: Thu, 9 Jul 2026 19:06:10 +0200 Subject: [PATCH] ci: add manual publish-dist workflow; share tap-push logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts the Homebrew/Scoop push into scripts/publish-tap.sh (VERSION + TAP_TOKEN env; no-ops without the token, skips prereleases) so the release job and a new manual workflow can't drift. publish-dist.yml is a workflow_dispatch entry point to (re)publish a version's tap files without re-running the whole release — handy for testing TAP_TOKEN or backfilling. Claude-Session: https://claude.ai/code/session_018dRMUUj9vpKp3tqKQFsvE9 --- .github/workflows/publish-dist.yml | 36 +++++++++++++++++++++++ .github/workflows/release.yml | 28 +++--------------- scripts/publish-tap.sh | 47 ++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/publish-dist.yml create mode 100644 scripts/publish-tap.sh diff --git a/.github/workflows/publish-dist.yml b/.github/workflows/publish-dist.yml new file mode 100644 index 0000000..59f79f1 --- /dev/null +++ b/.github/workflows/publish-dist.yml @@ -0,0 +1,36 @@ +name: Publish Homebrew + Scoop (manual) + +# Manually (re)publish the Homebrew formula + Scoop manifest for a version that +# is already on npm — without re-running the whole release (npm/docker). Use it +# to test the TAP_TOKEN wiring or to backfill a channel. Auto-publishing on +# release lives in the `dist` job of release.yml. +on: + workflow_dispatch: + inputs: + version: + description: Version to publish (blank = current package.json version) + required: false + default: '' + +permissions: + contents: read + +jobs: + dist: + name: Publish Homebrew + Scoop + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 + with: + node-version: 22 + + - name: Generate and push tap files + env: + TAP_TOKEN: ${{ secrets.TAP_TOKEN }} + INPUT_VERSION: ${{ inputs.version }} + run: | + V="${INPUT_VERSION:-$(node -p "require('./package.json').version")}" + echo "Publishing Homebrew + Scoop for $V" + node scripts/gen-dist.mjs "$V" + VERSION="$V" bash scripts/publish-tap.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f61295e..4bbddf0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -150,30 +150,10 @@ jobs: # Cross-repo push needs a PAT (the default GITHUB_TOKEN is scoped to this # repo). Add a fine-grained TAP_TOKEN secret with contents:write on # wavyx/homebrew-tap and wavyx/scoop-pdcli to enable auto-publish; without - # it this step no-ops so the release never fails on a missing secret. - # Prereleases are skipped (they must not move the stable formula/manifest). + # it publish-tap.sh no-ops so the release never fails. Prereleases skip. + # (Shared with the manual publish-dist workflow via scripts/publish-tap.sh.) - name: Push to tap repos env: TAP_TOKEN: ${{ secrets.TAP_TOKEN }} - V: ${{ steps.gen.outputs.v }} - run: | - case "$V" in *-*) echo "prerelease $V — skipping tap publish"; exit 0 ;; esac - if [ -z "$TAP_TOKEN" ]; then - echo "No TAP_TOKEN secret — skipping Homebrew/Scoop publish." - echo "Run 'node scripts/gen-dist.mjs $V' and push manually, or add the PAT." - exit 0 - fi - git config --global user.name "pdcli-release" - git config --global user.email "release@wavyx.dev" - push_file() { - repo="$1"; src="$2"; dest="$3" - tmp=$(mktemp -d) - git clone --depth 1 "https://x-access-token:${TAP_TOKEN}@github.com/${repo}.git" "$tmp" - mkdir -p "$(dirname "$tmp/$dest")" - cp "$src" "$tmp/$dest" - git -C "$tmp" add "$dest" - git -C "$tmp" commit -m "pdcli $V" || { echo "no change for $repo"; return 0; } - git -C "$tmp" push - } - push_file wavyx/homebrew-tap packaging/homebrew/pdcli.rb Formula/pdcli.rb - push_file wavyx/scoop-pdcli packaging/scoop/pdcli.json bucket/pdcli.json + VERSION: ${{ steps.gen.outputs.v }} + run: bash scripts/publish-tap.sh diff --git a/scripts/publish-tap.sh b/scripts/publish-tap.sh new file mode 100644 index 0000000..0c2642d --- /dev/null +++ b/scripts/publish-tap.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Push the generated Homebrew formula + Scoop manifest to the tap repos. +# +# Requires (env): +# VERSION the version being published (e.g. 0.22.0) +# TAP_TOKEN a fine-grained PAT with contents:write on wavyx/homebrew-tap and +# wavyx/scoop-pdcli. Absent -> this script no-ops (never fails). +# Requires (files): packaging/homebrew/pdcli.rb + packaging/scoop/pdcli.json, +# already generated by `node scripts/gen-dist.mjs "$VERSION"`. +# +# Shared by the release workflow (auto on tag) and the manual publish-dist +# workflow, so the two can never drift. +set -euo pipefail + +: "${VERSION:?VERSION required}" + +# A prerelease must never move the stable formula/manifest. +case "$VERSION" in + *-*) echo "prerelease $VERSION — skipping tap publish"; exit 0 ;; +esac + +if [ -z "${TAP_TOKEN:-}" ]; then + echo "No TAP_TOKEN — skipping Homebrew/Scoop publish." + echo "Add the PAT secret, or run 'node scripts/gen-dist.mjs $VERSION' and push manually." + exit 0 +fi + +git config --global user.name "pdcli-release" +git config --global user.email "release@wavyx.dev" + +push_file() { + repo="$1"; src="$2"; dest="$3" + tmp="$(mktemp -d)" + git clone --depth 1 "https://x-access-token:${TAP_TOKEN}@github.com/${repo}.git" "$tmp" + mkdir -p "$(dirname "$tmp/$dest")" + cp "$src" "$tmp/$dest" + git -C "$tmp" add "$dest" + if git -C "$tmp" commit -m "pdcli $VERSION"; then + git -C "$tmp" push + echo "pushed $repo/$dest" + else + echo "no change for $repo/$dest" + fi +} + +push_file wavyx/homebrew-tap packaging/homebrew/pdcli.rb Formula/pdcli.rb +push_file wavyx/scoop-pdcli packaging/scoop/pdcli.json bucket/pdcli.json