-
Notifications
You must be signed in to change notification settings - Fork 0
94 lines (86 loc) · 4.07 KB
/
Copy pathrelease.yml
File metadata and controls
94 lines (86 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# Publish to npm on a version tag, using OIDC trusted publishing.
#
# The one setting a human owns is on npmjs.com, not here: package `quac` →
# Settings → Trusted Publisher → GitHub Actions, org `jeyabbalas`, repo `quac`,
# workflow `release.yml`, no environment. Until that is configured, this
# workflow fails at `npm publish` with an auth error — which is the correct
# failure, since the alternative is a long-lived token in the repository.
name: Release
# `CI` runs on pushes to `main` and on pull requests, never on tags, so the two
# workflows cannot collide over the same commit.
on:
push:
tags: ['v*']
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
# The whole point: this mints the short-lived OIDC token npm exchanges for
# publish rights. No NPM_TOKEN exists in this repository, so a leaked
# secret is not a thing that can happen here.
id-token: write
contents: read
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
# Required even for trusted publishing: it writes the .npmrc that
# points the client at the registry the OIDC exchange happens with.
registry-url: https://registry.npmjs.org
cache: npm
# Trusted publishing needs npm >= 11.5.1. Node 24 ships npm 11.x, but the
# bundled patch version moves with the runner image, so assert rather than
# assume — a silent fallback to token auth would fail later and more
# confusingly, with no token to fall back to.
- name: Assert npm supports trusted publishing
run: |
need=11.5.1
have=$(npm --version)
echo "npm $have (need >= $need)"
if [ "$(printf '%s\n%s\n' "$need" "$have" | sort -V | head -1)" != "$need" ]; then
echo "::error::npm $have is too old for OIDC trusted publishing (need >= $need)."
echo "Add a 'npm install -g npm@latest' step, or pin a newer Node."
exit 1
fi
# A tag is cheap to mistype and impossible to reuse once published. This
# is the last chance to notice that v1.0.1 is about to publish 1.0.0.
- name: Assert the tag matches package.json
if: startsWith(github.ref, 'refs/tags/v')
run: |
tag="${GITHUB_REF_NAME#v}"
pkg=$(node -p "require('./package.json').version")
echo "tag $tag · package.json $pkg"
[ "$tag" = "$pkg" ] || {
echo "::error::tag v$tag does not match package.json version $pkg."
exit 1
}
- run: npm ci
# The same gate `main` is held to. A tag can only ever point at a commit
# that already passed CI, but the tag is what gets published, so it is
# what gets checked.
- run: npm run verify
- run: npm run test:cli
# v1.0.0 is published by hand, because npm cannot be told about a trusted
# publisher for a package that does not exist yet. So the very first `v*`
# tag would otherwise fire this workflow at a version already on the
# registry and fail with E403 — a red run on the release commit, for a
# release that went fine. A tag naming an already-published version is a
# no-op, not an error. This also makes re-running the workflow safe.
- name: Is this version already on the registry?
id: published
run: |
v=$(node -p "require('./package.json').version")
if npm view "@jeyabbalas/quac@$v" version >/dev/null 2>&1; then
echo "already=true" >> "$GITHUB_OUTPUT"
echo "::notice::@jeyabbalas/quac@$v is already published — skipping publish."
else
echo "already=false" >> "$GITHUB_OUTPUT"
echo "@jeyabbalas/quac@$v is not on the registry yet — will publish."
fi
# `prepack` builds dist-cli/. Provenance is attached automatically under
# trusted publishing — passing --provenance is unnecessary and, on some
# npm versions, an error.
- if: steps.published.outputs.already != 'true'
run: npm publish