Skip to content

Commit a28e35b

Browse files
authored
Merge pull request #47 from edgehero/ci/repo-release
ci: repo-level GitHub Release on version bump (fixes 'no releases on merge')
2 parents 76a49dc + 3c0e639 commit a28e35b

3 files changed

Lines changed: 92 additions & 7 deletions

File tree

.github/workflows/release.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# Publish @edgehero/pi-dispatch-admin and cut a GitHub Release when its version changes on main.
1+
# Publish @edgehero/pi-dispatch-admin (npm) and cut its GitHub Release when admin/package.json's version
2+
# changes on main. This is the EXTENSION's pipeline: it tags admin-v*. The whole TOOL's releases (v*) are cut
3+
# by repo-release.yml off the ROOT package.json version — the two never share a tag.
24
#
35
# main is branch-protected (PR + 1 approving review required), so a push here is an already-approved merge —
46
# the human gate is the merge, not this workflow (consistent with CONST-MERGE-NEVER-AUTOMATIC: nothing here
@@ -63,8 +65,10 @@ jobs:
6365
else
6466
echo "publish=yes" >> "$GITHUB_OUTPUT"
6567
fi
66-
if gh release view "v$V" >/dev/null 2>&1; then
67-
echo "release=no" >> "$GITHUB_OUTPUT"; echo "release v$V already exists — skip release"
68+
# The admin EXTENSION's GitHub releases are tagged admin-v* so the tool's own releases own the v*
69+
# namespace (see repo-release.yml). npm publish above is unaffected — it keys off the package version.
70+
if gh release view "admin-v$V" >/dev/null 2>&1; then
71+
echo "release=no" >> "$GITHUB_OUTPUT"; echo "release admin-v$V already exists — skip release"
6872
else
6973
echo "release=yes" >> "$GITHUB_OUTPUT"
7074
fi
@@ -81,7 +85,7 @@ jobs:
8185
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
8286
RELEASE_MODEL: ${{ vars.RELEASE_MODEL }}
8387
run: |
84-
PREV=$(git tag --list 'v*' --sort=-v:refname | head -n1)
88+
PREV=$(git tag --list 'admin-v*' --sort=-v:refname | head -n1)
8589
RANGE=${PREV:+$PREV..HEAD}
8690
COMMITS=$(git log $RANGE --no-merges --pretty=format:'- %s' -- admin/ | head -n 60)
8791
if [ -n "$ANTHROPIC_API_KEY" ] && COMMITS="$COMMITS" VERSION="v${{ steps.v.outputs.version }}" \
@@ -97,6 +101,6 @@ jobs:
97101
env:
98102
GH_TOKEN: ${{ github.token }}
99103
run: |
100-
gh release create "v${{ steps.v.outputs.version }}" \
101-
--title "v${{ steps.v.outputs.version }} — pi-dispatch operator extension" \
104+
gh release create "admin-v${{ steps.v.outputs.version }}" \
105+
--title "@edgehero/pi-dispatch-admin v${{ steps.v.outputs.version }}" \
102106
--notes-file /tmp/notes.md

.github/workflows/repo-release.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Cut a GitHub Release for the WHOLE pi-dispatch tool when the ROOT package.json version changes on main.
2+
#
3+
# This is distinct from release.yml, which PUBLISHES the @edgehero/pi-dispatch-admin npm package (and tags
4+
# its own releases admin-v*). This workflow owns the v* tags = the product's releases. To cut one, bump
5+
# `version` in the root package.json in a PR; it is idempotent (skips when the tag already exists), so an
6+
# unrelated root package.json edit — a dependency bump, a script tweak — is a no-op.
7+
#
8+
# main is branch-protected (PR + 1 approving review), so a push here is an already-approved merge — nothing
9+
# here merges anything (CONST-MERGE-NEVER-AUTOMATIC). No secret is required to tag a release; the optional
10+
# repo secret ANTHROPIC_API_KEY enables AI-written notes, and without it the release falls back to a plain
11+
# commit list. Optional repo variable RELEASE_MODEL (default: claude-sonnet-5).
12+
13+
name: repo-release
14+
15+
on:
16+
push:
17+
branches: [main]
18+
paths:
19+
- "package.json" # the ROOT one only (a bare path does not match nested workspace package.json files)
20+
- ".github/workflows/repo-release.yml"
21+
- ".github/scripts/release-notes.mjs"
22+
workflow_dispatch: {}
23+
24+
permissions:
25+
contents: write # create tags + releases
26+
27+
concurrency:
28+
group: repo-release
29+
cancel-in-progress: false
30+
31+
jobs:
32+
release:
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v4
36+
with:
37+
fetch-depth: 0 # full history for the release-notes commit range
38+
39+
- uses: actions/setup-node@v4
40+
with:
41+
node-version: "22.19"
42+
43+
- name: Resolve version + decide release
44+
id: v
45+
env:
46+
GH_TOKEN: ${{ github.token }}
47+
run: |
48+
V=$(node -p "require('./package.json').version")
49+
echo "version=$V" >> "$GITHUB_OUTPUT"
50+
if gh release view "v$V" >/dev/null 2>&1; then
51+
echo "release=no" >> "$GITHUB_OUTPUT"; echo "release v$V already exists — skip"
52+
else
53+
echo "release=yes" >> "$GITHUB_OUTPUT"
54+
fi
55+
56+
- name: Build release notes
57+
if: steps.v.outputs.release == 'yes'
58+
env:
59+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
60+
RELEASE_MODEL: ${{ vars.RELEASE_MODEL }}
61+
run: |
62+
# Range since the previous tool release (v*); the whole repo, not just one workspace.
63+
PREV=$(git tag --list 'v*' --sort=-v:refname | head -n1)
64+
RANGE=${PREV:+$PREV..HEAD}
65+
COMMITS=$(git log $RANGE --no-merges --pretty=format:'- %s' | head -n 80)
66+
if [ -n "$ANTHROPIC_API_KEY" ] && COMMITS="$COMMITS" VERSION="v${{ steps.v.outputs.version }}" \
67+
node .github/scripts/release-notes.mjs > /tmp/notes.md 2>/tmp/notes.err; then
68+
echo "release notes: AI-written"
69+
else
70+
echo "release notes: AI unavailable ($(head -n1 /tmp/notes.err 2>/dev/null)) — using commit list"
71+
{ echo "### Changes"; echo; printf '%s\n' "$COMMITS"; } > /tmp/notes.md
72+
fi
73+
74+
- name: Create GitHub Release
75+
if: steps.v.outputs.release == 'yes'
76+
env:
77+
GH_TOKEN: ${{ github.token }}
78+
run: |
79+
gh release create "v${{ steps.v.outputs.version }}" \
80+
--title "pi-dispatch v${{ steps.v.outputs.version }}" \
81+
--notes-file /tmp/notes.md

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pi-dispatch",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"private": true,
55
"description": "A containerized job harness for the pi coding agent",
66
"license": "MIT",

0 commit comments

Comments
 (0)