Skip to content

Commit b59171a

Browse files
author
David Elner
committed
Changed: Use shared release actions for JS package release
1 parent edfa259 commit b59171a

4 files changed

Lines changed: 226 additions & 162 deletions

File tree

.github/workflows/publish-js.yaml

Lines changed: 160 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,40 @@
1+
#
2+
# Publishes the `autoevals` npm package via the shared, centrally-maintained
3+
# release actions in braintrustdata/sdk-actions (pinned by SHA below). Bumping
4+
# that SHA pulls in upstream release-tooling improvements.
5+
#
6+
# Adapted from braintrustdata/sdk-actions .github/workflows/release-js.yml
7+
# @ dc38f223e415652eb4a4f17567a360662ba729b1
8+
#
9+
# ─────────────────────────────────────────────────────────────────────────────
10+
# SETUP REQUIREMENTS
11+
# ─────────────────────────────────────────────────────────────────────────────
12+
#
13+
# GitHub Environments (repo Settings → Environments):
14+
# npm-publish
15+
# - Required reviewers: SDK maintainers
16+
# - Deployment branches: main only
17+
# npm-publish-dry-run
18+
# - Required reviewers: at least yourself (to exercise the gate)
19+
# - Allow administrators to bypass: enabled
20+
#
21+
# npm Trusted Publishing (OIDC — no token):
22+
# npmjs.com → autoevals → Settings → Trusted Publisher
23+
# Repository: braintrustdata/autoevals
24+
# Workflow: publish-js.yaml
25+
# Environment: npm-publish ← MUST match, or the gated publish is rejected
26+
# Provenance requires a PUBLIC package; the publish job needs id-token: write.
27+
#
28+
# Slack (optional — steps self-guard and no-op if unset):
29+
# Repository variable SLACK_SDK_RELEASE_CHANNEL (channel ID)
30+
# Repository/org secret SLACK_BOT_TOKEN (Brainbot token; invite it to the channel)
31+
#
32+
# ─────────────────────────────────────────────────────────────────────────────
33+
134
name: publish-js
235

336
concurrency:
4-
group: publish-js-${{ inputs.release_type }}-${{ inputs.branch }}
37+
group: publish-js-${{ inputs.release_type }}-${{ inputs.sha }}
538
cancel-in-progress: false
639

740
on:
@@ -15,192 +48,178 @@ on:
1548
options:
1649
- stable
1750
- prerelease
18-
branch:
19-
description: Branch to release from
51+
sha:
52+
description: Commit SHA to release (full 40-char SHA)
2053
required: true
21-
default: main
2254
type: string
2355
prerelease_suffix:
2456
description: Optional shared prerelease suffix
2557
required: false
2658
default: ""
2759
type: string
60+
dry_run:
61+
description: "Dry run: build and pack without publishing"
62+
required: false
63+
default: false
64+
type: boolean
2865

