-
Notifications
You must be signed in to change notification settings - Fork 0
238 lines (207 loc) · 11.8 KB
/
Copy pathrelease.yml
File metadata and controls
238 lines (207 loc) · 11.8 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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# agent-pmo:b636503
name: Release
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
id-token: write # npm OIDC trusted publishing (no NPM_TOKEN secret)
actions: write # dispatch deploy-pages.yml after the release is created
jobs:
release:
name: Release
runs-on: ubuntu-latest
# TIMEOUT EXCEPTION: This release job stamps versions, runs CI, builds packages,
# and publishes npm, crates.io, and NuGet artifacts in one tag-triggered flow.
timeout-minutes: 40
environment: release
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# ── toolchains ──────────────────────────────────────────────────────────
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
with:
toolchain: stable
components: rustfmt, clippy, llvm-tools-preview
# Canonical npm OIDC trusted-publishing setup: registry-url so npm knows
# the registry; npm >= 11.5.1 then mints a short-lived token from the
# GitHub OIDC token. No NODE_AUTH_TOKEN secret. [SWR-SEC-OIDC-PUBLISH]
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
# npm OIDC trusted publishing requires npm >= 11.5.1 (action ships older).
# DIAGNOSTIC: surface the placeholder token + the generated .npmrc so we can
# see exactly what npm sees before deciding token-vs-OIDC.
- name: Upgrade npm + diagnose OIDC preconditions
run: |
npm install -g npm@latest
echo "npm=$(npm --version) registry=$(npm config get registry)"
echo "OIDC URL present: ${ACTIONS_ID_TOKEN_REQUEST_URL:+yes}${ACTIONS_ID_TOKEN_REQUEST_URL:-NO}"
echo "NODE_AUTH_TOKEN literal: [${NODE_AUTH_TOKEN}]"
echo "--- userconfig ($NPM_CONFIG_USERCONFIG) ---"
cat "${NPM_CONFIG_USERCONFIG:-$HOME/.npmrc}" 2>/dev/null | sed 's/_authToken=.*/_authToken=<redacted-if-real>/' || echo "(none)"
# DIAGNOSTIC: print the exact OIDC claims npm matches a Trusted Publisher
# against (NOT secret). If a publish fails "package not found", compare
# these to the npmjs.com Trusted Publisher fields character-for-character.
- name: Decode OIDC claims (diagnostic)
run: |
RESP=$(curl -sf -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm:registry.npmjs.org") || { echo "claim fetch failed (non-fatal)"; exit 0; }
echo "$RESP" | python3 -c "import sys,json,base64; t=json.load(sys.stdin)['value']; p=t.split('.')[1]; p+='='*(-len(p)%4); c=json.loads(base64.urlsafe_b64decode(p)); print(json.dumps({k:c.get(k) for k in ['repository','repository_id','repository_owner','workflow_ref','job_workflow_ref','environment','ref','ref_type']}, indent=0))" || echo "claim decode failed (non-fatal)"
- uses: actions/setup-dotnet@9a946fdbd5fb07b82b2f5a4466058b876ab72bb2 # v5.3.0
with:
dotnet-version: '9.x'
# `make ci` runs `make lint`, which now includes `dart analyze` for the Dart
# client. The release job must install Dart just like ci.yml does, or lint
# fails with `dart: not found` (Makefile lint, exit 127).
- uses: dart-lang/setup-dart@v1
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@7a79fe8c3a13344501c80d99cae481c1c9085912 # v2
with:
tool: cargo-llvm-cov
- name: Install pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
# ── stamp the release version ────────────────────────────────────────────
# Source carries the 0.0.0-dev placeholder; the real version lives only in
# the git tag. Stamp every manifest (Cargo.toml, package.json, *.csproj,
# pubspec.yaml) + build-info.json before CI, build, or publish runs.
- name: Stamp version from tag
run: cargo run --manifest-path tools/shipwright-version-stamp/Cargo.toml -- --tag "${{ github.ref_name }}" --root .
# ── CI gate ─────────────────────────────────────────────────────────────
- name: CI
run: make ci
# ── build npm packages ───────────────────────────────────────────────────
- name: Install npm dependencies
run: pnpm install --frozen-lockfile
- name: Build npm packages
run: |
pnpm --filter @nimblesite/shipwright-core build
pnpm --filter @nimblesite/shipwright-mcp build
pnpm --filter @nimblesite/shipwright-vscode build
# ── publish npm packages via OIDC trusted publishing ────────────────────
# Each package must be configured as a Trusted Publisher on npmjs.com
# pointing at: repo=Nimblesite/Shipwright, workflow=.github/workflows/release.yml,
# environment=release. No NPM_TOKEN secret is used — npm CLI 11.5.1+
# exchanges the GitHub-issued OIDC token for a short-lived publish token.
- name: Publish @nimblesite/shipwright-core
working-directory: clients/ts/packages/shipwright-core
run: |
PKG=$(node -p "require('./package.json').version")
if npm view @nimblesite/shipwright-core@$PKG version 2>/dev/null | grep -q "$PKG"; then
echo "@nimblesite/shipwright-core@$PKG already published — skipping"
else
# DIAGNOSTIC: override the setup-node placeholder token with empty so
# npm cannot auth with a bogus token; verbose log shows the OIDC path;
# dump npm's debug log on failure for the exact reason it falls back.
NODE_AUTH_TOKEN="" npm publish --provenance --access public --loglevel verbose 2>&1 \
|| { echo "=== npm debug log ==="; cat ~/.npm/_logs/*-debug-*.log 2>/dev/null | tail -120; exit 1; }
fi
- name: Publish @nimblesite/shipwright-mcp
working-directory: clients/ts/packages/shipwright-mcp
run: |
PKG=$(node -p "require('./package.json').version")
if npm view @nimblesite/shipwright-mcp@$PKG version 2>/dev/null | grep -q "$PKG"; then
echo "@nimblesite/shipwright-mcp@$PKG already published — skipping"
else
NODE_AUTH_TOKEN="" npm publish --provenance --access public
fi
# shipwright-vscode depends on shipwright-core via the workspace:*
# protocol. pnpm pack rewrites workspace:* to the concrete version in
# the tarball; npm publish then uploads that tarball under OIDC.
- name: Publish @nimblesite/shipwright-vscode
working-directory: clients/ts/packages/shipwright-vscode
run: |
PKG=$(node -p "require('./package.json').version")
if npm view @nimblesite/shipwright-vscode@$PKG version 2>/dev/null | grep -q "$PKG"; then
echo "@nimblesite/shipwright-vscode@$PKG already published — skipping"
else
pnpm pack
NODE_AUTH_TOKEN="" npm publish --provenance --access public nimblesite-shipwright-vscode-${PKG}.tgz
fi
- name: Publish @nimblesite/shipwright-validate-manifest
working-directory: tools/validate-manifest
run: |
PKG=$(node -p "require('./package.json').version")
if npm view @nimblesite/shipwright-validate-manifest@$PKG version 2>/dev/null | grep -q "$PKG"; then
echo "@nimblesite/shipwright-validate-manifest@$PKG already published — skipping"
else
NODE_AUTH_TOKEN="" npm publish --provenance --access public
fi
# ── publish to crates.io ─────────────────────────────────────────────────
# Order per docs/plans/release-pipeline.md §3.1:
# 1) shipwright-manifest (no internal deps)
# 2) shipwright-host + shipwright (both depend only on manifest)
# 3) shipwright-zed (depends on shipwright-host) + shipwright-version-stamp
# `cargo publish` (>=1.66) polls for each crate to appear in the index
# before returning (default 60s timeout, longer than the old 30s sleep),
# so the next crate resolves its path-and-version deps without a manual wait.
# crates.io OIDC Trusted Publishing: mint a short-lived registry token from
# the GitHub OIDC token — no stored CARGO_REGISTRY_TOKEN. Each crate has a
# Trusted Publisher (Nimblesite/Shipwright, release.yml, env release).
# [SWR-SEC-OIDC-PUBLISH]
- name: Authenticate to crates.io via OIDC
id: crates_auth
uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
- name: Publish shipwright-manifest to crates.io
run: scripts/cargo-publish-or-skip.sh shipwright-manifest
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
- name: Publish shipwright-host to crates.io
run: scripts/cargo-publish-or-skip.sh shipwright-host
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
- name: Publish shipwright to crates.io
run: scripts/cargo-publish-or-skip.sh shipwright
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
- name: Publish shipwright-zed to crates.io
run: scripts/cargo-publish-or-skip.sh shipwright-zed
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
- name: Publish shipwright-version-stamp to crates.io
run: scripts/cargo-publish-or-skip.sh shipwright-version-stamp
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token }}
# ── publish NuGet ────────────────────────────────────────────────────────
- name: Pack NuGet
run: |
dotnet pack clients/dotnet/Shipwright/Shipwright.csproj \
-c Release -o ./nupkg --include-symbols
# nuget.org OIDC Trusted Publishing: exchange the GitHub OIDC token for a
# short-lived API key — no stored NUGET_API_KEY. Policy: package owner
# Nimblesite, repo Nimblesite/Shipwright, release.yml, env release.
# [SWR-SEC-OIDC-PUBLISH]
- name: Authenticate to NuGet via OIDC
id: nuget_login
uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1.2.0
with:
user: Nimblesite
- name: Publish NuGet
run: |
dotnet nuget push ./nupkg/Shipwright.*.nupkg \
--api-key "$NUGET_API_KEY" \
--source https://api.nuget.org/v3/index.json \
--skip-duplicate
env:
NUGET_API_KEY: ${{ steps.nuget_login.outputs.NUGET_API_KEY }}
deploy-pages:
name: Trigger website deploy
runs-on: ubuntu-latest
timeout-minutes: 10
needs: release
steps:
- name: Trigger deploy-pages workflow
uses: actions/github-script@v8
with:
script: |
const ref = context.ref.replace(/^refs\/(heads|tags)\//, '');
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'deploy-pages.yml',
ref,
});