Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
10 changes: 10 additions & 0 deletions packages/vscode/e2e/fixtures/rslint/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
10 changes: 10 additions & 0 deletions packages/vscode/e2e/fixtures/rstack/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
10 changes: 10 additions & 0 deletions packages/vscode/e2e/fixtures/rstest/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
10 changes: 10 additions & 0 deletions packages/vscode/e2e/lint/fixtures/pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import * as assert from 'node:assert';
import { execFile as execFileCallback } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { promisify } from 'node:util';
import * as vscode from 'vscode';
import { pnpmInstallFrozen } from '../../pnpmInstall';
import type { StackState } from '../../../src/types';
import { waitForRslintDiagnostics } from '../utils/diagnostics';
import { extensionExports } from '../utils/extension';

const execFile = promisify(execFileCallback);

function lintExports(): {
getFolderStates(): ReadonlyMap<string, StackState>;
} {
Expand Down Expand Up @@ -61,17 +58,7 @@ suite('Rslint dependency polling recovery', function () {
const beforeContents = fs.readFileSync(lockfile);
const beforeMtime = fs.statSync(lockfile).mtimeMs;

await execFile(
'pnpm',
['install', '--frozen-lockfile', '--ignore-scripts'],
{
cwd: root,
timeout: 90_000,
// Match setupFixtures.mjs/run.mjs: Windows needs a shell for pnpm's
// .cmd shim. All arguments are fixed safe tokens; cwd is not interpolated.
shell: process.platform === 'win32',
},
);
await pnpmInstallFrozen(root);

assert.deepStrictEqual(
fs.readFileSync(lockfile),
Expand Down
34 changes: 34 additions & 0 deletions packages/vscode/e2e/pnpmInstall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { execFile as execFileCallback } from 'node:child_process';
import { promisify } from 'node:util';

const execFile = promisify(execFileCallback);

/**
* Runs `pnpm install --frozen-lockfile --ignore-scripts` in `cwd`. pnpm 11
* prints install errors (e.g. ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION) to
* stdout, while execFile's error message carries only stderr, so a failure
* rethrows with both streams appended.
*/
export async function pnpmInstallFrozen(cwd: string): Promise<void> {
try {
await execFile(
'pnpm',
['install', '--frozen-lockfile', '--ignore-scripts'],
{
cwd,
timeout: 90_000,
// Windows needs a shell for pnpm's .cmd shim; the arguments are fixed
// safe tokens and cwd is not interpolated.
shell: process.platform === 'win32',
},
);
} catch (error) {
const { stdout = '', stderr = '' } = error as {
stdout?: string;
stderr?: string;
};
throw new Error(`${(error as Error).message}\n${stdout}${stderr}`, {
cause: error,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# E2E fixture install config; rationale in packages/vscode/e2e/setupFixtures.mjs.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
- '@rstest/core'
- '@rsbuild/core'
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import assert from 'node:assert/strict';
import { execFile as execFileCallback } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { promisify } from 'node:util';
import vscode from 'vscode';
import { pnpmInstallFrozen } from '../../pnpmInstall';
import type { RstackExtensionExports } from '../../../src/types';
import { getProjectItems, getRstestExports, waitFor } from '../suite/helpers';

const execFile = promisify(execFileCallback);

suite('Rstest dependency polling recovery', function () {
this.timeout(180_000);

Expand All @@ -30,16 +27,7 @@ suite('Rstest dependency polling recovery', function () {
const lockfile = path.join(root, 'pnpm-lock.yaml');
const contents = fs.readFileSync(lockfile);
const mtime = fs.statSync(lockfile).mtimeMs;
await execFile(
'pnpm',
['install', '--frozen-lockfile', '--ignore-scripts'],
{
cwd: root,
timeout: 90_000,
// Windows needs a shell for pnpm.cmd; arguments are fixed safe tokens.
shell: process.platform === 'win32',
},
);
await pnpmInstallFrozen(root);
assert.deepEqual(
fs.readFileSync(lockfile),
contents,
Expand Down
24 changes: 14 additions & 10 deletions packages/vscode/e2e/setupFixtures.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@
// from the project, so a fixture that linked this repo's own node_modules would
// test nothing. `rstack@0.7.2` itself pins `@rslint/core@0.9.0` exactly, so the
// Rstack fixture pins its lint core transitively. Each fixture is its own
// independent install; `--ignore-workspace` keeps test setup out of the parent
// workspace. Exact toolchain pins make installs reproducible without committed
// lockfiles, and Renovate bumps those pins.
// independent install. Exact toolchain pins make installs reproducible
// without committed lockfiles, and Renovate bumps those pins.
//
// Each fixture carries a committed, settings-only `pnpm-workspace.yaml`. It
// stops pnpm from walking up into this repo's workspace, and it exempts the
// Rstack family from pnpm's `minimumReleaseAge` gate (fixtures pin releases
// that are often hours old; third-party packages stay gated). The exemption
// has to live in a file rather than `--config.minimumReleaseAge=0` because the
// dependency-recovery tests copy a fixture to the OS tmpdir and re-install
// with `--frozen-lockfile`, and pnpm 11 re-checks release age even when
// frozen, so the policy must travel with the copy. The same file rules out
// `--ignore-workspace`, under which pnpm ignores its settings. Setup-only
// options stay flags below. Keep the list in step with the root
// `pnpm-workspace.yaml`.
//
// Idempotent: pnpm is a no-op when the fixture is already up to date, so
// `test:e2e` can always run it.
Expand Down Expand Up @@ -65,9 +76,6 @@ const install = (name) => {
pnpmCommand,
[
'install',
// A fixture is a standalone project, never a workspace member of this
// repo: the whole point is a plain, published-versions install.
'--ignore-workspace',
// Fixtures pin exact toolchain versions rather than committing lockfiles;
// Renovate updates the pins.
'--no-frozen-lockfile',
Expand All @@ -76,10 +84,6 @@ const install = (name) => {
// `node_modules`, which it refuses to do without a TTY. The directory is
// disposable.
'--config.confirmModulesPurge=false',
// Fixtures deliberately install pinned published versions of the Rstack
// toolchain, which are often hours old — disable pnpm's
// minimum-release-age supply-chain gate for these sandboxes.
'--config.minimumReleaseAge=0',
// pnpm's build-script gate exits non-zero on unapproved postinstalls
// (e.g. core-js in the rstest fixture). These sandboxes install real
// published packages exactly like a user project would, so run their
Expand Down
2 changes: 2 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ allowBuilds:

# The whole point of this repo is tracking the freshest Rstack toolchain
# releases, so exempt them from the minimum-release-age supply-chain policy.
# Each E2E fixture's pnpm-workspace.yaml repeats this list; keep them in step.
minimumReleaseAgeExclude:
- rstack
- '@rslint/core'
Expand All @@ -19,3 +20,4 @@ minimumReleaseAgeExclude:
- '@rslib/core'
- '@rstackjs/*'
- rsbuild-plugin-dts
- '@rspack/*'