UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

176 lines (175 loc) • 8.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NEW_MIGRATE_FLAGS = exports.NEW_MIGRATE_FLAGS_FLOOR = void 0; exports.findNewMigrateFlag = findNewMigrateFlag; exports.targetsExistingRun = targetsExistingRun; exports.resolveNewMigrateFlagsRunTarget = resolveNewMigrateFlagsRunTarget; exports.assertWorkspaceNxSupportsNewMigrateFlags = assertWorkspaceNxSupportsNewMigrateFlags; const semver_1 = require("semver"); const logger_1 = require("../../utils/logger"); const output_1 = require("../../utils/output"); const version_utils_1 = require("./version-utils"); // The first stable release shipping --run-migration/--run-id. Deliberately // the final release rather than its first prerelease: 23.2.0 prereleases // published before the feature landed do not carry it, so a prerelease floor // would wrongly accept them. The cost is that a later 23.2.0 prerelease that // does carry the feature is refused too, which fails toward refusal. // Permanent; never bumped at release time, but it must name the release that // actually ships the feature: if that slips past 23.2.0, versions in the gap // pass this floor and route to a temp CLI that drops the new flags and runs // the plan phase instead. exports.NEW_MIGRATE_FLAGS_FLOOR = '23.2.0'; // yargs accepts both spellings of each flag and the raw argv is forwarded // across both migrate hops, so detection must catch every one. exports.NEW_MIGRATE_FLAGS = [ '--run-migration', '--runMigration', '--run-id', '--runId', '--step-action', '--stepAction', ]; const RUN_ID_FLAGS = ['--run-id', '--runId']; /** * Matches an exact token or `<flag>=<value>`. The `=` matters: a bare * `startsWith` would also match `--run-migrations` (trailing s). */ function findFlag(argv, flags) { for (const arg of argv) { // Everything after the -- separator is positional data, not options. if (arg === '--') { return undefined; } for (const flag of flags) { if (arg === flag || arg.startsWith(`${flag}=`)) { return flag; } } } return undefined; } function findNewMigrateFlag(argv) { return findFlag(argv, exports.NEW_MIGRATE_FLAGS); } /** * Whether the invocation names an existing orchestrated run. Such an * invocation has to execute against the workspace-local nx that owns the run's * state under `.nx/migrate-runs`, so it never routes to a temp installation. */ function targetsExistingRun(argv) { return findFlag(argv, RUN_ID_FLAGS) !== undefined; } /** * Guard A (local side, before hop A). The current nx knows the new flags, but * the temp CLI 'nx migrate' is about to install may be older and would * silently drop them. Decides where a new-flag invocation runs: * * - No new flag in `argv`, or the temp CLI version resolves at or above the * feature floor: 'temp-cli', the normal temp-installation path. * - The temp CLI resolves below the floor, or resolution fails (a registry * error, or a minimum-release-age violation that a temp install must not * bypass): 'local-nx', provided the workspace-local nx can take the flags. * The local nx qualifies when it is the exact version running this code * (it parsed the flag, so it supports it regardless of the floor) or is at * or above the floor. An unreadable local version throws: the hand-off's * spawn normally lands on the very install this read verifies, and a * layout where the version cannot be read gives no such assurance, so * handing off blind could run a below-floor nx that silently drops the * flag. * - Neither side is capable: throw with remediation. * * An explicit NX_MIGRATE_CLI_VERSION pinned below the floor throws instead of * silently overriding the user's pin with the local fallback. * * `cliVersionSpec` is NX_MIGRATE_CLI_VERSION when set, else 'latest'. */ async function resolveNewMigrateFlagsRunTarget(options) { const flag = findNewMigrateFlag(options.argv); if (!flag) { return 'temp-cli'; } // `valid()` returns null for a dist-tag like 'latest' and a normalized // version for a concrete spec, which then skips the registry round-trip. const concrete = (0, semver_1.valid)(options.cliVersionSpec); let resolved; try { resolved = concrete ?? (await options.resolveVersion(options.cliVersionSpec)); } catch (e) { // The local-fallback check below decides what a failed resolution means. logger_1.logger.verbose(`Could not resolve the nx version for '${options.cliVersionSpec}': ${e}`); } if (resolved !== undefined && !(0, semver_1.lt)((0, version_utils_1.normalizeVersion)(resolved), exports.NEW_MIGRATE_FLAGS_FLOOR)) { return 'temp-cli'; } if (resolved !== undefined && options.fromEnvOverride) { throw new Error(`The nx version 'nx migrate' is about to install (${resolved}) does not support ${flag}. ` + `This flag ships in nx ${exports.NEW_MIGRATE_FLAGS_FLOOR} or newer. ` + `NX_MIGRATE_CLI_VERSION is set to '${options.cliVersionSpec}'. ` + `Unset it or set it to nx ${exports.NEW_MIGRATE_FLAGS_FLOOR} or newer.`); } const localNxVersion = options.readLocalNxVersion(); if (localNxVersion !== undefined && (localNxVersion === options.ownNxVersion || !(0, semver_1.lt)((0, version_utils_1.normalizeVersion)(localNxVersion), exports.NEW_MIGRATE_FLAGS_FLOOR))) { // A pinned spec reaching this point failed to resolve: a resolved pin // either returned 'temp-cli' or threw above. if (options.fromEnvOverride) { output_1.output.warn({ title: `The nx version pinned by NX_MIGRATE_CLI_VERSION ('${options.cliVersionSpec}') could not be resolved. Running ${flag} with the workspace's installed nx (${localNxVersion}) instead.`, }); } return 'local-nx'; } const tempSideOutcome = resolved !== undefined ? `resolves to ${resolved}, which does not support it` : `could not be resolved`; const localSideOutcome = localNxVersion !== undefined ? `the workspace's installed nx (${localNxVersion}) does not support it either` : `the workspace's installed nx version could not be read to verify support`; // The worked example assumes the steady state, where 'latest' satisfies // the floor: this branch then fires only when the spec could not be // resolved (default or pinned), and updating the workspace to latest // genuinely fixes it. Before the floor's stable release the example // cannot resolve high enough; that window is deliberately not catered // for, since no stable release carries the flags then anyway. throw new Error(`${flag} requires nx ${exports.NEW_MIGRATE_FLAGS_FLOOR} or newer. ` + `'${options.cliVersionSpec}' (the version 'nx migrate' would install) ${tempSideOutcome}, ` + `and ${localSideOutcome}. ` + `Update the workspace to nx ${exports.NEW_MIGRATE_FLAGS_FLOOR} or newer first, ` + `for example by running 'nx migrate nx@latest' (without ${flag}) or by updating your dependencies.`); } /** * Guard B (temp side, before hop B). The temp CLI knows the new flags, but the * workspace-local nx it is about to hand off to may be older and would silently * drop them. * * A workspace pinned to a feature-carrying 23.2.0 prerelease is refused here * too: published prereleases that predate the feature cannot be told apart by * version alone. Guard A's same-version bypass does not apply on this side * because the invoking nx's version is not forwarded across hop A; the * refusal names the workspace update that resolves it. * * `readLocalNxVersion` returning undefined does not block: the hand-off then * resolves nx as it always does, which may fail visibly or land on another nx * the package manager locates. */ function assertWorkspaceNxSupportsNewMigrateFlags(options) { const flag = findNewMigrateFlag(options.argv); if (!flag) { return; } const localNxVersion = options.readLocalNxVersion(); if (!localNxVersion) { return; } if ((0, semver_1.lt)((0, version_utils_1.normalizeVersion)(localNxVersion), exports.NEW_MIGRATE_FLAGS_FLOOR)) { // The worked example assumes the steady state (latest at or above the // floor); the pre-floor stable window is deliberately not catered for. throw new Error(`The workspace's installed nx (${localNxVersion}) does not support ${flag}. ` + `Update the workspace to nx ${exports.NEW_MIGRATE_FLAGS_FLOOR} or newer first, ` + `for example by running 'nx migrate nx@latest' (without ${flag}) or by updating your dependencies.`); } }