nx 21.0.0-beta.0 → 21.0.0-beta.10
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/.eslintrc.json +5 -1
- package/migrations.json +5 -35
- package/package.json +12 -12
- package/release/index.d.ts +1 -1
- package/release/index.js +2 -1
- package/schemas/nx-schema.json +182 -35
- package/schemas/project-schema.json +5 -0
- package/src/adapter/compat.d.ts +1 -1
- package/src/adapter/compat.js +3 -0
- package/src/command-line/add/add.js +6 -16
- package/src/command-line/affected/command-object.js +6 -6
- package/src/command-line/examples.js +0 -4
- package/src/command-line/exec/command-object.js +1 -1
- package/src/command-line/generate/generator-utils.js +8 -3
- package/src/command-line/import/import.js +1 -1
- package/src/command-line/init/command-object.js +18 -6
- package/src/command-line/init/configure-plugins.d.ts +6 -7
- package/src/command-line/init/configure-plugins.js +52 -38
- package/src/command-line/init/implementation/add-nx-to-turborepo.d.ts +4 -0
- package/src/command-line/init/implementation/add-nx-to-turborepo.js +49 -0
- package/src/command-line/init/implementation/check-compatible-with-plugins.js +7 -1
- package/src/command-line/init/implementation/deduce-default-base.d.ts +1 -0
- package/src/command-line/init/implementation/deduce-default-base.js +53 -0
- package/src/command-line/init/implementation/react/add-vite-commands-to-package-scripts.js +6 -4
- package/src/command-line/init/implementation/react/index.d.ts +1 -1
- package/src/command-line/init/implementation/react/index.js +32 -185
- package/src/command-line/init/implementation/react/write-vite-config.js +19 -3
- package/src/command-line/init/implementation/utils.d.ts +6 -2
- package/src/command-line/init/implementation/utils.js +110 -45
- package/src/command-line/init/init-v1.js +1 -1
- package/src/command-line/init/init-v2.d.ts +1 -0
- package/src/command-line/init/init-v2.js +70 -39
- package/src/command-line/migrate/migrate-ui-api.d.ts +58 -0
- package/src/command-line/migrate/migrate-ui-api.js +227 -0
- package/src/command-line/migrate/migrate.d.ts +16 -3
- package/src/command-line/migrate/migrate.js +134 -101
- package/src/command-line/nx-commands.js +19 -5
- package/src/command-line/register/command-object.d.ts +6 -0
- package/src/command-line/{activate-powerpack → register}/command-object.js +9 -9
- package/src/command-line/register/register.d.ts +2 -0
- package/src/command-line/register/register.js +9 -0
- package/src/command-line/release/changelog.js +18 -15
- package/src/command-line/release/command-object.d.ts +8 -0
- package/src/command-line/release/command-object.js +9 -0
- package/src/command-line/release/config/config.d.ts +8 -7
- package/src/command-line/release/config/config.js +139 -45
- package/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
- package/src/command-line/release/config/use-legacy-versioning.js +9 -0
- package/src/command-line/release/index.d.ts +4 -0
- package/src/command-line/release/index.js +6 -1
- package/src/command-line/release/plan-check.js +6 -3
- package/src/command-line/release/plan.js +7 -3
- package/src/command-line/release/publish.js +7 -3
- package/src/command-line/release/release.js +8 -3
- package/src/command-line/release/utils/batch-projects-by-generator-config.js +6 -3
- package/src/command-line/release/utils/git.d.ts +3 -2
- package/src/command-line/release/utils/git.js +65 -9
- package/src/command-line/release/utils/github.js +3 -1
- package/src/command-line/release/utils/resolve-semver-specifier.d.ts +2 -1
- package/src/command-line/release/utils/resolve-semver-specifier.js +2 -1
- package/src/command-line/release/utils/semver.d.ts +8 -0
- package/src/command-line/release/utils/semver.js +8 -0
- package/src/command-line/release/utils/shared-legacy.d.ts +25 -0
- package/src/command-line/release/utils/shared-legacy.js +2 -0
- package/src/command-line/release/utils/shared.d.ts +11 -17
- package/src/command-line/release/version/derive-specifier-from-conventional-commits.d.ts +7 -0
- package/src/command-line/release/version/derive-specifier-from-conventional-commits.js +47 -0
- package/src/command-line/release/version/deriver-specifier-from-version-plans.d.ts +8 -0
- package/src/command-line/release/version/deriver-specifier-from-version-plans.js +59 -0
- package/src/command-line/release/version/project-logger.d.ts +8 -0
- package/src/command-line/release/version/project-logger.js +45 -0
- package/src/command-line/release/version/release-group-processor.d.ts +252 -0
- package/src/command-line/release/version/release-group-processor.js +1057 -0
- package/src/command-line/release/version/resolve-current-version.d.ts +32 -0
- package/src/command-line/release/version/resolve-current-version.js +241 -0
- package/src/command-line/release/version/test-utils.d.ts +93 -0
- package/src/command-line/release/version/test-utils.js +415 -0
- package/src/command-line/release/version/topological-sort.d.ts +9 -0
- package/src/command-line/release/version/topological-sort.js +41 -0
- package/src/command-line/release/version/version-actions.d.ts +171 -0
- package/src/command-line/release/version/version-actions.js +195 -0
- package/src/command-line/release/version-legacy.d.ts +46 -0
- package/src/command-line/release/version-legacy.js +453 -0
- package/src/command-line/release/version.d.ts +0 -40
- package/src/command-line/release/version.js +84 -262
- package/src/command-line/repair/repair.js +0 -1
- package/src/command-line/report/report.d.ts +7 -3
- package/src/command-line/report/report.js +52 -18
- package/src/command-line/run/command-object.js +2 -2
- package/src/command-line/run/executor-utils.d.ts +6 -1
- package/src/command-line/run/executor-utils.js +10 -1
- package/src/command-line/run/run.js +2 -2
- package/src/command-line/run-many/command-object.js +2 -2
- package/src/command-line/yargs-utils/shared-options.d.ts +4 -0
- package/src/command-line/yargs-utils/shared-options.js +20 -0
- package/src/config/misc-interfaces.d.ts +11 -1
- package/src/config/nx-json.d.ts +160 -16
- package/src/config/project-graph.d.ts +4 -2
- package/src/config/project-graph.js +8 -0
- package/src/config/workspace-json-project-json.d.ts +2 -2
- package/src/core/graph/main.js +1 -1
- package/src/core/graph/runtime.js +1 -1
- package/src/core/graph/styles.css +2 -2
- package/src/core/graph/styles.js +1 -1
- package/src/daemon/client/client.d.ts +2 -0
- package/src/daemon/client/client.js +15 -0
- package/src/daemon/message-types/glob.d.ts +7 -0
- package/src/daemon/message-types/glob.js +9 -1
- package/src/daemon/message-types/hash-glob.d.ts +6 -0
- package/src/daemon/message-types/hash-glob.js +9 -1
- package/src/daemon/server/handle-glob.d.ts +1 -0
- package/src/daemon/server/handle-glob.js +8 -0
- package/src/daemon/server/handle-hash-glob.d.ts +1 -0
- package/src/daemon/server/handle-hash-glob.js +8 -0
- package/src/daemon/server/logger.js +2 -1
- package/src/daemon/server/server.js +7 -0
- package/src/devkit-internals.d.ts +3 -2
- package/src/devkit-internals.js +5 -1
- package/src/executors/run-commands/run-commands.impl.d.ts +2 -5
- package/src/executors/run-commands/run-commands.impl.js +14 -42
- package/src/executors/run-commands/running-tasks.d.ts +9 -4
- package/src/executors/run-commands/running-tasks.js +103 -30
- package/src/executors/run-script/run-script.impl.js +4 -3
- package/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +8 -0
- package/src/generators/testing-utils/create-tree.js +5 -1
- package/src/migrations/{update-17-0-0/rm-default-collection-npm-scope.d.ts → update-21-0-0/release-version-config-changes.d.ts} +1 -1
- package/src/migrations/update-21-0-0/release-version-config-changes.js +111 -0
- package/src/native/index.d.ts +98 -19
- package/src/native/index.js +16 -2
- package/src/native/native-bindings.js +7 -0
- package/src/native/nx.wasi-browser.js +20 -19
- package/src/native/nx.wasi.cjs +20 -19
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/nx-cloud/nx-cloud-tasks-runner-shell.js +3 -3
- package/src/plugins/js/lock-file/lock-file.js +28 -13
- package/src/plugins/js/lock-file/utils/package-json.d.ts +1 -1
- package/src/plugins/js/lock-file/utils/package-json.js +8 -6
- package/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -3
- package/src/plugins/js/lock-file/yarn-parser.js +85 -39
- package/src/plugins/js/project-graph/affected/lock-file-changes.js +1 -0
- package/src/plugins/js/project-graph/build-dependencies/explicit-project-dependencies.js +1 -1
- package/src/plugins/js/project-graph/build-dependencies/target-project-locator.d.ts +10 -1
- package/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +59 -6
- package/src/plugins/js/utils/packages.js +22 -3
- package/src/plugins/js/utils/register.js +1 -0
- package/src/plugins/js/utils/typescript.js +3 -3
- package/src/plugins/package-json/create-nodes.d.ts +1 -1
- package/src/plugins/package-json/create-nodes.js +4 -2
- package/src/project-graph/affected/locators/project-glob-changes.js +2 -2
- package/src/project-graph/error-types.js +32 -2
- package/src/project-graph/file-utils.d.ts +1 -10
- package/src/project-graph/file-utils.js +2 -77
- package/src/project-graph/nx-deps-cache.js +7 -2
- package/src/project-graph/plugins/get-plugins.js +2 -1
- package/src/project-graph/plugins/in-process-loader.js +1 -1
- package/src/project-graph/plugins/isolation/plugin-worker.js +12 -6
- package/src/project-graph/plugins/loaded-nx-plugin.d.ts +2 -1
- package/src/project-graph/plugins/loaded-nx-plugin.js +3 -7
- package/src/project-graph/plugins/public-api.d.ts +1 -1
- package/src/project-graph/plugins/utils.d.ts +2 -2
- package/src/project-graph/plugins/utils.js +2 -2
- package/src/project-graph/project-graph.js +5 -2
- package/src/project-graph/utils/project-configuration-utils.d.ts +3 -3
- package/src/project-graph/utils/project-configuration-utils.js +54 -21
- package/src/project-graph/utils/retrieve-workspace-files.d.ts +1 -1
- package/src/project-graph/utils/retrieve-workspace-files.js +14 -18
- package/src/tasks-runner/batch/batch-messages.d.ts +2 -0
- package/src/tasks-runner/batch/run-batch.js +3 -4
- package/src/tasks-runner/cache.d.ts +20 -6
- package/src/tasks-runner/cache.js +104 -20
- package/src/tasks-runner/create-task-graph.d.ts +0 -1
- package/src/tasks-runner/create-task-graph.js +11 -11
- package/src/tasks-runner/default-tasks-runner.js +5 -14
- package/src/tasks-runner/forked-process-task-runner.d.ts +8 -3
- package/src/tasks-runner/forked-process-task-runner.js +59 -46
- package/src/tasks-runner/init-tasks-runner.d.ts +15 -1
- package/src/tasks-runner/init-tasks-runner.js +62 -2
- package/src/tasks-runner/is-tui-enabled.d.ts +2 -0
- package/src/tasks-runner/is-tui-enabled.js +64 -0
- package/src/tasks-runner/life-cycle.d.ts +14 -3
- package/src/tasks-runner/life-cycle.js +37 -2
- package/src/tasks-runner/life-cycles/task-history-life-cycle-old.d.ts +2 -0
- package/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +15 -7
- package/src/tasks-runner/life-cycles/task-history-life-cycle.d.ts +5 -0
- package/src/tasks-runner/life-cycles/task-history-life-cycle.js +35 -5
- package/src/tasks-runner/life-cycles/tui-summary-life-cycle.d.ts +18 -0
- package/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +229 -0
- package/src/tasks-runner/pseudo-terminal.d.ts +10 -7
- package/src/tasks-runner/pseudo-terminal.js +37 -35
- package/src/tasks-runner/run-command.d.ts +4 -1
- package/src/tasks-runner/run-command.js +220 -42
- package/src/tasks-runner/running-tasks/node-child-process.js +4 -11
- package/src/tasks-runner/running-tasks/running-task.d.ts +3 -0
- package/src/tasks-runner/running-tasks/shared-running-task.d.ts +14 -0
- package/src/tasks-runner/running-tasks/shared-running-task.js +30 -0
- package/src/tasks-runner/task-env.d.ts +1 -4
- package/src/tasks-runner/task-env.js +2 -0
- package/src/tasks-runner/task-orchestrator.d.ts +26 -10
- package/src/tasks-runner/task-orchestrator.js +212 -57
- package/src/tasks-runner/tasks-runner.d.ts +1 -0
- package/src/tasks-runner/tasks-schedule.d.ts +1 -0
- package/src/tasks-runner/tasks-schedule.js +9 -0
- package/src/tasks-runner/utils.d.ts +2 -2
- package/src/tasks-runner/utils.js +18 -12
- package/src/utils/child-process.d.ts +4 -0
- package/src/utils/child-process.js +23 -30
- package/src/utils/command-line-utils.d.ts +1 -1
- package/src/utils/find-matching-projects.js +2 -2
- package/src/utils/git-utils.d.ts +1 -1
- package/src/utils/git-utils.js +8 -3
- package/src/utils/handle-errors.js +15 -0
- package/src/utils/is-ci.js +4 -1
- package/src/utils/is-using-prettier.d.ts +3 -0
- package/src/utils/is-using-prettier.js +62 -0
- package/src/utils/nx-key.d.ts +7 -0
- package/src/utils/nx-key.js +52 -0
- package/src/utils/package-json.d.ts +1 -1
- package/src/utils/package-json.js +16 -2
- package/src/utils/package-manager.js +2 -2
- package/src/utils/path.js +1 -1
- package/src/utils/require-nx-key.d.ts +1 -0
- package/src/utils/require-nx-key.js +22 -0
- package/src/utils/workspace-context.d.ts +2 -0
- package/src/utils/workspace-context.js +16 -0
- package/src/command-line/activate-powerpack/activate-powerpack.d.ts +0 -2
- package/src/command-line/activate-powerpack/activate-powerpack.js +0 -34
- package/src/command-line/activate-powerpack/command-object.d.ts +0 -6
- package/src/command-line/init/implementation/react/write-craco-config.d.ts +0 -1
- package/src/command-line/init/implementation/react/write-craco-config.js +0 -61
- package/src/migrations/update-17-0-0/move-cache-directory.d.ts +0 -2
- package/src/migrations/update-17-0-0/move-cache-directory.js +0 -35
- package/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +0 -72
- package/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.d.ts +0 -2
- package/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +0 -122
- package/src/migrations/update-17-2-0/move-default-base.d.ts +0 -5
- package/src/migrations/update-17-2-0/move-default-base.js +0 -21
- package/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
- package/src/migrations/update-17-3-0/nx-release-path.js +0 -47
- package/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.d.ts +0 -2
- package/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +0 -11
- package/src/utils/powerpack.d.ts +0 -5
- package/src/utils/powerpack.js +0 -33
@@ -0,0 +1,1057 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ReleaseGroupProcessor = exports.BUMP_TYPE_REASON_TEXT = void 0;
|
4
|
+
const semver = require("semver");
|
5
|
+
const config_1 = require("../config/config");
|
6
|
+
const git_1 = require("../utils/git");
|
7
|
+
const resolve_semver_specifier_1 = require("../utils/resolve-semver-specifier");
|
8
|
+
const version_1 = require("../version");
|
9
|
+
const derive_specifier_from_conventional_commits_1 = require("./derive-specifier-from-conventional-commits");
|
10
|
+
const deriver_specifier_from_version_plans_1 = require("./deriver-specifier-from-version-plans");
|
11
|
+
const project_logger_1 = require("./project-logger");
|
12
|
+
const resolve_current_version_1 = require("./resolve-current-version");
|
13
|
+
const topological_sort_1 = require("./topological-sort");
|
14
|
+
const version_actions_1 = require("./version-actions");
|
15
|
+
exports.BUMP_TYPE_REASON_TEXT = {
|
16
|
+
DEPENDENCY_WAS_BUMPED: ', because a dependency was bumped, ',
|
17
|
+
USER_SPECIFIER: ', from the given specifier, ',
|
18
|
+
PROMPTED_USER_SPECIFIER: ', from the prompted specifier, ',
|
19
|
+
CONVENTIONAL_COMMITS: ', derived from conventional commits data, ',
|
20
|
+
VERSION_PLANS: ', read from version plan {versionPlanPath}, ',
|
21
|
+
DEPENDENCY_ACROSS_GROUPS_WAS_BUMPED: ', because a dependency project belonging to another release group was bumped, ',
|
22
|
+
OTHER_PROJECT_IN_FIXED_GROUP_WAS_BUMPED_DUE_TO_DEPENDENCY: ', because of a dependency-only bump to another project in the same fixed release group, ',
|
23
|
+
};
|
24
|
+
class ReleaseGroupProcessor {
|
25
|
+
constructor(tree, projectGraph, nxReleaseConfig, releaseGroups, releaseGroupToFilteredProjects, options) {
|
26
|
+
this.tree = tree;
|
27
|
+
this.projectGraph = projectGraph;
|
28
|
+
this.nxReleaseConfig = nxReleaseConfig;
|
29
|
+
this.releaseGroups = releaseGroups;
|
30
|
+
this.releaseGroupToFilteredProjects = releaseGroupToFilteredProjects;
|
31
|
+
this.options = options;
|
32
|
+
/**
|
33
|
+
* Stores the relationships between release groups, including their dependencies
|
34
|
+
* and dependents. This is used for determining processing order and propagating
|
35
|
+
* version changes between related groups.
|
36
|
+
*/
|
37
|
+
this.groupGraph = new Map();
|
38
|
+
/**
|
39
|
+
* Tracks which release groups have already been processed to avoid
|
40
|
+
* processing them multiple times. Used during the group traversal.
|
41
|
+
*/
|
42
|
+
this.processedGroups = new Set();
|
43
|
+
/**
|
44
|
+
* Keeps track of which projects have already had their versions bumped.
|
45
|
+
* This is used to avoid redundant version bumping and to determine which
|
46
|
+
* projects need their dependencies updated.
|
47
|
+
*/
|
48
|
+
this.bumpedProjects = new Set();
|
49
|
+
/**
|
50
|
+
* Cache of release groups sorted in topological order to ensure dependencies
|
51
|
+
* are processed before dependents. Computed once and reused throughout processing.
|
52
|
+
*/
|
53
|
+
this.sortedReleaseGroups = [];
|
54
|
+
/**
|
55
|
+
* Maps each release group to its projects sorted in topological order.
|
56
|
+
* Ensures projects are processed after their dependencies within each group.
|
57
|
+
*/
|
58
|
+
this.sortedProjects = new Map();
|
59
|
+
/**
|
60
|
+
* Track the unique afterAllProjectsVersioned functions involved in the current versioning process,
|
61
|
+
* so that we can ensure they are only invoked once per versioning execution.
|
62
|
+
*/
|
63
|
+
this.uniqueAfterAllProjectsVersioned = new Map();
|
64
|
+
/**
|
65
|
+
* Track the versionActions for each project so that we can invoke certain instance methods.
|
66
|
+
*/
|
67
|
+
this.projectsToVersionActions = new Map();
|
68
|
+
/**
|
69
|
+
* versionData that will ultimately be returned to the nx release version handler by getVersionData()
|
70
|
+
*/
|
71
|
+
this.versionData = new Map();
|
72
|
+
/**
|
73
|
+
* Set of all projects that are configured in the nx release config.
|
74
|
+
* Used to validate dependencies and identify projects that should be updated.
|
75
|
+
*/
|
76
|
+
this.allProjectsConfiguredForNxRelease = new Set();
|
77
|
+
/**
|
78
|
+
* Set of projects that will be processed in the current run.
|
79
|
+
* This is potentially a subset of allProjectsConfiguredForNxRelease based on filters
|
80
|
+
* and dependency relationships.
|
81
|
+
*/
|
82
|
+
this.allProjectsToProcess = new Set();
|
83
|
+
/**
|
84
|
+
* Caches the current version of each project to avoid repeated disk/registry/git tag lookups.
|
85
|
+
* Often used during new version calculation. Will be null if the current version resolver is set to 'none'.
|
86
|
+
*/
|
87
|
+
this.cachedCurrentVersions = new Map();
|
88
|
+
/**
|
89
|
+
* Caches git tag information for projects that resolve their version from git tags.
|
90
|
+
* This avoids performing expensive git operations multiple times for the same project.
|
91
|
+
*/
|
92
|
+
this.cachedLatestMatchingGitTag = new Map();
|
93
|
+
/**
|
94
|
+
* Temporary storage for dependent project names while building the dependency graph.
|
95
|
+
* This is used as an intermediate step before creating the full dependent projects data.
|
96
|
+
*/
|
97
|
+
this.tmpCachedDependentProjects = new Map();
|
98
|
+
/**
|
99
|
+
* Resolve the data regarding dependent projects for each project upfront so that it remains accurate
|
100
|
+
* even after updates are applied to manifests.
|
101
|
+
*/
|
102
|
+
this.originalDependentProjectsPerProject = new Map();
|
103
|
+
/**
|
104
|
+
* In the case of fixed release groups that are configured to resolve the current version from a registry
|
105
|
+
* or a git tag, it would be a waste of time and resources to resolve the current version for each individual
|
106
|
+
* project, therefore we maintain a cache of the current version for each applicable fixed release group here.
|
107
|
+
*/
|
108
|
+
this.currentVersionsPerFixedReleaseGroup = new Map();
|
109
|
+
/**
|
110
|
+
* Cache of project loggers for each project.
|
111
|
+
*/
|
112
|
+
this.projectLoggers = new Map();
|
113
|
+
/**
|
114
|
+
* Track any version plan files that have been processed so that we can delete them after versioning is complete,
|
115
|
+
* while leaving any unprocessed files in place.
|
116
|
+
*/
|
117
|
+
this.processedVersionPlanFiles = new Set();
|
118
|
+
/**
|
119
|
+
* Certain configuration options can be overridden at the project level, and otherwise fall back to the release group level.
|
120
|
+
* Many also have a specific default value if nothing is set at either level. To avoid applying this hierarchy for each project
|
121
|
+
* every time such a configuration option is needed, we cache the result per project here.
|
122
|
+
*/
|
123
|
+
this.finalConfigsByProject = new Map();
|
124
|
+
/**
|
125
|
+
* Maps each project to its release group for quick O(1) lookups.
|
126
|
+
* This avoids having to scan through all release groups to find a project.
|
127
|
+
*/
|
128
|
+
this.projectToReleaseGroup = new Map();
|
129
|
+
/**
|
130
|
+
* Maps each project to its dependents (projects that depend on it).
|
131
|
+
* This is the inverse of the projectToDependencies map and enables
|
132
|
+
* efficient lookup of dependent projects for propagating version changes.
|
133
|
+
*/
|
134
|
+
this.projectToDependents = new Map();
|
135
|
+
/**
|
136
|
+
* Maps each project to its dependencies (projects it depends on).
|
137
|
+
* Used for building dependency graphs and determining processing order.
|
138
|
+
*/
|
139
|
+
this.projectToDependencies = new Map();
|
140
|
+
/**
|
141
|
+
* Caches the updateDependents setting for each project to avoid repeated
|
142
|
+
* lookups and calculations. This determines if dependent projects should
|
143
|
+
* be automatically updated when a dependency changes.
|
144
|
+
*/
|
145
|
+
this.projectToUpdateDependentsSetting = new Map();
|
146
|
+
/**
|
147
|
+
* To match legacy versioning behavior in the case of semver versions with leading "v" characters,
|
148
|
+
* e.g. "v1.0.0", we strip the leading "v" and use the rest of the string as the user given specifier
|
149
|
+
* to ensure that it is valid. If it is a non-semver version, we just use the string as is.
|
150
|
+
*
|
151
|
+
* TODO: re-evaluate if this is definitely what we want... Maybe we can just delegate isValid to the
|
152
|
+
* version actions implementation during prompting?
|
153
|
+
*/
|
154
|
+
if (options.userGivenSpecifier?.startsWith('v')) {
|
155
|
+
const userGivenSpecifierWithoutLeadingV = options.userGivenSpecifier?.replace(/^v/, '');
|
156
|
+
if (semver.valid(userGivenSpecifierWithoutLeadingV)) {
|
157
|
+
this.userGivenSpecifier = userGivenSpecifierWithoutLeadingV;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
else {
|
161
|
+
this.userGivenSpecifier = options.userGivenSpecifier;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
/**
|
165
|
+
* Initialize the processor by building the group graph and preparing for processing.
|
166
|
+
* This method must be called before processGroups().
|
167
|
+
*/
|
168
|
+
async init() {
|
169
|
+
// Precompute project to release group mapping for O(1) lookups
|
170
|
+
this.setupProjectReleaseGroupMapping();
|
171
|
+
// Setup projects to process and resolve version actions
|
172
|
+
await this.setupProjectsToProcess();
|
173
|
+
// Precompute dependency relationships
|
174
|
+
await this.precomputeDependencyRelationships();
|
175
|
+
// Process dependency graph to find dependents to process
|
176
|
+
this.findDependentsToProcess();
|
177
|
+
// Build the group graph structure
|
178
|
+
for (const group of this.releaseGroups) {
|
179
|
+
this.groupGraph.set(group.name, {
|
180
|
+
group,
|
181
|
+
dependencies: new Set(),
|
182
|
+
dependents: new Set(),
|
183
|
+
});
|
184
|
+
}
|
185
|
+
// Process each project within each release group
|
186
|
+
for (const [, releaseGroupNode] of this.groupGraph) {
|
187
|
+
for (const projectName of releaseGroupNode.group.projects) {
|
188
|
+
const projectGraphNode = this.projectGraph.nodes[projectName];
|
189
|
+
// Check if the project has been filtered out of explicit versioning before continuing any further
|
190
|
+
if (!this.allProjectsToProcess.has(projectName)) {
|
191
|
+
continue;
|
192
|
+
}
|
193
|
+
const versionActions = this.getVersionActionsForProject(projectName);
|
194
|
+
const finalConfigForProject = this.getFinalConfigForProject(projectName);
|
195
|
+
let latestMatchingGitTag;
|
196
|
+
const releaseTagPattern = releaseGroupNode.group.releaseTagPattern;
|
197
|
+
// Cache the last matching git tag for relevant projects
|
198
|
+
if (finalConfigForProject.currentVersionResolver === 'git-tag') {
|
199
|
+
latestMatchingGitTag = await (0, git_1.getLatestGitTagForPattern)(releaseTagPattern, {
|
200
|
+
projectName: projectGraphNode.name,
|
201
|
+
}, releaseGroupNode.group.releaseTagPatternCheckAllBranchesWhen);
|
202
|
+
this.cachedLatestMatchingGitTag.set(projectName, latestMatchingGitTag);
|
203
|
+
}
|
204
|
+
// Cache the current version for the project
|
205
|
+
const currentVersion = await (0, resolve_current_version_1.resolveCurrentVersion)(this.tree, projectGraphNode, releaseGroupNode.group, versionActions, this.projectLoggers.get(projectName), this.currentVersionsPerFixedReleaseGroup, finalConfigForProject, releaseTagPattern, latestMatchingGitTag);
|
206
|
+
this.cachedCurrentVersions.set(projectName, currentVersion);
|
207
|
+
}
|
208
|
+
// Ensure that there is an entry in versionData for each project being processed, even if they don't end up being bumped
|
209
|
+
for (const projectName of this.allProjectsToProcess) {
|
210
|
+
this.versionData.set(projectName, {
|
211
|
+
currentVersion: this.getCurrentCachedVersionForProject(projectName),
|
212
|
+
newVersion: null,
|
213
|
+
dependentProjects: this.getOriginalDependentProjects(projectName),
|
214
|
+
});
|
215
|
+
}
|
216
|
+
}
|
217
|
+
// Build the dependency relationships between groups
|
218
|
+
this.buildGroupDependencyGraph();
|
219
|
+
// Topologically sort the release groups and projects for efficient processing
|
220
|
+
this.sortedReleaseGroups = this.topologicallySortReleaseGroups();
|
221
|
+
// Sort projects within each release group
|
222
|
+
for (const group of this.releaseGroups) {
|
223
|
+
this.sortedProjects.set(group.name, this.topologicallySortProjects(group));
|
224
|
+
}
|
225
|
+
// Populate the dependent projects data
|
226
|
+
await this.populateDependentProjectsData();
|
227
|
+
}
|
228
|
+
/**
|
229
|
+
* Setup mapping from project to release group and cache updateDependents settings
|
230
|
+
*/
|
231
|
+
setupProjectReleaseGroupMapping() {
|
232
|
+
for (const group of this.releaseGroups) {
|
233
|
+
for (const project of group.projects) {
|
234
|
+
this.projectToReleaseGroup.set(project, group);
|
235
|
+
// Cache updateDependents setting relevant for each project
|
236
|
+
const updateDependents = group.version
|
237
|
+
?.updateDependents || 'auto';
|
238
|
+
this.projectToUpdateDependentsSetting.set(project, updateDependents);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
/**
|
243
|
+
* Determine which projects should be processed and resolve their version actions
|
244
|
+
*/
|
245
|
+
async setupProjectsToProcess() {
|
246
|
+
// Track the projects being directly versioned
|
247
|
+
let projectsToProcess = new Set();
|
248
|
+
// Precompute all projects in nx release config
|
249
|
+
for (const [groupName, group] of Object.entries(this.nxReleaseConfig.groups)) {
|
250
|
+
for (const project of group.projects) {
|
251
|
+
this.allProjectsConfiguredForNxRelease.add(project);
|
252
|
+
// Create a project logger for the project
|
253
|
+
this.projectLoggers.set(project, new project_logger_1.ProjectLogger(project));
|
254
|
+
// If group filtering is applied and the current group is captured by the filter, add the project to the projectsToProcess
|
255
|
+
if (this.options.filters.groups?.includes(groupName)) {
|
256
|
+
projectsToProcess.add(project);
|
257
|
+
// Otherwise, if project filtering is applied and the current project is captured by the filter, add the project to the projectsToProcess
|
258
|
+
}
|
259
|
+
else if (this.options.filters.projects?.includes(project)) {
|
260
|
+
projectsToProcess.add(project);
|
261
|
+
}
|
262
|
+
const projectGraphNode = this.projectGraph.nodes[project];
|
263
|
+
/**
|
264
|
+
* Try and resolve a cached ReleaseGroupWithName for the project. It may not be present
|
265
|
+
* if the user filtered by group and excluded this parent group from direct versioning,
|
266
|
+
* so fallback to the release group config and apply the name manually.
|
267
|
+
*/
|
268
|
+
let releaseGroup = this.projectToReleaseGroup.get(project);
|
269
|
+
if (!releaseGroup) {
|
270
|
+
releaseGroup = {
|
271
|
+
...group,
|
272
|
+
name: groupName,
|
273
|
+
resolvedVersionPlans: false,
|
274
|
+
};
|
275
|
+
}
|
276
|
+
// Resolve the final configuration for the project
|
277
|
+
const finalConfigForProject = this.resolveFinalConfigForProject(releaseGroup, projectGraphNode);
|
278
|
+
this.finalConfigsByProject.set(project, finalConfigForProject);
|
279
|
+
const { versionActionsPath, versionActions, afterAllProjectsVersioned, } = await (0, version_actions_1.resolveVersionActionsForProject)(this.tree, releaseGroup, projectGraphNode, finalConfigForProject);
|
280
|
+
if (!this.uniqueAfterAllProjectsVersioned.has(versionActionsPath)) {
|
281
|
+
this.uniqueAfterAllProjectsVersioned.set(versionActionsPath, afterAllProjectsVersioned);
|
282
|
+
}
|
283
|
+
this.projectsToVersionActions.set(project, versionActions);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
// If no filters are applied, process all projects
|
287
|
+
if (!this.options.filters.groups?.length &&
|
288
|
+
!this.options.filters.projects?.length) {
|
289
|
+
projectsToProcess = this.allProjectsConfiguredForNxRelease;
|
290
|
+
}
|
291
|
+
// If no projects are set to be processed, throw an error. This should be impossible because the filter validation in version.ts should have already caught this
|
292
|
+
if (projectsToProcess.size === 0) {
|
293
|
+
throw new Error('No projects are set to be processed, please report this as a bug on https://github.com/nrwl/nx/issues');
|
294
|
+
}
|
295
|
+
this.allProjectsToProcess = new Set(projectsToProcess);
|
296
|
+
}
|
297
|
+
/**
|
298
|
+
* Find all dependents that should be processed due to dependency updates
|
299
|
+
*/
|
300
|
+
findDependentsToProcess() {
|
301
|
+
const projectsToProcess = Array.from(this.allProjectsToProcess);
|
302
|
+
const allTrackedDependents = new Set();
|
303
|
+
const dependentsToProcess = new Set();
|
304
|
+
// BFS traversal of dependency graph to find all transitive dependents
|
305
|
+
let currentLevel = [...projectsToProcess];
|
306
|
+
while (currentLevel.length > 0) {
|
307
|
+
const nextLevel = [];
|
308
|
+
// Get all dependents for the current level at once
|
309
|
+
const dependents = this.getAllNonImplicitDependents(currentLevel);
|
310
|
+
// Process each dependent
|
311
|
+
for (const dep of dependents) {
|
312
|
+
// Skip if we've already seen this dependent or it's already in projectsToProcess
|
313
|
+
if (allTrackedDependents.has(dep) ||
|
314
|
+
this.allProjectsToProcess.has(dep)) {
|
315
|
+
continue;
|
316
|
+
}
|
317
|
+
// Track that we've seen this dependent
|
318
|
+
allTrackedDependents.add(dep);
|
319
|
+
// If both the dependent and its dependency have updateDependents='auto',
|
320
|
+
// add the dependent to the projects to process
|
321
|
+
if (this.hasAutoUpdateDependents(dep)) {
|
322
|
+
// Check if any of its dependencies in the current level have auto update
|
323
|
+
const hasDependencyWithAutoUpdate = currentLevel.some((proj) => this.hasAutoUpdateDependents(proj) &&
|
324
|
+
this.getProjectDependents(proj).has(dep));
|
325
|
+
if (hasDependencyWithAutoUpdate) {
|
326
|
+
dependentsToProcess.add(dep);
|
327
|
+
}
|
328
|
+
}
|
329
|
+
// Add to next level for traversal
|
330
|
+
nextLevel.push(dep);
|
331
|
+
}
|
332
|
+
// Move to next level
|
333
|
+
currentLevel = nextLevel;
|
334
|
+
}
|
335
|
+
// Add all dependents that should be processed to allProjectsToProcess
|
336
|
+
dependentsToProcess.forEach((dep) => this.allProjectsToProcess.add(dep));
|
337
|
+
}
|
338
|
+
buildGroupDependencyGraph() {
|
339
|
+
for (const [releaseGroupName, releaseGroupNode] of this.groupGraph) {
|
340
|
+
for (const projectName of releaseGroupNode.group.projects) {
|
341
|
+
const projectDeps = this.getProjectDependencies(projectName);
|
342
|
+
for (const dep of projectDeps) {
|
343
|
+
const dependencyGroup = this.getReleaseGroupNameForProject(dep);
|
344
|
+
if (dependencyGroup && dependencyGroup !== releaseGroupName) {
|
345
|
+
releaseGroupNode.dependencies.add(dependencyGroup);
|
346
|
+
this.groupGraph
|
347
|
+
.get(dependencyGroup)
|
348
|
+
.dependents.add(releaseGroupName);
|
349
|
+
}
|
350
|
+
}
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
async populateDependentProjectsData() {
|
355
|
+
for (const [projectName, dependentProjectNames] of this
|
356
|
+
.tmpCachedDependentProjects) {
|
357
|
+
const dependentProjectsData = [];
|
358
|
+
for (const dependentProjectName of dependentProjectNames) {
|
359
|
+
const versionActions = this.getVersionActionsForProject(dependentProjectName);
|
360
|
+
const { currentVersion, dependencyCollection } = await versionActions.readCurrentVersionOfDependency(this.tree, this.projectGraph, projectName);
|
361
|
+
dependentProjectsData.push({
|
362
|
+
source: dependentProjectName,
|
363
|
+
target: projectName,
|
364
|
+
type: 'static',
|
365
|
+
dependencyCollection,
|
366
|
+
rawVersionSpec: currentVersion,
|
367
|
+
});
|
368
|
+
}
|
369
|
+
this.originalDependentProjectsPerProject.set(projectName, dependentProjectsData);
|
370
|
+
}
|
371
|
+
}
|
372
|
+
getReleaseGroupNameForProject(projectName) {
|
373
|
+
const group = this.projectToReleaseGroup.get(projectName);
|
374
|
+
return group ? group.name : null;
|
375
|
+
}
|
376
|
+
getNextGroup() {
|
377
|
+
for (const [groupName, groupNode] of this.groupGraph) {
|
378
|
+
if (!this.processedGroups.has(groupName) &&
|
379
|
+
Array.from(groupNode.dependencies).every((dep) => this.processedGroups.has(dep))) {
|
380
|
+
return groupName;
|
381
|
+
}
|
382
|
+
}
|
383
|
+
return null;
|
384
|
+
}
|
385
|
+
async processGroups() {
|
386
|
+
const processOrder = [];
|
387
|
+
// Use the topologically sorted groups instead of getNextGroup
|
388
|
+
for (const nextGroup of this.sortedReleaseGroups) {
|
389
|
+
// Skip groups that have already been processed (could happen with circular dependencies)
|
390
|
+
if (this.processedGroups.has(nextGroup)) {
|
391
|
+
continue;
|
392
|
+
}
|
393
|
+
const allDependenciesProcessed = Array.from(this.groupGraph.get(nextGroup).dependencies).every((dep) => this.processedGroups.has(dep));
|
394
|
+
if (!allDependenciesProcessed) {
|
395
|
+
// If we encounter a group whose dependencies aren't all processed,
|
396
|
+
// it means there's a circular dependency that our topological sort broke.
|
397
|
+
// We need to process any unprocessed dependencies first.
|
398
|
+
for (const dep of this.groupGraph.get(nextGroup).dependencies) {
|
399
|
+
if (!this.processedGroups.has(dep)) {
|
400
|
+
await this.processGroup(dep);
|
401
|
+
this.processedGroups.add(dep);
|
402
|
+
processOrder.push(dep);
|
403
|
+
}
|
404
|
+
}
|
405
|
+
}
|
406
|
+
await this.processGroup(nextGroup);
|
407
|
+
this.processedGroups.add(nextGroup);
|
408
|
+
processOrder.push(nextGroup);
|
409
|
+
}
|
410
|
+
return processOrder;
|
411
|
+
}
|
412
|
+
flushAllProjectLoggers() {
|
413
|
+
for (const projectLogger of this.projectLoggers.values()) {
|
414
|
+
projectLogger.flush();
|
415
|
+
}
|
416
|
+
}
|
417
|
+
deleteProcessedVersionPlanFiles() {
|
418
|
+
for (const versionPlanPath of this.processedVersionPlanFiles) {
|
419
|
+
this.tree.delete(versionPlanPath);
|
420
|
+
}
|
421
|
+
}
|
422
|
+
getVersionData() {
|
423
|
+
return Object.fromEntries(this.versionData);
|
424
|
+
}
|
425
|
+
/**
|
426
|
+
* Invoke the afterAllProjectsVersioned functions for each unique versionActions type.
|
427
|
+
* This can be useful for performing actions like updating a workspace level lock file.
|
428
|
+
*
|
429
|
+
* Because the tree has already been flushed to disk at this point, each afterAllProjectsVersioned
|
430
|
+
* function is responsible for returning the list of changed and deleted files that it affected.
|
431
|
+
*
|
432
|
+
* The root level `release.version.versionActionsOptions` is what is passed in here because this
|
433
|
+
* is a one time action for the whole workspace. Release group and project level overrides are
|
434
|
+
* not applicable.
|
435
|
+
*/
|
436
|
+
async afterAllProjectsVersioned(rootVersionActionsOptions) {
|
437
|
+
const changedFiles = new Set();
|
438
|
+
const deletedFiles = new Set();
|
439
|
+
for (const [, afterAllProjectsVersioned] of this
|
440
|
+
.uniqueAfterAllProjectsVersioned) {
|
441
|
+
const { changedFiles: changedFilesForVersionActions, deletedFiles: deletedFilesForVersionActions, } = await afterAllProjectsVersioned(this.tree.root, {
|
442
|
+
dryRun: this.options.dryRun,
|
443
|
+
verbose: this.options.verbose,
|
444
|
+
rootVersionActionsOptions,
|
445
|
+
});
|
446
|
+
for (const file of changedFilesForVersionActions) {
|
447
|
+
changedFiles.add(file);
|
448
|
+
}
|
449
|
+
for (const file of deletedFilesForVersionActions) {
|
450
|
+
deletedFiles.add(file);
|
451
|
+
}
|
452
|
+
}
|
453
|
+
return {
|
454
|
+
changedFiles: Array.from(changedFiles),
|
455
|
+
deletedFiles: Array.from(deletedFiles),
|
456
|
+
};
|
457
|
+
}
|
458
|
+
async processGroup(releaseGroupName) {
|
459
|
+
const groupNode = this.groupGraph.get(releaseGroupName);
|
460
|
+
const bumped = await this.bumpVersions(groupNode.group);
|
461
|
+
// Flush the project loggers for the group
|
462
|
+
for (const project of groupNode.group.projects) {
|
463
|
+
const projectLogger = this.getProjectLoggerForProject(project);
|
464
|
+
projectLogger.flush();
|
465
|
+
}
|
466
|
+
if (bumped) {
|
467
|
+
await this.propagateChangesToDependentGroups(releaseGroupName);
|
468
|
+
}
|
469
|
+
}
|
470
|
+
async propagateChangesToDependentGroups(changedReleaseGroupName) {
|
471
|
+
const changedGroupNode = this.groupGraph.get(changedReleaseGroupName);
|
472
|
+
for (const depGroupName of changedGroupNode.dependents) {
|
473
|
+
if (!this.processedGroups.has(depGroupName)) {
|
474
|
+
await this.propagateChanges(depGroupName, changedReleaseGroupName);
|
475
|
+
}
|
476
|
+
}
|
477
|
+
}
|
478
|
+
async bumpVersions(releaseGroup) {
|
479
|
+
if (releaseGroup.projectsRelationship === 'fixed') {
|
480
|
+
return this.bumpFixedVersionGroup(releaseGroup);
|
481
|
+
}
|
482
|
+
else {
|
483
|
+
return this.bumpIndependentVersionGroup(releaseGroup);
|
484
|
+
}
|
485
|
+
}
|
486
|
+
async bumpFixedVersionGroup(releaseGroup) {
|
487
|
+
if (releaseGroup.projects.length === 0) {
|
488
|
+
return false;
|
489
|
+
}
|
490
|
+
let bumped = false;
|
491
|
+
const firstProject = releaseGroup.projects[0];
|
492
|
+
const { newVersionInput, newVersionInputReason, newVersionInputReasonData, } = await this.determineVersionBumpForProject(releaseGroup, firstProject);
|
493
|
+
if (newVersionInput === 'none') {
|
494
|
+
// No direct bump for this group, but we may still need to bump if a dependency group has been bumped
|
495
|
+
let bumpedByDependency = false;
|
496
|
+
// Use sorted projects to check for dependencies in processed groups
|
497
|
+
const sortedProjects = this.sortedProjects.get(releaseGroup.name) || [];
|
498
|
+
// Iterate through each project in the release group in topological order
|
499
|
+
for (const project of sortedProjects) {
|
500
|
+
const dependencies = this.projectGraph.dependencies[project] || [];
|
501
|
+
for (const dep of dependencies) {
|
502
|
+
const depGroup = this.getReleaseGroupNameForProject(dep.target);
|
503
|
+
if (depGroup &&
|
504
|
+
depGroup !== releaseGroup.name &&
|
505
|
+
this.processedGroups.has(depGroup)) {
|
506
|
+
const depGroupBumpType = await this.getFixedReleaseGroupBumpType(depGroup);
|
507
|
+
// If a dependency group has been bumped, determine if it should trigger a bump in this group
|
508
|
+
if (depGroupBumpType !== 'none') {
|
509
|
+
bumpedByDependency = true;
|
510
|
+
const depBumpType = this.determineSideEffectBump(releaseGroup, depGroupBumpType);
|
511
|
+
await this.bumpVersionForProject(project, depBumpType, 'DEPENDENCY_ACROSS_GROUPS_WAS_BUMPED', {});
|
512
|
+
this.bumpedProjects.add(project);
|
513
|
+
// Update any dependencies in the manifest
|
514
|
+
await this.updateDependenciesForProject(project);
|
515
|
+
}
|
516
|
+
}
|
517
|
+
}
|
518
|
+
}
|
519
|
+
// If any project in the group was bumped due to dependency changes, we must bump all projects in the fixed group
|
520
|
+
if (bumpedByDependency) {
|
521
|
+
// Update all projects in topological order
|
522
|
+
for (const project of sortedProjects) {
|
523
|
+
if (!this.bumpedProjects.has(project)) {
|
524
|
+
await this.bumpVersionForProject(project, 'patch', 'OTHER_PROJECT_IN_FIXED_GROUP_WAS_BUMPED_DUE_TO_DEPENDENCY', {});
|
525
|
+
// Ensure the bump for remaining projects
|
526
|
+
this.bumpedProjects.add(project);
|
527
|
+
await this.updateDependenciesForProject(project);
|
528
|
+
}
|
529
|
+
}
|
530
|
+
}
|
531
|
+
else {
|
532
|
+
/**
|
533
|
+
* No projects in the group are being bumped, but as it stands only the first project would have an appropriate log,
|
534
|
+
* therefore add in an extra log for each additional project in the group, and we also need to make sure that the
|
535
|
+
* versionData is fully populated.
|
536
|
+
*/
|
537
|
+
for (const project of releaseGroup.projects) {
|
538
|
+
this.versionData.set(project, {
|
539
|
+
currentVersion: this.getCurrentCachedVersionForProject(project),
|
540
|
+
newVersion: null,
|
541
|
+
dependentProjects: this.getOriginalDependentProjects(project),
|
542
|
+
});
|
543
|
+
if (project === firstProject) {
|
544
|
+
continue;
|
545
|
+
}
|
546
|
+
const projectLogger = this.getProjectLoggerForProject(project);
|
547
|
+
projectLogger.buffer(`🚫 Skipping versioning for ${project} as it is a part of a fixed release group with ${firstProject} and no dependency bumps were detected`);
|
548
|
+
}
|
549
|
+
}
|
550
|
+
return bumpedByDependency;
|
551
|
+
}
|
552
|
+
const { newVersion } = await this.calculateNewVersion(firstProject, newVersionInput, newVersionInputReason, newVersionInputReasonData);
|
553
|
+
// Use sorted projects for processing projects in the right order
|
554
|
+
const sortedProjects = this.sortedProjects.get(releaseGroup.name) || releaseGroup.projects;
|
555
|
+
// First, update versions for all projects in the fixed group in topological order
|
556
|
+
for (const project of sortedProjects) {
|
557
|
+
const versionActions = this.getVersionActionsForProject(project);
|
558
|
+
const projectLogger = this.getProjectLoggerForProject(project);
|
559
|
+
const currentVersion = this.getCurrentCachedVersionForProject(project);
|
560
|
+
// The first project's version was determined above, so this log is only appropriate for the remaining projects
|
561
|
+
if (project !== firstProject) {
|
562
|
+
projectLogger.buffer(`❓ Applied version ${newVersion} directly, because the project is a member of a fixed release group containing ${firstProject}`);
|
563
|
+
}
|
564
|
+
/**
|
565
|
+
* Update the project's version based on the implementation details of the configured VersionActions
|
566
|
+
* and display any returned log messages to the user.
|
567
|
+
*/
|
568
|
+
const logMessages = await versionActions.updateProjectVersion(this.tree, newVersion);
|
569
|
+
for (const logMessage of logMessages) {
|
570
|
+
projectLogger.buffer(logMessage);
|
571
|
+
}
|
572
|
+
this.bumpedProjects.add(project);
|
573
|
+
bumped = true;
|
574
|
+
// Populate version data for each project
|
575
|
+
this.versionData.set(project, {
|
576
|
+
currentVersion,
|
577
|
+
newVersion,
|
578
|
+
dependentProjects: this.getOriginalDependentProjects(project),
|
579
|
+
});
|
580
|
+
}
|
581
|
+
// Then, update dependencies for all projects in the fixed group, also in topological order
|
582
|
+
if (bumped) {
|
583
|
+
for (const project of sortedProjects) {
|
584
|
+
await this.updateDependenciesForProject(project);
|
585
|
+
}
|
586
|
+
}
|
587
|
+
return bumped;
|
588
|
+
}
|
589
|
+
async bumpIndependentVersionGroup(releaseGroup) {
|
590
|
+
const releaseGroupFilteredProjects = this.releaseGroupToFilteredProjects.get(releaseGroup);
|
591
|
+
let bumped = false;
|
592
|
+
const projectBumpTypes = new Map();
|
593
|
+
const projectsToUpdate = new Set();
|
594
|
+
// First pass: Determine bump types
|
595
|
+
for (const project of this.allProjectsToProcess) {
|
596
|
+
const { newVersionInput: bumpType, newVersionInputReason: bumpTypeReason, newVersionInputReasonData: bumpTypeReasonData, } = await this.determineVersionBumpForProject(releaseGroup, project);
|
597
|
+
projectBumpTypes.set(project, {
|
598
|
+
bumpType,
|
599
|
+
bumpTypeReason,
|
600
|
+
bumpTypeReasonData,
|
601
|
+
});
|
602
|
+
if (bumpType !== 'none') {
|
603
|
+
projectsToUpdate.add(project);
|
604
|
+
}
|
605
|
+
}
|
606
|
+
// Second pass: Update versions using topologically sorted projects
|
607
|
+
// This ensures dependencies are processed before dependents
|
608
|
+
const sortedProjects = this.sortedProjects.get(releaseGroup.name) || [];
|
609
|
+
// Process projects in topological order
|
610
|
+
for (const project of sortedProjects) {
|
611
|
+
if (projectsToUpdate.has(project) &&
|
612
|
+
releaseGroupFilteredProjects.has(project)) {
|
613
|
+
const { bumpType: finalBumpType, bumpTypeReason: finalBumpTypeReason, bumpTypeReasonData: finalBumpTypeReasonData, } = projectBumpTypes.get(project);
|
614
|
+
if (finalBumpType !== 'none') {
|
615
|
+
await this.bumpVersionForProject(project, finalBumpType, finalBumpTypeReason, finalBumpTypeReasonData);
|
616
|
+
this.bumpedProjects.add(project);
|
617
|
+
bumped = true;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
}
|
621
|
+
// Third pass: Update dependencies also in topological order
|
622
|
+
for (const project of sortedProjects) {
|
623
|
+
if (projectsToUpdate.has(project) &&
|
624
|
+
releaseGroupFilteredProjects.has(project)) {
|
625
|
+
await this.updateDependenciesForProject(project);
|
626
|
+
}
|
627
|
+
}
|
628
|
+
return bumped;
|
629
|
+
}
|
630
|
+
async determineVersionBumpForProject(releaseGroup, projectName) {
|
631
|
+
// User given specifier has the highest precedence
|
632
|
+
if (this.userGivenSpecifier) {
|
633
|
+
return {
|
634
|
+
newVersionInput: this.userGivenSpecifier,
|
635
|
+
newVersionInputReason: 'USER_SPECIFIER',
|
636
|
+
newVersionInputReasonData: {},
|
637
|
+
};
|
638
|
+
}
|
639
|
+
const projectGraphNode = this.projectGraph.nodes[projectName];
|
640
|
+
const projectLogger = this.getProjectLoggerForProject(projectName);
|
641
|
+
const cachedFinalConfigForProject = this.getCachedFinalConfigForProject(projectName);
|
642
|
+
if (cachedFinalConfigForProject.specifierSource === 'conventional-commits') {
|
643
|
+
const currentVersion = this.getCurrentCachedVersionForProject(projectName);
|
644
|
+
const bumpType = await (0, derive_specifier_from_conventional_commits_1.deriveSpecifierFromConventionalCommits)(this.nxReleaseConfig, this.projectGraph, projectLogger, releaseGroup, projectGraphNode, !!semver.prerelease(currentVersion ?? ''), this.cachedLatestMatchingGitTag.get(projectName), cachedFinalConfigForProject.fallbackCurrentVersionResolver, this.options.preid);
|
645
|
+
return {
|
646
|
+
newVersionInput: bumpType,
|
647
|
+
newVersionInputReason: 'CONVENTIONAL_COMMITS',
|
648
|
+
newVersionInputReasonData: {},
|
649
|
+
};
|
650
|
+
}
|
651
|
+
// Resolve the semver relative bump via version-plans
|
652
|
+
if (releaseGroup.versionPlans) {
|
653
|
+
const currentVersion = this.getCurrentCachedVersionForProject(projectName);
|
654
|
+
const { bumpType, versionPlanPath } = await (0, deriver_specifier_from_version_plans_1.deriveSpecifierFromVersionPlan)(projectLogger, releaseGroup, projectGraphNode, currentVersion);
|
655
|
+
if (bumpType !== 'none') {
|
656
|
+
this.processedVersionPlanFiles.add(versionPlanPath);
|
657
|
+
}
|
658
|
+
return {
|
659
|
+
newVersionInput: bumpType,
|
660
|
+
newVersionInputReason: 'VERSION_PLANS',
|
661
|
+
newVersionInputReasonData: {
|
662
|
+
versionPlanPath,
|
663
|
+
},
|
664
|
+
};
|
665
|
+
}
|
666
|
+
// Only add the release group name to the log if it is one set by the user, otherwise it is useless noise
|
667
|
+
const maybeLogReleaseGroup = (log) => {
|
668
|
+
if (releaseGroup.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
|
669
|
+
return log;
|
670
|
+
}
|
671
|
+
return `${log} within release group "${releaseGroup.name}"`;
|
672
|
+
};
|
673
|
+
if (cachedFinalConfigForProject.specifierSource === 'prompt') {
|
674
|
+
let specifier;
|
675
|
+
if (releaseGroup.projectsRelationship === 'independent') {
|
676
|
+
specifier = await (0, resolve_semver_specifier_1.resolveSemverSpecifierFromPrompt)(`${maybeLogReleaseGroup(`What kind of change is this for project "${projectName}"`)}?`, `${maybeLogReleaseGroup(`What is the exact version for project "${projectName}"`)}?`);
|
677
|
+
}
|
678
|
+
else {
|
679
|
+
specifier = await (0, resolve_semver_specifier_1.resolveSemverSpecifierFromPrompt)(`${maybeLogReleaseGroup(`What kind of change is this for the ${releaseGroup.projects.length} matched projects(s)`)}?`, `${maybeLogReleaseGroup(`What is the exact version for the ${releaseGroup.projects.length} matched project(s)`)}?`);
|
680
|
+
}
|
681
|
+
return {
|
682
|
+
newVersionInput: specifier,
|
683
|
+
newVersionInputReason: 'PROMPTED_USER_SPECIFIER',
|
684
|
+
newVersionInputReasonData: {},
|
685
|
+
};
|
686
|
+
}
|
687
|
+
throw new Error(`Unhandled version bump config, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
688
|
+
}
|
689
|
+
getVersionActionsForProject(projectName) {
|
690
|
+
const versionActions = this.projectsToVersionActions.get(projectName);
|
691
|
+
if (!versionActions) {
|
692
|
+
throw new Error(`No versionActions found for project ${projectName}, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
693
|
+
}
|
694
|
+
return versionActions;
|
695
|
+
}
|
696
|
+
getFinalConfigForProject(projectName) {
|
697
|
+
const finalConfig = this.finalConfigsByProject.get(projectName);
|
698
|
+
if (!finalConfig) {
|
699
|
+
throw new Error(`No final config found for project ${projectName}, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
700
|
+
}
|
701
|
+
return finalConfig;
|
702
|
+
}
|
703
|
+
getProjectLoggerForProject(projectName) {
|
704
|
+
const projectLogger = this.projectLoggers.get(projectName);
|
705
|
+
if (!projectLogger) {
|
706
|
+
throw new Error(`No project logger found for project ${projectName}, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
707
|
+
}
|
708
|
+
return projectLogger;
|
709
|
+
}
|
710
|
+
getCurrentCachedVersionForProject(projectName) {
|
711
|
+
return this.cachedCurrentVersions.get(projectName);
|
712
|
+
}
|
713
|
+
getCachedFinalConfigForProject(projectName) {
|
714
|
+
const cachedFinalConfig = this.finalConfigsByProject.get(projectName);
|
715
|
+
if (!cachedFinalConfig) {
|
716
|
+
throw new Error(`Unexpected error: No cached config found for project ${projectName}, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
717
|
+
}
|
718
|
+
return cachedFinalConfig;
|
719
|
+
}
|
720
|
+
/**
|
721
|
+
* Apply project and release group precedence and default values, as well as validate the final configuration,
|
722
|
+
* ready to be cached.
|
723
|
+
*/
|
724
|
+
resolveFinalConfigForProject(releaseGroup, projectGraphNode) {
|
725
|
+
const releaseGroupVersionConfig = releaseGroup.version;
|
726
|
+
const projectVersionConfig = projectGraphNode.data.release?.version;
|
727
|
+
/**
|
728
|
+
* specifierSource
|
729
|
+
*
|
730
|
+
* If the user has provided a specifier, it always takes precedence,
|
731
|
+
* so the effective specifier source is 'prompt', regardless of what
|
732
|
+
* the project or release group config says.
|
733
|
+
*/
|
734
|
+
const specifierSource = this.userGivenSpecifier
|
735
|
+
? 'prompt'
|
736
|
+
: projectVersionConfig?.specifierSource ??
|
737
|
+
releaseGroupVersionConfig?.specifierSource ??
|
738
|
+
'prompt';
|
739
|
+
/**
|
740
|
+
* versionPrefix, defaults to auto
|
741
|
+
*/
|
742
|
+
const versionPrefix = projectVersionConfig?.versionPrefix ??
|
743
|
+
releaseGroupVersionConfig?.versionPrefix ??
|
744
|
+
'auto';
|
745
|
+
if (versionPrefix && !version_1.validReleaseVersionPrefixes.includes(versionPrefix)) {
|
746
|
+
throw new Error(`Invalid value for versionPrefix: "${versionPrefix}"
|
747
|
+
|
748
|
+
Valid values are: ${version_1.validReleaseVersionPrefixes
|
749
|
+
.map((s) => `"${s}"`)
|
750
|
+
.join(', ')}`);
|
751
|
+
}
|
752
|
+
/**
|
753
|
+
* currentVersionResolver, defaults to disk
|
754
|
+
*/
|
755
|
+
const currentVersionResolver = projectVersionConfig?.currentVersionResolver ??
|
756
|
+
releaseGroupVersionConfig?.currentVersionResolver ??
|
757
|
+
'disk';
|
758
|
+
if (specifierSource === 'conventional-commits' &&
|
759
|
+
currentVersionResolver !== 'git-tag') {
|
760
|
+
throw new Error(`Invalid currentVersionResolver "${currentVersionResolver}" provided for project "${projectGraphNode.name}". Must be "git-tag" when "specifierSource" is "conventional-commits"`);
|
761
|
+
}
|
762
|
+
/**
|
763
|
+
* currentVersionResolverMetadata, defaults to {}
|
764
|
+
*/
|
765
|
+
const currentVersionResolverMetadata = projectVersionConfig?.currentVersionResolverMetadata ??
|
766
|
+
releaseGroupVersionConfig?.currentVersionResolverMetadata ??
|
767
|
+
{};
|
768
|
+
/**
|
769
|
+
* preserveLocalDependencyProtocols
|
770
|
+
*
|
771
|
+
* This was false by default in legacy versioning, but is true by default now.
|
772
|
+
*/
|
773
|
+
const preserveLocalDependencyProtocols = projectVersionConfig?.preserveLocalDependencyProtocols ??
|
774
|
+
releaseGroupVersionConfig?.preserveLocalDependencyProtocols ??
|
775
|
+
true;
|
776
|
+
/**
|
777
|
+
* fallbackCurrentVersionResolver, defaults to disk when performing a first release, otherwise undefined
|
778
|
+
*/
|
779
|
+
const fallbackCurrentVersionResolver = projectVersionConfig?.fallbackCurrentVersionResolver ??
|
780
|
+
releaseGroupVersionConfig?.fallbackCurrentVersionResolver ??
|
781
|
+
// Always fall back to disk if this is the first release
|
782
|
+
(this.options.firstRelease ? 'disk' : undefined);
|
783
|
+
/**
|
784
|
+
* versionActionsOptions, defaults to {}
|
785
|
+
*/
|
786
|
+
let versionActionsOptions = projectVersionConfig?.versionActionsOptions ??
|
787
|
+
releaseGroupVersionConfig?.versionActionsOptions ??
|
788
|
+
{};
|
789
|
+
// Apply any optional overrides that may be passed in from the programmatic API
|
790
|
+
versionActionsOptions = {
|
791
|
+
...versionActionsOptions,
|
792
|
+
...(this.options.versionActionsOptionsOverrides ?? {}),
|
793
|
+
};
|
794
|
+
const manifestRootsToUpdate = (projectVersionConfig?.manifestRootsToUpdate ??
|
795
|
+
releaseGroupVersionConfig?.manifestRootsToUpdate ??
|
796
|
+
[]).map((manifestRoot) => {
|
797
|
+
if (typeof manifestRoot === 'string') {
|
798
|
+
return {
|
799
|
+
path: manifestRoot,
|
800
|
+
// Apply the project level preserveLocalDependencyProtocols setting that was already resolved
|
801
|
+
preserveLocalDependencyProtocols,
|
802
|
+
};
|
803
|
+
}
|
804
|
+
return manifestRoot;
|
805
|
+
});
|
806
|
+
return {
|
807
|
+
specifierSource,
|
808
|
+
currentVersionResolver,
|
809
|
+
currentVersionResolverMetadata,
|
810
|
+
fallbackCurrentVersionResolver,
|
811
|
+
versionPrefix,
|
812
|
+
preserveLocalDependencyProtocols,
|
813
|
+
versionActionsOptions,
|
814
|
+
manifestRootsToUpdate,
|
815
|
+
};
|
816
|
+
}
|
817
|
+
async calculateNewVersion(project, newVersionInput, // any arbitrary string, whether or not it is valid is dependent upon the version actions implementation
|
818
|
+
newVersionInputReason, newVersionInputReasonData) {
|
819
|
+
const currentVersion = this.getCurrentCachedVersionForProject(project);
|
820
|
+
const versionActions = this.getVersionActionsForProject(project);
|
821
|
+
const { newVersion, logText } = await versionActions.calculateNewVersion(currentVersion, newVersionInput, newVersionInputReason, newVersionInputReasonData, this.options.preid);
|
822
|
+
const projectLogger = this.getProjectLoggerForProject(project);
|
823
|
+
projectLogger.buffer(logText);
|
824
|
+
return { currentVersion, newVersion };
|
825
|
+
}
|
826
|
+
async updateDependenciesForProject(projectName) {
|
827
|
+
if (!this.allProjectsToProcess.has(projectName)) {
|
828
|
+
throw new Error(`Unable to find ${projectName} in allProjectsToProcess, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
829
|
+
}
|
830
|
+
const versionActions = this.getVersionActionsForProject(projectName);
|
831
|
+
const cachedFinalConfigForProject = this.getCachedFinalConfigForProject(projectName);
|
832
|
+
const dependenciesToUpdate = {};
|
833
|
+
const dependencies = this.projectGraph.dependencies[projectName] || [];
|
834
|
+
for (const dep of dependencies) {
|
835
|
+
if (this.allProjectsToProcess.has(dep.target) &&
|
836
|
+
this.bumpedProjects.has(dep.target)) {
|
837
|
+
const targetVersionData = this.versionData.get(dep.target);
|
838
|
+
if (targetVersionData) {
|
839
|
+
const { currentVersion: currentDependencyVersion } = await versionActions.readCurrentVersionOfDependency(this.tree, this.projectGraph, dep.target);
|
840
|
+
if (!currentDependencyVersion) {
|
841
|
+
continue;
|
842
|
+
}
|
843
|
+
let finalPrefix = '';
|
844
|
+
if (cachedFinalConfigForProject.versionPrefix === 'auto') {
|
845
|
+
const prefixMatch = currentDependencyVersion?.match(/^([~^=])/);
|
846
|
+
finalPrefix = prefixMatch ? prefixMatch[1] : '';
|
847
|
+
}
|
848
|
+
else if (['~', '^', '='].includes(cachedFinalConfigForProject.versionPrefix)) {
|
849
|
+
finalPrefix = cachedFinalConfigForProject.versionPrefix;
|
850
|
+
}
|
851
|
+
// Remove any existing prefix from the new version before applying the finalPrefix
|
852
|
+
const cleanNewVersion = targetVersionData.newVersion.replace(/^[~^=]/, '');
|
853
|
+
dependenciesToUpdate[dep.target] = `${finalPrefix}${cleanNewVersion}`;
|
854
|
+
}
|
855
|
+
}
|
856
|
+
}
|
857
|
+
const projectLogger = this.getProjectLoggerForProject(projectName);
|
858
|
+
const logMessages = await versionActions.updateProjectDependencies(this.tree, this.projectGraph, dependenciesToUpdate);
|
859
|
+
for (const logMessage of logMessages) {
|
860
|
+
projectLogger.buffer(logMessage);
|
861
|
+
}
|
862
|
+
}
|
863
|
+
async bumpVersionForProject(projectName, bumpType, bumpTypeReason, bumpTypeReasonData) {
|
864
|
+
const projectLogger = this.getProjectLoggerForProject(projectName);
|
865
|
+
if (bumpType === 'none') {
|
866
|
+
projectLogger.buffer(`⏩ Skipping bump for ${projectName} as bump type is "none"`);
|
867
|
+
return;
|
868
|
+
}
|
869
|
+
const versionActions = this.getVersionActionsForProject(projectName);
|
870
|
+
const { currentVersion, newVersion } = await this.calculateNewVersion(projectName, bumpType, bumpTypeReason, bumpTypeReasonData);
|
871
|
+
/**
|
872
|
+
* Update the project's version based on the implementation details of the configured VersionActions
|
873
|
+
* and display any returned log messages to the user.
|
874
|
+
*/
|
875
|
+
const logMessages = await versionActions.updateProjectVersion(this.tree, newVersion);
|
876
|
+
for (const logMessage of logMessages) {
|
877
|
+
projectLogger.buffer(logMessage);
|
878
|
+
}
|
879
|
+
// Update version data and bumped projects
|
880
|
+
this.versionData.set(projectName, {
|
881
|
+
currentVersion,
|
882
|
+
newVersion,
|
883
|
+
dependentProjects: this.getOriginalDependentProjects(projectName),
|
884
|
+
});
|
885
|
+
this.bumpedProjects.add(projectName);
|
886
|
+
// Find the release group for this project
|
887
|
+
const releaseGroupName = this.getReleaseGroupNameForProject(projectName);
|
888
|
+
if (!releaseGroupName) {
|
889
|
+
projectLogger.buffer(`⚠️ Cannot find release group for ${projectName}, skipping dependent updates`);
|
890
|
+
return;
|
891
|
+
}
|
892
|
+
const releaseGroup = this.groupGraph.get(releaseGroupName).group;
|
893
|
+
const releaseGroupVersionConfig = releaseGroup.version;
|
894
|
+
// Get updateDependents from the release group level config
|
895
|
+
const updateDependents = releaseGroupVersionConfig?.updateDependents ||
|
896
|
+
'auto';
|
897
|
+
// Only update dependencies for dependents if the group's updateDependents is 'auto'
|
898
|
+
if (updateDependents === 'auto') {
|
899
|
+
const dependents = this.getNonImplicitDependentsForProject(projectName);
|
900
|
+
await this.updateDependenciesForDependents(dependents);
|
901
|
+
for (const dependent of dependents) {
|
902
|
+
if (this.allProjectsToProcess.has(dependent) &&
|
903
|
+
!this.bumpedProjects.has(dependent)) {
|
904
|
+
await this.bumpVersionForProject(dependent, 'patch', 'DEPENDENCY_WAS_BUMPED', {});
|
905
|
+
}
|
906
|
+
}
|
907
|
+
}
|
908
|
+
else {
|
909
|
+
const releaseGroupText = releaseGroupName !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
|
910
|
+
? ` in release group "${releaseGroupName}" `
|
911
|
+
: ' ';
|
912
|
+
projectLogger.buffer(`⏩ Skipping dependent updates as "updateDependents"${releaseGroupText}is not "auto"`);
|
913
|
+
}
|
914
|
+
}
|
915
|
+
async updateDependenciesForDependents(dependents) {
|
916
|
+
for (const dependent of dependents) {
|
917
|
+
if (!this.allProjectsToProcess.has(dependent)) {
|
918
|
+
throw new Error(`Unable to find project "${dependent}" in allProjectsToProcess, please report this as a bug on https://github.com/nrwl/nx/issues`);
|
919
|
+
}
|
920
|
+
await this.updateDependenciesForProject(dependent);
|
921
|
+
}
|
922
|
+
}
|
923
|
+
getOriginalDependentProjects(project) {
|
924
|
+
return this.originalDependentProjectsPerProject.get(project) || [];
|
925
|
+
}
|
926
|
+
async propagateChanges(releaseGroupName, changedDependencyGroup) {
|
927
|
+
const releaseGroup = this.groupGraph.get(releaseGroupName).group;
|
928
|
+
const releaseGroupFilteredProjects = this.releaseGroupToFilteredProjects.get(releaseGroup);
|
929
|
+
// Get updateDependents from the release group level config
|
930
|
+
const releaseGroupVersionConfig = releaseGroup.version;
|
931
|
+
const updateDependents = releaseGroupVersionConfig?.updateDependents ||
|
932
|
+
'auto';
|
933
|
+
// If updateDependents is not 'auto', skip propagating changes to this group
|
934
|
+
if (updateDependents !== 'auto') {
|
935
|
+
const projectLogger = this.getProjectLoggerForProject(releaseGroupFilteredProjects.values().next().value);
|
936
|
+
projectLogger.buffer(`⏩ Skipping dependency updates for release group "${releaseGroupName}" as "updateDependents" is not "auto"`);
|
937
|
+
return;
|
938
|
+
}
|
939
|
+
let groupBumped = false;
|
940
|
+
let bumpType = 'none';
|
941
|
+
if (releaseGroup.projectsRelationship === 'fixed') {
|
942
|
+
// For fixed groups, we only need to check one project
|
943
|
+
const project = releaseGroupFilteredProjects[0];
|
944
|
+
const dependencies = this.projectGraph.dependencies[project] || [];
|
945
|
+
const hasDependencyInChangedGroup = dependencies.some((dep) => this.getReleaseGroupNameForProject(dep.target) ===
|
946
|
+
changedDependencyGroup);
|
947
|
+
if (hasDependencyInChangedGroup) {
|
948
|
+
const dependencyBumpType = await this.getFixedReleaseGroupBumpType(changedDependencyGroup);
|
949
|
+
bumpType = this.determineSideEffectBump(releaseGroup, dependencyBumpType);
|
950
|
+
groupBumped = bumpType !== 'none';
|
951
|
+
}
|
952
|
+
}
|
953
|
+
if (groupBumped) {
|
954
|
+
for (const project of releaseGroupFilteredProjects) {
|
955
|
+
if (!this.bumpedProjects.has(project)) {
|
956
|
+
await this.bumpVersionForProject(project, bumpType, 'DEPENDENCY_ACROSS_GROUPS_WAS_BUMPED', {});
|
957
|
+
this.bumpedProjects.add(project);
|
958
|
+
}
|
959
|
+
}
|
960
|
+
}
|
961
|
+
}
|
962
|
+
async getFixedReleaseGroupBumpType(releaseGroupName) {
|
963
|
+
const releaseGroup = this.groupGraph.get(releaseGroupName).group;
|
964
|
+
const releaseGroupFilteredProjects = this.releaseGroupToFilteredProjects.get(releaseGroup);
|
965
|
+
if (releaseGroupFilteredProjects.size === 0) {
|
966
|
+
return 'none';
|
967
|
+
}
|
968
|
+
const { newVersionInput } = await this.determineVersionBumpForProject(releaseGroup,
|
969
|
+
// It's a fixed release group, so we can just pick any project in the group
|
970
|
+
releaseGroupFilteredProjects.values().next().value);
|
971
|
+
return newVersionInput;
|
972
|
+
}
|
973
|
+
// TODO: Support influencing the side effect bump in a future version, always patch for now like in legacy versioning
|
974
|
+
determineSideEffectBump(releaseGroup, dependencyBumpType) {
|
975
|
+
const sideEffectBump = 'patch';
|
976
|
+
return sideEffectBump;
|
977
|
+
}
|
978
|
+
getProjectDependents(project) {
|
979
|
+
return this.projectToDependents.get(project) || new Set();
|
980
|
+
}
|
981
|
+
getAllNonImplicitDependents(projects) {
|
982
|
+
return projects
|
983
|
+
.flatMap((project) => {
|
984
|
+
const dependentProjectNames = this.getNonImplicitDependentsForProject(project);
|
985
|
+
this.tmpCachedDependentProjects.set(project, dependentProjectNames);
|
986
|
+
return dependentProjectNames;
|
987
|
+
})
|
988
|
+
.filter((dep) => !this.allProjectsToProcess.has(dep));
|
989
|
+
}
|
990
|
+
getNonImplicitDependentsForProject(project) {
|
991
|
+
// Use the cached dependents for O(1) lookup instead of O(n) scan
|
992
|
+
return Array.from(this.getProjectDependents(project));
|
993
|
+
}
|
994
|
+
hasAutoUpdateDependents(projectName) {
|
995
|
+
return this.projectToUpdateDependentsSetting.get(projectName) === 'auto';
|
996
|
+
}
|
997
|
+
topologicallySortReleaseGroups() {
|
998
|
+
// Get all release group names
|
999
|
+
const groupNames = Array.from(this.groupGraph.keys());
|
1000
|
+
// Function to get dependencies of a group
|
1001
|
+
const getGroupDependencies = (groupName) => {
|
1002
|
+
const groupNode = this.groupGraph.get(groupName);
|
1003
|
+
if (!groupNode) {
|
1004
|
+
return [];
|
1005
|
+
}
|
1006
|
+
return Array.from(groupNode.dependencies);
|
1007
|
+
};
|
1008
|
+
// Perform topological sort
|
1009
|
+
return (0, topological_sort_1.topologicalSort)(groupNames, getGroupDependencies);
|
1010
|
+
}
|
1011
|
+
topologicallySortProjects(releaseGroup) {
|
1012
|
+
// For fixed relationship groups, the order doesn't matter since all projects will
|
1013
|
+
// be versioned identically, but we still sort them for consistency
|
1014
|
+
const projects = releaseGroup.projects.filter((p) =>
|
1015
|
+
// Only include projects that are in allProjectsToProcess
|
1016
|
+
this.allProjectsToProcess.has(p));
|
1017
|
+
// Function to get dependencies of a project that are in the same release group
|
1018
|
+
const getProjectDependenciesInSameGroup = (project) => {
|
1019
|
+
const deps = this.getProjectDependencies(project);
|
1020
|
+
// Only include dependencies that are in the same release group and in allProjectsToProcess
|
1021
|
+
return Array.from(deps).filter((dep) => this.getReleaseGroupNameForProject(dep) === releaseGroup.name &&
|
1022
|
+
this.allProjectsToProcess.has(dep));
|
1023
|
+
};
|
1024
|
+
// Perform topological sort
|
1025
|
+
return (0, topological_sort_1.topologicalSort)(projects, getProjectDependenciesInSameGroup);
|
1026
|
+
}
|
1027
|
+
/**
|
1028
|
+
* Precompute project -> dependents/dependencies relationships for O(1) lookups
|
1029
|
+
*/
|
1030
|
+
async precomputeDependencyRelationships() {
|
1031
|
+
for (const projectName of this.allProjectsConfiguredForNxRelease) {
|
1032
|
+
const versionActions = this.projectsToVersionActions.get(projectName);
|
1033
|
+
// Create a new set for this project's dependencies
|
1034
|
+
if (!this.projectToDependencies.has(projectName)) {
|
1035
|
+
this.projectToDependencies.set(projectName, new Set());
|
1036
|
+
}
|
1037
|
+
const deps = await versionActions.readDependencies(this.tree, this.projectGraph);
|
1038
|
+
for (const dep of deps) {
|
1039
|
+
// Skip dependencies not covered by nx release
|
1040
|
+
if (!this.allProjectsConfiguredForNxRelease.has(dep.target)) {
|
1041
|
+
continue;
|
1042
|
+
}
|
1043
|
+
// Add this dependency to the project's dependencies
|
1044
|
+
this.projectToDependencies.get(projectName).add(dep.target);
|
1045
|
+
// Add this project as a dependent of the target
|
1046
|
+
if (!this.projectToDependents.has(dep.target)) {
|
1047
|
+
this.projectToDependents.set(dep.target, new Set());
|
1048
|
+
}
|
1049
|
+
this.projectToDependents.get(dep.target).add(projectName);
|
1050
|
+
}
|
1051
|
+
}
|
1052
|
+
}
|
1053
|
+
getProjectDependencies(project) {
|
1054
|
+
return this.projectToDependencies.get(project) || new Set();
|
1055
|
+
}
|
1056
|
+
}
|
1057
|
+
exports.ReleaseGroupProcessor = ReleaseGroupProcessor;
|