fix: validate the Node 24.9 runtime floor
This commit is contained in:
1 parent
c6a59a1ae9
commit
cfb65d3bb2
60 files changed
+256
-127
No files matched your search
@@ -5,6 +5,7 @@ import { spawnSync } from 'node:child_process'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { BUILD_BACKED_NODE_COMPAT_VERSION } from './run-gates.ts'
|
||||
|
||||
interface Step {
|
||||
name?: string
|
||||
@@ -54,6 +55,14 @@ function route(options: { mode?: string; author?: string; repository?: string; f
|
||||
}
|
||||
|
||||
describe('Node compatibility self-hosted routing', () => {
|
||||
it('runs the build-backed compatibility minor and declares it for installed CLI users', () => {
|
||||
expect(job.strategy.matrix.include.filter(entry => String(entry.node) === BUILD_BACKED_NODE_COMPAT_VERSION)).toHaveLength(1)
|
||||
for (const manifest of ['package.json', 'apps/cli/package.json']) {
|
||||
const pkg = JSON.parse(readFileSync(resolve(import.meta.dirname, '..', manifest), 'utf8')) as { engines: { node: string } }
|
||||
expect(pkg.engines.node).toBe(`>=${BUILD_BACKED_NODE_COMPAT_VERSION}.0`)
|
||||
}
|
||||
})
|
||||
|
||||
it('uses the Linux pool only for opted-in repository-owned PRs', () => {
|
||||
expect(route()).toEqual(labels)
|
||||
for (const mode of ['', 'hosted', 'unexpected']) expect(route({ mode })).toBe('ubuntu-latest')
|
||||
@@ -71,7 +80,7 @@ describe('Node compatibility self-hosted routing', () => {
|
||||
expect(job.if).toBe("github.event_name == 'pull_request'")
|
||||
expect(job.strategy['fail-fast']).toBe(false)
|
||||
expect(job.strategy.matrix.include).toEqual([
|
||||
{ node: '24.0', name: 'node 24.0', runner: 'ubuntu-latest', gate_concurrency: '1' },
|
||||
{ node: '24.9', name: 'node 24.9', runner: 'ubuntu-latest', gate_concurrency: '1' },
|
||||
{ node: 26, name: 'node 26', runner: 'ubuntu-latest', gate_concurrency: '1' },
|
||||
])
|
||||
expect(job.env.DSH_GATE_CONCURRENCY).toBe('${{ matrix.gate_concurrency }}')
|
||||
@@ -132,8 +141,8 @@ describe('Node compatibility self-hosted routing', () => {
|
||||
const step = job.steps.find(candidate => candidate.name === 'Verify isolated Node installation')!
|
||||
expect(step.if).toBe("runner.environment == 'self-hosted'")
|
||||
for (const [executable, status] of [
|
||||
['/runner temp/node-compat-toolcache/node/24.0.0/x64/bin/node', 0],
|
||||
['/shared/toolcache/node/24.0.0/x64/bin/node', 1],
|
||||
['/runner temp/node-compat-toolcache/node/24.9.0/x64/bin/node', 0],
|
||||
['/shared/toolcache/node/24.9.0/x64/bin/node', 1],
|
||||
['/runner temp/node-compat-toolcache-other/node', 1],
|
||||
] as const) {
|
||||
const child = spawnSync('bash', ['-e', '-u', '-o', 'pipefail', '-c', 'node() { printf "%s" "$TEST_EXECUTABLE"; }; ' + step.run!], {
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('CI workflow', () => {
|
||||
expect(compatibilityLimit).toBeGreaterThan(0)
|
||||
expect(compatibility.strategy).toMatchObject({
|
||||
'fail-fast': false,
|
||||
matrix: { include: [{ node: '24.0' }, { node: 26 }] },
|
||||
matrix: { include: [{ node: '24.9' }, { node: 26 }] },
|
||||
})
|
||||
expect(workflowJob(ci, 'all-checks-passed').needs).toContain('node-compat')
|
||||
const ordinaryJobs = Object.entries(ci.jobs)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/** Compatibility checks execute command entrypoints; importing helpers cannot detect a silent no-op. */
|
||||
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { resolve } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
|
||||
describe('repository command entrypoints', () => {
|
||||
it.each([
|
||||
['run-gates.ts', ['invalid-compat-mode'], 'run-gates: expected mode'],
|
||||
['build.ts', ['--scope', 'invalid-compat-scope'], 'build: --scope must be'],
|
||||
] as const)('executes %s argument validation on the running Node version', (script, args, diagnostic) => {
|
||||
const child = spawnSync(process.execPath, ['--import', 'tsx/esm', resolve(root, 'scripts', script), ...args], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
timeout: 30_000,
|
||||
})
|
||||
expect(child.error).toBeUndefined()
|
||||
expect(child.signal).toBeNull()
|
||||
expect(child.status).toBe(1)
|
||||
expect(child.stderr).toContain(diagnostic)
|
||||
})
|
||||
})
|
||||
@@ -37,7 +37,7 @@ function fixture(options: {
|
||||
version: '0.0.1',
|
||||
type: 'module',
|
||||
license: 'MIT',
|
||||
engines: { node: '>=24.0.0' },
|
||||
engines: { node: '>=24.9.0' },
|
||||
sideEffects: false,
|
||||
files: ['lib'],
|
||||
exports: { '.': { default: options.exportPath ?? './lib/index.js' } },
|
||||
|
||||
@@ -846,7 +846,7 @@ describe('Typert contract preparation', () => {
|
||||
})
|
||||
|
||||
describe('Node compatibility graph', () => {
|
||||
it.each(['24.0.0', '24.19.0', '26.0.0'])('runs all source compatibility smokes serially on Node %s', (version) => {
|
||||
it.each(['24.9.0', '24.19.0', '26.0.0'])('runs all source compatibility smokes serially on Node %s', (version) => {
|
||||
const subject = withNodeVersion(version, () =>
|
||||
withPnpmEntrypoint(() => gatesForMode('node-compat')))
|
||||
|
||||
@@ -861,6 +861,7 @@ describe('Node compatibility graph', () => {
|
||||
'packages/session/session-persistence-jsonl/tests/zstd.compat.spec.ts',
|
||||
'apps/cli/tests/source-launch.compat.spec.ts',
|
||||
'scripts/vitest-environment.compat.spec.ts',
|
||||
'scripts/command-entrypoints.compat.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution-service.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution-worker-bootstrap.spec.ts',
|
||||
@@ -886,8 +887,8 @@ describe('Node compatibility graph', () => {
|
||||
expect(subject.map(item => item.id)).not.toContain('cli-lazy-search-startup-smoke')
|
||||
})
|
||||
|
||||
it.each([undefined, '1'])('builds the complete Node 24.0 artifacts once with skip-typecheck=%s', (skipTypecheck) => {
|
||||
const subject = withNodeVersion('24.0.0', () =>
|
||||
it.each([undefined, '1'])('builds the complete Node 24.9 artifacts once with skip-typecheck=%s', (skipTypecheck) => {
|
||||
const subject = withNodeVersion('24.9.0', () =>
|
||||
withEnv('DSH_NODE_COMPAT_SKIP_TYPECHECK', skipTypecheck, () =>
|
||||
withPnpmEntrypoint(() => gatesForMode('node-compat'))))
|
||||
|
||||
@@ -902,8 +903,8 @@ describe('Node compatibility graph', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it.each(['passed', 'failed'] as const)('runs the Node 24.0 lazy-search smoke only after a passed build (%s)', async (buildStatus) => {
|
||||
const subject = withNodeVersion('24.0.0', () =>
|
||||
it.each(['passed', 'failed'] as const)('runs the Node 24.9 lazy-search smoke only after a passed build (%s)', async (buildStatus) => {
|
||||
const subject = withNodeVersion('24.9.0', () =>
|
||||
withEnv('DSH_NODE_COMPAT_SKIP_TYPECHECK', '1', () =>
|
||||
withPnpmEntrypoint(() => gatesForMode('node-compat'))))
|
||||
let buildCompleted = false
|
||||
|
||||
@@ -95,6 +95,9 @@ type ResultObserver = (result: GateResult) => void
|
||||
/** Worker cap of the documentation and hygiene aggregates, locally and in CI, whose leaves each build a full ts.Program. */
|
||||
const PROGRAM_MODE_CAP = 8
|
||||
|
||||
/** CI pins this minor in .github/workflows/ci.yml; its compatibility leg owns the built CLI smoke. */
|
||||
export const BUILD_BACKED_NODE_COMPAT_VERSION = '24.9'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
if (import.meta.main) {
|
||||
process.exitCode = await main(process.argv.slice(2))
|
||||
@@ -429,7 +432,7 @@ function nodeCompatGates(): Gate[] {
|
||||
const typecheck = flagEnabled('DSH_NODE_COMPAT_SKIP_TYPECHECK')
|
||||
? []
|
||||
: [pnpmScript('typecheck', 'typecheck')]
|
||||
if (!process.versions.node.startsWith('24.0.')) {
|
||||
if (!process.versions.node.startsWith(`${BUILD_BACKED_NODE_COMPAT_VERSION}.`)) {
|
||||
return [...typecheck, ...nodeCompatSmokeGates()]
|
||||
}
|
||||
return [
|
||||
@@ -452,6 +455,7 @@ function nodeCompatSmokeGates(options: { cliSmoke?: boolean } = {}): Gate[] {
|
||||
'packages/session/session-persistence-jsonl/tests/zstd.compat.spec.ts',
|
||||
'apps/cli/tests/source-launch.compat.spec.ts',
|
||||
'scripts/vitest-environment.compat.spec.ts',
|
||||
'scripts/command-entrypoints.compat.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution-service.spec.ts',
|
||||
'packages/boot/app-boot/tests/profile-resolution-worker-bootstrap.spec.ts',
|
||||
|
||||
Reference in new issue
Block a user