Files
2026-07-13 12:38:36 +08:00

153 lines
5.3 KiB
TypeScript

import { Config } from '@jest/types';
import { existsSync, removeSync } from 'fs-extra';
import * as isCI from 'is-ci';
import { exec, execSync } from 'node:child_process';
import { join } from 'node:path';
import { mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { registerTsConfigPaths } from '../../packages/nx/src/plugins/js/utils/register';
import { runLocalRelease } from '../../scripts/local-registry/populate-storage';
export default async function (globalConfig: Config.ConfigGlobals) {
try {
// TEMP DIAGNOSTIC (cache-miss hunt): log the exact checkout + any working-tree
// drift on the agent. Distinguishes "runs are on different SHAs" from
// "same SHA but a task mutated the tree". Safe to remove once resolved.
if (process.env.CI) {
try {
const head = execSync('git rev-parse HEAD').toString().trim();
const porcelain = execSync('git status --porcelain').toString().trim();
console.log(
`\n=== [tree-state] target=${process.env.NX_TASK_TARGET_TARGET} HEAD=${head} ===\n` +
`git status --porcelain:\n${porcelain || '(clean)'}\n`
);
} catch (err) {
console.log(
`[tree-state] diagnostic failed: ${(err as Error).message}`
);
}
}
const isVerbose: boolean =
process.env.NX_VERBOSE_LOGGING === 'true' || !!globalConfig.verbose;
/**
* For e2e-ci, e2e-local and macos-local-e2e we populate the verdaccio storage up front, but for other workflows we need
* to run the full local release process before running tests.
*/
const prefixes = ['e2e-ci', 'e2e-macos-local', 'e2e-local'];
const requiresLocalRelease = !prefixes.some((prefix) =>
process.env.NX_TASK_TARGET_TARGET?.startsWith(prefix)
);
const listenAddress = 'localhost';
const port = process.env.NX_LOCAL_REGISTRY_PORT ?? '4873';
const registry = `http://${listenAddress}:${port}`;
const authToken = 'secretVerdaccioToken';
while (true) {
await new Promise((resolve) => setTimeout(resolve, 250));
try {
await assertLocalRegistryIsRunning(registry);
break;
} catch {
console.log(`Waiting for Local registry to start on ${registry}...`);
}
}
process.env.npm_config_registry = registry;
// Use environment variable instead of npm config command to avoid polluting other tests
process.env[`npm_config_//${listenAddress}:${port}/:_authToken`] =
authToken;
// bun
process.env.BUN_CONFIG_REGISTRY = registry;
process.env.BUN_CONFIG_TOKEN = authToken;
// yarnv1
process.env.YARN_REGISTRY = registry;
// yarnv2
process.env.YARN_NPM_REGISTRY_SERVER = registry;
process.env.YARN_UNSAFE_HTTP_WHITELIST = listenAddress;
// Use fresh cache directories to avoid serving stale packages when the
// same version is republished to the local registry.
const e2eCacheDir = mkdtempSync(join(tmpdir(), 'nx-e2e-cache-'));
process.env.npm_config_cache = join(e2eCacheDir, 'npm');
// yarnv1
process.env.YARN_CACHE_FOLDER = join(e2eCacheDir, 'yarn');
// yarnv2
process.env.YARN_ENABLE_GLOBAL_CACHE = 'false';
process.env.NX_SKIP_PROVENANCE_CHECK = 'true';
global.e2eTeardown = () => {
// Clean up environment variable instead of npm config command
delete process.env[`npm_config_//${listenAddress}:${port}/:_authToken`];
};
/**
* Set the published version based on what has previously been loaded into the
* verdaccio storage.
*/
if (!requiresLocalRelease) {
let publishedVersion = await getPublishedVersion();
console.log(`Testing Published version: Nx ${publishedVersion}`);
if (publishedVersion) {
process.env.PUBLISHED_VERSION = publishedVersion;
}
}
if (
process.env.NX_E2E_SKIP_GLOBAL_CLEANUP !== 'true' ||
!existsSync('./build')
) {
if (!isCI) {
registerTsConfigPaths(join(__dirname, '../../tsconfig.base.json'));
const { e2eCwd } = await import('./get-env-info');
removeSync(e2eCwd);
}
if (requiresLocalRelease) {
console.log('Publishing packages to local registry');
const publishVersion = process.env.PUBLISHED_VERSION ?? 'major';
// Always show full release logs on CI, they should only happen once via e2e-ci
await runLocalRelease(publishVersion, isCI || isVerbose);
}
}
} catch (err) {
// Clean up registry if possible after setup related errors
if (typeof global.e2eTeardown === 'function') {
global.e2eTeardown();
console.log('Killed local registry process due to an error during setup');
}
throw err;
}
}
function getPublishedVersion(): Promise<string | undefined> {
execSync(`npm config get registry`, {
stdio: 'inherit',
});
return new Promise((resolve) => {
// Resolve the published nx version from verdaccio
exec(
'npm view nx@latest version',
{
windowsHide: false,
},
(error, stdout, stderr) => {
if (error) {
return resolve(undefined);
}
return resolve(stdout.trim());
}
);
});
}
async function assertLocalRegistryIsRunning(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
}