2966
jobs:
30-
prepare-release:
67+
# autoevals glue: fail-fast version sync + version/channel computation (all pre-gate).
68+
compute-metadata:
3169
runs-on: ubuntu-latest
3270
timeout-minutes: 10
3371
outputs:
34-
version: ${{ steps.release_metadata.outputs.version }}
35-
release_tag: ${{ steps.release_metadata.outputs.release_tag }}
36-
branch: ${{ steps.release_metadata.outputs.branch }}
37-
commit: ${{ steps.release_metadata.outputs.commit }}
38-
release_type: ${{ steps.release_metadata.outputs.release_type }}
72+
version: ${{ steps.meta.outputs.version }}
73+
channel: ${{ steps.meta.outputs.channel }}
74+
github_release: ${{ steps.meta.outputs.github_release }}
75+
release_type: ${{ steps.meta.outputs.release_type }}
3976
steps:
4077
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4178
with:
79+
ref: ${{ inputs.sha }}
4280
fetch-depth: 1
43-
ref: ${{ inputs.branch }}
81+
82+
# Only place version-sync runs — pre-gate, fail-fast.
4483
- name: Check version sync
4584
run: python3 .github/scripts/check_version_sync.py
46-
- name: Set up Node.js
47-
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
48-
with:
49-
node-version-file: .tool-versions
50-
- name: Determine release metadata
51-
id: release_metadata
85+
86+
- name: Compute release metadata
87+
id: meta
5288
env:
5389
RELEASE_TYPE: ${{ inputs.release_type }}
54-
TARGET_BRANCH: ${{ inputs.branch }}
5590
PRERELEASE_SUFFIX: ${{ inputs.prerelease_suffix }}
5691
run: |
5792
set -euo pipefail
5893
59-
CURRENT_VERSION=$(node -p "require('./package.json').version")
60-
RELEASE_COMMIT=$(git rev-parse HEAD)
61-
62-
if [[ -z "${PRERELEASE_SUFFIX}" ]]; then
63-
PRERELEASE_SUFFIX="${GITHUB_RUN_NUMBER}"
64-
fi
65-
94+
CURRENT=$(node -p "require('./package.json').version")
6695
echo "release_type=${RELEASE_TYPE}" >> "$GITHUB_OUTPUT"
67-
echo "branch=${TARGET_BRANCH}" >> "$GITHUB_OUTPUT"
68-
echo "commit=${RELEASE_COMMIT}" >> "$GITHUB_OUTPUT"
6996
7097
if [[ "$RELEASE_TYPE" == "stable" ]]; then
71-
RELEASE_TAG="js-${CURRENT_VERSION}"
72-
73-
if git ls-remote --exit-code --tags origin "refs/tags/${RELEASE_TAG}" >/dev/null 2>&1; then
74-
echo "Tag ${RELEASE_TAG} already exists on origin" >&2
75-
exit 1
76-
fi
77-
78-
echo "version=${CURRENT_VERSION}" >> "$GITHUB_OUTPUT"
79-
echo "release_tag=${RELEASE_TAG}" >> "$GITHUB_OUTPUT"
98+
echo "version=${CURRENT}" >> "$GITHUB_OUTPUT"
99+
echo "channel=latest" >> "$GITHUB_OUTPUT"
100+
echo "github_release=true" >> "$GITHUB_OUTPUT"
80101
else
81-
VERSION="${CURRENT_VERSION}-rc.${PRERELEASE_SUFFIX}"
82-
83-
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
84-
echo "release_tag=" >> "$GITHUB_OUTPUT"
102+
SUFFIX="${PRERELEASE_SUFFIX:-$GITHUB_RUN_NUMBER}"
103+
echo "version=${CURRENT}-rc.${SUFFIX}" >> "$GITHUB_OUTPUT"
104+
echo "channel=rc" >> "$GITHUB_OUTPUT"
105+
echo "github_release=false" >> "$GITHUB_OUTPUT"
85106
fi
86107
108+
validate:
109+
needs: compute-metadata
110+
runs-on: ubuntu-latest
111+
timeout-minutes: 10
112+
permissions:
113+
contents: read
114+
outputs:
115+
release_tag: ${{ steps.validate.outputs.release_tag }}
116+
prev_release: ${{ steps.validate.outputs.prev_release }}
117+
branch: ${{ steps.validate.outputs.branch }}
118+
on_release_branch: ${{ steps.validate.outputs.on_release_branch }}
119+
commit_message: ${{ steps.validate.outputs.commit_message }}
120+
steps:
121+
- name: Validate release
122+
id: validate
123+
uses: braintrustdata/sdk-actions/actions/release/lang/js/validate@dc38f223e415652eb4a4f17567a360662ba729b1
124+
with:
125+
sha: ${{ inputs.sha }}
126+
version: ${{ needs.compute-metadata.outputs.version }} # computed override (esp. prerelease)
127+
node_version: .tool-versions
128+
tag_format: 'js-{version}'
129+
package_name: autoevals # enables the npm-availability fail-fast (covers prereleases)
130+
channel: ${{ needs.compute-metadata.outputs.channel }}
131+
allowed_channels: 'latest,rc'
132+
dry_run: ${{ inputs.dry_run }}
133+
134+
prepare:
135+
needs: validate
136+
runs-on: ubuntu-latest
137+
timeout-minutes: 5
138+
permissions:
139+
contents: write # required for the releases/generate-notes API
140+
outputs:
141+
pr_list: ${{ steps.prepare.outputs.pr_list }}
142+
notes: ${{ steps.prepare.outputs.notes }}
143+
steps:
144+
- name: Prepare release
145+
id: prepare
146+
uses: braintrustdata/sdk-actions/actions/release/prepare@dc38f223e415652eb4a4f17567a360662ba729b1
147+
with:
148+
release_tag: ${{ needs.validate.outputs.release_tag }}
149+
sha: ${{ inputs.sha }}
150+
prev_release: ${{ needs.validate.outputs.prev_release }}
151+
152+
notify-pending:
153+
needs: [validate, prepare]
154+
runs-on: ubuntu-latest
155+
timeout-minutes: 5
156+
permissions: {}
157+
steps:
158+
- name: Notify release pending
159+
uses: braintrustdata/sdk-actions/actions/release/notify-pending@dc38f223e415652eb4a4f17567a360662ba729b1
160+
with:
161+
sha: ${{ inputs.sha }}
162+
release_tag: ${{ needs.validate.outputs.release_tag }}
163+
prev_release: ${{ needs.validate.outputs.prev_release }}
164+
branch: ${{ needs.validate.outputs.branch }}
165+
on_release_branch: ${{ needs.validate.outputs.on_release_branch }}
166+
commit_message: ${{ needs.validate.outputs.commit_message }}
167+
pr_list: ${{ needs.prepare.outputs.pr_list }}
168+
notes: ${{ needs.prepare.outputs.notes }}
169+
dry_run: ${{ inputs.dry_run }}
170+
slack_token: ${{ secrets.SLACK_BOT_TOKEN }}
171+
slack_channel: ${{ vars.SLACK_SDK_RELEASE_CHANNEL }}
172+
label: 'autoevals (js)'
173+
emoji: ':javascript:'
174+
87175
publish:
88-
needs: prepare-release
176+
needs: [compute-metadata, validate, prepare, notify-pending]
89177
runs-on: ubuntu-latest
90178
timeout-minutes: 20
179+
environment: ${{ inputs.dry_run && 'npm-publish-dry-run' || 'npm-publish' }}
91180
permissions:
92181
contents: write
93-
id-token: write
94-
env:
95-
PACKAGE_NAME: autoevals
96-
VERSION: ${{ needs.prepare-release.outputs.version }}
97-
RELEASE_TAG: ${{ needs.prepare-release.outputs.release_tag }}
98-
RELEASE_TYPE: ${{ needs.prepare-release.outputs.release_type }}
99-
TARGET_BRANCH: ${{ needs.prepare-release.outputs.branch }}
100-
RELEASE_COMMIT: ${{ needs.prepare-release.outputs.commit }}
182+
id-token: write # OIDC trusted publishing + provenance
101183
steps:
102184
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
103185
with:
186+
ref: ${{ inputs.sha }}
104187
fetch-depth: 0
105-
ref: ${{ needs.prepare-release.outputs.branch }}
106188

