Repository navigation
463 lines (404 loc) · 17.5 KB
/
Copy pathrelease.yml
File metadata and controls
463 lines (404 loc) · 17.5 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
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
name: Release
on:
push:
branches: [main]
paths:
- 'packages/cli/package.json'
permissions: {}
env:
RELEASE_BUILD: 'true'
DEBUG: 'napi:*'
jobs:
check:
if: github.repository == 'voidzero-dev/vite-plus'
name: Check version
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version_changed: ${{ steps.version.outputs.changed }}
version: ${{ steps.version.outputs.version }}
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- name: Check version changes
uses: EndBug/version-check@095362f3cd50f690c8fa0e6afeea81834bd8d320 # v3.0.0
id: version
with:
static-checking: localIsNew
file-url: https://unpkg.com/vite-plus@latest/package.json
file-name: packages/cli/package.json
build-rust:
name: Build bindings and binaries
needs: check
if: needs.check.outputs.version_changed == 'true'
permissions:
contents: read
uses: ./.github/workflows/reusable-release-build.yml
with:
version: ${{ needs.check.outputs.version }}
cache-key: release
request-approval:
runs-on: ubuntu-latest
needs: [check, build-rust]
if: needs.check.outputs.version_changed == 'true'
steps:
- uses: tsickert/discord-webhook@b217a69502f52803de774ded2b1ab7c282e99645 # v7.0.0
with:
webhook-url: ${{ secrets.DISCORD_RELEASES_WEBHOOK_URL }}
content: 'Requesting approval for vite-plus v${{ needs.check.outputs.version }}: ${{ github.server_url }}/${{ github.repository }}/actions/workflows/release.yml'
Release:
runs-on: ubuntu-latest
environment: release
needs: [check, build-rust, request-approval]
if: needs.check.outputs.version_changed == 'true'
permissions:
actions: read # restore the lockfile on release job retries
contents: write
packages: write
id-token: write # Required for OIDC
env:
VERSION: ${{ needs.check.outputs.version }}
# npm publish-time scanning makes a successful upload temporarily
# unavailable to installs. After each dependency tier becomes visible on
# this runner's registry edge, allow time for other CDN edges to settle.
PUBLISH_PROPAGATION_MIN_SECONDS: '60'
PUBLISH_PROPAGATION_TIMEOUT_SECONDS: '600'
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- uses: ./.github/actions/clone
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .node-version
package-manager-cache: false
registry-url: 'https://registry.npmjs.org'
# OIDC dist-tag operations require npm >=11.21.0 and the vite-plus
# trusted publisher's "Allow npm dist-tag" permission.
- name: Install npm with OIDC dist-tag support
run: npm install --global npm@11.21.0
- name: Install dependencies
run: pnpm install
- name: Download cli dist
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: packages/cli/dist
pattern: cli
merge-multiple: true
- name: Download cli docs
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: packages/cli/docs
pattern: cli-docs
merge-multiple: true
- name: Download cli binding
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: packages/cli/artifacts
pattern: vite-plus-native-*
- name: Download core dist
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: packages/core/dist
pattern: core
merge-multiple: true
- name: Download prompts dist
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: prompts
path: packages/prompts/dist
- name: Download LICENSE files
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: packages
pattern: licenses
merge-multiple: true
- uses: ./.github/actions/download-rolldown-binaries
with:
github-token: ${{ github.token }}
target: x86_64-unknown-linux-gnu
upload: 'false'
- name: Download Rust CLI binaries
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: rust-cli-artifacts
pattern: vp-global-cli-*
- name: Download installer binaries (Windows)
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: installer-artifacts
pattern: vp-setup-*
- name: Prepare installer binaries for release
run: |
mkdir -p installer-release
for artifact_dir in installer-artifacts/vp-setup-*/; do
if [ -d "$artifact_dir" ]; then
dir_name=$(basename "$artifact_dir")
target_name=${dir_name#vp-setup-}
cp "$artifact_dir/vp-setup.exe" "installer-release/vp-setup-${target_name}.exe"
fi
done
echo "Installer binaries:"
ls -la installer-release/ || echo "No installer binaries found"
- name: Download release archives
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: binary-release
pattern: vp-release-archive-*
merge-multiple: true
- name: Prepare and publish native addons
run: node ./packages/cli/publish-native-addons.ts --mode npm --phase native
- name: Publish prompts
run: >-
node ./.github/scripts/publish-npm-package.ts
"@voidzero-dev/vite-plus-prompts@${VERSION}"
--
pnpm publish --filter=./packages/prompts --tag latest --access public --no-git-checks
- name: Publish core dependency tier
run: >-
node ./.github/scripts/publish-npm-package.ts
"@voidzero-dev/vite-plus-core@${VERSION}"
--
pnpm publish --filter=./packages/core --tag latest --access public --no-git-checks
# The CLI pins core via workspace:* (rewritten to this exact version).
# Wait for both its install metadata and tarball before publishing the CLI.
- name: Wait for core to propagate
run: >-
node ./.github/scripts/wait-for-npm-packages.ts
"@voidzero-dev/vite-plus-core@${VERSION}"
# Make the exact local CLI version installable without moving latest.
# Bootstrap keeps selecting the previous release until its matching global
# packages and lockfile are available.
- name: Publish local CLI with the staging tag
run: >-
node ./.github/scripts/publish-npm-package.ts
"vite-plus@${VERSION}"
--
pnpm publish --filter=./packages/cli --tag staging --access public --no-git-checks
- name: Wait for the local CLI to propagate
run: >-
node ./.github/scripts/wait-for-npm-packages.ts
"vite-plus@${VERSION}"
"@voidzero-dev/vite-plus-prompts@${VERSION}"
# Keep the first pnpm resolution when retrying a partially published release.
- name: Restore installation lockfile from an earlier attempt
id: install-lockfile
env:
GH_TOKEN: ${{ github.token }}
run: |
artifact_id=$(gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts" \
--jq '.artifacts[] | select(.name == "installation-lockfile" and .expired == false) | .id')
if [ -n "$artifact_id" ]; then
gh api "repos/${GITHUB_REPOSITORY}/actions/artifacts/${artifact_id}/zip" > "$RUNNER_TEMP/installation-lockfile.zip"
unzip -o "$RUNNER_TEMP/installation-lockfile.zip" -d binary-release
echo "restored=true" >> "$GITHUB_OUTPUT"
fi
- name: Generate global installation lockfile
run: node ./packages/cli/generate-install-lockfile.ts
# Save before publishing any platform package, including while npm still
# hides accepted versions during scanning. Retries must not resolve again.
- name: Save installation lockfile for release retries
if: steps.install-lockfile.outputs.restored != 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: installation-lockfile
path: binary-release/vp-install-lock.yaml
if-no-files-found: error
- name: Publish CLI binaries with the installation lockfile
run: node ./packages/cli/publish-native-addons.ts --mode npm --phase cli
# The preceding step waits for every global package to propagate.
# Promote the existing version; never repack or republish the local CLI.
- name: Promote the local CLI to latest
run: npm dist-tag add "vite-plus@${VERSION}" latest
- name: Create release archive checksums
working-directory: binary-release
run: sha256sum vp-* > vp-checksums.txt
# create-vite-plus pins vite-plus via workspace:* (rewritten to this exact
# version), so it publishes only after vite-plus is installable.
- name: Publish create-vite-plus
run: >-
node ./.github/scripts/publish-npm-package.ts
"create-vite-plus@${VERSION}"
--
pnpm publish --filter=./packages/create-vite-plus --tag latest --access public --no-git-checks
# Publishing can succeed even if the runner loses the response. Do not
# replace assets on a published release, including an immutable release.
- name: Check whether the GitHub release is already published
id: github-release
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
try {
const { data } = await github.rest.repos.getReleaseByTag({
...context.repo,
tag: `v${process.env.VERSION}`,
});
core.setOutput('published', String(!data.draft));
} catch (error) {
if (error.status !== 404) throw error;
core.setOutput('published', 'false');
}
- name: Create release body
if: steps.github-release.outputs.published != 'true'
env:
REPOSITORY: ${{ github.repository }}
COMMIT_SHA: ${{ github.sha }}
run: |
INSTALL_BASH="curl -fsSL https://vite.plus | bash"
INSTALL_PS1="irm https://vite.plus/ps1 | iex"
cat > ./RELEASE_BODY.md <<EOF
## vite-plus v${VERSION}
### Published Packages
- \`@voidzero-dev/vite-plus-core@${VERSION}\`
- \`vite-plus@${VERSION}\`
- \`create-vite-plus@${VERSION}\`
### Installation
**macOS/Linux:**
\`\`\`bash
${INSTALL_BASH}
\`\`\`
**Windows:**
\`\`\`powershell
${INSTALL_PS1}
\`\`\`
Or download and run \`vp-setup.exe\` from the assets below.
View the full commit: https://github.com/${REPOSITORY}/commit/${COMMIT_SHA}
EOF
- name: Create GitHub Release
if: steps.github-release.outputs.published != 'true'
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
id: release
with:
body_path: ./RELEASE_BODY.md
draft: true
make_latest: true
prerelease: false
name: vite-plus v${{ env.VERSION }}
tag_name: v${{ env.VERSION }}
target_commitish: ${{ github.sha }}
overwrite_files: true
fail_on_unmatched_files: true
files: |
installer-release/vp-setup-*.exe
binary-release/vp-*.tar.gz
binary-release/vp-*.zip
binary-release/vp-checksums.txt
binary-release/vp-install-lock.yaml
- name: Publish GitHub Release
if: steps.github-release.outputs.published != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release edit "v${VERSION}" --draft=false --repo "${{ github.repository }}"
# Deploy viteplus.dev from the release commit after the npm packages and the
# GitHub release are published, so the site and the install scripts always
# match the released vp. Skipped for prereleases: production docs must keep
# describing the latest stable release. See rfcs/deploy-docs-on-release.md.
deploy-docs:
name: Deploy docs
runs-on: ubuntu-latest
needs: [check, Release]
if: >-
needs.check.outputs.version_changed == 'true' &&
!contains(needs.check.outputs.version, '-')
# Shared with deploy-docs.yml so production deploys serialize across both
# entry paths. Only the newest pending run survives in the group; if this
# job's pending run is replaced by a manual dispatch, the canceled job
# holds back discord-notify and the deploy must be re-run.
concurrency:
group: deploy-docs
cancel-in-progress: false
permissions:
contents: read
id-token: write # authenticate remote cache uploads
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- uses: ./.github/actions/deploy-docs
with:
void-project: viteplus
void-token: ${{ secrets.VOID_TOKEN }}
# Build and push the official toolchain Docker image to GHCR after the npm
# release is published (the image installs vp from npm, so the version must
# exist first). See docker/Dockerfile and docs/guide/docker.md.
publish-docker:
name: Publish Docker image
runs-on: ubuntu-latest
needs: [check, Release]
if: needs.check.outputs.version_changed == 'true'
permissions:
contents: read
packages: write
env:
VERSION: ${{ needs.check.outputs.version }}
IMAGE: ghcr.io/voidzero-dev/vite-plus
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Log in to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.IMAGE }}
flavor: latest=false
tags: |
type=semver,pattern={{version}},value=${{ env.VERSION }}
type=semver,pattern={{major}}.{{minor}},value=${{ env.VERSION }}
type=semver,pattern={{major}},value=${{ env.VERSION }}
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: docker
file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VP_VERSION=${{ env.VERSION }}
provenance: false
# Announce the release on Discord last, after the Docker images and the docs
# are published, so the message never points at a missing image or a site
# that still shows the previous release.
discord-notify:
name: Notify Discord
runs-on: ubuntu-latest
# publish-docker already needs Release, so depending on it orders this last.
# deploy-docs is skipped for prereleases; gate on its result explicitly so
# prerelease announcements still go out, while a failed docs deploy on a
# stable release holds the announcement back.
needs: [check, publish-docker, deploy-docs]
if: >-
!cancelled() &&
needs.check.outputs.version_changed == 'true' &&
needs.publish-docker.result == 'success' &&
(needs.deploy-docs.result == 'success' || needs.deploy-docs.result == 'skipped')
env:
VERSION: ${{ needs.check.outputs.version }}
IMAGE: ghcr.io/voidzero-dev/vite-plus
steps:
# Non-blocking: a webhook failure must not mark the release run as failed
# (npm, GitHub release, and Docker images are already published).
- name: Send Discord notification
continue-on-error: true
uses: tsickert/discord-webhook@b217a69502f52803de774ded2b1ab7c282e99645 # v7.0.0
with:
webhook-url: ${{ secrets.DISCORD_RELEASES_WEBHOOK_URL }}
embed-title: vite-plus v${{ env.VERSION }}
embed-description: |
A new release is available!
**Published Packages:**
• @voidzero-dev/vite-plus-core@${{ env.VERSION }}
• vite-plus@${{ env.VERSION }}
• create-vite-plus@${{ env.VERSION }}
**Docker (GHCR):**
• `docker pull ${{ env.IMAGE }}:${{ env.VERSION }}`
**Install:**
• macOS/Linux: `curl -fsSL https://vite.plus | bash`
• Windows: `irm https://vite.plus/ps1 | iex`
embed-url: https://github.com/${{ github.repository }}/releases/tag/v${{ env.VERSION }}