Skip to content

Commit 618db01

Browse files
authored
Merge branch 'main' into fix/pnpm-short-alias-shims
2 parents 561ed8e + f0e06ab commit 618db01

454 files changed

Lines changed: 23487 additions & 1950 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/skills/release-manager/SKILL.md‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Run a standard vite-plus release from version bump to published announcement. An
1919
When given a release PR (URL or number), do not start from step 1. First audit the release's current state, then continue from the earliest unfinished step:
2020

2121
- Is the binding version synced? (step 2: `grep -c "'<prev>'" packages/cli/binding/index.cjs` on the release branch)
22+
- Do the release version examples in the migration guide and the setup, migration, and upgrade prompts match `packages/cli/package.json`? (step 2)
2223
- Is the PR description still the `prepare_release` boilerplate, or already a categorized changelog? (step 3)
2324
- Is a preview build present and for the current head? (step 4)
2425
- Does `main` have commits the release branch lacks? (`git log origin/release/vX.Y.Z..origin/main`, step 5)
@@ -32,7 +33,7 @@ Before post-release work, fetch `origin/main` and read its copy of this skill (`
3233
## Pipeline overview
3334

3435
1. `Prepare Release` workflow bumps versions and opens the release PR (`release/vX.Y.Z` -> `main`).
35-
2. Release manager: sync `binding/index.cjs`, write the changelog PR description, offer the preview-build smoke test (recommend it when the release has more than 10 commits since the previous tag), get CI green.
36+
2. Release manager: sync `binding/index.cjs` and the release versions in the documentation and prompts, write the changelog PR description, offer the preview-build smoke test (recommend it when the release has more than 10 commits since the previous tag), get CI green.
3637
3. Merging the PR pushes a `packages/cli/package.json` change to `main`, which triggers `release.yml`: build, manual approval gate, npm publish, GitHub release, Docker image, Discord notification.
3738
4. Release manager: polish the GitHub release notes, verify installs, announce.
3839

@@ -46,7 +47,9 @@ gh workflow run prepare_release.yml --repo voidzero-dev/vite-plus -f version=X.Y
4647

4748
The workflow bumps `packages/cli/package.json`, `packages/core/package.json`, `packages/cli/binding/Cargo.toml`, and `crates/vp_global_cli/Cargo.toml`, refreshes `Cargo.lock`, and opens a PR titled `release: vX.Y.Z` from branch `release/vX.Y.Z`. The PR body ends with `Merging this PR will trigger the release workflow.` and that line must survive every later edit.
4849

49-
## 2. Sync the NAPI binding version (required every release)
50+
## 2. Sync release versions (required every release)
51+
52+
### NAPI binding
5053

5154
NAPI bakes the package version into version checks in `packages/cli/binding/index.cjs` (26+ sites). `prepare_release` bumps `package.json` but does not regenerate this file, so CI's `Ensure no unexpected file changes after build` step in the `CLI E2E test` job fails until it is synced. Do this immediately; do not wait for CI to fail.
5255

@@ -79,7 +82,20 @@ regenerate this file, so the CI build's regeneration step produces a
7982
diff that the post-build no-unexpected-changes guard rejects.
8083
```
8184

82-
This is the only kind of commit that goes directly on the release branch. Everything else goes through `main` (see step 5).
85+
### Documentation and prompts
86+
87+
Use the version in the release branch's `packages/cli/package.json` as the target release version in these files:
88+
89+
- `docs/guide/migrate.md`: pnpm and npm migration command examples and matching release prose.
90+
- `docs/.vitepress/theme/data/migration-prompts.ts`: `setupPrompt`, `migrationPrompt`, `upgradePrompt`, and their shared instructions, including command examples and matching release prose. `CopyPrompt` uses `setupPrompt` on both the homepage and Getting Started guide.
91+
92+
Update every `--package=vite-plus@<curr>` pin and the corresponding `For the <curr> release` and `Replace <curr>` text. Keep an exact version; do not replace it with a placeholder, a major range, or `latest`.
93+
94+
Preserve historical versions such as the migration's source version and the release that introduced a breaking change. Leave Node.js requirements, bundled tool versions, and preview-registry instructions unchanged unless their requirements change.
95+
96+
Commit these updates on the release branch with the binding sync or in a separate release-version sync commit. Recheck both files and the binding after a target-version change or a merge from `main`. Before merging, confirm that the guide and all three prompts use the target release in both package-manager commands and their matching prose, then run `git diff --check`.
97+
98+
Only these release-version sync commits go directly on the release branch. Everything else goes through `main` (see step 5).
8399

84100
## 3. Write the release PR description
85101

@@ -326,7 +342,7 @@ Two fork-CI blockers are worth fixing rather than reporting, both on the **test
326342

327343
Match checks to the current PR head and the latest applicable workflow runs. Superseded canceled runs can leave failed aggregate checks in the PR rollup. Check required statuses with `gh pr checks <PR#> --required`, and report required reviewer approval separately from technical CI readiness.
328344

329-
Fixes for CI failures go through a **separate PR to `main`**, never as commits on the release branch (the binding sync in step 2 is the sole exception). After the fix PR merges:
345+
Fixes for CI failures go through a **separate PR to `main`**, never as commits on the release branch (the release-version syncs in step 2 are the exceptions). After the fix PR merges:
330346

331347
```bash
332348
git checkout release/vX.Y.Z && git merge origin/main --no-edit && git push origin release/vX.Y.Z
@@ -341,7 +357,7 @@ Known release-branch-only failure modes:
341357

342358
## 6. Merge
343359

344-
Merging the release PR is the release trigger. Before merging confirm: CI green, changelog validated, binding synced, and (if used) the preview build verified.
360+
Merging the release PR is the release trigger. Before merging confirm: CI green, changelog validated, binding and documentation versions synced (including all three prompts), and (if used) the preview build verified.
345361

346362
Auto-merge being enabled is not a completed merge. Confirm `mergedAt` and the merge commit, then follow the Release run for that commit; older successful runs can have skipped publishing because the version did not change.
347363

@@ -492,6 +508,7 @@ After the release ships and announcements are approved or confirmed complete, re
492508
493509
- [ ] `prepare_release` run for the target version; release PR open
494510
- [ ] `binding/index.cjs` synced on the release branch (step 2 commit message shape)
511+
- [ ] The migration guide and all three prompts in the step 2 files use the exact target version from `packages/cli/package.json` in their command examples and matching release prose
495512
- [ ] PR description written from the head branch data; every PR exactly once except documented omissions; breaking changes in their own section above Highlights; no em/en dashes; closing boilerplate intact
496513
- [ ] Dependency-upgrade PRs consolidated; vite-task bump expanded with upstream credits; security advisories linked
497514
- [ ] Smoke test offered to the release manager at both levels (local sweep and fork-PR CI), with the commit count stated and a recommendation to run it when that count is above 10; if accepted, forks synced to upstream first, preview build published, and the full ecosystem-ci catalog verified via `test-pkg-pr-new-migrate` (following TESTING.md), with every failure triaged and regressions ruled out against the previous release

‎.github/actions/build-upstream/action.yml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ runs:
3131
- uses: ./.github/actions/compute-native-cache-input-hash
3232
id: native-cache-inputs
3333

34-
# Include env vars (RELEASE_BUILD, DEBUG, VERSION) to ensure cache miss on release builds.
34+
# Include the documentation origin so preview binaries cannot reuse release links.
3535
- name: Compute NAPI binding cache key
3636
id: cache-key
3737
shell: bash
3838
run: |
39-
echo "key=napi-binding-v3-${INPUTS_TARGET}-${RELEASE_BUILD}-${DEBUG}-${VERSION}-${NPM_TAG}-${{ steps.native-cache-inputs.outputs.hash }}" >> "$GITHUB_OUTPUT"
39+
DOCS_ORIGIN_HASH=$(node -e 'process.stdout.write(require("node:crypto").createHash("sha256").update(process.env.VITE_PLUS_DOCS_ORIGIN || "https://viteplus.dev").digest("hex").slice(0, 16))')
40+
echo "key=napi-binding-v3-${INPUTS_TARGET}-${RELEASE_BUILD}-${DEBUG}-${VERSION}-${NPM_TAG}-${DOCS_ORIGIN_HASH}-${{ steps.native-cache-inputs.outputs.hash }}" >> "$GITHUB_OUTPUT"
4041
env:
4142
INPUTS_TARGET: ${{ inputs.target }}
4243

‎.github/actions/clone/action.yml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ runs:
4747
ref: ${{ steps.upstream-versions.outputs.ROLLDOWN_VITE_HASH }}
4848
persist-credentials: false
4949

50+
# Match the manifests used by sync-remote when it generated the root lockfile.
51+
# setup-node installs with --frozen-lockfile, so this must run before it.
52+
# The runner's preinstalled Node may not support direct TypeScript execution.
53+
- name: Align vendored Vite's Vitest dependencies
54+
shell: bash
55+
run: npx tsx packages/tools/src/vendored-vitest.ts
56+
5057
# Disable autocrlf to preserve LF line endings on Windows
5158
# This prevents prettier/eslint from failing with "Delete ␍" errors
5259
- name: Configure git for LF line endings

‎.github/scripts/__tests__/docs-fork-preview.mjs‎

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { tmpdir } from 'node:os';
66
import { join } from 'node:path';
77
import { test } from 'node:test';
88

9+
import { resolveDocsSiteOrigin } from '../../../docs/.vitepress/site-origin.ts';
910
import {
1011
authorizePreview,
1112
commentPreview,
@@ -241,12 +242,75 @@ await test('reuses the PR origin across commits, builds, and reruns while pinnin
241242
assert.match(deploy, /--preview-alias "\$PREVIEW_ALIAS"/);
242243
});
243244

244-
await test('uses each PR origin for shell and PowerShell installer links', async (t) => {
245+
await test('resolves Workers branch origins without an explicit docs origin', () => {
246+
for (const branch of ['rfc/vitest-v5-upgrade', '--RFC//Vitest_V5-Upgrade--']) {
247+
assert.equal(
248+
resolveDocsSiteOrigin({ WORKERS_CI: '1', WORKERS_CI_BRANCH: branch }),
249+
'https://rfc-vitest-v5-upgrade-viteplus-dev.voidzero-docs.workers.dev',
250+
);
251+
}
252+
});
253+
254+
await test('preserves explicit origins and production defaults', () => {
255+
assert.equal(
256+
resolveDocsSiteOrigin({
257+
DOCS_SITE_ORIGIN: 'https://viteplus-staging.void.app/',
258+
WORKERS_CI: '1',
259+
WORKERS_CI_BRANCH: 'rfc/vitest-v5-upgrade',
260+
}),
261+
'https://viteplus-staging.void.app',
262+
);
263+
for (const env of [
264+
{},
265+
{ DOCS_SITE_ORIGIN: '' },
266+
{ WORKERS_CI_BRANCH: 'rfc/vitest-v5-upgrade' },
267+
{ WORKERS_CI: '1' },
268+
{ WORKERS_CI: '1', WORKERS_CI_BRANCH: 'main' },
269+
]) {
270+
assert.equal(resolveDocsSiteOrigin(env), undefined);
271+
}
272+
});
273+
274+
await test('matches Wrangler long-branch aliases without collisions after truncation', () => {
275+
for (const [branch, hash] of [
276+
[`feature/${'a'.repeat(80)}`, '288d'],
277+
[`feature/${'a'.repeat(79)}b`, 'ee30'],
278+
]) {
279+
const origin = resolveDocsSiteOrigin({ WORKERS_CI: '1', WORKERS_CI_BRANCH: branch });
280+
assert.equal(
281+
origin,
282+
`https://feature-${'a'.repeat(37)}-${hash}-viteplus-dev.voidzero-docs.workers.dev`,
283+
);
284+
assert.equal(new URL(origin).hostname.split('.')[0].length, 63);
285+
}
286+
});
287+
288+
await test('requires an explicit origin when Wrangler cannot create a branch alias', () => {
289+
for (const branch of ['123-fix', '___']) {
290+
const env = { WORKERS_CI: '1', WORKERS_CI_BRANCH: branch };
291+
assert.throws(() => resolveDocsSiteOrigin(env), /Set DOCS_SITE_ORIGIN/);
292+
assert.equal(
293+
resolveDocsSiteOrigin({ ...env, DOCS_SITE_ORIGIN: previewUrl(2684) }),
294+
previewUrl(2684),
295+
);
296+
}
297+
});
298+
299+
await test('uses each deploy origin for shell and PowerShell installer links', async (t) => {
245300
const directory = await mkdtemp(join(tmpdir(), 'docs-preview-installers-'));
246301
t.after(() => rm(directory, { recursive: true, force: true }));
247302
const snapshots = [];
248-
for (const number of [2684, 2685]) {
249-
const root = join(directory, String(number));
303+
const cases = [
304+
{ env: { DOCS_SITE_ORIGIN: previewUrl(2684) }, origin: previewUrl(2684) },
305+
{ env: { DOCS_SITE_ORIGIN: previewUrl(2685) }, origin: previewUrl(2685) },
306+
{
307+
env: { WORKERS_CI: '1', WORKERS_CI_BRANCH: 'rfc/vitest-v5-upgrade' },
308+
origin: 'https://rfc-vitest-v5-upgrade-viteplus-dev.voidzero-docs.workers.dev',
309+
},
310+
{ env: {}, origin: 'https://viteplus.dev' },
311+
];
312+
for (const [index, { env, origin }] of cases.entries()) {
313+
const root = join(directory, String(index));
250314
const scripts = join(root, 'docs', '.vitepress', 'scripts');
251315
const output = join(root, 'docs', 'public');
252316
const installers = join(root, 'packages', 'cli');
@@ -258,21 +322,32 @@ await test('uses each PR origin for shell and PowerShell installer links', async
258322
new URL('../../../docs/.vitepress/scripts/copy-installers.mjs', import.meta.url),
259323
script,
260324
);
325+
await copyFile(
326+
new URL('../../../docs/.vitepress/site-origin.ts', import.meta.url),
327+
join(scripts, '..', 'site-origin.ts'),
328+
);
261329
for (const name of ['install.sh', 'install.ps1', 'install-legacy.sh', 'install-legacy.ps1']) {
262330
await copyFile(
263331
new URL(`../../../packages/cli/${name}`, import.meta.url),
264332
join(installers, name),
265333
);
266334
}
267-
const origin = previewUrl(number);
268-
execFileSync(process.execPath, [script], { env: { ...process.env, DOCS_SITE_ORIGIN: origin } });
335+
execFileSync(process.execPath, [script], {
336+
env: {
337+
...process.env,
338+
DOCS_SITE_ORIGIN: '',
339+
WORKERS_CI: '',
340+
WORKERS_CI_BRANCH: '',
341+
...env,
342+
},
343+
});
269344
const shell = await readFile(join(output, 'install.sh'), 'utf8');
270345
const powershell = await readFile(join(output, 'install.ps1'), 'utf8');
271346
assert.ok(shell.includes(`${origin}/install-legacy.sh`));
272347
assert.ok(powershell.includes(`${origin}/install-legacy.ps1`));
273348
snapshots.push({ origin, shell, powershell });
274349
}
275-
assert.equal(new Set(snapshots.map((snapshot) => snapshot.origin)).size, 2);
350+
assert.equal(new Set(snapshots.map((snapshot) => snapshot.origin)).size, cases.length);
276351
for (const snapshot of snapshots) {
277352
for (const other of snapshots) {
278353
if (other.origin !== snapshot.origin) {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import assert from 'node:assert/strict';
2+
import { readFileSync } from 'node:fs';
3+
import { test } from 'node:test';
4+
5+
import { resolveDocsSiteOrigin } from '../../../docs/.vitepress/site-origin.ts';
6+
import { previewUrl } from '../docs-fork-preview.mjs';
7+
import { previewDocsOrigin } from '../preview-docs-origin.ts';
8+
9+
const pr = {
10+
number: 2551,
11+
head: { ref: 'rfc/vitest-v5-upgrade', repo: { full_name: 'voidzero-dev/vite-plus' } },
12+
base: { repo: { full_name: 'voidzero-dev/vite-plus' } },
13+
};
14+
15+
const read = (file) => readFileSync(new URL(file, import.meta.url), 'utf8');
16+
17+
await test('uses the head branch docs for same-repo and stacked PRs', () => {
18+
assert.equal(
19+
previewDocsOrigin(pr),
20+
'https://rfc-vitest-v5-upgrade-viteplus-dev.voidzero-docs.workers.dev',
21+
);
22+
for (const branch of ['--RFC//Vitest_V5-Upgrade--', `feature/${'a'.repeat(80)}`]) {
23+
assert.equal(
24+
previewDocsOrigin({ ...pr, head: { ...pr.head, ref: branch } }),
25+
resolveDocsSiteOrigin({ WORKERS_CI: '1', WORKERS_CI_BRANCH: branch }),
26+
);
27+
}
28+
});
29+
30+
await test('uses the PR alias for forks, never a same-named repository branch', () => {
31+
assert.equal(
32+
previewDocsOrigin({
33+
...pr,
34+
head: { ...pr.head, repo: { full_name: 'contributor/vite-plus' } },
35+
}),
36+
previewUrl(pr.number),
37+
);
38+
});
39+
40+
await test('passes the origin to native builds and includes it in the native cache key', () => {
41+
const preview = read('../../workflows/publish-preview.yml');
42+
const release = read('../../workflows/reusable-release-build.yml');
43+
const build = read('../../actions/build-upstream/action.yml');
44+
assert.match(preview, /previewDocsOrigin\(context\.payload\.pull_request\)/);
45+
assert.match(preview, /docs-origin: \$\{\{ steps\.docs\.outputs\.origin \}\}/);
46+
assert.match(preview, /docs-origin: \$\{\{ needs\.prepare\.outputs\.docs-origin \}\}/);
47+
assert.match(release, /default: 'https:\/\/viteplus\.dev'/);
48+
assert.match(release, /VITE_PLUS_DOCS_ORIGIN: \$\{\{ inputs\.docs-origin \}\}/);
49+
assert.match(build, /process\.env\.VITE_PLUS_DOCS_ORIGIN/);
50+
assert.match(build, /napi-binding-v3-.*\$\{DOCS_ORIGIN_HASH\}/);
51+
});

‎.github/scripts/__tests__/upgrade-deps-utils.spec.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ test('selects the highest stable version from the supported major', () => {
1616
test('returns undefined when the supported major has no stable release', () => {
1717
expect(findLatestStableVersionForMajor(['4.2.0-beta.1', '5.0.0'], 4)).toBeUndefined();
1818
});
19+
20+
test('keeps Vitest upgrades on v5 after the migration', () => {
21+
expect(
22+
findLatestStableVersionForMajor(['4.1.11', '5.0.0', '5.1.0', '5.2.0-beta.1', '6.0.0'], 5),
23+
).toBe('5.1.0');
24+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { resolveDocsSiteOrigin } from '../../docs/.vitepress/site-origin.ts';
2+
import { previewUrl } from './docs-fork-preview.mjs';
3+
4+
/** Use the same URLs as Workers Builds (same-repo) and the fork docs workflow. */
5+
export function previewDocsOrigin(pr: {
6+
number: number;
7+
head: { ref: string; repo: { full_name: string } };
8+
base: { repo: { full_name: string } };
9+
}): string {
10+
if (pr.head.repo.full_name !== pr.base.repo.full_name) {
11+
return previewUrl(pr.number);
12+
}
13+
return (
14+
resolveDocsSiteOrigin({ WORKERS_CI: '1', WORKERS_CI_BRANCH: pr.head.ref }) ??
15+
'https://viteplus.dev'
16+
);
17+
}

‎.github/scripts/upgrade-deps.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ type PnpmWorkspaceEntry = {
7373
const STABLE_SEMVER_TAG_RE = /^v?\d+\.\d+\.\d+$/;
7474
// Vitest major upgrades can change the bundled API, export shims, and CLI
7575
// behavior. Advance this only after Vite+ has adapted to the new major.
76-
const SUPPORTED_VITEST_MAJOR = 4;
76+
const SUPPORTED_VITEST_MAJOR = 5;
7777

7878
const isFullSha = (s: string): boolean => /^[0-9a-f]{40}$/.test(s);
7979

@@ -212,18 +212,15 @@ async function updatePnpmWorkspace(versions: PnpmWorkspaceVersions): Promise<voi
212212
let content = fs.readFileSync(filePath, 'utf8');
213213

214214
// oxlint's trailing \n in the pattern disambiguates from oxlint-tsgolint.
215-
// All @vitest/* catalog entries (browser + core direct deps) must stay pinned
215+
// Official @vitest/* catalog entries (browser + core direct deps) stay pinned
216216
// to the same exact version as `vitest` itself, otherwise the catalog drifts
217217
// from VITEST_VERSION.
218218
const vitestExactVersionPackages = [
219219
'@vitest/browser',
220220
'@vitest/browser-playwright',
221221
'@vitest/browser-preview',
222-
'@vitest/browser-webdriverio',
223-
'@vitest/expect',
224222
'@vitest/mocker',
225223
'@vitest/pretty-format',
226-
'@vitest/runner',
227224
'@vitest/snapshot',
228225
'@vitest/spy',
229226
'@vitest/utils',

‎.github/workflows/ci.yml‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,10 +375,13 @@ jobs:
375375
include:
376376
- os: namespace-profile-linux-x64-default
377377
target: x86_64-unknown-linux-gnu
378+
test-node: 22.18.0
378379
- os: namespace-profile-mac-default
379380
target: aarch64-apple-darwin
381+
test-node: 24.11.0
380382
- os: namespace-profile-windows-4c-8g
381383
target: x86_64-pc-windows-msvc
384+
test-node: 26.0.0
382385
runs-on: ${{ matrix.os }}
383386
steps:
384387
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
@@ -463,8 +466,9 @@ jobs:
463466
run: vp check
464467

465468
- name: Run unit tests
466-
run: RUST_BACKTRACE=1 pnpm test:unit
469+
run: vp env exec --node ${{ matrix.test-node }} node packages/cli/dist/bin.js test run
467470
env:
471+
RUST_BACKTRACE: '1'
468472
RUST_MIN_STACK: 8388608
469473

470474
- name: Test global package install (powershell)

0 commit comments

Comments
 (0)