107-
- name: Check version sync
108-
run: python3 .github/scripts/check_version_sync.py
109-
110-
- name: Set up Node.js
111-
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
112-
with:
113-
node-version-file: .tool-versions
114-
registry-url: https://registry.npmjs.org
115-
116-
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
117-
with:
118-
version: 10.33.0
119-
120-
- name: Check npm version availability
121-
run: |
122-
set -euo pipefail
123-
124-
if npm view "${PACKAGE_NAME}@${VERSION}" version --registry=https://registry.npmjs.org >/dev/null 2>&1; then
125-
echo "${PACKAGE_NAME}@${VERSION} already exists on npm" >&2
126-
exit 1
127-
fi
128-
129-
- name: Install dependencies
130-
run: pnpm install --frozen-lockfile
131-
132-
- name: Prepare prerelease package metadata
133-
if: ${{ env.RELEASE_TYPE == 'prerelease' }}
189+
# Write the computed version into package.json before publish. For a
190+
# prerelease this applies the -rc.N suffix (and deliberately diverges from
191+
# py/version.py); for stable it confirms the already-bumped version.
192+
# publish runs with checkout:false so this edit survives into the build.
193+
- name: Patch package.json version
194+
env:
195+
VERSION: ${{ needs.compute-metadata.outputs.version }}
134196
run: |
135-
set -euo pipefail
136-
137197
node -e '
138198
const fs = require("fs");
139199
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
140200
pkg.version = process.env.VERSION;
141201
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n");
142202
'
143203
144-
- name: Build package
145-
run: pnpm run build
146-
147-
- name: Publish stable release to npm
148-
if: ${{ env.RELEASE_TYPE == 'stable' }}
149-
env:
150-
NODE_AUTH_TOKEN: ""
151-
NPM_TOKEN: ""
152-
run: npm publish --provenance --access public
153-
154-
- name: Publish prerelease to npm
155-
if: ${{ env.RELEASE_TYPE == 'prerelease' }}
156-
env:
157-
NODE_AUTH_TOKEN: ""
158-
NPM_TOKEN: ""
159-
run: npm publish --tag rc --provenance --access public
160-
161-
- name: Create and push stable release tag
162-
if: ${{ env.RELEASE_TYPE == 'stable' }}
163-
run: |
164-
set -euo pipefail
165-
166-
git config user.name "github-actions[bot]"
167-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
168-
git tag "${RELEASE_TAG}" "${RELEASE_COMMIT}"
169-
git push origin "${RELEASE_TAG}"
170-
171-
- name: Create GitHub release
172-
if: ${{ env.RELEASE_TYPE == 'stable' }}
173-
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
174-
env:
175-
RELEASE_TAG: ${{ env.RELEASE_TAG }}
176-
VERSION: ${{ env.VERSION }}
204+
- name: Publish
205+
uses: braintrustdata/sdk-actions/actions/release/lang/js/publish@dc38f223e415652eb4a4f17567a360662ba729b1
177206
with:
178-
script: |
179-
await github.rest.repos.createRelease({
180-
owner: context.repo.owner,
181-
repo: context.repo.repo,
182-
tag_name: process.env.RELEASE_TAG,
183-
name: `autoevals JavaScript v${process.env.VERSION}`,
184-
draft: false,
185-
prerelease: false,
186-
generate_release_notes: true,
187-
});
188-
189-
- name: Summarize release
190-
run: |
191-
set -euo pipefail
192-
193-
{
194-
echo "## npm publish complete"
195-
echo
196-
echo "- Package: \`${PACKAGE_NAME}\`"
197-
echo "- Version: \`${VERSION}\`"
198-
echo "- Release type: \`${RELEASE_TYPE}\`"
199-
if [ "${RELEASE_TYPE}" = "prerelease" ]; then
200-
echo "- npm tag: \`rc\`"
201-
echo "- Install: \`npm install ${PACKAGE_NAME}@rc\`"
202-
else
203-
echo "- Git tag: \`${RELEASE_TAG}\`"
204-
echo "- Install: \`npm install ${PACKAGE_NAME}\`"
205-
fi
206-
} >> "$GITHUB_STEP_SUMMARY"
207+
sha: ${{ inputs.sha }}
208+
checkout: 'false' # keep the patched package.json (checked out + patched above)
209+
node_version: .tool-versions
210+
version: ${{ needs.compute-metadata.outputs.version }}
211+
release_tag: ${{ needs.validate.outputs.release_tag }}
212+
channel: ${{ needs.compute-metadata.outputs.channel }}
213+
github_release: ${{ needs.compute-metadata.outputs.github_release }} # stable only
214+
release_title: autoevals JavaScript v${{ needs.compute-metadata.outputs.version }}
215+
package_name: autoevals
216+
label: 'autoevals (js)'
217+
dry_run: ${{ inputs.dry_run }}
218+
notes: ${{ needs.prepare.outputs.notes }}
219+
prev_release: ${{ needs.validate.outputs.prev_release }}
220+
branch: ${{ needs.validate.outputs.branch }}
221+
on_release_branch: ${{ needs.validate.outputs.on_release_branch }}
222+
pr_list: ${{ needs.prepare.outputs.pr_list }}
223+
slack_token: ${{ secrets.SLACK_BOT_TOKEN }}
224+
slack_channel: ${{ vars.SLACK_SDK_RELEASE_CHANNEL }}
225+
emoji: ':javascript:'

0 commit comments

Comments
 (0)