Skip to content

Commit 691b401

Browse files
ci: full automation for tag releases
Extends release-binaries.yml with two new jobs that run after the binary build: publish-npm — publishes the matching tarball to npm (NPM_TOKEN). Verifies tag matches package.json version first to catch tagging mistakes. update-homebrew — checks out VladoIvankovic/homebrew-codeep, computes SHA256 of the freshly published npm tarball, updates url + sha256 + version pin in Formula/codeep.rb, commits, and pushes (HOMEBREW_TAP_TOKEN). Each job depends on the previous so a failure halts the chain — no half-released states. Pushing a single tag now ships GitHub binaries + npm + Homebrew in one go. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent e325dfd commit 691b401

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

.github/workflows/release-binaries.yml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
name: Release Binaries
22

3+
# Triggered when any v*-prefixed tag is pushed. Three jobs run in sequence:
4+
#
5+
# 1. build — compiles cross-platform binaries and uploads them to
6+
# a GitHub Release for the tag.
7+
# 2. publish-npm — publishes the matching tarball to npm.
8+
# 3. update-homebrew — bumps Formula/codeep.rb in the homebrew-codeep tap to
9+
# point at the just-published npm tarball.
10+
#
11+
# Each job depends on the previous one so a failure halts the chain (no half-
12+
# released states). All credentials come from repository secrets:
13+
#
14+
# GITHUB_TOKEN (provided by Actions)
15+
# NPM_TOKEN (npm Automation token)
16+
# HOMEBREW_TAP_TOKEN (PAT with write access to VladoIvankovic/homebrew-codeep)
17+
318
on:
419
push:
520
tags:
@@ -57,3 +72,117 @@ jobs:
5772
dist/bin/codeep-darwin-x86_64.tar.gz
5873
dist/bin/codeep-linux-x86_64.tar.gz
5974
dist/bin/codeep-linux-aarch64.tar.gz
75+
76+
publish-npm:
77+
name: Publish to npm
78+
needs: build
79+
runs-on: ubuntu-latest
80+
steps:
81+
- uses: oven-sh/setup-bun@v2
82+
83+
- name: Checkout
84+
uses: actions/checkout@v4
85+
86+
- name: Install dependencies
87+
run: bun install --frozen-lockfile
88+
89+
- name: Build TypeScript
90+
run: bun run build
91+
92+
- name: Setup Node + npm registry
93+
uses: actions/setup-node@v4
94+
with:
95+
node-version: '20'
96+
registry-url: 'https://registry.npmjs.org'
97+
98+
- name: Verify tag matches package.json version
99+
run: |
100+
# The tag should be v<version>; if it doesn't match package.json, abort.
101+
# Catches the case where someone tagged the wrong commit.
102+
TAG="${GITHUB_REF#refs/tags/v}"
103+
PKG=$(node -p "require('./package.json').version")
104+
if [ "$TAG" != "$PKG" ]; then
105+
echo "::error::Tag $TAG does not match package.json version $PKG. Aborting publish."
106+
exit 1
107+
fi
108+
109+
- name: Publish
110+
run: npm publish --access public
111+
env:
112+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
113+
114+
update-homebrew:
115+
name: Update Homebrew formula
116+
needs: publish-npm
117+
runs-on: ubuntu-latest
118+
steps:
119+
- name: Checkout homebrew-codeep tap
120+
uses: actions/checkout@v4
121+
with:
122+
repository: VladoIvankovic/homebrew-codeep
123+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
124+
path: tap
125+
126+
- name: Resolve version from tag
127+
id: ver
128+
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
129+
130+
- name: Wait for npm registry, fetch tarball, compute SHA256
131+
id: hash
132+
run: |
133+
# npm publish is eventually consistent across registry mirrors; give
134+
# it up to 60s before giving up. Each retry is 5s apart.
135+
VERSION="${{ steps.ver.outputs.version }}"
136+
URL="https://registry.npmjs.org/codeep/-/codeep-${VERSION}.tgz"
137+
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
138+
if curl -fsSL "$URL" -o codeep.tgz; then
139+
echo "Fetched on attempt $i"
140+
break
141+
fi
142+
echo "Attempt $i failed, sleeping 5s..."
143+
sleep 5
144+
done
145+
if [ ! -s codeep.tgz ]; then
146+
echo "::error::Could not fetch $URL"
147+
exit 1
148+
fi
149+
SHA=$(shasum -a 256 codeep.tgz | awk '{print $1}')
150+
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
151+
echo "url=$URL" >> "$GITHUB_OUTPUT"
152+
echo "Tarball SHA256: $SHA"
153+
154+
- name: Update Formula/codeep.rb
155+
working-directory: tap
156+
run: |
157+
VERSION="${{ steps.ver.outputs.version }}"
158+
SHA="${{ steps.hash.outputs.sha }}"
159+
URL="${{ steps.hash.outputs.url }}"
160+
# Use Python for the substitutions — sed across multiline ruby is
161+
# finicky with @-lines and quoting. Python keeps the diff minimal.
162+
python3 - <<EOF
163+
import re, pathlib
164+
p = pathlib.Path('Formula/codeep.rb')
165+
src = p.read_text()
166+
src = re.sub(r'url ".*"', f'url "$URL"', src, count=1)
167+
src = re.sub(r'sha256 ".*"', f'sha256 "$SHA"', src, count=1)
168+
src = re.sub(r'codeep@\d+\.\d+\.\d+', f'codeep@$VERSION', src)
169+
p.write_text(src)
170+
EOF
171+
echo "--- updated codeep.rb ---"
172+
cat Formula/codeep.rb
173+
174+
- name: Commit and push
175+
working-directory: tap
176+
run: |
177+
VERSION="${{ steps.ver.outputs.version }}"
178+
git config user.name 'github-actions[bot]'
179+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
180+
git add Formula/codeep.rb
181+
# Skip the commit if nothing actually changed (e.g. a re-run of the
182+
# same tag) — `git commit` would otherwise fail and break the job.
183+
if git diff --staged --quiet; then
184+
echo "Formula already up to date for v$VERSION; nothing to commit."
185+
exit 0
186+
fi
187+
git commit -m "codeep $VERSION"
188+
git push

0 commit comments

Comments
 (0)