nx 23.0.0-beta.2 → 23.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/init-local.js +11 -20
- package/dist/bin/nx.d.ts +1 -0
- package/dist/bin/nx.js +28 -2
- package/dist/plugins/package-json.js +4 -2
- package/dist/src/adapter/ngcli-adapter.d.ts +2 -1
- package/dist/src/adapter/ngcli-adapter.js +25 -2
- package/dist/src/ai/clone-ai-config-repo.js +20 -3
- package/dist/src/analytics/analytics.js +10 -1
- package/dist/src/command-line/add/completion.d.ts +1 -0
- package/dist/src/command-line/add/completion.js +15 -0
- package/dist/src/command-line/affected/completion.d.ts +1 -0
- package/dist/src/command-line/affected/completion.js +15 -0
- package/dist/src/command-line/completion/argv-layout.d.ts +6 -0
- package/dist/src/command-line/completion/argv-layout.js +19 -0
- package/dist/src/command-line/completion/command-completions.d.ts +19 -0
- package/dist/src/command-line/completion/command-completions.js +120 -0
- package/dist/src/command-line/completion/command-handlers.d.ts +30 -0
- package/dist/src/command-line/completion/command-handlers.js +69 -0
- package/dist/src/command-line/completion/command-object.d.ts +10 -0
- package/dist/src/command-line/completion/command-object.js +95 -0
- package/dist/src/command-line/completion/completion-providers.d.ts +21 -0
- package/dist/src/command-line/completion/completion-providers.js +194 -0
- package/dist/src/command-line/completion/infix-targets.d.ts +1 -0
- package/dist/src/command-line/completion/infix-targets.js +48 -0
- package/dist/src/command-line/completion/metadata.d.ts +22 -0
- package/dist/src/command-line/completion/metadata.js +71 -0
- package/dist/src/command-line/completion/registrations.d.ts +9 -0
- package/dist/src/command-line/completion/registrations.js +16 -0
- package/dist/src/command-line/completion/scripts/bash.sh +51 -0
- package/dist/src/command-line/completion/scripts/fish.fish +47 -0
- package/dist/src/command-line/completion/scripts/powershell.ps1 +52 -0
- package/dist/src/command-line/completion/scripts/zsh.zsh +69 -0
- package/dist/src/command-line/completion/scripts.d.ts +18 -0
- package/dist/src/command-line/completion/scripts.js +140 -0
- package/dist/src/command-line/completion/trigger.d.ts +3 -0
- package/dist/src/command-line/completion/trigger.js +21 -0
- package/dist/src/command-line/completion/value-completions.d.ts +3 -0
- package/dist/src/command-line/completion/value-completions.js +21 -0
- package/dist/src/command-line/examples.js +1 -1
- package/dist/src/command-line/format/format.js +15 -5
- package/dist/src/command-line/generate/completion.d.ts +1 -0
- package/dist/src/command-line/generate/completion.js +9 -0
- package/dist/src/command-line/graph/completion.d.ts +1 -0
- package/dist/src/command-line/graph/completion.js +13 -0
- package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +14 -18
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +1 -0
- package/dist/src/command-line/init/implementation/utils.d.ts +7 -1
- package/dist/src/command-line/init/implementation/utils.js +51 -14
- package/dist/src/command-line/migrate/agentic/capture-generator-output.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/capture-generator-output.js +100 -0
- package/dist/src/command-line/migrate/agentic/cli-args.d.ts +12 -0
- package/dist/src/command-line/migrate/agentic/cli-args.js +38 -0
- package/dist/src/command-line/migrate/agentic/definitions.d.ts +6 -0
- package/dist/src/command-line/migrate/agentic/definitions.js +98 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/detect-installed.js +68 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +87 -0
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +63 -0
- package/dist/src/command-line/migrate/agentic/handoff.js +183 -0
- package/dist/src/command-line/migrate/agentic/inception.d.ts +9 -0
- package/dist/src/command-line/migrate/agentic/inception.js +15 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +22 -0
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +50 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +65 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +44 -0
- package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +52 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +21 -0
- package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +26 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +18 -0
- package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +130 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +46 -0
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +88 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +51 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +121 -0
- package/dist/src/command-line/migrate/agentic/runner.d.ts +33 -0
- package/dist/src/command-line/migrate/agentic/runner.js +442 -0
- package/dist/src/command-line/migrate/agentic/select.d.ts +14 -0
- package/dist/src/command-line/migrate/agentic/select.js +150 -0
- package/dist/src/command-line/migrate/agentic/types.d.ts +102 -0
- package/dist/src/command-line/migrate/agentic/types.js +2 -0
- package/dist/src/command-line/migrate/command-object.d.ts +1 -0
- package/dist/src/command-line/migrate/command-object.js +32 -7
- package/dist/src/command-line/migrate/migrate-commits.d.ts +50 -0
- package/dist/src/command-line/migrate/migrate-commits.js +102 -0
- package/dist/src/command-line/migrate/migrate-output.d.ts +180 -0
- package/dist/src/command-line/migrate/migrate-output.js +258 -0
- package/dist/src/command-line/migrate/migrate.d.ts +122 -12
- package/dist/src/command-line/migrate/migrate.js +1036 -217
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/migration-shape.js +13 -0
- package/dist/src/command-line/migrate/multi-major.d.ts +30 -0
- package/dist/src/command-line/migrate/multi-major.js +185 -0
- package/dist/src/command-line/migrate/prompt-files.d.ts +31 -0
- package/dist/src/command-line/migrate/prompt-files.js +141 -0
- package/dist/src/command-line/migrate/run-migration-process.js +28 -6
- package/dist/src/command-line/migrate/safe-prompt.d.ts +28 -0
- package/dist/src/command-line/migrate/safe-prompt.js +49 -0
- package/dist/src/command-line/migrate/update-filters.d.ts +11 -0
- package/dist/src/command-line/migrate/update-filters.js +44 -0
- package/dist/src/command-line/migrate/version-utils.d.ts +6 -0
- package/dist/src/command-line/migrate/version-utils.js +59 -0
- package/dist/src/command-line/nx-commands.js +9 -0
- package/dist/src/command-line/release/config/config.d.ts +3 -6
- package/dist/src/command-line/release/config/config.js +77 -45
- package/dist/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
- package/dist/src/command-line/release/config/use-legacy-versioning.js +8 -0
- package/dist/src/command-line/release/utils/release-graph.js +2 -3
- package/dist/src/command-line/release/utils/repository-git-tags.js +1 -1
- package/dist/src/command-line/release/utils/resolve-changelog-renderer.js +7 -19
- package/dist/src/command-line/release/version/resolve-current-version.js +1 -1
- package/dist/src/command-line/release/version/version-actions.js +3 -7
- package/dist/src/command-line/report/report.js +2 -2
- package/dist/src/command-line/run/completion.d.ts +1 -0
- package/dist/src/command-line/run/completion.js +7 -0
- package/dist/src/command-line/run-many/completion.d.ts +1 -0
- package/dist/src/command-line/run-many/completion.js +13 -0
- package/dist/src/command-line/show/completion.d.ts +1 -0
- package/dist/src/command-line/show/completion.js +27 -0
- package/dist/src/command-line/show/show-target/info.d.ts +1 -0
- package/dist/src/command-line/show/show-target/info.js +100 -19
- package/dist/src/command-line/watch/command-object.js +24 -4
- package/dist/src/command-line/watch/completion.d.ts +1 -0
- package/dist/src/command-line/watch/completion.js +10 -0
- package/dist/src/command-line/watch/watch.d.ts +7 -0
- package/dist/src/command-line/watch/watch.js +1 -1
- package/dist/src/config/misc-interfaces.d.ts +25 -2
- package/dist/src/config/nx-json.d.ts +43 -56
- package/dist/src/config/schema-utils.d.ts +21 -0
- package/dist/src/config/schema-utils.js +92 -18
- package/dist/src/config/task-graph.d.ts +4 -107
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.css +2 -3
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +1 -1
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +1 -1
- package/dist/src/daemon/server/file-watching/route-workspace-changes.d.ts +9 -0
- package/dist/src/daemon/server/file-watching/route-workspace-changes.js +76 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +45 -11
- package/dist/src/daemon/server/server.js +4 -43
- package/dist/src/daemon/server/start.d.ts +1 -1
- package/dist/src/daemon/server/start.js +2 -0
- package/dist/src/devkit-exports.d.ts +2 -2
- package/dist/src/devkit-internals.d.ts +5 -1
- package/dist/src/devkit-internals.js +17 -1
- package/dist/src/executors/run-commands/running-tasks.d.ts +7 -0
- package/dist/src/executors/run-commands/running-tasks.js +178 -105
- package/dist/src/executors/run-script/run-script.impl.js +3 -10
- package/dist/src/executors/utils/convert-nx-executor.js +1 -1
- package/dist/src/hasher/hash-plan-inspector.d.ts +1 -1
- package/dist/src/hasher/task-hasher.js +6 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +0 -3
- package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +6 -2
- package/dist/src/migrations/update-17-0-0/move-cache-directory.md +31 -0
- package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +20 -4
- package/dist/src/migrations/update-20-0-0/move-use-daemon-process.md +27 -0
- package/dist/src/migrations/update-20-0-1/use-legacy-cache.md +24 -0
- package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.md +49 -0
- package/dist/src/migrations/update-21-0-0/release-version-config-changes.md +54 -0
- package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.md +28 -0
- package/dist/src/migrations/update-21-0-0/remove-legacy-cache.md +22 -0
- package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.md +11 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.d.ts +2 -0
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +16 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +9 -0
- package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +18 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +35 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +139 -0
- package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.md +66 -0
- package/dist/src/native/index.d.ts +79 -2
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/npm-parser.js +37 -19
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +51 -4
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +12 -4
- package/dist/src/plugins/js/utils/packages.js +1 -1
- package/dist/src/plugins/js/utils/register.d.ts +103 -14
- package/dist/src/plugins/js/utils/register.js +434 -39
- package/dist/src/plugins/js/utils/typescript.d.ts +7 -0
- package/dist/src/plugins/js/utils/typescript.js +39 -0
- package/dist/src/plugins/package-json/create-nodes.d.ts +3 -2
- package/dist/src/plugins/package-json/create-nodes.js +7 -5
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +2 -1
- package/dist/src/project-graph/build-project-graph.d.ts +5 -0
- package/dist/src/project-graph/build-project-graph.js +6 -2
- package/dist/src/project-graph/file-map-utils.d.ts +5 -0
- package/dist/src/project-graph/file-map-utils.js +10 -1
- package/dist/src/project-graph/plugins/get-plugins.d.ts +7 -2
- package/dist/src/project-graph/plugins/get-plugins.js +8 -5
- package/dist/src/project-graph/plugins/isolation/plugin-worker.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +2 -0
- package/dist/src/project-graph/plugins/resolve-plugin.d.ts +7 -4
- package/dist/src/project-graph/plugins/resolve-plugin.js +152 -33
- package/dist/src/project-graph/plugins/tasks-execution-hooks.js +4 -2
- package/dist/src/project-graph/plugins/transpiler.d.ts +12 -0
- package/dist/src/project-graph/plugins/transpiler.js +37 -0
- package/dist/src/project-graph/plugins/utils.js +13 -7
- package/dist/src/project-graph/project-graph.js +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +95 -4
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +515 -68
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +13 -5
- package/dist/src/project-graph/utils/project-configuration-utils.js +14 -6
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -1
- package/dist/src/tasks-runner/create-task-graph.d.ts +4 -4
- package/dist/src/tasks-runner/create-task-graph.js +1 -1
- package/dist/src/tasks-runner/default-tasks-runner.d.ts +0 -2
- package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.js +11 -6
- package/dist/src/tasks-runner/init-tasks-runner.d.ts +0 -15
- package/dist/src/tasks-runner/init-tasks-runner.js +0 -63
- package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +18 -0
- package/dist/src/tasks-runner/legacy-depends-on-warning.js +109 -0
- package/dist/src/tasks-runner/life-cycle.d.ts +7 -8
- package/dist/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +6 -6
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +13 -2
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -5
- package/dist/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +11 -2
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/run-command.js +8 -11
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
- package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
- package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
- package/dist/src/tasks-runner/task-env.d.ts +1 -1
- package/dist/src/tasks-runner/task-env.js +6 -1
- package/dist/src/tasks-runner/task-orchestrator.d.ts +11 -1
- package/dist/src/tasks-runner/task-orchestrator.js +112 -38
- package/dist/src/tasks-runner/tasks-schedule.js +3 -3
- package/dist/src/tasks-runner/utils.d.ts +7 -8
- package/dist/src/tasks-runner/utils.js +23 -27
- package/dist/src/utils/child-process.js +2 -2
- package/dist/src/utils/compile-cache.d.ts +24 -0
- package/dist/src/utils/compile-cache.js +49 -0
- package/dist/src/utils/enable-compile-cache.d.ts +1 -0
- package/dist/src/utils/enable-compile-cache.js +7 -0
- package/dist/src/utils/fileutils.d.ts +0 -8
- package/dist/src/utils/fileutils.js +0 -40
- package/dist/src/utils/git-utils.d.ts +15 -0
- package/dist/src/utils/git-utils.js +138 -0
- package/dist/src/utils/handle-import.d.ts +4 -1
- package/dist/src/utils/handle-import.js +56 -2
- package/dist/src/utils/has-nx-js-plugin.d.ts +9 -0
- package/dist/src/utils/has-nx-js-plugin.js +24 -0
- package/dist/src/utils/installed-nx-version.d.ts +14 -4
- package/dist/src/utils/installed-nx-version.js +54 -7
- package/dist/src/utils/logger.d.ts +12 -1
- package/dist/src/utils/logger.js +57 -36
- package/dist/src/utils/nx-key.d.ts +0 -1
- package/dist/src/utils/nx-key.js +20 -23
- package/dist/src/utils/nx-package-group.d.ts +8 -0
- package/dist/src/utils/nx-package-group.js +15 -0
- package/dist/src/utils/output.d.ts +3 -2
- package/dist/src/utils/output.js +29 -28
- package/dist/src/utils/package-json.d.ts +14 -1
- package/dist/src/utils/package-json.js +20 -21
- package/dist/src/utils/perf-logging.js +3 -1
- package/dist/src/utils/plugin-cache-utils.d.ts +13 -4
- package/dist/src/utils/plugin-cache-utils.js +23 -13
- package/dist/src/utils/plugins/local-plugins.d.ts +18 -0
- package/dist/src/utils/plugins/local-plugins.js +30 -0
- package/dist/src/utils/tar.d.ts +8 -0
- package/dist/src/utils/tar.js +44 -0
- package/migrations.json +16 -0
- package/package.json +28 -28
- package/schemas/nx-schema.json +114 -80
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.d.ts +0 -7
- package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.js +0 -155
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.d.ts +0 -16
- package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.js +0 -121
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Migrator = void 0;
|
|
3
|
+
exports.ChangedDepInstaller = exports.isHybridMigration = exports.isPromptOnlyMigration = exports.filterDowngradedUpdates = exports.Migrator = exports.normalizeVersion = void 0;
|
|
4
4
|
exports.formatCommandFailure = formatCommandFailure;
|
|
5
|
-
exports.
|
|
5
|
+
exports.resolveCanonicalNxPackage = resolveCanonicalNxPackage;
|
|
6
|
+
exports.resolveMode = resolveMode;
|
|
6
7
|
exports.parseMigrationsOptions = parseMigrationsOptions;
|
|
7
8
|
exports.isNpmPeerDepsError = isNpmPeerDepsError;
|
|
9
|
+
exports.resolveAgenticRunId = resolveAgenticRunId;
|
|
10
|
+
exports.formatSkippedPromptsNextStep = formatSkippedPromptsNextStep;
|
|
11
|
+
exports.resolveCreateCommits = resolveCreateCommits;
|
|
12
|
+
exports.resolveShouldRunValidation = resolveShouldRunValidation;
|
|
8
13
|
exports.executeMigrations = executeMigrations;
|
|
9
14
|
exports.runNxOrAngularMigration = runNxOrAngularMigration;
|
|
15
|
+
exports.parseMigrationReturn = parseMigrationReturn;
|
|
10
16
|
exports.migrate = migrate;
|
|
11
17
|
exports.runMigration = runMigration;
|
|
12
18
|
exports.readMigrationCollection = readMigrationCollection;
|
|
@@ -15,7 +21,7 @@ exports.nxCliPath = nxCliPath;
|
|
|
15
21
|
const tslib_1 = require("tslib");
|
|
16
22
|
const pc = tslib_1.__importStar(require("picocolors"));
|
|
17
23
|
const child_process_1 = require("child_process");
|
|
18
|
-
const
|
|
24
|
+
const safe_prompt_1 = require("./safe-prompt");
|
|
19
25
|
const handle_import_1 = require("../../utils/handle-import");
|
|
20
26
|
const path_1 = require("path");
|
|
21
27
|
const module_1 = require("module");
|
|
@@ -25,6 +31,7 @@ const node_url_1 = require("node:url");
|
|
|
25
31
|
const util_1 = require("util");
|
|
26
32
|
const tree_1 = require("../../generators/tree");
|
|
27
33
|
const fileutils_1 = require("../../utils/fileutils");
|
|
34
|
+
const tar_1 = require("../../utils/tar");
|
|
28
35
|
const write_formatted_json_file_1 = require("../../utils/write-formatted-json-file");
|
|
29
36
|
const logger_1 = require("../../utils/logger");
|
|
30
37
|
const git_utils_1 = require("../../utils/git-utils");
|
|
@@ -37,6 +44,7 @@ const fs_1 = require("fs");
|
|
|
37
44
|
const workspace_root_1 = require("../../utils/workspace-root");
|
|
38
45
|
const is_ci_1 = require("../../utils/is-ci");
|
|
39
46
|
const installation_directory_1 = require("../../utils/installation-directory");
|
|
47
|
+
const installed_nx_version_1 = require("../../utils/installed-nx-version");
|
|
40
48
|
const configuration_1 = require("../../config/configuration");
|
|
41
49
|
const child_process_2 = require("../../utils/child-process");
|
|
42
50
|
const client_1 = require("../../daemon/client/client");
|
|
@@ -45,6 +53,19 @@ const project_graph_1 = require("../../project-graph/project-graph");
|
|
|
45
53
|
const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
|
|
46
54
|
const provenance_1 = require("../../utils/provenance");
|
|
47
55
|
const catalog_1 = require("../../utils/catalog");
|
|
56
|
+
const multi_major_1 = require("./multi-major");
|
|
57
|
+
const prompt_files_1 = require("./prompt-files");
|
|
58
|
+
const command_object_1 = require("./command-object");
|
|
59
|
+
const handoff_gitignore_1 = require("./agentic/handoff-gitignore");
|
|
60
|
+
const migrate_commits_1 = require("./migrate-commits");
|
|
61
|
+
const migrate_output_1 = require("./migrate-output");
|
|
62
|
+
const migration_shape_1 = require("./migration-shape");
|
|
63
|
+
Object.defineProperty(exports, "isHybridMigration", { enumerable: true, get: function () { return migration_shape_1.isHybridMigration; } });
|
|
64
|
+
Object.defineProperty(exports, "isPromptOnlyMigration", { enumerable: true, get: function () { return migration_shape_1.isPromptOnlyMigration; } });
|
|
65
|
+
const update_filters_1 = require("./update-filters");
|
|
66
|
+
Object.defineProperty(exports, "filterDowngradedUpdates", { enumerable: true, get: function () { return update_filters_1.filterDowngradedUpdates; } });
|
|
67
|
+
const version_utils_1 = require("./version-utils");
|
|
68
|
+
Object.defineProperty(exports, "normalizeVersion", { enumerable: true, get: function () { return version_utils_1.normalizeVersion; } });
|
|
48
69
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
49
70
|
function formatCommandFailure(command, error) {
|
|
50
71
|
const normalizeCommandOutput = (output) => {
|
|
@@ -76,33 +97,6 @@ function runOrReturnExitCode(run) {
|
|
|
76
97
|
throw e;
|
|
77
98
|
}
|
|
78
99
|
}
|
|
79
|
-
function normalizeVersion(version) {
|
|
80
|
-
const [semver, ...prereleaseTagParts] = version.split('-');
|
|
81
|
-
// Handle versions like 1.0.0-beta-next.2
|
|
82
|
-
const prereleaseTag = prereleaseTagParts.join('-');
|
|
83
|
-
const [major, minor, patch] = semver.split('.');
|
|
84
|
-
const newSemver = `${major || 0}.${minor || 0}.${patch || 0}`;
|
|
85
|
-
const newVersion = prereleaseTag
|
|
86
|
-
? `${newSemver}-${prereleaseTag}`
|
|
87
|
-
: newSemver;
|
|
88
|
-
const withoutPatch = `${major || 0}.${minor || 0}.0`;
|
|
89
|
-
const withoutPatchAndMinor = `${major || 0}.0.0`;
|
|
90
|
-
const variationsToCheck = [
|
|
91
|
-
newVersion,
|
|
92
|
-
newSemver,
|
|
93
|
-
withoutPatch,
|
|
94
|
-
withoutPatchAndMinor,
|
|
95
|
-
];
|
|
96
|
-
for (const variation of variationsToCheck) {
|
|
97
|
-
try {
|
|
98
|
-
if ((0, semver_1.gt)(variation, '0.0.0')) {
|
|
99
|
-
return variation;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
catch { }
|
|
103
|
-
}
|
|
104
|
-
return '0.0.0';
|
|
105
|
-
}
|
|
106
100
|
function cleanSemver(version) {
|
|
107
101
|
return (0, semver_1.clean)(version) ?? (0, semver_1.coerce)(version);
|
|
108
102
|
}
|
|
@@ -114,6 +108,10 @@ class Migrator {
|
|
|
114
108
|
this.packageUpdates = {};
|
|
115
109
|
this.collectedVersions = {};
|
|
116
110
|
this.promptAnswers = {};
|
|
111
|
+
if ((opts.mode === 'first-party' || opts.mode === 'third-party') &&
|
|
112
|
+
!opts.firstPartyPackages) {
|
|
113
|
+
throw new Error(`Error: 'firstPartyPackages' is required when 'mode' is '${opts.mode}'.`);
|
|
114
|
+
}
|
|
117
115
|
this.packageJson = opts.packageJson;
|
|
118
116
|
this.nxInstallation = opts.nxInstallation;
|
|
119
117
|
this.getInstalledPackageVersion = opts.getInstalledPackageVersion;
|
|
@@ -122,6 +120,8 @@ class Migrator {
|
|
|
122
120
|
this.to = opts.to;
|
|
123
121
|
this.interactive = opts.interactive;
|
|
124
122
|
this.excludeAppliedMigrations = opts.excludeAppliedMigrations;
|
|
123
|
+
this.mode = opts.mode;
|
|
124
|
+
this.firstPartyPackages = opts.firstPartyPackages;
|
|
125
125
|
}
|
|
126
126
|
async fetchMigrationConfig(packageName, packageVersion) {
|
|
127
127
|
const migrationConfig = await this.fetch(packageName, packageVersion);
|
|
@@ -135,14 +135,17 @@ class Migrator {
|
|
|
135
135
|
version: targetVersion,
|
|
136
136
|
addToPackageJson: false,
|
|
137
137
|
});
|
|
138
|
-
|
|
138
|
+
this.applyModeFilter();
|
|
139
|
+
const { migrations, promptContents } = await this.createMigrateJson();
|
|
139
140
|
return {
|
|
140
141
|
packageUpdates: this.packageUpdates,
|
|
141
142
|
migrations,
|
|
143
|
+
...(Object.keys(promptContents).length > 0 ? { promptContents } : {}),
|
|
142
144
|
minVersionWithSkippedUpdates: this.minVersionWithSkippedUpdates,
|
|
143
145
|
};
|
|
144
146
|
}
|
|
145
147
|
async createMigrateJson() {
|
|
148
|
+
const promptContents = {};
|
|
146
149
|
const migrations = await Promise.all(Object.keys(this.packageUpdates).map(async (packageName) => {
|
|
147
150
|
if (this.packageUpdates[packageName].ignoreMigrations) {
|
|
148
151
|
return [];
|
|
@@ -151,10 +154,15 @@ class Migrator {
|
|
|
151
154
|
if (currentVersion === null)
|
|
152
155
|
return [];
|
|
153
156
|
const { version } = this.packageUpdates[packageName];
|
|
154
|
-
const { generators } = await this.fetchMigrationConfig(packageName, version);
|
|
155
|
-
if (!
|
|
157
|
+
const { generators: migrationEntries, resolvedPromptFiles } = await this.fetchMigrationConfig(packageName, version);
|
|
158
|
+
if (!migrationEntries)
|
|
156
159
|
return [];
|
|
157
|
-
|
|
160
|
+
if (resolvedPromptFiles) {
|
|
161
|
+
for (const [promptPath, content] of Object.entries(resolvedPromptFiles)) {
|
|
162
|
+
promptContents[(0, prompt_files_1.promptContentKey)(packageName, promptPath)] = content;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return Object.entries(migrationEntries)
|
|
158
166
|
.filter(([, migration]) => migration.version &&
|
|
159
167
|
this.gt(migration.version, currentVersion) &&
|
|
160
168
|
this.lte(migration.version, version) &&
|
|
@@ -165,7 +173,7 @@ class Migrator {
|
|
|
165
173
|
name: migrationName,
|
|
166
174
|
}));
|
|
167
175
|
}));
|
|
168
|
-
return migrations.flat();
|
|
176
|
+
return { migrations: migrations.flat(), promptContents };
|
|
169
177
|
}
|
|
170
178
|
async buildPackageJsonUpdates(targetPackage, target) {
|
|
171
179
|
const packagesToCheck = await this.populatePackageJsonUpdatesAndGetPackagesToCheck(targetPackage, target);
|
|
@@ -263,7 +271,7 @@ class Migrator {
|
|
|
263
271
|
if (ignorePackageGroup) {
|
|
264
272
|
return [];
|
|
265
273
|
}
|
|
266
|
-
const packageGroup = packageName === '@nrwl/workspace' && (0,
|
|
274
|
+
const packageGroup = packageName === '@nrwl/workspace' && (0, version_utils_1.isLegacyEra)(targetVersion)
|
|
267
275
|
? LEGACY_NRWL_PACKAGE_GROUP
|
|
268
276
|
: (migrationConfig.packageGroup ?? []);
|
|
269
277
|
let packageGroupOrder = [];
|
|
@@ -307,6 +315,9 @@ class Migrator {
|
|
|
307
315
|
};
|
|
308
316
|
const filtered = {};
|
|
309
317
|
for (const [packageName, packageUpdate] of Object.entries(packageJsonUpdate.packages)) {
|
|
318
|
+
if (this.shouldExcludePackage(packageName)) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
310
321
|
if (this.shouldApplyPackageUpdate(packageUpdate, packageName, dependencies)) {
|
|
311
322
|
filtered[packageName] = {
|
|
312
323
|
version: packageUpdate.version,
|
|
@@ -331,6 +342,29 @@ class Migrator {
|
|
|
331
342
|
}
|
|
332
343
|
return filteredPackageJsonUpdates;
|
|
333
344
|
}
|
|
345
|
+
shouldExcludePackage(packageName) {
|
|
346
|
+
if (!this.firstPartyPackages) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
if (this.mode === 'first-party') {
|
|
350
|
+
return !this.firstPartyPackages.has(packageName);
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
applyModeFilter() {
|
|
355
|
+
if (this.mode !== 'third-party') {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// Cascade walks through first-party packages so cross-plugin third-party
|
|
359
|
+
// deps (e.g. typescript managed by @nx/js but used by @nx/angular) get
|
|
360
|
+
// surfaced. Drop the first-party set from the final result here so only
|
|
361
|
+
// third-party updates land in package.json.
|
|
362
|
+
for (const name of Object.keys(this.packageUpdates)) {
|
|
363
|
+
if (this.firstPartyPackages.has(name)) {
|
|
364
|
+
delete this.packageUpdates[name];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
334
368
|
shouldApplyPackageUpdate(packageUpdate, packageName, dependencies) {
|
|
335
369
|
return ((!packageUpdate.ifPackageInstalled ||
|
|
336
370
|
this.getPkgVersion(packageUpdate.ifPackageInstalled)) &&
|
|
@@ -423,7 +457,7 @@ class Migrator {
|
|
|
423
457
|
// @ts-expect-error -- enquirer types aren't correct, footer does exist
|
|
424
458
|
promptConfig.footer = () => pc.dim(` View migration details at https://nx.dev/nx-api/${packageName.replace('@nx/', '')}#${packageUpdateKey.replace(/[-\.]/g, '')}packageupdates`);
|
|
425
459
|
}
|
|
426
|
-
return await (0,
|
|
460
|
+
return await (0, safe_prompt_1.migratePrompt)([promptConfig]).then(({ shouldApply }) => {
|
|
427
461
|
this.promptAnswers[promptKey] = shouldApply;
|
|
428
462
|
if (!shouldApply &&
|
|
429
463
|
(!this.minVersionWithSkippedUpdates ||
|
|
@@ -442,13 +476,13 @@ class Migrator {
|
|
|
442
476
|
return this.getInstalledPackageVersion(pkg, this.installedPkgVersionOverrides);
|
|
443
477
|
}
|
|
444
478
|
gt(v1, v2) {
|
|
445
|
-
return (0, semver_1.gt)(normalizeVersion(v1), normalizeVersion(v2));
|
|
479
|
+
return (0, semver_1.gt)((0, version_utils_1.normalizeVersion)(v1), (0, version_utils_1.normalizeVersion)(v2));
|
|
446
480
|
}
|
|
447
481
|
lt(v1, v2) {
|
|
448
|
-
return (0, semver_1.lt)(normalizeVersion(v1), normalizeVersion(v2));
|
|
482
|
+
return (0, semver_1.lt)((0, version_utils_1.normalizeVersion)(v1), (0, version_utils_1.normalizeVersion)(v2));
|
|
449
483
|
}
|
|
450
484
|
lte(v1, v2) {
|
|
451
|
-
return (0, semver_1.lte)(normalizeVersion(v1), normalizeVersion(v2));
|
|
485
|
+
return (0, semver_1.lte)((0, version_utils_1.normalizeVersion)(v1), (0, version_utils_1.normalizeVersion)(v2));
|
|
452
486
|
}
|
|
453
487
|
}
|
|
454
488
|
exports.Migrator = Migrator;
|
|
@@ -475,17 +509,59 @@ const LEGACY_NRWL_PACKAGE_GROUP = [
|
|
|
475
509
|
{ package: '@nrwl/expo', version: '*' },
|
|
476
510
|
{ package: '@nrwl/tao', version: '*' },
|
|
477
511
|
];
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
512
|
+
function resolveFirstPartyPackages(targetPackage, packageGroup) {
|
|
513
|
+
const set = new Set([targetPackage]);
|
|
514
|
+
for (const { package: name } of packageGroup ?? []) {
|
|
515
|
+
set.add(name);
|
|
516
|
+
}
|
|
517
|
+
return set;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* The canonical Nx package for a given target version: `@nrwl/workspace` for
|
|
521
|
+
* legacy (`< 14.0.0-beta.0`), `nx` otherwise. Non-semver inputs (e.g. the
|
|
522
|
+
* literal `'latest'` sentinel before tag resolution) resolve to modern era.
|
|
523
|
+
* Used by `--mode=third-party` to silently swap `@nx/workspace` → `nx` when
|
|
524
|
+
* walking the cascade.
|
|
525
|
+
*/
|
|
526
|
+
function resolveCanonicalNxPackage(targetVersion) {
|
|
527
|
+
return (0, version_utils_1.isLegacyEra)(targetVersion) ? '@nrwl/workspace' : 'nx';
|
|
528
|
+
}
|
|
529
|
+
async function resolveMode(mode, targetPackage, targetVersion, context = {
|
|
530
|
+
hasFrom: false,
|
|
531
|
+
hasExcludeAppliedMigrations: false,
|
|
532
|
+
}) {
|
|
533
|
+
if (mode) {
|
|
534
|
+
return mode;
|
|
535
|
+
}
|
|
536
|
+
if (!(0, version_utils_1.isNxEquivalentTarget)(targetPackage, targetVersion)) {
|
|
537
|
+
return 'all';
|
|
538
|
+
}
|
|
539
|
+
if (!process.stdin.isTTY || (0, is_ci_1.isCI)()) {
|
|
540
|
+
return 'all';
|
|
541
|
+
}
|
|
542
|
+
const choices = [
|
|
543
|
+
{
|
|
544
|
+
name: 'first-party',
|
|
545
|
+
message: 'First-party only (Nx and its official packages)',
|
|
546
|
+
},
|
|
547
|
+
];
|
|
548
|
+
if (!context.hasFrom && !context.hasExcludeAppliedMigrations) {
|
|
549
|
+
choices.push({
|
|
550
|
+
name: 'third-party',
|
|
551
|
+
message: 'Third-party only (deps managed by Nx)',
|
|
552
|
+
});
|
|
487
553
|
}
|
|
488
|
-
|
|
554
|
+
choices.push({
|
|
555
|
+
name: 'all',
|
|
556
|
+
message: 'All (first-party and third-party)',
|
|
557
|
+
});
|
|
558
|
+
const { mode: selected } = await (0, safe_prompt_1.migratePrompt)({
|
|
559
|
+
type: 'select',
|
|
560
|
+
name: 'mode',
|
|
561
|
+
message: 'Which packages would you like to migrate?',
|
|
562
|
+
choices,
|
|
563
|
+
});
|
|
564
|
+
return selected;
|
|
489
565
|
}
|
|
490
566
|
async function versionOverrides(overrides, param) {
|
|
491
567
|
const res = {};
|
|
@@ -499,7 +575,7 @@ async function versionOverrides(overrides, param) {
|
|
|
499
575
|
if (!selectedPackage || !selectedVersion) {
|
|
500
576
|
throw new Error(`Incorrect '${param}' section. Use --${param}="package@version"`);
|
|
501
577
|
}
|
|
502
|
-
return normalizeVersionWithTagCheck(selectedPackage, selectedVersion).then((version) => {
|
|
578
|
+
return (0, version_utils_1.normalizeVersionWithTagCheck)(selectedPackage, selectedVersion).then((version) => {
|
|
503
579
|
res[normalizeSlashes(selectedPackage)] = version;
|
|
504
580
|
});
|
|
505
581
|
});
|
|
@@ -513,78 +589,219 @@ async function parseTargetPackageAndVersion(args) {
|
|
|
513
589
|
if (args.indexOf('@') > -1) {
|
|
514
590
|
const i = args.lastIndexOf('@');
|
|
515
591
|
if (i === 0) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const targetPackage = !['latest', 'next', 'canary'].includes(args) &&
|
|
541
|
-
(0, semver_1.lt)(targetVersion, '14.0.0-beta.0')
|
|
542
|
-
? '@nrwl/workspace'
|
|
543
|
-
: 'nx';
|
|
544
|
-
return {
|
|
545
|
-
targetPackage,
|
|
546
|
-
targetVersion,
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
550
|
-
return {
|
|
551
|
-
targetPackage: args,
|
|
552
|
-
targetVersion: 'latest',
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
}
|
|
592
|
+
return { targetPackage: args.trim(), targetVersion: 'latest' };
|
|
593
|
+
}
|
|
594
|
+
const targetPackage = args.substring(0, i);
|
|
595
|
+
const maybeVersion = args.substring(i + 1);
|
|
596
|
+
if (!targetPackage || !maybeVersion) {
|
|
597
|
+
throw new Error(`Provide the correct package name and version. E.g., my-package@9.0.0.`);
|
|
598
|
+
}
|
|
599
|
+
const targetVersion = await (0, version_utils_1.normalizeVersionWithTagCheck)(targetPackage, maybeVersion);
|
|
600
|
+
return { targetPackage, targetVersion };
|
|
601
|
+
}
|
|
602
|
+
if (version_utils_1.DIST_TAGS.includes(args) ||
|
|
603
|
+
(0, semver_1.valid)(args) ||
|
|
604
|
+
args.match(/^\d+(?:\.\d+)?(?:\.\d+)?$/)) {
|
|
605
|
+
// Passing `nx` here may seem wrong, but nx and @nrwl/workspace are synced in version.
|
|
606
|
+
// We could duplicate the ternary below, but its not necessary since they are equivalent
|
|
607
|
+
// on the registry
|
|
608
|
+
const targetVersion = await (0, version_utils_1.normalizeVersionWithTagCheck)('nx', args);
|
|
609
|
+
const isDistTag = version_utils_1.DIST_TAGS.includes(args);
|
|
610
|
+
const targetPackage = isDistTag
|
|
611
|
+
? 'nx'
|
|
612
|
+
: resolveCanonicalNxPackage(targetVersion);
|
|
613
|
+
return { targetPackage, targetVersion };
|
|
614
|
+
}
|
|
615
|
+
return { targetPackage: args, targetVersion: 'latest' };
|
|
556
616
|
}
|
|
557
617
|
async function parseMigrationsOptions(options) {
|
|
558
618
|
if (options.runMigrations === '') {
|
|
559
619
|
options.runMigrations = 'migrations.json';
|
|
560
620
|
}
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
-
options.from
|
|
564
|
-
? versionOverrides(options.from, 'from')
|
|
565
|
-
: Promise.resolve({}),
|
|
566
|
-
options.to
|
|
567
|
-
? await versionOverrides(options.to, 'to')
|
|
568
|
-
: Promise.resolve({}),
|
|
569
|
-
]);
|
|
570
|
-
const { targetPackage, targetVersion } = await parseTargetPackageAndVersion(options['packageAndVersion']);
|
|
571
|
-
return {
|
|
572
|
-
type: 'generateMigrations',
|
|
573
|
-
targetPackage: normalizeSlashes(targetPackage),
|
|
574
|
-
targetVersion,
|
|
575
|
-
from,
|
|
576
|
-
to,
|
|
577
|
-
interactive: options.interactive,
|
|
578
|
-
excludeAppliedMigrations: options.excludeAppliedMigrations,
|
|
579
|
-
};
|
|
621
|
+
if (options.mode && options.runMigrations) {
|
|
622
|
+
throw new Error(`Error: '--mode' cannot be combined with '--run-migrations'.`);
|
|
580
623
|
}
|
|
581
|
-
|
|
624
|
+
if (options.multiMajorMode && options.runMigrations) {
|
|
625
|
+
throw new Error(`Error: '--multi-major-mode' cannot be combined with '--run-migrations'.`);
|
|
626
|
+
}
|
|
627
|
+
if (options.runMigrations) {
|
|
582
628
|
return {
|
|
583
629
|
type: 'runMigrations',
|
|
584
630
|
runMigrations: options.runMigrations,
|
|
585
631
|
ifExists: options.ifExists,
|
|
632
|
+
agentic: options.agentic,
|
|
633
|
+
validate: options.validate,
|
|
586
634
|
};
|
|
587
635
|
}
|
|
636
|
+
assertThirdPartyModeFlagCompatibility(options);
|
|
637
|
+
const [from, to] = await Promise.all([
|
|
638
|
+
options.from
|
|
639
|
+
? versionOverrides(options.from, 'from')
|
|
640
|
+
: Promise.resolve({}),
|
|
641
|
+
options.to
|
|
642
|
+
? await versionOverrides(options.to, 'to')
|
|
643
|
+
: Promise.resolve({}),
|
|
644
|
+
]);
|
|
645
|
+
const positional = options['packageAndVersion'];
|
|
646
|
+
const resolved = await resolveTargetAndMode({ positional, from, options });
|
|
647
|
+
const { mode, installedNxVersion } = resolved;
|
|
648
|
+
let { targetPackage, targetVersion } = resolved;
|
|
649
|
+
// Crossing more than one major can silently skip migrations: each
|
|
650
|
+
// major's metadata may have pruned entries from much-older versions.
|
|
651
|
+
const multiMajorResult = await (0, multi_major_1.maybePromptOrWarnMultiMajorMigration)({
|
|
652
|
+
mode,
|
|
653
|
+
options,
|
|
654
|
+
targetPackage,
|
|
655
|
+
targetVersion,
|
|
656
|
+
});
|
|
657
|
+
targetVersion = multiMajorResult.chosen;
|
|
658
|
+
if (mode === 'third-party') {
|
|
659
|
+
assertThirdPartyTargetBounds({
|
|
660
|
+
targetPackage,
|
|
661
|
+
targetVersion,
|
|
662
|
+
to,
|
|
663
|
+
installedNxVersion,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
type: 'generateMigrations',
|
|
668
|
+
targetPackage,
|
|
669
|
+
targetVersion,
|
|
670
|
+
from,
|
|
671
|
+
to,
|
|
672
|
+
interactive: options.interactive,
|
|
673
|
+
excludeAppliedMigrations: options.excludeAppliedMigrations,
|
|
674
|
+
mode,
|
|
675
|
+
originalTargetVersion: multiMajorResult.originalTarget,
|
|
676
|
+
multiMajorMode: multiMajorResult.gradual ? 'gradual' : undefined,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function assertThirdPartyModeFlagCompatibility(options) {
|
|
680
|
+
if (options.mode !== 'third-party')
|
|
681
|
+
return;
|
|
682
|
+
if (options.from) {
|
|
683
|
+
throw new Error(`Error: '--mode=third-party' cannot be combined with '--from'.`);
|
|
684
|
+
}
|
|
685
|
+
if (options.excludeAppliedMigrations === true) {
|
|
686
|
+
throw new Error(`Error: '--mode=third-party' cannot be combined with '--exclude-applied-migrations'.`);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Defaults target package/version mode-aware (third-party → installed
|
|
690
|
+
// canonical, otherwise nx@latest) and enforces the era gate when --mode
|
|
691
|
+
// is explicit.
|
|
692
|
+
async function resolveTargetAndMode(args) {
|
|
693
|
+
const { positional, from, options } = args;
|
|
694
|
+
let targetPackage;
|
|
695
|
+
let targetVersion;
|
|
696
|
+
if (positional) {
|
|
697
|
+
const parsed = await parseTargetPackageAndVersion(positional);
|
|
698
|
+
targetPackage = normalizeSlashes(parsed.targetPackage);
|
|
699
|
+
targetVersion = parsed.targetVersion;
|
|
700
|
+
}
|
|
701
|
+
// Resolve mode before defaulting target so the default can depend on the
|
|
702
|
+
// resolved mode (third-party defaults to nx@<installed>; otherwise nx@latest).
|
|
703
|
+
// For bare invocation, `targetPackage='nx'` and `targetVersion='latest'` are
|
|
704
|
+
// safe sentinels: `isNxEquivalentTarget` treats the literal `'latest'` as
|
|
705
|
+
// modern era (semver `lt('latest', '14.0.0-beta.0')` is false).
|
|
706
|
+
const mode = await resolveMode(options.mode, targetPackage ?? 'nx', targetVersion ?? 'latest', {
|
|
707
|
+
hasFrom: Object.keys(from).length > 0,
|
|
708
|
+
hasExcludeAppliedMigrations: options.excludeAppliedMigrations === true,
|
|
709
|
+
});
|
|
710
|
+
let installedNxVersion;
|
|
711
|
+
// For third-party, anchor `targetPackage`/`targetVersion` to the installed
|
|
712
|
+
// canonical when the positional was either omitted or a bare package name
|
|
713
|
+
// (no semver). This keeps the era gate accepting legacy workspaces, the
|
|
714
|
+
// upper-bound gate meaningful, and downstream semver comparisons safe from
|
|
715
|
+
// the literal `'latest'` that `parseTargetPackageAndVersion` emits for bare
|
|
716
|
+
// package names.
|
|
717
|
+
if (mode === 'third-party' && (!positional || !(0, semver_1.valid)(targetVersion))) {
|
|
718
|
+
const installed = resolveInstalledCanonical();
|
|
719
|
+
if (!installed) {
|
|
720
|
+
throw new Error(`Error: '--mode=third-party' requires 'nx' (or '@nrwl/workspace' on Nx <14) to be installed in your workspace. Install dependencies first, then re-run.`);
|
|
721
|
+
}
|
|
722
|
+
installedNxVersion = installed.version;
|
|
723
|
+
targetPackage = installed.canonical;
|
|
724
|
+
targetVersion = installed.version;
|
|
725
|
+
}
|
|
726
|
+
else if (!positional) {
|
|
727
|
+
// Bare invocation: default to `nx@latest` as a literal sentinel rather
|
|
728
|
+
// than resolving via the registry here. Multi-major resolves the dist-tag
|
|
729
|
+
// when needed (and bails gracefully on registry failure), and the cascade
|
|
730
|
+
// resolves it for the walk (honouring `NX_MIGRATE_SKIP_REGISTRY_FETCH`).
|
|
731
|
+
// This matches the resilience of `nx migrate nx`.
|
|
732
|
+
targetPackage = 'nx';
|
|
733
|
+
targetVersion = 'latest';
|
|
734
|
+
}
|
|
735
|
+
if (options.mode && !(0, version_utils_1.isNxEquivalentTarget)(targetPackage, targetVersion)) {
|
|
736
|
+
const isLegacy = (0, version_utils_1.isLegacyEra)(targetVersion);
|
|
737
|
+
const validTargets = isLegacy
|
|
738
|
+
? `'@nrwl/workspace'`
|
|
739
|
+
: `'nx' or '@nx/workspace'`;
|
|
740
|
+
const eraNote = isLegacy ? ' for Nx <14.0.0' : '';
|
|
741
|
+
throw new Error(`Error: '--mode' requires the target to be ${validTargets}${eraNote}. Got '${targetPackage}@${targetVersion}'.`);
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
targetPackage: targetPackage,
|
|
745
|
+
targetVersion: targetVersion,
|
|
746
|
+
mode,
|
|
747
|
+
installedNxVersion,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
// `--mode=third-party` upper-bound gate. The third-party walk follows nx's
|
|
751
|
+
// `packageGroup`; a target or `--to` above the installed version would
|
|
752
|
+
// expand the walk past it and surface third-party bumps that only exist in
|
|
753
|
+
// the newer plugin's history. The first-party set is sourced from the
|
|
754
|
+
// installed nx package's declared `packageGroup` (authoritative for the
|
|
755
|
+
// user's current Nx universe). Legacy era falls back to the hardcoded
|
|
756
|
+
// `LEGACY_NRWL_PACKAGE_GROUP`.
|
|
757
|
+
function assertThirdPartyTargetBounds(args) {
|
|
758
|
+
const { targetPackage, targetVersion, to, installedNxVersion } = args;
|
|
759
|
+
const canonical = resolveCanonicalNxPackage(targetVersion);
|
|
760
|
+
const isLegacy = canonical === '@nrwl/workspace';
|
|
761
|
+
// Reuse the resolved installed version from `resolveTargetAndMode` when
|
|
762
|
+
// present (it's already era-aware via `resolveInstalledCanonical`).
|
|
763
|
+
// Otherwise fall back to the era-specific reader.
|
|
764
|
+
const installed = installedNxVersion ??
|
|
765
|
+
(isLegacy
|
|
766
|
+
? (0, installed_nx_version_1.getInstalledLegacyNrwlWorkspaceVersion)()
|
|
767
|
+
: (0, installed_nx_version_1.getInstalledNxVersion)());
|
|
768
|
+
if (!installed) {
|
|
769
|
+
throw new Error(`Error: '--mode=third-party' requires '${canonical}' to be installed in your workspace. Install dependencies first, then re-run.`);
|
|
770
|
+
}
|
|
771
|
+
if ((0, semver_1.gt)(targetVersion, installed)) {
|
|
772
|
+
throw new Error(`Error: '--mode=third-party' cannot migrate to a version higher than what is currently installed (got '${targetPackage}@${targetVersion}', installed '${canonical}@${installed}'). Either drop '--mode=third-party' or lower the target.`);
|
|
773
|
+
}
|
|
774
|
+
const firstPartySet = isLegacy
|
|
775
|
+
? new Set([
|
|
776
|
+
'@nrwl/workspace',
|
|
777
|
+
...LEGACY_NRWL_PACKAGE_GROUP.map((p) => p.package),
|
|
778
|
+
])
|
|
779
|
+
: (0, installed_nx_version_1.getInstalledNxPackageGroup)();
|
|
780
|
+
for (const [pkg, version] of Object.entries(to)) {
|
|
781
|
+
if (firstPartySet.has(pkg) && (0, semver_1.gt)(version, installed)) {
|
|
782
|
+
throw new Error(`Error: '--mode=third-party' cannot migrate to a version higher than what is currently installed (got '--to ${pkg}@${version}', installed '${canonical}@${installed}'). Either drop '--mode=third-party' or lower the '--to' value.`);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Pick the canonical Nx package + version for `--mode=third-party` when the
|
|
788
|
+
* user didn't supply an explicit version. Returns `'nx'` for modern era,
|
|
789
|
+
* falls back to `'@nrwl/workspace'` (legacy era) when only that is installed
|
|
790
|
+
* or when the installed `nx` itself is `<14`.
|
|
791
|
+
*/
|
|
792
|
+
function resolveInstalledCanonical() {
|
|
793
|
+
const installedNx = (0, installed_nx_version_1.getInstalledNxVersion)();
|
|
794
|
+
if (installedNx) {
|
|
795
|
+
return {
|
|
796
|
+
canonical: resolveCanonicalNxPackage(installedNx),
|
|
797
|
+
version: installedNx,
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
const installedLegacy = (0, installed_nx_version_1.getInstalledLegacyNrwlWorkspaceVersion)();
|
|
801
|
+
if (installedLegacy) {
|
|
802
|
+
return { canonical: '@nrwl/workspace', version: installedLegacy };
|
|
803
|
+
}
|
|
804
|
+
return null;
|
|
588
805
|
}
|
|
589
806
|
function createInstalledPackageVersionsResolver(root) {
|
|
590
807
|
const cache = {};
|
|
@@ -731,11 +948,22 @@ async function downloadPackageMigrationsFromRegistry(packageName, packageVersion
|
|
|
731
948
|
let result;
|
|
732
949
|
try {
|
|
733
950
|
const { tarballPath } = await (0, package_manager_1.packageRegistryPack)(dir, packageName, packageVersion);
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
951
|
+
const fullTarballPath = (0, path_1.join)(dir, tarballPath);
|
|
952
|
+
let migrations;
|
|
953
|
+
try {
|
|
954
|
+
migrations = await (0, tar_1.extractFileFromTarball)(fullTarballPath, (0, path_2.joinPathFragments)('package', migrationsFilePath), (0, path_1.join)(dir, migrationsFilePath)).then((path) => (0, fileutils_1.readJsonFile)(path));
|
|
955
|
+
}
|
|
956
|
+
catch {
|
|
957
|
+
throw new Error(`Failed to find migrations file "${migrationsFilePath}" in package "${packageName}@${packageVersion}".`);
|
|
958
|
+
}
|
|
959
|
+
(0, prompt_files_1.validateMigrationEntries)(packageName, packageVersion, migrations);
|
|
960
|
+
const resolvedPromptFiles = await (0, prompt_files_1.extractPromptFilesFromTarball)(packageName, packageVersion, migrations, migrationsFilePath, fullTarballPath, dir);
|
|
961
|
+
result = {
|
|
962
|
+
...migrations,
|
|
963
|
+
packageGroup,
|
|
964
|
+
version: packageVersion,
|
|
965
|
+
...(resolvedPromptFiles ? { resolvedPromptFiles } : {}),
|
|
966
|
+
};
|
|
739
967
|
}
|
|
740
968
|
finally {
|
|
741
969
|
await cleanup();
|
|
@@ -789,10 +1017,18 @@ async function getPackageMigrationsUsingInstallImpl(packageName, packageVersion)
|
|
|
789
1017
|
});
|
|
790
1018
|
const { migrations: migrationsFilePath, packageGroup, packageJson, } = readPackageMigrationConfig(packageName, dir);
|
|
791
1019
|
let migrations = undefined;
|
|
1020
|
+
let resolvedPromptFiles;
|
|
792
1021
|
if (migrationsFilePath) {
|
|
793
1022
|
migrations = (0, fileutils_1.readJsonFile)(migrationsFilePath);
|
|
794
|
-
|
|
795
|
-
|
|
1023
|
+
(0, prompt_files_1.validateMigrationEntries)(packageName, packageVersion, migrations);
|
|
1024
|
+
resolvedPromptFiles = await (0, prompt_files_1.readPromptFilesFromInstall)(packageName, packageVersion, migrations, migrationsFilePath);
|
|
1025
|
+
}
|
|
1026
|
+
result = {
|
|
1027
|
+
...migrations,
|
|
1028
|
+
packageGroup,
|
|
1029
|
+
version: packageJson.version,
|
|
1030
|
+
...(resolvedPromptFiles ? { resolvedPromptFiles } : {}),
|
|
1031
|
+
};
|
|
796
1032
|
}
|
|
797
1033
|
catch (e) {
|
|
798
1034
|
const pmc = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(dir), dir);
|
|
@@ -836,12 +1072,13 @@ async function createMigrationsFile(root, migrations) {
|
|
|
836
1072
|
async function updatePackageJson(root, updatedPackages) {
|
|
837
1073
|
const packageJsonPath = (0, path_1.join)(root, 'package.json');
|
|
838
1074
|
if (!(0, fs_1.existsSync)(packageJsonPath)) {
|
|
839
|
-
return;
|
|
1075
|
+
return false;
|
|
840
1076
|
}
|
|
841
1077
|
const parseOptions = {};
|
|
842
1078
|
const json = (0, fileutils_1.readJsonFile)(packageJsonPath, parseOptions);
|
|
843
1079
|
const manager = (0, catalog_1.getCatalogManager)(root);
|
|
844
1080
|
const catalogUpdates = [];
|
|
1081
|
+
let modified = false;
|
|
845
1082
|
Object.keys(updatedPackages).forEach((p) => {
|
|
846
1083
|
const existingVersion = json.dependencies?.[p] ?? json.devDependencies?.[p];
|
|
847
1084
|
if (existingVersion && manager?.isCatalogReference(existingVersion)) {
|
|
@@ -856,28 +1093,40 @@ async function updatePackageJson(root, updatedPackages) {
|
|
|
856
1093
|
}
|
|
857
1094
|
// Update non-catalog packages in package.json
|
|
858
1095
|
if (json.devDependencies?.[p]) {
|
|
859
|
-
json.devDependencies[p]
|
|
1096
|
+
if (json.devDependencies[p] !== updatedPackages[p].version) {
|
|
1097
|
+
json.devDependencies[p] = updatedPackages[p].version;
|
|
1098
|
+
modified = true;
|
|
1099
|
+
}
|
|
860
1100
|
return;
|
|
861
1101
|
}
|
|
862
1102
|
if (json.dependencies?.[p]) {
|
|
863
|
-
json.dependencies[p]
|
|
1103
|
+
if (json.dependencies[p] !== updatedPackages[p].version) {
|
|
1104
|
+
json.dependencies[p] = updatedPackages[p].version;
|
|
1105
|
+
modified = true;
|
|
1106
|
+
}
|
|
864
1107
|
return;
|
|
865
1108
|
}
|
|
866
1109
|
const dependencyType = updatedPackages[p].addToPackageJson;
|
|
867
1110
|
if (typeof dependencyType === 'string') {
|
|
868
1111
|
json[dependencyType] ??= {};
|
|
869
|
-
json[dependencyType][p]
|
|
1112
|
+
if (json[dependencyType][p] !== updatedPackages[p].version) {
|
|
1113
|
+
json[dependencyType][p] = updatedPackages[p].version;
|
|
1114
|
+
modified = true;
|
|
1115
|
+
}
|
|
870
1116
|
}
|
|
871
1117
|
});
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1118
|
+
if (modified) {
|
|
1119
|
+
await (0, write_formatted_json_file_1.writeFormattedJsonFile)(packageJsonPath, json, {
|
|
1120
|
+
appendNewLine: parseOptions.endsWithNewline,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
875
1123
|
// Update catalog definitions
|
|
876
1124
|
if (catalogUpdates.length) {
|
|
877
1125
|
// manager is guaranteed to be defined when there are catalog updates
|
|
878
1126
|
manager.updateCatalogVersions(root, catalogUpdates);
|
|
879
1127
|
await formatCatalogDefinitionFiles(manager, root);
|
|
880
1128
|
}
|
|
1129
|
+
return modified || catalogUpdates.length > 0;
|
|
881
1130
|
}
|
|
882
1131
|
async function formatCatalogDefinitionFiles(manager, root) {
|
|
883
1132
|
const catalogDefinitionFilePaths = manager.getCatalogDefinitionFilePaths();
|
|
@@ -899,29 +1148,38 @@ async function updateInstallationDetails(root, updatedPackages) {
|
|
|
899
1148
|
const parseOptions = {};
|
|
900
1149
|
const nxJson = (0, fileutils_1.readJsonFile)(nxJsonPath, parseOptions);
|
|
901
1150
|
if (!nxJson.installation) {
|
|
902
|
-
return;
|
|
1151
|
+
return false;
|
|
903
1152
|
}
|
|
1153
|
+
let modified = false;
|
|
904
1154
|
const nxVersion = updatedPackages.nx?.version;
|
|
905
|
-
if (nxVersion) {
|
|
1155
|
+
if (nxVersion && nxJson.installation.version !== nxVersion) {
|
|
906
1156
|
nxJson.installation.version = nxVersion;
|
|
1157
|
+
modified = true;
|
|
907
1158
|
}
|
|
908
1159
|
if (nxJson.installation.plugins) {
|
|
909
1160
|
for (const dep in nxJson.installation.plugins) {
|
|
910
1161
|
const update = updatedPackages[dep];
|
|
911
1162
|
if (update) {
|
|
912
|
-
|
|
1163
|
+
const newVersion = (0, semver_1.valid)(update.version)
|
|
913
1164
|
? update.version
|
|
914
1165
|
: await (0, package_manager_1.resolvePackageVersionUsingRegistry)(dep, update.version);
|
|
1166
|
+
if (nxJson.installation.plugins[dep] !== newVersion) {
|
|
1167
|
+
nxJson.installation.plugins[dep] = newVersion;
|
|
1168
|
+
modified = true;
|
|
1169
|
+
}
|
|
915
1170
|
}
|
|
916
1171
|
}
|
|
917
1172
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1173
|
+
if (modified) {
|
|
1174
|
+
await (0, write_formatted_json_file_1.writeFormattedJsonFile)(nxJsonPath, nxJson, {
|
|
1175
|
+
appendNewLine: parseOptions.endsWithNewline,
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
return modified;
|
|
921
1179
|
}
|
|
922
1180
|
async function isMigratingToNewMajor(from, to) {
|
|
923
|
-
from = normalizeVersion(from);
|
|
924
|
-
to = ['latest', 'next', 'canary'].includes(to) ? to : normalizeVersion(to);
|
|
1181
|
+
from = (0, version_utils_1.normalizeVersion)(from);
|
|
1182
|
+
to = ['latest', 'next', 'canary'].includes(to) ? to : (0, version_utils_1.normalizeVersion)(to);
|
|
925
1183
|
if (!(0, semver_1.valid)(from)) {
|
|
926
1184
|
from = await (0, package_manager_1.resolvePackageVersionUsingRegistry)('nx', from);
|
|
927
1185
|
}
|
|
@@ -945,34 +1203,107 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
|
|
|
945
1203
|
const originalNxJson = (0, configuration_1.readNxJson)();
|
|
946
1204
|
const from = originalNxJson.installation?.version ??
|
|
947
1205
|
readNxVersion(originalPackageJson, root);
|
|
1206
|
+
const mode = opts.mode;
|
|
1207
|
+
let walkedTargetPackage = opts.targetPackage;
|
|
1208
|
+
let fromOverrides = opts.from;
|
|
1209
|
+
let excludeApplied = opts.excludeAppliedMigrations;
|
|
1210
|
+
if (mode === 'third-party') {
|
|
1211
|
+
// For third-party, walk the canonical Nx target so cross-plugin
|
|
1212
|
+
// third-party dependencies (e.g. typescript managed by @nx/js but
|
|
1213
|
+
// used by @nx/angular) stay consistent.
|
|
1214
|
+
const canonical = resolveCanonicalNxPackage(opts.targetVersion);
|
|
1215
|
+
walkedTargetPackage = canonical;
|
|
1216
|
+
fromOverrides = { [canonical]: '0.0.0' };
|
|
1217
|
+
excludeApplied = true;
|
|
1218
|
+
}
|
|
948
1219
|
logger_1.logger.info(`Fetching meta data about packages.`);
|
|
949
1220
|
logger_1.logger.info(`It may take a few minutes.`);
|
|
1221
|
+
const fetch = createFetcher();
|
|
1222
|
+
let firstPartyPackages;
|
|
1223
|
+
if (mode === 'first-party' || mode === 'third-party') {
|
|
1224
|
+
// `@nx/workspace` is version-synced with `nx` and declares an
|
|
1225
|
+
// intentionally narrow `packageGroup` ({ nx, nx-cloud }) via its
|
|
1226
|
+
// `ng-update` field, whereas `nx` declares the full @nx/* plugin
|
|
1227
|
+
// fan-out. Their transitive first-party closures are equivalent.
|
|
1228
|
+
const sourcePackage = walkedTargetPackage === '@nx/workspace' ? 'nx' : walkedTargetPackage;
|
|
1229
|
+
const rootMetadata = await fetch(sourcePackage, opts.targetVersion);
|
|
1230
|
+
// Legacy `@nrwl/workspace<14` doesn't ship a complete `packageGroup`
|
|
1231
|
+
// in its metadata; the Migrator's cascade injects
|
|
1232
|
+
// `LEGACY_NRWL_PACKAGE_GROUP` for that case, and the post-build
|
|
1233
|
+
// third-party filter must mirror that set or first-party `@nrwl/*`
|
|
1234
|
+
// plugins slip past it.
|
|
1235
|
+
const packageGroup = sourcePackage === '@nrwl/workspace' && (0, version_utils_1.isLegacyEra)(opts.targetVersion)
|
|
1236
|
+
? LEGACY_NRWL_PACKAGE_GROUP
|
|
1237
|
+
: rootMetadata.packageGroup;
|
|
1238
|
+
firstPartyPackages = resolveFirstPartyPackages(sourcePackage, packageGroup);
|
|
1239
|
+
}
|
|
1240
|
+
const installedPackageVersions = createInstalledPackageVersionsResolver(root);
|
|
950
1241
|
const migrator = new Migrator({
|
|
951
1242
|
packageJson: originalPackageJson,
|
|
952
1243
|
nxInstallation: originalNxJson.installation,
|
|
953
|
-
getInstalledPackageVersion:
|
|
954
|
-
fetch
|
|
955
|
-
from:
|
|
1244
|
+
getInstalledPackageVersion: installedPackageVersions,
|
|
1245
|
+
fetch,
|
|
1246
|
+
from: fromOverrides,
|
|
956
1247
|
to: opts.to,
|
|
957
1248
|
interactive: opts.interactive && !(0, is_ci_1.isCI)(),
|
|
958
|
-
excludeAppliedMigrations:
|
|
1249
|
+
excludeAppliedMigrations: excludeApplied,
|
|
1250
|
+
mode,
|
|
1251
|
+
firstPartyPackages,
|
|
959
1252
|
});
|
|
960
|
-
const { migrations, packageUpdates, minVersionWithSkippedUpdates } = await migrator.migrate(
|
|
961
|
-
|
|
962
|
-
|
|
1253
|
+
const { migrations, packageUpdates, promptContents, minVersionWithSkippedUpdates, } = await migrator.migrate(walkedTargetPackage, opts.targetVersion);
|
|
1254
|
+
// The cascade collects packageJsonUpdates entries against the cascade
|
|
1255
|
+
// root's installed version, but inner per-package pins are only gated
|
|
1256
|
+
// against the in-flight cascade tally — not against each inner package's
|
|
1257
|
+
// installed version. A from-zero walk (e.g. `--mode=third-party`) can
|
|
1258
|
+
// surface a stale historical pin that would write a lower version than
|
|
1259
|
+
// the user already has. Drop those before writing; nx migrate is
|
|
1260
|
+
// forward-only, never a downgrade.
|
|
1261
|
+
const writableUpdates = (0, update_filters_1.filterDowngradedUpdates)(packageUpdates, originalPackageJson, installedPackageVersions);
|
|
1262
|
+
const wrotePackageJson = await updatePackageJson(root, writableUpdates);
|
|
1263
|
+
const wroteNxJsonInstallation = await updateInstallationDetails(root, writableUpdates);
|
|
1264
|
+
const promptMigrationFiles = (0, prompt_files_1.writePromptMigrationFiles)(root, migrations, promptContents ?? {}, packageUpdates[walkedTargetPackage].version);
|
|
963
1265
|
if (migrations.length > 0) {
|
|
964
1266
|
await createMigrationsFile(root, [
|
|
965
|
-
...addSplitConfigurationMigrationIfAvailable(from,
|
|
1267
|
+
...addSplitConfigurationMigrationIfAvailable(from, writableUpdates),
|
|
966
1268
|
...migrations,
|
|
967
1269
|
]);
|
|
968
1270
|
}
|
|
1271
|
+
const modeLine = mode === 'first-party'
|
|
1272
|
+
? `- Processed Nx first-party packages only (skipped third-party dependency bumps).`
|
|
1273
|
+
: mode === 'third-party'
|
|
1274
|
+
? `- Processed third-party dependencies only (skipped Nx first-party package updates).`
|
|
1275
|
+
: null;
|
|
1276
|
+
const noChanges = !wrotePackageJson && !wroteNxJsonInstallation && migrations.length === 0;
|
|
1277
|
+
if (noChanges) {
|
|
1278
|
+
output_1.output.success({
|
|
1279
|
+
title: `No updates were applied.`,
|
|
1280
|
+
bodyLines: [
|
|
1281
|
+
...(modeLine ? [modeLine] : []),
|
|
1282
|
+
mode === 'third-party'
|
|
1283
|
+
? `- No third-party dependency bumps were found for the installed Nx version. Either your dependencies are already up to date, or this workspace doesn't manage them in a place 'nx migrate' writes to (e.g. non-JS workspaces only track Nx and its plugins).`
|
|
1284
|
+
: `- No package updates or migrations were found.`,
|
|
1285
|
+
],
|
|
1286
|
+
});
|
|
1287
|
+
// Nothing was applied; skip the "Next steps" guidance below — it would
|
|
1288
|
+
// tell the user to inspect package.json changes that don't exist.
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
969
1291
|
output_1.output.success({
|
|
970
1292
|
title: `The migrate command has run successfully.`,
|
|
971
1293
|
bodyLines: [
|
|
972
|
-
|
|
1294
|
+
...(modeLine ? [modeLine] : []),
|
|
1295
|
+
...(wrotePackageJson ? [`- package.json has been updated.`] : []),
|
|
1296
|
+
...(wroteNxJsonInstallation
|
|
1297
|
+
? [`- nx.json (installation) has been updated.`]
|
|
1298
|
+
: []),
|
|
973
1299
|
migrations.length > 0
|
|
974
1300
|
? `- migrations.json has been generated.`
|
|
975
1301
|
: `- There are no migrations to run, so migrations.json has not been created.`,
|
|
1302
|
+
...(promptMigrationFiles.length > 0
|
|
1303
|
+
? [
|
|
1304
|
+
`- ${promptMigrationFiles.length} AI migration prompt(s) have been written to ${prompt_files_1.AI_MIGRATIONS_DIR}/.`,
|
|
1305
|
+
]
|
|
1306
|
+
: []),
|
|
976
1307
|
],
|
|
977
1308
|
});
|
|
978
1309
|
try {
|
|
@@ -1006,9 +1337,21 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
|
|
|
1006
1337
|
]
|
|
1007
1338
|
: [
|
|
1008
1339
|
`- Make sure package.json changes make sense and then run '${pmc.install}',`,
|
|
1340
|
+
...(promptMigrationFiles.length > 0
|
|
1341
|
+
? [
|
|
1342
|
+
`- Review and tweak the AI migration prompts in ${prompt_files_1.AI_MIGRATIONS_DIR}/ as needed.`,
|
|
1343
|
+
]
|
|
1344
|
+
: []),
|
|
1009
1345
|
...(migrations.length > 0
|
|
1010
1346
|
? [`- Run '${pmc.exec} nx migrate --run-migrations'`]
|
|
1011
1347
|
: []),
|
|
1348
|
+
...(opts.originalTargetVersion
|
|
1349
|
+
? [
|
|
1350
|
+
`- After applying these migrations, run '${pmc.exec} nx migrate ${opts.targetPackage}@${opts.originalTargetVersion} --mode=${opts.mode}${opts.multiMajorMode === 'gradual'
|
|
1351
|
+
? ` ${multi_major_1.MULTI_MAJOR_MODE_FLAG}=gradual`
|
|
1352
|
+
: ''}' to continue toward your original target.`,
|
|
1353
|
+
]
|
|
1354
|
+
: []),
|
|
1012
1355
|
...(opts.interactive && minVersionWithSkippedUpdates
|
|
1013
1356
|
? [
|
|
1014
1357
|
`- You opted out of some migrations for now. Write the following command down somewhere to apply these migrations later:`,
|
|
@@ -1040,7 +1383,7 @@ function addSplitConfigurationMigrationIfAvailable(from, packageJson) {
|
|
|
1040
1383
|
if (!packageJson['@nrwl/workspace'])
|
|
1041
1384
|
return [];
|
|
1042
1385
|
if ((0, semver_1.gte)(packageJson['@nrwl/workspace'].version, '15.7.0-beta.0') &&
|
|
1043
|
-
(0, semver_1.lt)(normalizeVersion(from), '15.7.0-beta.0')) {
|
|
1386
|
+
(0, semver_1.lt)((0, version_utils_1.normalizeVersion)(from), '15.7.0-beta.0')) {
|
|
1044
1387
|
return [
|
|
1045
1388
|
{
|
|
1046
1389
|
version: '15.7.0-beta.0',
|
|
@@ -1177,10 +1520,90 @@ function logNpmPeerDepsError(phase) {
|
|
|
1177
1520
|
});
|
|
1178
1521
|
}
|
|
1179
1522
|
}
|
|
1180
|
-
|
|
1523
|
+
function resolveAgenticRunId(migrations) {
|
|
1524
|
+
return (0, semver_1.rsort)(migrations.map((m) => (0, version_utils_1.normalizeVersion)(m.version)))[0];
|
|
1525
|
+
}
|
|
1526
|
+
function formatSkippedPromptsNextStep(skipped) {
|
|
1527
|
+
return [
|
|
1528
|
+
'Some prompt migrations were skipped. Review and apply each of the following prompt files to the workspace, in the listed order:',
|
|
1529
|
+
...skipped.map((m) => ` - ${m.prompt}`),
|
|
1530
|
+
].join('\n');
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Resolves the effective `--create-commits` state once the agentic flow has
|
|
1534
|
+
* been resolved. The agent's outer prompt only embeds the impl-phase file list
|
|
1535
|
+
* when per-migration commits isolate each migration's diff, so the diff-context
|
|
1536
|
+
* flag returned here gates that section.
|
|
1537
|
+
*/
|
|
1538
|
+
function resolveCreateCommits(args) {
|
|
1539
|
+
const { createCommits, agenticKind, isGitRepo, commitPrefixIsCustom } = args;
|
|
1540
|
+
// Explicit `--create-commits` without git is a hard error — the user asked
|
|
1541
|
+
// for something we cannot deliver.
|
|
1542
|
+
if (createCommits === true && !isGitRepo) {
|
|
1543
|
+
return {
|
|
1544
|
+
effective: false,
|
|
1545
|
+
agenticHasDiffContext: false,
|
|
1546
|
+
error: '`--create-commits` requires a git repository. Run `git init` first, or omit the flag.',
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
if (agenticKind === 'enabled') {
|
|
1550
|
+
if (createCommits === false) {
|
|
1551
|
+
return {
|
|
1552
|
+
effective: false,
|
|
1553
|
+
agenticHasDiffContext: false,
|
|
1554
|
+
warning: "--no-create-commits was passed alongside --agentic. Without per-migration commits, the agent can't isolate the current migration's changes from earlier migrations in this run. Drop --no-create-commits for accurate per-migration review." +
|
|
1555
|
+
(commitPrefixIsCustom
|
|
1556
|
+
? ' Note: the custom --commit-prefix value will have no effect because commits are disabled.'
|
|
1557
|
+
: ''),
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
// Without git we cannot soft-force commits the user didn't explicitly
|
|
1561
|
+
// opt into. Degrade rather than error: continue the agentic run, but
|
|
1562
|
+
// without per-file diff context (which depends on per-migration commits).
|
|
1563
|
+
if (!isGitRepo) {
|
|
1564
|
+
return {
|
|
1565
|
+
effective: false,
|
|
1566
|
+
agenticHasDiffContext: false,
|
|
1567
|
+
warning: '`--agentic` enables per-migration commits by default, but the workspace is not a git repository. Continuing without commits — the agent will not receive per-file diff context. Run `git init` to enable.' +
|
|
1568
|
+
(commitPrefixIsCustom
|
|
1569
|
+
? ' The custom --commit-prefix value will have no effect.'
|
|
1570
|
+
: ''),
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
return { effective: true, agenticHasDiffContext: true };
|
|
1574
|
+
}
|
|
1575
|
+
return {
|
|
1576
|
+
effective: createCommits === true,
|
|
1577
|
+
agenticHasDiffContext: false,
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Resolves whether the framework-owned generic-validation agent step should run
|
|
1582
|
+
* after generator-only migrations.
|
|
1583
|
+
*
|
|
1584
|
+
* Default-on when the agentic flow resolved to `enabled`; silently ignored
|
|
1585
|
+
* otherwise (no warning emitted) — `--validate` requires an active agent
|
|
1586
|
+
* session by definition. An explicit `--no-validate` (`validate === false`)
|
|
1587
|
+
* opts out even when agentic is enabled.
|
|
1588
|
+
*/
|
|
1589
|
+
function resolveShouldRunValidation(args) {
|
|
1590
|
+
return args.validate !== false && args.agenticKind === 'enabled';
|
|
1591
|
+
}
|
|
1592
|
+
async function executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false, agentic, agenticHasDiffContext = false, shouldRunValidation = false) {
|
|
1181
1593
|
const changedDepInstaller = new ChangedDepInstaller(root, shouldSkipInstall);
|
|
1182
1594
|
const migrationsWithNoChanges = [];
|
|
1183
1595
|
const sortedMigrations = migrations.sort((a, b) => {
|
|
1596
|
+
// Under `--agentic`, hoist the v23 migration that ignores
|
|
1597
|
+
// `.nx/migrate-runs` to position 0 so its .gitignore update lands
|
|
1598
|
+
// before any per-migration commit absorbs the run's handoff scratch.
|
|
1599
|
+
// See `agentic/handoff-gitignore.ts` for the full rationale and the
|
|
1600
|
+
// inline-fallback path that covers intra-pre-v23 agentic runs.
|
|
1601
|
+
if (agentic?.kind === 'enabled') {
|
|
1602
|
+
if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(a))
|
|
1603
|
+
return -1;
|
|
1604
|
+
if ((0, handoff_gitignore_1.isHandoffGitignoreMigration)(b))
|
|
1605
|
+
return 1;
|
|
1606
|
+
}
|
|
1184
1607
|
// special case for the split configuration migration to run first
|
|
1185
1608
|
if (a.name === '15-7-0-split-configuration-into-project-json-files') {
|
|
1186
1609
|
return -1;
|
|
@@ -1188,40 +1611,319 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
1188
1611
|
if (b.name === '15-7-0-split-configuration-into-project-json-files') {
|
|
1189
1612
|
return 1;
|
|
1190
1613
|
}
|
|
1191
|
-
return (0, semver_1.lt)(normalizeVersion(a.version), normalizeVersion(b.version))
|
|
1614
|
+
return (0, semver_1.lt)((0, version_utils_1.normalizeVersion)(a.version), (0, version_utils_1.normalizeVersion)(b.version))
|
|
1192
1615
|
? -1
|
|
1193
1616
|
: 1;
|
|
1194
1617
|
});
|
|
1618
|
+
// Lazy-load the agentic chain so non-agentic runs don't pay its startup cost.
|
|
1619
|
+
let agenticRun;
|
|
1620
|
+
if (agentic?.kind === 'enabled' && sortedMigrations.length > 0) {
|
|
1621
|
+
const { initRunDir } = require('./agentic/handoff');
|
|
1622
|
+
const { runAgenticPromptStep } = require('./agentic/run-step');
|
|
1623
|
+
agenticRun = {
|
|
1624
|
+
agentic,
|
|
1625
|
+
runDir: initRunDir(root, resolveAgenticRunId(sortedMigrations)),
|
|
1626
|
+
runStep: runAgenticPromptStep,
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
const printDroppedAgentContext = agentic?.kind === 'inside-agent'
|
|
1630
|
+
? require('./agentic/print-dropped-agent-context').printDroppedAgentContextForOuterAgent
|
|
1631
|
+
: undefined;
|
|
1195
1632
|
logger_1.logger.info(`Running the following migrations:`);
|
|
1196
|
-
sortedMigrations.forEach((m) => logger_1.logger.info(
|
|
1197
|
-
|
|
1198
|
-
|
|
1633
|
+
sortedMigrations.forEach((m) => logger_1.logger.info(m.description
|
|
1634
|
+
? `- ${m.package}: ${m.name} — ${m.description}`
|
|
1635
|
+
: `- ${m.package}: ${m.name}`));
|
|
1636
|
+
logger_1.logger.info('');
|
|
1637
|
+
// Tracked separately from `skippedPrompts` so the end-of-run logic can
|
|
1638
|
+
// render them distinctly per resolution mode.
|
|
1639
|
+
const migrationEmittedNextSteps = [];
|
|
1640
|
+
const skippedPrompts = [];
|
|
1641
|
+
// One record per migration the loop touched. `status: 'completed'` records
|
|
1642
|
+
// are pushed at the end of each successful iteration; `status: 'aborted'`
|
|
1643
|
+
// is pushed by the catch block when a migration throws mid-iteration, so
|
|
1644
|
+
// `outcomes` is the single source of truth for the recap and tally — no
|
|
1645
|
+
// parallel "pending" list. `outcomes.length` always equals `migrationIndex`
|
|
1646
|
+
// after the loop body runs.
|
|
1647
|
+
const outcomes = [];
|
|
1648
|
+
// Prompt-only migrations whose agent never ran. Hybrid migrations with a
|
|
1649
|
+
// skipped prompt are NOT counted here — their deterministic half still ran.
|
|
1650
|
+
let notRunMigrationsCount = 0;
|
|
1651
|
+
const skipReason = agentic?.kind === 'inside-agent'
|
|
1652
|
+
? 'deferred to the AI agent driving this run'
|
|
1653
|
+
: 'agentic flow disabled';
|
|
1654
|
+
const installDepsIfChanged = () => changedDepInstaller.installDepsIfChanged();
|
|
1655
|
+
// Returns the migrations whose own commits failed and whose diffs are
|
|
1656
|
+
// still sitting in the working tree — derived live from `outcomes`. The
|
|
1657
|
+
// next successful commit absorbs them via `git add -A`; its commit body
|
|
1658
|
+
// lists them so a reader of `git log -p` can see which prior migrations'
|
|
1659
|
+
// diffs got pulled in.
|
|
1660
|
+
const pendingForCommitBody = () => outcomes
|
|
1661
|
+
.filter((o) => o.commit.kind === 'failed')
|
|
1662
|
+
.map((o) => ({ package: o.migration.package, name: o.migration.name }));
|
|
1663
|
+
// True while at least one prior migration's commit has failed and its
|
|
1664
|
+
// diff hasn't been absorbed yet. While true, the working tree carries
|
|
1665
|
+
// prior-migration state, so the `hasDiffContext` flag in the hybrid-
|
|
1666
|
+
// agentic and validation-agentic prompt branches is suppressed (the
|
|
1667
|
+
// prompt-only-with-agentic branch doesn't use `hasDiffContext`).
|
|
1668
|
+
const hasPendingCommitDebt = () => outcomes.some((o) => o.commit.kind === 'failed');
|
|
1669
|
+
// Single funnel for per-migration commit attempts. Returns the
|
|
1670
|
+
// `CommitState` to record on the migration's outcome. On `committed`,
|
|
1671
|
+
// back-annotates any prior failed-commit outcomes to `kind: 'absorbed'`
|
|
1672
|
+
// (their diffs were just rolled into this commit via `git add -A`).
|
|
1673
|
+
async function attemptMigrationCommit(m) {
|
|
1674
|
+
const pending = pendingForCommitBody();
|
|
1675
|
+
const result = await (0, migrate_commits_1.commitMigrationIfRequested)(root, m, shouldCreateCommits, commitPrefix, installDepsIfChanged, pending);
|
|
1676
|
+
if (result.status === 'committed') {
|
|
1677
|
+
// This commit absorbed every pending failed-commit migration's diff.
|
|
1678
|
+
// Transition their `commit.kind: 'failed'` records to `'absorbed'` so
|
|
1679
|
+
// the failure recap (if a later migration throws) can anchor them
|
|
1680
|
+
// and the retained-state filter no longer counts them as
|
|
1681
|
+
// uncommitted.
|
|
1682
|
+
//
|
|
1683
|
+
// The key is `package:name`; matching on `name` alone would conflate
|
|
1684
|
+
// across packages. Guard the kind check so a subsequent absorption-
|
|
1685
|
+
// of-same-name cannot overwrite an earlier annotation.
|
|
1686
|
+
if (pending.length > 0) {
|
|
1687
|
+
const absorbedKeys = new Set(pending.map((p) => `${p.package}:${p.name}`));
|
|
1688
|
+
for (const o of outcomes) {
|
|
1689
|
+
const key = `${o.migration.package}:${o.migration.name}`;
|
|
1690
|
+
if (absorbedKeys.has(key) && o.commit.kind === 'failed') {
|
|
1691
|
+
o.commit = {
|
|
1692
|
+
kind: 'absorbed',
|
|
1693
|
+
into: { name: m.name, sha: result.sha },
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return { kind: 'landed', sha: result.sha };
|
|
1699
|
+
}
|
|
1700
|
+
if (result.status === 'failed') {
|
|
1701
|
+
// Diff is still in WT. Subsequent prompts cannot claim git-isolation
|
|
1702
|
+
// until a later commit absorbs the backlog.
|
|
1703
|
+
return { kind: 'failed' };
|
|
1704
|
+
}
|
|
1705
|
+
// `no-changes` and `disabled` — no commit attempted, nothing to record
|
|
1706
|
+
// as a commit failure.
|
|
1707
|
+
return { kind: 'none' };
|
|
1708
|
+
}
|
|
1709
|
+
const totalMigrations = sortedMigrations.length;
|
|
1710
|
+
let migrationIndex = 0;
|
|
1199
1711
|
for (const m of sortedMigrations) {
|
|
1200
|
-
|
|
1712
|
+
migrationIndex++;
|
|
1713
|
+
(0, migrate_output_1.logMigrationBoundary)(migrationIndex, totalMigrations, m.package, m.name);
|
|
1714
|
+
// Snapshot the WT for before/after comparison in the catch block.
|
|
1715
|
+
// Content-sensitive so a dirty→dirty case (this migration mutating an
|
|
1716
|
+
// already-dirty shared file like `package.json`) doesn't collapse.
|
|
1717
|
+
const baselineWorkingTreeSnapshot = (0, git_utils_1.getUncommittedChangesSnapshot)(root);
|
|
1201
1718
|
try {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
if (
|
|
1205
|
-
|
|
1719
|
+
let outcome;
|
|
1720
|
+
let commit = { kind: 'none' };
|
|
1721
|
+
if ((0, migration_shape_1.isPromptOnlyMigration)(m)) {
|
|
1722
|
+
if (agenticRun) {
|
|
1723
|
+
const stepResult = await agenticRun.runStep({
|
|
1724
|
+
root,
|
|
1725
|
+
migration: m,
|
|
1726
|
+
agentic: agenticRun.agentic,
|
|
1727
|
+
runDir: agenticRun.runDir,
|
|
1728
|
+
installDepsIfChanged,
|
|
1729
|
+
});
|
|
1730
|
+
commit = await attemptMigrationCommit(m);
|
|
1731
|
+
(0, migrate_output_1.logAgenticSuccessOutcome)(stepResult.ambiguous ? 'Marked complete by user' : 'Applied', commit.kind === 'landed' ? commit.sha : null, stepResult.summary);
|
|
1732
|
+
outcome = 'applied';
|
|
1733
|
+
}
|
|
1734
|
+
else {
|
|
1735
|
+
logger_1.logger.info(pc.dim(`↷ Skipped — ${skipReason}. Listed in next steps.`));
|
|
1736
|
+
skippedPrompts.push(m);
|
|
1737
|
+
notRunMigrationsCount++;
|
|
1738
|
+
outcome = 'deferred';
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
else if ((0, migration_shape_1.isHybridMigration)(m)) {
|
|
1742
|
+
const { changes, nextSteps, agentContext, logs, madeChanges } = await runNxOrAngularMigration(root, m, isVerbose,
|
|
1743
|
+
/* captureGeneratorOutput: */ !!agenticRun);
|
|
1744
|
+
migrationEmittedNextSteps.push(...nextSteps);
|
|
1745
|
+
if (agenticRun) {
|
|
1746
|
+
// Install any deps the deterministic phase added/bumped before the
|
|
1747
|
+
// agent runs — the prompt half may depend on them being present in
|
|
1748
|
+
// node_modules.
|
|
1749
|
+
await installDepsIfChanged();
|
|
1750
|
+
const stepResult = await agenticRun.runStep({
|
|
1751
|
+
root,
|
|
1752
|
+
migration: m,
|
|
1753
|
+
agentic: agenticRun.agentic,
|
|
1754
|
+
runDir: agenticRun.runDir,
|
|
1755
|
+
installDepsIfChanged,
|
|
1756
|
+
implContext: {
|
|
1757
|
+
logs,
|
|
1758
|
+
changes,
|
|
1759
|
+
agentContext,
|
|
1760
|
+
// When prior commits failed, the working tree carries their
|
|
1761
|
+
// diff. The git-inspect path of the prompt would mislead the
|
|
1762
|
+
// agent in that case; fall back to embedded `<files_changed>`.
|
|
1763
|
+
hasDiffContext: agenticHasDiffContext && !hasPendingCommitDebt(),
|
|
1764
|
+
},
|
|
1765
|
+
});
|
|
1766
|
+
commit = await attemptMigrationCommit(m);
|
|
1767
|
+
(0, migrate_output_1.logAgenticSuccessOutcome)(stepResult.ambiguous ? 'Marked complete by user' : 'Applied', commit.kind === 'landed' ? commit.sha : null, stepResult.summary);
|
|
1768
|
+
outcome = 'applied';
|
|
1769
|
+
}
|
|
1770
|
+
else {
|
|
1771
|
+
// The inner prompt step doesn't run here (agentic disabled, or
|
|
1772
|
+
// running inside an outer agent). Under `inside-agent`, surface the
|
|
1773
|
+
// generator-emitted `agentContext` to stdout so the outer driving
|
|
1774
|
+
// agent can ingest it. Under `disabled` the run is human-driven;
|
|
1775
|
+
// agent-targeted context would only add noise — drop.
|
|
1776
|
+
logger_1.logger.info(pc.dim(`↷ Prompt phase skipped — ${skipReason}. Listed in next steps.`));
|
|
1777
|
+
if (printDroppedAgentContext && agentContext.length > 0) {
|
|
1778
|
+
printDroppedAgentContext({ migration: m, agentContext });
|
|
1779
|
+
}
|
|
1780
|
+
skippedPrompts.push(m);
|
|
1781
|
+
if (!madeChanges) {
|
|
1782
|
+
migrationsWithNoChanges.push(m);
|
|
1783
|
+
}
|
|
1784
|
+
// Only attempt a commit when this migration's deterministic
|
|
1785
|
+
// phase actually produced changes. Otherwise the absorbing
|
|
1786
|
+
// `git add -A` would build a commit subject naming this no-op
|
|
1787
|
+
// migration even though its content is entirely prior pending
|
|
1788
|
+
// diffs — confusing `git log` / `git blame` attribution. Pending
|
|
1789
|
+
// stays pending and the next change-producing migration absorbs.
|
|
1790
|
+
if (madeChanges) {
|
|
1791
|
+
commit = await attemptMigrationCommit(m);
|
|
1792
|
+
}
|
|
1793
|
+
if (commit.kind === 'landed' && commit.sha) {
|
|
1794
|
+
logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
|
|
1795
|
+
}
|
|
1796
|
+
outcome = 'deferred';
|
|
1797
|
+
}
|
|
1206
1798
|
}
|
|
1207
|
-
|
|
1799
|
+
else {
|
|
1800
|
+
// Defer commit until validation succeeds; failed validation leaves
|
|
1801
|
+
// changes uncommitted in the working tree for the user to review.
|
|
1802
|
+
const validationRun = agenticRun && shouldRunValidation ? agenticRun : undefined;
|
|
1803
|
+
const { changes, nextSteps, agentContext, logs, madeChanges } = await runNxOrAngularMigration(root, m, isVerbose,
|
|
1804
|
+
/* captureGeneratorOutput: */ !!validationRun);
|
|
1805
|
+
migrationEmittedNextSteps.push(...nextSteps);
|
|
1806
|
+
const canRunValidation = !!validationRun && changes.length > 0;
|
|
1807
|
+
if (canRunValidation) {
|
|
1808
|
+
// Install any deps the deterministic phase added/bumped before the
|
|
1809
|
+
// validation agent runs — the agent may run tasks that need them.
|
|
1810
|
+
await installDepsIfChanged();
|
|
1811
|
+
const stepResult = await validationRun.runStep({
|
|
1812
|
+
root,
|
|
1813
|
+
migration: m,
|
|
1814
|
+
agentic: validationRun.agentic,
|
|
1815
|
+
runDir: validationRun.runDir,
|
|
1816
|
+
installDepsIfChanged,
|
|
1817
|
+
implContext: {
|
|
1818
|
+
logs,
|
|
1819
|
+
changes,
|
|
1820
|
+
agentContext,
|
|
1821
|
+
// See the hybrid agentic branch above for the rationale on
|
|
1822
|
+
// why pending commit debt gates git-inspect context.
|
|
1823
|
+
hasDiffContext: agenticHasDiffContext && !hasPendingCommitDebt(),
|
|
1824
|
+
},
|
|
1825
|
+
mode: 'generic-validation',
|
|
1826
|
+
});
|
|
1827
|
+
commit = await attemptMigrationCommit(m);
|
|
1828
|
+
(0, migrate_output_1.logAgenticSuccessOutcome)(stepResult.ambiguous
|
|
1829
|
+
? 'Marked complete by user'
|
|
1830
|
+
: 'Validation passed', commit.kind === 'landed' ? commit.sha : null, stepResult.summary);
|
|
1831
|
+
outcome = 'applied';
|
|
1832
|
+
}
|
|
1833
|
+
else {
|
|
1834
|
+
// Inner validation step didn't run. Surface `agentContext` under
|
|
1835
|
+
// `inside-agent` so the outer driving agent can ingest it.
|
|
1836
|
+
if (printDroppedAgentContext && agentContext.length > 0) {
|
|
1837
|
+
printDroppedAgentContext({ migration: m, agentContext });
|
|
1838
|
+
}
|
|
1839
|
+
if (!madeChanges) {
|
|
1840
|
+
migrationsWithNoChanges.push(m);
|
|
1841
|
+
outcome = 'no-changes';
|
|
1842
|
+
}
|
|
1843
|
+
else {
|
|
1844
|
+
commit = await attemptMigrationCommit(m);
|
|
1845
|
+
if (commit.kind === 'landed' && commit.sha) {
|
|
1846
|
+
logger_1.logger.info(pc.dim(`Committed as ${commit.sha}`));
|
|
1847
|
+
}
|
|
1848
|
+
outcome = 'applied';
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
outcomes.push({
|
|
1853
|
+
migration: { package: m.package, name: m.name },
|
|
1854
|
+
status: 'completed',
|
|
1855
|
+
kind: outcome,
|
|
1856
|
+
commit,
|
|
1857
|
+
});
|
|
1858
|
+
logger_1.logger.info('');
|
|
1208
1859
|
}
|
|
1209
1860
|
catch (e) {
|
|
1861
|
+
// Record the in-flight migration as `aborted` so the recap and tally
|
|
1862
|
+
// see it. `commit: 'failed'` requires both: (1) commits were
|
|
1863
|
+
// requested — otherwise the "could not be created" recap line is
|
|
1864
|
+
// false; (2) the WT snapshot diverged from the iteration baseline —
|
|
1865
|
+
// net-new state, not the pre-existing pending diff. Else `'none'`.
|
|
1866
|
+
const leftNewDiff = (0, git_utils_1.getUncommittedChangesSnapshot)(root) !== baselineWorkingTreeSnapshot;
|
|
1867
|
+
outcomes.push({
|
|
1868
|
+
migration: { package: m.package, name: m.name },
|
|
1869
|
+
status: 'aborted',
|
|
1870
|
+
commit: shouldCreateCommits && leftNewDiff
|
|
1871
|
+
? { kind: 'failed' }
|
|
1872
|
+
: { kind: 'none' },
|
|
1873
|
+
});
|
|
1210
1874
|
if (!(e instanceof NpmPeerDepsInstallError)) {
|
|
1875
|
+
// `withGeneratorOutputCapture` attaches the generator's `console.*`
|
|
1876
|
+
// output as `capturedLogs` (best-effort; may be absent). Surface it
|
|
1877
|
+
// so the user sees what the generator printed before it crashed.
|
|
1878
|
+
const capturedLogs = e?.capturedLogs;
|
|
1879
|
+
const bodyLines = typeof capturedLogs === 'string' && capturedLogs.length > 0
|
|
1880
|
+
? [
|
|
1881
|
+
'Output from the generator before it failed:',
|
|
1882
|
+
'',
|
|
1883
|
+
...capturedLogs.split('\n'),
|
|
1884
|
+
]
|
|
1885
|
+
: undefined;
|
|
1211
1886
|
output_1.output.error({
|
|
1212
1887
|
title: `Failed to run ${m.name} from ${m.package}. This workspace is NOT up to date!`,
|
|
1888
|
+
bodyLines,
|
|
1889
|
+
});
|
|
1890
|
+
(0, migrate_output_1.logFailureRecap)({
|
|
1891
|
+
migrationIndex,
|
|
1892
|
+
totalMigrations,
|
|
1893
|
+
outcomes,
|
|
1894
|
+
migrationEmittedNextSteps,
|
|
1895
|
+
insideAgent: agentic?.kind === 'inside-agent',
|
|
1213
1896
|
});
|
|
1214
1897
|
}
|
|
1215
1898
|
throw e;
|
|
1216
1899
|
}
|
|
1217
1900
|
}
|
|
1218
1901
|
if (!shouldCreateCommits) {
|
|
1219
|
-
await
|
|
1902
|
+
await installDepsIfChanged();
|
|
1220
1903
|
}
|
|
1221
1904
|
if (changedDepInstaller.skippedInstall) {
|
|
1222
1905
|
logSkippedPostMigrationInstall(root);
|
|
1223
1906
|
}
|
|
1224
|
-
|
|
1907
|
+
// Combined-view next-steps array kept for back-compat with repair.ts, which
|
|
1908
|
+
// consumes the single `nextSteps` field.
|
|
1909
|
+
const combinedNextSteps = [...migrationEmittedNextSteps];
|
|
1910
|
+
if (skippedPrompts.length > 0) {
|
|
1911
|
+
combinedNextSteps.push(formatSkippedPromptsNextStep(skippedPrompts));
|
|
1912
|
+
}
|
|
1913
|
+
return {
|
|
1914
|
+
migrationsWithNoChanges,
|
|
1915
|
+
skippedPromptsCount: skippedPrompts.length,
|
|
1916
|
+
notRunMigrationsCount,
|
|
1917
|
+
nextSteps: combinedNextSteps,
|
|
1918
|
+
skippedPrompts,
|
|
1919
|
+
migrationEmittedNextSteps,
|
|
1920
|
+
committedShasCount: (0, migrate_output_1.countLandedCommits)(outcomes),
|
|
1921
|
+
// Migrations whose commits failed and never got absorbed by a later
|
|
1922
|
+
// commit. The caller surfaces them so a successful run doesn't claim
|
|
1923
|
+
// "up to date" while leaving uncommitted diffs in the working tree.
|
|
1924
|
+
// Formatted as `package: name` for direct display.
|
|
1925
|
+
retainedAtSuccess: (0, migrate_output_1.retainedMigrations)(outcomes).map((p) => `${p.package}: ${p.name}`),
|
|
1926
|
+
};
|
|
1225
1927
|
}
|
|
1226
1928
|
class ChangedDepInstaller {
|
|
1227
1929
|
constructor(root, shouldSkipInstall = false) {
|
|
@@ -1246,6 +1948,7 @@ class ChangedDepInstaller {
|
|
|
1246
1948
|
this.initialDeps = currentDeps;
|
|
1247
1949
|
}
|
|
1248
1950
|
}
|
|
1951
|
+
exports.ChangedDepInstaller = ChangedDepInstaller;
|
|
1249
1952
|
function logSkippedPostMigrationInstall(root) {
|
|
1250
1953
|
const packageManager = (0, package_manager_1.detectPackageManager)(root);
|
|
1251
1954
|
const installCommand = (0, package_manager_1.getPackageManagerCommand)(packageManager, root).install;
|
|
@@ -1254,21 +1957,28 @@ function logSkippedPostMigrationInstall(root) {
|
|
|
1254
1957
|
bodyLines: [`Run "${installCommand}" to install the updated dependencies.`],
|
|
1255
1958
|
});
|
|
1256
1959
|
}
|
|
1257
|
-
async function runNxOrAngularMigration(root, migration, isVerbose,
|
|
1258
|
-
if (!installDepsIfChanged) {
|
|
1259
|
-
const changedDepInstaller = new ChangedDepInstaller(root);
|
|
1260
|
-
installDepsIfChanged = () => changedDepInstaller.installDepsIfChanged();
|
|
1261
|
-
}
|
|
1960
|
+
async function runNxOrAngularMigration(root, migration, isVerbose, captureGeneratorOutput = false) {
|
|
1262
1961
|
const { collection, collectionPath } = readMigrationCollection(migration.package, root);
|
|
1263
1962
|
let changes = [];
|
|
1264
1963
|
let nextSteps = [];
|
|
1964
|
+
let agentContext = [];
|
|
1965
|
+
let logs = '';
|
|
1966
|
+
// Angular's `ngResult.changes` is synthesized from the schematic's
|
|
1967
|
+
// DryRunEvent stream so Nx and Angular paths can share commit/validation
|
|
1968
|
+
// gating via `changes.length > 0`.
|
|
1969
|
+
let madeChanges = false;
|
|
1970
|
+
logger_1.logger.info(pc.dim('→ Running generator…'));
|
|
1265
1971
|
if (!isAngularMigration(collection, migration.name)) {
|
|
1266
|
-
({ nextSteps, changes } = await runNxMigration(root, collectionPath, collection, migration.name, migration.version));
|
|
1972
|
+
({ nextSteps, changes, agentContext, logs } = await runNxMigration(root, collectionPath, collection, migration.name, migration.version, captureGeneratorOutput));
|
|
1973
|
+
madeChanges = changes.length > 0;
|
|
1267
1974
|
logger_1.logger.info(`Ran ${migration.name} from ${migration.package}`);
|
|
1268
|
-
|
|
1269
|
-
|
|
1975
|
+
if (migration.description) {
|
|
1976
|
+
logger_1.logger.info(` ${migration.description}`);
|
|
1977
|
+
}
|
|
1978
|
+
logger_1.logger.info('');
|
|
1979
|
+
if (!madeChanges) {
|
|
1270
1980
|
logger_1.logger.info(`No changes were made\n`);
|
|
1271
|
-
return { changes, nextSteps };
|
|
1981
|
+
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
1272
1982
|
}
|
|
1273
1983
|
logger_1.logger.info('Changes:');
|
|
1274
1984
|
(0, tree_1.printChanges)(changes, ' ');
|
|
@@ -1277,40 +1987,26 @@ async function runNxOrAngularMigration(root, migration, isVerbose, shouldCreateC
|
|
|
1277
1987
|
else {
|
|
1278
1988
|
const ngCliAdapter = await getNgCompatLayer();
|
|
1279
1989
|
const migrationProjectGraph = await (0, project_graph_1.createProjectGraphAsync)();
|
|
1280
|
-
const
|
|
1990
|
+
const ngResult = await ngCliAdapter.runMigration(root, migration.package, migration.name, (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(migrationProjectGraph).projects, isVerbose, migrationProjectGraph);
|
|
1991
|
+
changes = ngResult.changes;
|
|
1992
|
+
madeChanges = ngResult.madeChanges;
|
|
1993
|
+
logs = ngResult.loggingQueue.join('\n');
|
|
1281
1994
|
logger_1.logger.info(`Ran ${migration.name} from ${migration.package}`);
|
|
1282
|
-
|
|
1995
|
+
if (migration.description) {
|
|
1996
|
+
logger_1.logger.info(` ${migration.description}`);
|
|
1997
|
+
}
|
|
1998
|
+
logger_1.logger.info('');
|
|
1283
1999
|
if (!madeChanges) {
|
|
1284
2000
|
logger_1.logger.info(`No changes were made\n`);
|
|
1285
|
-
return { changes, nextSteps };
|
|
2001
|
+
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
1286
2002
|
}
|
|
1287
2003
|
logger_1.logger.info('Changes:');
|
|
1288
|
-
loggingQueue.forEach((log) => logger_1.logger.info(' ' + log));
|
|
2004
|
+
ngResult.loggingQueue.forEach((log) => logger_1.logger.info(' ' + log));
|
|
1289
2005
|
logger_1.logger.info('');
|
|
1290
2006
|
}
|
|
1291
|
-
|
|
1292
|
-
await installDepsIfChanged();
|
|
1293
|
-
const commitMessage = `${commitPrefix}${migration.name}`;
|
|
1294
|
-
try {
|
|
1295
|
-
const committedSha = (0, git_utils_1.commitChanges)(commitMessage, root);
|
|
1296
|
-
if (committedSha) {
|
|
1297
|
-
logger_1.logger.info(pc.dim(`- Commit created for changes: ${committedSha}`));
|
|
1298
|
-
}
|
|
1299
|
-
else {
|
|
1300
|
-
logger_1.logger.info(pc.red(`- A commit could not be created/retrieved for an unknown reason`));
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
catch (e) {
|
|
1304
|
-
logger_1.logger.info(pc.red(`- ${e.message}`));
|
|
1305
|
-
}
|
|
1306
|
-
// if we are running this function alone, we need to install deps internally
|
|
1307
|
-
}
|
|
1308
|
-
else if (handleInstallDeps) {
|
|
1309
|
-
await installDepsIfChanged();
|
|
1310
|
-
}
|
|
1311
|
-
return { changes, nextSteps };
|
|
2007
|
+
return { changes, nextSteps, agentContext, logs, madeChanges };
|
|
1312
2008
|
}
|
|
1313
|
-
async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits
|
|
2009
|
+
async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false) {
|
|
1314
2010
|
if (!shouldSkipInstall && !process.env.NX_MIGRATE_SKIP_INSTALL) {
|
|
1315
2011
|
await runInstall();
|
|
1316
2012
|
}
|
|
@@ -1340,26 +2036,130 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits =
|
|
|
1340
2036
|
else if (!opts.ifExists && !migrationsExists) {
|
|
1341
2037
|
throw new Error(`File '${opts.runMigrations}' doesn't exist, can't run migrations. Use flag --if-exists to run migrations only if the file exists`);
|
|
1342
2038
|
}
|
|
2039
|
+
const migrations = (0, fileutils_1.readJsonFile)((0, path_1.join)(root, opts.runMigrations)).migrations;
|
|
2040
|
+
const { resolveAgentic } = require('./agentic/select');
|
|
2041
|
+
const agentic = await resolveAgentic({
|
|
2042
|
+
agentic: opts.agentic,
|
|
2043
|
+
migrations,
|
|
2044
|
+
});
|
|
2045
|
+
const { effective: effectiveCreateCommits, agenticHasDiffContext, warning: createCommitsWarning, error: createCommitsError, } = resolveCreateCommits({
|
|
2046
|
+
createCommits: shouldCreateCommits,
|
|
2047
|
+
agenticKind: agentic.kind,
|
|
2048
|
+
isGitRepo: (0, git_utils_1.isGitRepository)(root),
|
|
2049
|
+
commitPrefixIsCustom: commitPrefix !== command_object_1.DEFAULT_MIGRATION_COMMIT_PREFIX,
|
|
2050
|
+
});
|
|
2051
|
+
if (createCommitsError) {
|
|
2052
|
+
throw new Error(createCommitsError);
|
|
2053
|
+
}
|
|
2054
|
+
if (createCommitsWarning) {
|
|
2055
|
+
output_1.output.warn({ title: createCommitsWarning });
|
|
2056
|
+
}
|
|
2057
|
+
const shouldRunValidation = resolveShouldRunValidation({
|
|
2058
|
+
validate: opts.validate,
|
|
2059
|
+
agenticKind: agentic.kind,
|
|
2060
|
+
});
|
|
1343
2061
|
output_1.output.log({
|
|
1344
2062
|
title: `Running migrations from '${opts.runMigrations}'` +
|
|
1345
|
-
(
|
|
2063
|
+
(effectiveCreateCommits
|
|
2064
|
+
? ', with each applied in a dedicated commit'
|
|
2065
|
+
: ''),
|
|
1346
2066
|
});
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
2067
|
+
if (effectiveCreateCommits) {
|
|
2068
|
+
(0, migrate_commits_1.commitCheckpointBeforeMigrations)(root, commitPrefix);
|
|
2069
|
+
}
|
|
2070
|
+
if (agentic.kind === 'enabled') {
|
|
2071
|
+
const { packageJson: nxPackageJson } = (0, package_json_1.readModulePackageJson)('nx', (0, installation_directory_1.getNxRequirePaths)(root));
|
|
2072
|
+
await (0, handoff_gitignore_1.applyAgenticHandoffGitignoreFallback)({
|
|
2073
|
+
migrations,
|
|
2074
|
+
installedNxVersion: nxPackageJson.version,
|
|
2075
|
+
effectiveCreateCommits,
|
|
2076
|
+
commitPrefix,
|
|
2077
|
+
root,
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
const { migrationsWithNoChanges, skippedPromptsCount, notRunMigrationsCount, skippedPrompts, migrationEmittedNextSteps, committedShasCount, retainedAtSuccess, } = await executeMigrations(root, migrations, isVerbose, effectiveCreateCommits, commitPrefix, shouldSkipInstall, agentic, agenticHasDiffContext, shouldRunValidation);
|
|
2081
|
+
const ranWithChangesCount = migrations.length - notRunMigrationsCount - migrationsWithNoChanges.length;
|
|
2082
|
+
// The "applied" tally counts fully-completed migrations — those that
|
|
2083
|
+
// left no deferred work behind. Hybrid migrations whose prompt half was
|
|
2084
|
+
// deferred count as "deferred", not "applied".
|
|
2085
|
+
const appliedCount = migrations.length - skippedPrompts.length;
|
|
2086
|
+
const insideAgent = agentic.kind === 'inside-agent';
|
|
2087
|
+
const tallyLine = (0, migrate_output_1.buildTallyBodyLine)({
|
|
2088
|
+
appliedCount,
|
|
2089
|
+
committedShasCount,
|
|
2090
|
+
skippedPromptsCount,
|
|
2091
|
+
insideAgent,
|
|
2092
|
+
});
|
|
2093
|
+
const tallyBody = tallyLine ? [tallyLine] : undefined;
|
|
2094
|
+
// Only claim "up to date" when there's nothing pending: no deferred
|
|
2095
|
+
// prompts AND no migrations whose commits failed without being absorbed.
|
|
2096
|
+
const upToDateSuffix = skippedPromptsCount > 0 || retainedAtSuccess.length > 0
|
|
2097
|
+
? ''
|
|
2098
|
+
: ' This workspace is up to date!';
|
|
2099
|
+
// Demote `output.success` to `output.warn` when there's uncommitted state
|
|
2100
|
+
// retained from failed commits — the run did its work, but it would be
|
|
2101
|
+
// misleading to lead with a green "Successfully finished" before the
|
|
2102
|
+
// retained-state block. `.bind(output)` is required: assigning the method
|
|
2103
|
+
// reference to a local would otherwise call it with `this === undefined`.
|
|
2104
|
+
const completionLog = (retainedAtSuccess.length > 0 ? output_1.output.warn : output_1.output.success).bind(output_1.output);
|
|
2105
|
+
const completionTitlePrefix = retainedAtSuccess.length > 0
|
|
2106
|
+
? 'Finished running migrations with uncommitted state retained'
|
|
2107
|
+
: 'Successfully finished running migrations';
|
|
2108
|
+
if (notRunMigrationsCount === migrations.length && migrations.length > 0) {
|
|
2109
|
+
const remediation = insideAgent
|
|
2110
|
+
? 'The AI agent driving this run should apply each prompt — see next steps below.'
|
|
2111
|
+
: 'Re-run with --agentic to apply them. See next steps below.';
|
|
2112
|
+
output_1.output.warn({
|
|
2113
|
+
title: `No migrations from '${opts.runMigrations}' were applied — every entry is a prompt-only migration. ${remediation}`,
|
|
2114
|
+
bodyLines: tallyBody,
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
else if (ranWithChangesCount > 0) {
|
|
2118
|
+
completionLog({
|
|
2119
|
+
title: `${completionTitlePrefix} from '${opts.runMigrations}'.${upToDateSuffix}`,
|
|
2120
|
+
bodyLines: tallyBody,
|
|
1352
2121
|
});
|
|
1353
2122
|
}
|
|
1354
2123
|
else {
|
|
1355
|
-
|
|
1356
|
-
|
|
2124
|
+
// Pathological-but-possible: a no-op run that still has retained state
|
|
2125
|
+
// (e.g. pre-existing pending diffs that no commit absorbed). Demote
|
|
2126
|
+
// explicitly rather than rely on the implicit invariant.
|
|
2127
|
+
completionLog({
|
|
2128
|
+
title: `No changes were made from running '${opts.runMigrations}'.${upToDateSuffix}`,
|
|
2129
|
+
bodyLines: tallyBody,
|
|
2130
|
+
});
|
|
2131
|
+
}
|
|
2132
|
+
if (retainedAtSuccess.length > 0) {
|
|
2133
|
+
output_1.output.warn({
|
|
2134
|
+
title: `Working-tree state retained from ${retainedAtSuccess.length} migration${retainedAtSuccess.length === 1 ? '' : 's'} whose commits could not be created`,
|
|
2135
|
+
bodyLines: (0, migrate_output_1.buildRetainedAtSuccessBody)(retainedAtSuccess),
|
|
1357
2136
|
});
|
|
1358
2137
|
}
|
|
1359
|
-
if (
|
|
2138
|
+
if (insideAgent) {
|
|
2139
|
+
// Under inside-agent, emit a directive block so the outer agent has
|
|
2140
|
+
// explicit instructions to act on, not just relay.
|
|
2141
|
+
const directiveLines = (0, migrate_output_1.buildDirectiveBlockBodyLines)({
|
|
2142
|
+
skippedPrompts,
|
|
2143
|
+
migrationEmittedNextSteps,
|
|
2144
|
+
});
|
|
2145
|
+
if (directiveLines.length > 0) {
|
|
2146
|
+
output_1.output.log({
|
|
2147
|
+
title: 'Next steps for the AI agent driving this run',
|
|
2148
|
+
bodyLines: directiveLines,
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
else if (skippedPromptsCount > 0 || migrationEmittedNextSteps.length > 0) {
|
|
2153
|
+
// Non-inside-agent path keeps the legacy "additional information" shape —
|
|
2154
|
+
// the consumer is the human user.
|
|
2155
|
+
const bodyLines = [];
|
|
2156
|
+
if (skippedPromptsCount > 0) {
|
|
2157
|
+
bodyLines.push(formatSkippedPromptsNextStep(skippedPrompts));
|
|
2158
|
+
}
|
|
2159
|
+
bodyLines.push(...migrationEmittedNextSteps);
|
|
1360
2160
|
output_1.output.log({
|
|
1361
2161
|
title: `Some migrations have additional information, see below.`,
|
|
1362
|
-
bodyLines:
|
|
2162
|
+
bodyLines: bodyLines.map((line) => `- ${line}`),
|
|
1363
2163
|
});
|
|
1364
2164
|
}
|
|
1365
2165
|
}
|
|
@@ -1374,22 +2174,47 @@ function getStringifiedPackageJsonDeps(root) {
|
|
|
1374
2174
|
return '';
|
|
1375
2175
|
}
|
|
1376
2176
|
}
|
|
1377
|
-
async function runNxMigration(root, collectionPath, collection, name, migrationVersion) {
|
|
2177
|
+
async function runNxMigration(root, collectionPath, collection, name, migrationVersion, captureGeneratorOutput) {
|
|
1378
2178
|
const { path: implPath, fnSymbol } = getImplementationPath(collection, collectionPath, name, migrationVersion);
|
|
1379
2179
|
const fn = require(implPath)[fnSymbol];
|
|
1380
2180
|
const host = new tree_1.FsTree(root, process.env.NX_VERBOSE_LOGGING === 'true', `migration ${collection.name}:${name}`);
|
|
1381
|
-
let
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
2181
|
+
let result;
|
|
2182
|
+
let logs = '';
|
|
2183
|
+
if (captureGeneratorOutput) {
|
|
2184
|
+
const { withGeneratorOutputCapture } = require('./agentic/capture-generator-output');
|
|
2185
|
+
({ result, logs } = await withGeneratorOutputCapture(() => fn(host, {})));
|
|
2186
|
+
}
|
|
2187
|
+
else {
|
|
2188
|
+
result = await fn(host, {});
|
|
1388
2189
|
}
|
|
2190
|
+
const { nextSteps, agentContext } = parseMigrationReturn(result);
|
|
1389
2191
|
host.lock();
|
|
1390
2192
|
const changes = host.listChanges();
|
|
1391
2193
|
(0, tree_1.flushChanges)(root, changes);
|
|
1392
|
-
return { changes, nextSteps };
|
|
2194
|
+
return { changes, nextSteps, agentContext, logs };
|
|
2195
|
+
}
|
|
2196
|
+
function parseMigrationReturn(value) {
|
|
2197
|
+
if (Array.isArray(value)) {
|
|
2198
|
+
return { nextSteps: filterStrings(value), agentContext: [] };
|
|
2199
|
+
}
|
|
2200
|
+
if (value && typeof value === 'object') {
|
|
2201
|
+
const obj = value;
|
|
2202
|
+
return {
|
|
2203
|
+
nextSteps: filterStrings(obj.nextSteps),
|
|
2204
|
+
agentContext: filterStrings(obj.agentContext),
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
// Catches `void`, mistakenly-returned generator callbacks, malformed values.
|
|
2208
|
+
return { nextSteps: [], agentContext: [] };
|
|
2209
|
+
}
|
|
2210
|
+
// Bucket-level tolerance: a single non-string entry shouldn't discard the
|
|
2211
|
+
// whole `nextSteps` / `agentContext` array. Migration authors occasionally
|
|
2212
|
+
// push `null` / `undefined` / a number into the array; we drop the bad entries
|
|
2213
|
+
// and keep the rest so end-of-run guidance isn't silently lost.
|
|
2214
|
+
function filterStrings(value) {
|
|
2215
|
+
if (!Array.isArray(value))
|
|
2216
|
+
return [];
|
|
2217
|
+
return value.filter((v) => typeof v === 'string');
|
|
1393
2218
|
}
|
|
1394
2219
|
async function migrate(root, args, rawArgs) {
|
|
1395
2220
|
await client_1.daemonClient.stop();
|
|
@@ -1490,7 +2315,7 @@ function buildMigrationMissingMessage(baseMessage, collectionPath, migrationVers
|
|
|
1490
2315
|
const packageJson = (0, fileutils_1.readJsonFile)(packageJsonPath);
|
|
1491
2316
|
const installedVersion = packageJson.version;
|
|
1492
2317
|
if (installedVersion &&
|
|
1493
|
-
(0, semver_1.lt)(normalizeVersion(installedVersion), normalizeVersion(migrationVersion))) {
|
|
2318
|
+
(0, semver_1.lt)((0, version_utils_1.normalizeVersion)(installedVersion), (0, version_utils_1.normalizeVersion)(migrationVersion))) {
|
|
1494
2319
|
const packageManager = (0, package_manager_1.detectPackageManager)();
|
|
1495
2320
|
const pmc = (0, package_manager_1.getPackageManagerCommand)(packageManager);
|
|
1496
2321
|
const overrideFieldName = getOverrideFieldName(packageManager);
|
|
@@ -1600,9 +2425,3 @@ const getNgCompatLayer = (() => {
|
|
|
1600
2425
|
return _ngCliAdapter;
|
|
1601
2426
|
};
|
|
1602
2427
|
})();
|
|
1603
|
-
function isStringArray(value) {
|
|
1604
|
-
if (!Array.isArray(value)) {
|
|
1605
|
-
return false;
|
|
1606
|
-
}
|
|
1607
|
-
return value.every((v) => typeof v === 'string');
|
|
1608
|
-
}
|