nx 23.1.0 → 23.1.2
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/nx.js +2 -1
- package/dist/release/changelog-renderer/index.js +4 -5
- package/dist/release/index.d.ts +1 -1
- package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
- package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
- package/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +16 -8
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/add/add.js +13 -1
- package/dist/src/command-line/affected/affected.js +1 -0
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
- package/dist/src/command-line/graph/graph.d.ts +1 -0
- package/dist/src/command-line/graph/graph.js +15 -6
- package/dist/src/command-line/import/import.js +2 -3
- package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
- package/dist/src/command-line/init/command-object.js +10 -2
- package/dist/src/command-line/init/configure-plugins.js +3 -2
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
- package/dist/src/command-line/init/implementation/angular/index.js +4 -2
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
- package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
- package/dist/src/command-line/init/implementation/utils.js +22 -3
- package/dist/src/command-line/init/init-v2.js +4 -5
- package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
- package/dist/src/command-line/migrate/execute-migration.js +389 -0
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/migrate/migrate.d.ts +5 -45
- package/dist/src/command-line/migrate/migrate.js +122 -402
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/release/changelog.js +5 -0
- package/dist/src/command-line/release/index.d.ts +1 -1
- package/dist/src/command-line/release/utils/git.js +7 -3
- package/dist/src/command-line/release/utils/release-graph.d.ts +19 -2
- package/dist/src/command-line/release/utils/release-graph.js +71 -19
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +7 -1
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
- package/dist/src/command-line/release/utils/shared.d.ts +2 -2
- package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
- package/dist/src/command-line/release/version/release-group-processor.js +80 -6
- package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
- package/dist/src/command-line/release/version/version-actions.js +9 -1
- package/dist/src/command-line/release/version.js +9 -5
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/command-line/run/run-one.js +1 -0
- package/dist/src/command-line/run-many/run-many.js +1 -0
- package/dist/src/command-line/show/show-target/info.js +11 -2
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/watch/watch.js +13 -0
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/commands-runner/create-command-graph.js +5 -0
- package/dist/src/config/nx-json.d.ts +5 -3
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +52 -3
- package/dist/src/daemon/client/client.js +177 -55
- package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
- package/dist/src/daemon/client/daemon-environment.js +110 -2
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
- package/dist/src/daemon/message-types/daemon-message.js +25 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/latest-nx.js +5 -2
- package/dist/src/daemon/server/server.js +31 -4
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +96 -3
- package/dist/src/devkit-internals.js +200 -4
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
- package/dist/src/generators/tree.d.ts +4 -2
- package/dist/src/generators/utils/nx-json.js +13 -3
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
- package/dist/src/native/index.d.ts +31 -2
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
- package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
- package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
- package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +110 -17
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +15 -9
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
- package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
- package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
- package/dist/src/plugins/js/utils/register.d.ts +18 -0
- package/dist/src/plugins/js/utils/register.js +81 -0
- package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
- package/dist/src/plugins/js/utils/typescript.js +15 -0
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/error-types.d.ts +12 -1
- package/dist/src/project-graph/error-types.js +68 -3
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +22 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/plugins/transpiler.js +4 -0
- package/dist/src/project-graph/project-graph.js +23 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +16 -15
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
- package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
- package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
- package/dist/src/tasks-runner/run-command.js +4 -2
- package/dist/src/tasks-runner/task-env.d.ts +9 -0
- package/dist/src/tasks-runner/task-env.js +31 -4
- package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
- package/dist/src/tasks-runner/task-orchestrator.js +23 -10
- package/dist/src/tasks-runner/utils.js +2 -6
- package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
- package/dist/src/utils/acknowledge-build-scripts.js +102 -0
- package/dist/src/utils/analytics-prompt.d.ts +0 -6
- package/dist/src/utils/analytics-prompt.js +0 -51
- package/dist/src/utils/assert-workspace-validity.js +7 -2
- package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
- package/dist/src/utils/catalog/manager-utils.js +22 -5
- package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
- package/dist/src/utils/catalog/pnpm-manager.js +3 -15
- package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
- package/dist/src/utils/catalog/yarn-manager.js +3 -15
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/fileutils.d.ts +5 -0
- package/dist/src/utils/fileutils.js +7 -2
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +16 -3
- package/dist/src/utils/git-utils.js +146 -52
- package/dist/src/utils/git-worktrees.d.ts +30 -0
- package/dist/src/utils/git-worktrees.js +212 -0
- package/dist/src/utils/ignore.d.ts +128 -1
- package/dist/src/utils/ignore.js +182 -12
- package/dist/src/utils/long-running-target.d.ts +10 -0
- package/dist/src/utils/long-running-target.js +19 -0
- package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
- package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
- package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-json.js +11 -7
- package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
- package/dist/src/utils/package-manager-config/bunfig.js +49 -0
- package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
- package/dist/src/utils/package-manager-config/npmrc.js +124 -0
- package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
- package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
- package/dist/src/utils/package-manager.d.ts +23 -2
- package/dist/src/utils/package-manager.js +264 -43
- package/dist/src/utils/provenance.js +18 -16
- package/dist/src/utils/registry-config/bun.d.ts +2 -0
- package/dist/src/utils/registry-config/bun.js +257 -0
- package/dist/src/utils/registry-config/index.d.ts +13 -0
- package/dist/src/utils/registry-config/index.js +102 -0
- package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
- package/dist/src/utils/registry-config/pnpm.js +1551 -0
- package/dist/src/utils/registry-config/utils.d.ts +195 -0
- package/dist/src/utils/registry-config/utils.js +496 -0
- package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-berry.js +612 -0
- package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/dist/src/utils/workspace-id.d.ts +20 -0
- package/dist/src/utils/workspace-id.js +54 -0
- package/migrations.json +13 -1
- package/package.json +22 -17
- package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
- package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
- package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
- package/dist/src/utils/min-release-age/npmrc.js +0 -45
|
@@ -13,10 +13,10 @@ const delayed_spinner_1 = require("../../utils/delayed-spinner");
|
|
|
13
13
|
const plugin_progress_text_1 = require("../../utils/plugin-progress-text");
|
|
14
14
|
const progress_topics_1 = require("../../utils/progress-topics");
|
|
15
15
|
const error_types_1 = require("../error-types");
|
|
16
|
-
const source_maps_1 = require("./project-configuration/source-maps");
|
|
17
16
|
const target_defaults_1 = require("./project-configuration/target-defaults");
|
|
18
17
|
var target_merging_1 = require("./project-configuration/target-merging");
|
|
19
18
|
Object.defineProperty(exports, "mergeTargetConfigurations", { enumerable: true, get: function () { return target_merging_1.mergeTargetConfigurations; } });
|
|
19
|
+
const target_merging_2 = require("./project-configuration/target-merging");
|
|
20
20
|
var target_defaults_2 = require("./project-configuration/target-defaults");
|
|
21
21
|
Object.defineProperty(exports, "readTargetDefaultsForTarget", { enumerable: true, get: function () { return target_defaults_2.readTargetDefaultsForTarget; } });
|
|
22
22
|
/**
|
|
@@ -123,14 +123,13 @@ async function createProjectConfigurationsWithPlugins(root = workspace_root_1.wo
|
|
|
123
123
|
* Runs a single plugin batch through two passes:
|
|
124
124
|
*
|
|
125
125
|
* 1. Every project node in every plugin result is handed to `mergeFn`,
|
|
126
|
-
* which
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* onto the shared `externalNodes` record.
|
|
126
|
+
* which merges it into the manager's rootMap. Any failure is
|
|
127
|
+
* collected into `errors`; processing keeps going. External nodes
|
|
128
|
+
* are accumulated onto the shared `externalNodes` record.
|
|
130
129
|
* 2. After every project in the batch has been merged, name-reference
|
|
131
|
-
* sentinels for the batch are registered against
|
|
132
|
-
*
|
|
133
|
-
*
|
|
130
|
+
* sentinels for the batch are registered against the manager's
|
|
131
|
+
* rootMap, so sentinels point at the target objects that actually
|
|
132
|
+
* received the merges.
|
|
134
133
|
*
|
|
135
134
|
* The two passes can't be collapsed: a sentinel registered too early
|
|
136
135
|
* would point at the pre-merge object, and a later project in the same
|
|
@@ -138,7 +137,11 @@ async function createProjectConfigurationsWithPlugins(root = workspace_root_1.wo
|
|
|
138
137
|
* the registration into a second pass also lets forward references
|
|
139
138
|
* inside the same batch resolve eagerly.
|
|
140
139
|
*/
|
|
141
|
-
function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesManager,
|
|
140
|
+
function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesManager, externalNodes, errors) {
|
|
141
|
+
mergeSinglePluginResults(pluginResults, mergeFn, externalNodes, errors);
|
|
142
|
+
registerNameRefsFromSinglePlugin(pluginResults, nodesManager, errors);
|
|
143
|
+
}
|
|
144
|
+
function mergeSinglePluginResults(pluginResults, mergeFn, externalNodes, errors) {
|
|
142
145
|
for (const result of pluginResults) {
|
|
143
146
|
const [pluginName, file, nodes, pluginIndex] = result;
|
|
144
147
|
const { projects: projectNodes, externalNodes: pluginExternalNodes } = nodes;
|
|
@@ -156,11 +159,13 @@ function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesMa
|
|
|
156
159
|
}
|
|
157
160
|
Object.assign(externalNodes, pluginExternalNodes);
|
|
158
161
|
}
|
|
162
|
+
}
|
|
163
|
+
function registerNameRefsFromSinglePlugin(pluginResults, nodesManager, errors) {
|
|
159
164
|
for (const result of pluginResults) {
|
|
160
165
|
const [pluginName, file, nodes, pluginIndex] = result;
|
|
161
166
|
const { projects: projectNodes } = nodes;
|
|
162
167
|
try {
|
|
163
|
-
nodesManager.registerNameRefs(projectNodes
|
|
168
|
+
nodesManager.registerNameRefs(projectNodes);
|
|
164
169
|
}
|
|
165
170
|
catch (error) {
|
|
166
171
|
errors.push(new error_types_1.MergeNodesError({ file, pluginName, error, pluginIndex }));
|
|
@@ -170,110 +175,83 @@ function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesMa
|
|
|
170
175
|
/**
|
|
171
176
|
* Merges create nodes results into a single rootMap.
|
|
172
177
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
178
|
+
* Every layer merges into the manager through the same source-map-aware
|
|
179
|
+
* merge, in precedence order:
|
|
180
|
+
*
|
|
181
|
+
* specified plugins → synthetic target defaults → default plugins
|
|
182
|
+
*
|
|
183
|
+
* so field-level provenance is decided by the merge itself for all three
|
|
184
|
+
* layers — whichever layer a field's final value came from owns its
|
|
185
|
+
* attribution, and `'...'` spreads in default-plugin configs resolve against
|
|
186
|
+
* the accumulated specified + target-defaults base.
|
|
180
187
|
*
|
|
181
|
-
*
|
|
182
|
-
* (
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
188
|
+
* Target-default synthesis needs the *merged* shape of the default layer
|
|
189
|
+
* (to predict each target's eventual executor/command) before that layer
|
|
190
|
+
* merges into the manager. To get it, default results are first staged into
|
|
191
|
+
* a throwaway intermediate rootMap with unresolvable `'...'` spreads
|
|
192
|
+
* deferred. The staging output feeds only `createTargetDefaultsResults`; the
|
|
193
|
+
* default plugins then merge into the manager from their original results.
|
|
186
194
|
*/
|
|
187
195
|
function mergeCreateNodesResults(specifiedResults, defaultResults, nxJsonConfiguration, workspaceRoot, errors) {
|
|
188
196
|
perf_hooks_1.performance.mark('createNodes:merge - start');
|
|
189
197
|
const nodesManager = new project_nodes_manager_1.ProjectNodesManager();
|
|
190
198
|
const externalNodes = {};
|
|
191
199
|
const configurationSourceMaps = {};
|
|
192
|
-
const intermediateDefaultRootMap = {};
|
|
193
|
-
// Kept separate so the intermediate merge doesn't clobber
|
|
194
|
-
// specified/TD attribution on fields the defaults don't touch.
|
|
195
|
-
const defaultConfigurationSourceMaps = {};
|
|
196
200
|
const mergeToManager = (project, sourceInfo) => nodesManager.mergeProjectNode(project, configurationSourceMaps, sourceInfo);
|
|
197
|
-
const mergeToIntermediate = (project, sourceInfo) => {
|
|
198
|
-
(0, project_nodes_manager_1.mergeProjectConfigurationIntoRootMap)(intermediateDefaultRootMap, project, defaultConfigurationSourceMaps, sourceInfo);
|
|
199
|
-
};
|
|
200
201
|
for (const pluginResults of specifiedResults) {
|
|
201
|
-
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager,
|
|
202
|
-
}
|
|
203
|
-
for (const pluginResults of defaultResults) {
|
|
204
|
-
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToIntermediate, nodesManager, intermediateDefaultRootMap, externalNodes, errors);
|
|
205
|
-
}
|
|
206
|
-
const targetDefaultsResults = (0, target_defaults_1.createTargetDefaultsResults)(nodesManager.getRootMap(), intermediateDefaultRootMap, nxJsonConfiguration, configurationSourceMaps, defaultConfigurationSourceMaps);
|
|
207
|
-
if (targetDefaultsResults.length > 0) {
|
|
208
|
-
mergeCreateNodesResultsFromSinglePlugin(targetDefaultsResults, mergeToManager, nodesManager, nodesManager.getRootMap(), externalNodes, errors);
|
|
202
|
+
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
209
203
|
}
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
204
|
+
// Without target defaults there is nothing to synthesize, and the staging
|
|
205
|
+
// pass exists only to feed synthesis — skip straight to the default-plugin
|
|
206
|
+
// merge.
|
|
207
|
+
if (Object.keys(nxJsonConfiguration.targetDefaults ?? {}).length > 0) {
|
|
208
|
+
// Throwaway staging area: the default layer's merged shape (unresolvable
|
|
209
|
+
// `'...'` spreads deferred), read only by target-default synthesis. The
|
|
210
|
+
// default plugins merge into the manager from their original results, not
|
|
211
|
+
// from this map. No source maps are kept for it — synthesis attributes
|
|
212
|
+
// targets without them (a default plugin can never be named by a
|
|
213
|
+
// `filter.plugin`); the real default merge writes the manager's.
|
|
214
|
+
const intermediateDefaultRootMap = {};
|
|
215
|
+
// The rootMap merge adopts input arrays/objects by reference and grows
|
|
216
|
+
// them in place (e.g. `mergeMetadata`), so staging works on deep clones —
|
|
217
|
+
// handing it the plugin results themselves would corrupt them before the
|
|
218
|
+
// real merge below reads them.
|
|
219
|
+
const mergeToIntermediate = (project, sourceInfo) => {
|
|
220
|
+
(0, project_nodes_manager_1.mergeProjectConfigurationIntoRootMap)(intermediateDefaultRootMap, (0, target_merging_2.deepClone)(project), undefined, sourceInfo, false, true);
|
|
221
|
+
};
|
|
222
|
+
// Stage the default layer for synthesis. Merge errors are discarded and
|
|
223
|
+
// external nodes land in a scratch object — the same results merge into
|
|
224
|
+
// the manager below, where both surface once with proper plugin context.
|
|
225
|
+
// The discard is safe because every merge throw is base-independent in
|
|
226
|
+
// both its condition and its reachability: each throw's condition reads
|
|
227
|
+
// only the plugin's own config, and the spread-ambiguity throws fire even
|
|
228
|
+
// when a key is dropped by a base-owns-key shortcut, because those
|
|
229
|
+
// shortcuts eagerly validate the dropped value (`assertNoIntegerLikeSpreadKey`).
|
|
230
|
+
// So a given config raises the same error in this pass and the real merge
|
|
231
|
+
// below despite their bases differing.
|
|
232
|
+
// Name references are NOT registered here: `applySubstitutions` sweeps only
|
|
233
|
+
// the manager's `rootMap`, so sentinels registered against this throwaway
|
|
234
|
+
// rootMap would never be visited and would never resolve.
|
|
235
|
+
const stagingErrors = [];
|
|
236
|
+
const stagingExternalNodes = {};
|
|
237
|
+
for (const pluginResults of defaultResults) {
|
|
238
|
+
mergeSinglePluginResults(pluginResults, mergeToIntermediate, stagingExternalNodes, stagingErrors);
|
|
218
239
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pluginName: 'nx/default-plugins',
|
|
223
|
-
error,
|
|
224
|
-
pluginIndex: undefined,
|
|
225
|
-
}));
|
|
240
|
+
const targetDefaultsResults = (0, target_defaults_1.createTargetDefaultsResults)(nodesManager.getRootMap(), intermediateDefaultRootMap, nxJsonConfiguration, configurationSourceMaps);
|
|
241
|
+
if (targetDefaultsResults.length > 0) {
|
|
242
|
+
mergeCreateNodesResultsFromSinglePlugin(targetDefaultsResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
226
243
|
}
|
|
227
244
|
}
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
// `
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// target defaults, and that attribution is strictly more correct:
|
|
239
|
-
// - For fields the default plugin never shadowed, the existing entry
|
|
240
|
-
// already matches what the default plugin would overlay.
|
|
241
|
-
// - For fields where a default plugin placed `...` after other keys,
|
|
242
|
-
// those keys yielded to the base during the single-layer apply
|
|
243
|
-
// above. The stale default-plugin entry in
|
|
244
|
-
// `defaultConfigurationSourceMaps` must NOT clobber the base
|
|
245
|
-
// attribution that the specified plugin / TD already recorded.
|
|
246
|
-
const mainRootMap = nodesManager.getRootMap();
|
|
247
|
-
for (const root in defaultConfigurationSourceMaps) {
|
|
248
|
-
const existing = (configurationSourceMaps[root] ??= {});
|
|
249
|
-
const incoming = defaultConfigurationSourceMaps[root];
|
|
250
|
-
// A default plugin's targets are synthesized into the main rootmap by
|
|
251
|
-
// target defaults *before* the default layer is applied, so target
|
|
252
|
-
// defaults wrote the main source map's entry for the target node and its
|
|
253
|
-
// identity fields first — even though it never authored them (it only
|
|
254
|
-
// stamps them as a merge guard and cannot bring a target into existence).
|
|
255
|
-
// The identity fields are the executor/command plus, for run-commands, the
|
|
256
|
-
// `options.command`/`options.commands` the synthetic copies from the winner
|
|
257
|
-
// to stay compatible (#36067). For those keys, the real default plugin's
|
|
258
|
-
// attribution must override the target-defaults stamp.
|
|
259
|
-
const identityKeys = new Set();
|
|
260
|
-
for (const targetName in mainRootMap[root]?.targets ?? {}) {
|
|
261
|
-
const base = (0, source_maps_1.targetSourceMapKey)(targetName);
|
|
262
|
-
identityKeys.add(base);
|
|
263
|
-
identityKeys.add(`${base}.executor`);
|
|
264
|
-
identityKeys.add(`${base}.command`);
|
|
265
|
-
identityKeys.add(`${base}.options.command`);
|
|
266
|
-
identityKeys.add(`${base}.options.commands`);
|
|
267
|
-
}
|
|
268
|
-
for (const key in incoming) {
|
|
269
|
-
if (existing[key] === undefined) {
|
|
270
|
-
existing[key] = incoming[key];
|
|
271
|
-
}
|
|
272
|
-
else if (identityKeys.has(key) &&
|
|
273
|
-
existing[key][1] === source_maps_1.TARGET_DEFAULTS_PLUGIN_NAME) {
|
|
274
|
-
existing[key] = incoming[key];
|
|
275
|
-
}
|
|
276
|
-
}
|
|
245
|
+
// Merge the default plugins into the manager on top of the specified + TD
|
|
246
|
+
// base, from their original results. This is the same source-map-aware path
|
|
247
|
+
// the other layers take, so every field a default plugin wins — including
|
|
248
|
+
// fields it overrides on a specified/TD target — is attributed to it by the
|
|
249
|
+
// merge itself, `'...'` spreads resolve against the real base (keys a spread
|
|
250
|
+
// lets the base win keep their base attribution), and identity provenance
|
|
251
|
+
// follows the node-ownership rules in `recordTargetIdentitySourceMapInfo` /
|
|
252
|
+
// `getMergeValueResult`.
|
|
253
|
+
for (const pluginResults of defaultResults) {
|
|
254
|
+
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
277
255
|
}
|
|
278
256
|
const projectRootMap = nodesManager.getRootMap();
|
|
279
257
|
try {
|
|
@@ -29,15 +29,20 @@ export interface Timespan {
|
|
|
29
29
|
/** `parallelism: false` tasks running during the slice (each one holds every slot). */
|
|
30
30
|
nonParallel: number;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* A task and how long it ran (ms). The unit the report's task lists are built from —
|
|
34
|
+
* shared with the renderers so the producer and the formatters can't drift.
|
|
35
|
+
*/
|
|
36
|
+
export interface TaskDurationRow {
|
|
37
|
+
id: string;
|
|
38
|
+
duration: number;
|
|
39
|
+
}
|
|
32
40
|
export interface PerformanceSummary {
|
|
33
41
|
runDuration: number;
|
|
34
42
|
criticalPathDuration: number;
|
|
35
43
|
criticalPathTaskCount: number;
|
|
36
44
|
/** Longest critical-path tasks that ran (desc, capped at a few), cache hits excluded; empty when the path was fully cached. */
|
|
37
|
-
criticalPathTop:
|
|
38
|
-
id: string;
|
|
39
|
-
duration: number;
|
|
40
|
-
}>;
|
|
45
|
+
criticalPathTop: TaskDurationRow[];
|
|
41
46
|
/** Ids of tasks that failed (slowest first), for the GitHub Actions summary's failed-tasks list. Continuous tasks and tasks without a complete window are excluded. */
|
|
42
47
|
failedTasks: string[];
|
|
43
48
|
/** runDuration − criticalPathDuration. */
|
|
@@ -60,6 +65,8 @@ export interface PerformanceSummary {
|
|
|
60
65
|
cacheableCount: number;
|
|
61
66
|
cacheSkipped: boolean;
|
|
62
67
|
remoteCacheEnabled: boolean;
|
|
68
|
+
/** The workspace opted out of Nx Cloud (`neverConnectToCloud` / NX_NO_CLOUD) — never recommend it. */
|
|
69
|
+
cloudOptedOut: boolean;
|
|
63
70
|
}
|
|
64
71
|
/** Construction-time inputs for {@link PerformanceLifeCycle}. */
|
|
65
72
|
export interface PerformanceLifeCycleOptions {
|
|
@@ -18,6 +18,8 @@ const CACHE_HIT_STATUSES = new Set([
|
|
|
18
18
|
]);
|
|
19
19
|
/** Gap (ms) still counted as the same pre-dispatch hashing phase; a larger gap means older, unrelated hashing (e.g. a daemon's previous run). */
|
|
20
20
|
const PRE_DISPATCH_HASH_GAP = 1000;
|
|
21
|
+
/** A critical-path task shorter than this fraction of the path is noise, not a speed-up target. */
|
|
22
|
+
const CRITICAL_PATH_TOP_MIN_FRACTION = 0.2;
|
|
21
23
|
/**
|
|
22
24
|
* Pure analysis over one finished run's collected timings — no lifecycle state and no
|
|
23
25
|
* mutation. Built once per run from the {@link PerformanceLifeCycle}'s accumulated
|
|
@@ -171,15 +173,17 @@ class PerformanceAnalysis {
|
|
|
171
173
|
* (their duration is just restore time); no-status tasks (synthetic test runs) are
|
|
172
174
|
* kept.
|
|
173
175
|
*/
|
|
174
|
-
computeCriticalPathTop(criticalPathTasks, durations) {
|
|
175
|
-
return criticalPathTasks
|
|
176
|
+
computeCriticalPathTop(criticalPathTasks, durations, criticalPathDuration) {
|
|
177
|
+
return (criticalPathTasks
|
|
176
178
|
.filter((id) => {
|
|
177
179
|
const status = this.statuses.get(id);
|
|
178
180
|
return !status || !CACHE_HIT_STATUSES.has(status);
|
|
179
181
|
})
|
|
180
182
|
.map((id) => ({ id, duration: durations.get(id) ?? 0 }))
|
|
183
|
+
// Only tasks that meaningfully shape the path are worth speeding up.
|
|
184
|
+
.filter((t) => t.duration >= CRITICAL_PATH_TOP_MIN_FRACTION * criticalPathDuration)
|
|
181
185
|
.sort((a, b) => b.duration - a.duration)
|
|
182
|
-
.slice(0, 3);
|
|
186
|
+
.slice(0, 3));
|
|
183
187
|
}
|
|
184
188
|
/** Cache outcome: tasks restored (`cacheHits`) and the total with a cache outcome (`cacheableCount` = hits + ran). No-status tasks count for neither. */
|
|
185
189
|
computeCacheStats() {
|
|
@@ -244,12 +248,15 @@ class PerformanceAnalysis {
|
|
|
244
248
|
cores,
|
|
245
249
|
criticalPathDuration,
|
|
246
250
|
});
|
|
247
|
-
const criticalPathTop = this.computeCriticalPathTop(criticalPathTasks, durations);
|
|
251
|
+
const criticalPathTop = this.computeCriticalPathTop(criticalPathTasks, durations, criticalPathDuration);
|
|
248
252
|
const { cacheHits, cacheableCount } = this.computeCacheStats();
|
|
249
253
|
// `skipNxCache` already folds in NX_SKIP_NX_CACHE / NX_DISABLE_NX_CACHE
|
|
250
254
|
// (normalized in command-line-utils) — don't re-read those env vars here.
|
|
251
255
|
const cacheSkipped = this.options.skipNxCache === true;
|
|
252
256
|
const remoteCacheEnabled = this.remoteCacheEnabled();
|
|
257
|
+
const cloudOptedOut = this.options.nxJson
|
|
258
|
+
? !!(0, nx_cloud_utils_1.isNxCloudDisabled)(this.options.nxJson)
|
|
259
|
+
: false;
|
|
253
260
|
// Coordinator-dominated: hashing/scheduling outweighs task work by >3x the
|
|
254
261
|
// critical path, which keeps cold runs critical-path-bound.
|
|
255
262
|
const coordinatorDominated = coordinatorOverhead >= performance_report_1.MEANINGFUL_OVERHEAD &&
|
|
@@ -271,14 +278,16 @@ class PerformanceAnalysis {
|
|
|
271
278
|
parallel,
|
|
272
279
|
cores,
|
|
273
280
|
isCI,
|
|
274
|
-
// Can only start distributing in CI when not already doing so
|
|
275
|
-
|
|
281
|
+
// Can only start distributing in CI when not already doing so — and never
|
|
282
|
+
// suggest Nx Agents to a workspace that opted out of Nx Cloud.
|
|
283
|
+
canDistribute: isCI && !distributing && !cloudOptedOut,
|
|
276
284
|
distributing,
|
|
277
285
|
coordinatorDominated,
|
|
278
286
|
cacheHits,
|
|
279
287
|
cacheableCount,
|
|
280
288
|
cacheSkipped,
|
|
281
289
|
remoteCacheEnabled,
|
|
290
|
+
cloudOptedOut,
|
|
282
291
|
};
|
|
283
292
|
}
|
|
284
293
|
}
|
|
@@ -142,8 +142,9 @@ function flushPerformanceReport() {
|
|
|
142
142
|
// restore_terminal cooks the terminal back post-TUI, so console.log's plain \n
|
|
143
143
|
// renders fine; it also supplies the single trailing newline formatReport omits.
|
|
144
144
|
console.log((0, performance_report_1.formatReport)(summary));
|
|
145
|
-
// In GitHub Actions, also append the report
|
|
146
|
-
//
|
|
145
|
+
// In GitHub Actions, also append the report to the job summary page — the same stats
|
|
146
|
+
// as above, led by the run's outcome (a failed-tasks list, or a success line).
|
|
147
|
+
// Independent of the console.log above so neither masks the other.
|
|
147
148
|
writePerformanceReportToGitHubActions(summary);
|
|
148
149
|
}
|
|
149
150
|
catch (e) {
|
|
@@ -157,8 +158,8 @@ function flushPerformanceReport() {
|
|
|
157
158
|
/**
|
|
158
159
|
* Append the performance report to the GitHub Actions job summary page when running in
|
|
159
160
|
* Actions (`$GITHUB_STEP_SUMMARY` is set there and nowhere else). No-op otherwise. The
|
|
160
|
-
*
|
|
161
|
-
* write failure must never affect the run.
|
|
161
|
+
* Markdown is rendered below the guard, so non-CI runs don't pay to format a report
|
|
162
|
+
* nothing reads. Best-effort: a write failure must never affect the run.
|
|
162
163
|
*
|
|
163
164
|
* Skipped for a nested run (one nx command invoked by another nx task's command), so only
|
|
164
165
|
* the outermost run writes to the summary. Nx sets `NX_TASK_TARGET_PROJECT` on every task's
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { PerformanceSummaryPayload } from '../../native';
|
|
2
|
-
import type { PerformanceSummary } from './performance-analysis';
|
|
2
|
+
import type { PerformanceSummary, TaskDurationRow } from './performance-analysis';
|
|
3
3
|
/**
|
|
4
|
-
* A recommendation built from structured parts so the link text comes from the
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* A recommendation built from structured parts so the link text comes from the link
|
|
5
|
+
* definition (not a substring scanned out of the assembled report). A part is literal
|
|
6
|
+
* text, a {@link RecLink}, or a {@link RecTaskRows}, projected to each output string by
|
|
7
|
+
* {@link renderRecommendation}.
|
|
8
|
+
*
|
|
9
|
+
* String parts must be single-line — multi-line content needs its own structured part (as
|
|
10
|
+
* {@link RecTaskRows} is). TS can't enforce this: `string` is already a handled member, so
|
|
11
|
+
* a multi-line one compiles and then breaks the Markdown nested list.
|
|
8
12
|
*/
|
|
9
|
-
type RecPart = string | RecLink;
|
|
13
|
+
type RecPart = string | RecLink | RecTaskRows;
|
|
10
14
|
export type Recommendation = RecPart[];
|
|
11
15
|
/**
|
|
12
16
|
* A docs link inside a recommendation: a sentence is the visible text and the whole of
|
|
@@ -15,16 +19,22 @@ export type Recommendation = RecPart[];
|
|
|
15
19
|
* re-links the phrase from {@link PerformanceSummaryPayload.links}.
|
|
16
20
|
*/
|
|
17
21
|
interface RecLink {
|
|
18
|
-
/** Visible label: the sentence that links. */
|
|
19
22
|
visible: string;
|
|
20
|
-
/** OSC 8 click target / appended URL: the utm-tagged URL. */
|
|
21
23
|
href: string;
|
|
22
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* The critical path's longest tasks as data, so each renderer formats them natively:
|
|
27
|
+
* the terminal and payload as space-aligned columns, Markdown as a nested list
|
|
28
|
+
* (HTML collapses space runs, so aligned columns don't survive rendering there).
|
|
29
|
+
*/
|
|
30
|
+
type RecTaskRows = TaskDurationRow[];
|
|
23
31
|
/**
|
|
24
32
|
* The recommendation string the napi payload ships and the Rust popup matches against.
|
|
25
33
|
* Links are URL-less (the popup re-links them from {@link PerformanceSummaryPayload.links}).
|
|
26
34
|
*/
|
|
27
35
|
export declare function recommendationToPayloadString(rec: Recommendation): string;
|
|
36
|
+
/** Below this run duration (ms), the run is already fast — recommend nothing. */
|
|
37
|
+
export declare const MIN_RECOMMENDATION_RUN_DURATION = 30000;
|
|
28
38
|
/** Below this (ms) overhead is noise, not worth a recommendation. */
|
|
29
39
|
export declare const MEANINGFUL_OVERHEAD = 1000;
|
|
30
40
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MEANINGFUL_OVERHEAD = void 0;
|
|
3
|
+
exports.MEANINGFUL_OVERHEAD = exports.MIN_RECOMMENDATION_RUN_DURATION = void 0;
|
|
4
4
|
exports.recommendationToPayloadString = recommendationToPayloadString;
|
|
5
5
|
exports.buildRecommendations = buildRecommendations;
|
|
6
6
|
exports.formatReport = formatReport;
|
|
@@ -25,15 +25,49 @@ const NX_DISTRIBUTE_CTA = 'Distribute across machines with Nx Agents';
|
|
|
25
25
|
function phraseLink(phrase, taggedUrl) {
|
|
26
26
|
return { visible: phrase, href: taggedUrl };
|
|
27
27
|
}
|
|
28
|
+
// Discriminate positively — test for what each part *is*. A `!isRecTaskRows` catch-all
|
|
29
|
+
// would misclassify a future `RecPart` member as a link; TS can't catch that (it never
|
|
30
|
+
// checks a predicate body), so `recommendationLinks`' `.filter(isRecLink)` would ship
|
|
31
|
+
// `{text: undefined, href: undefined}` to the popup.
|
|
28
32
|
function isRecLink(part) {
|
|
29
|
-
return typeof part !== 'string';
|
|
33
|
+
return typeof part !== 'string' && 'href' in part;
|
|
34
|
+
}
|
|
35
|
+
function isRecTaskRows(part) {
|
|
36
|
+
return Array.isArray(part);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Project a recommendation to a string, formatting each non-text part with the caller's
|
|
40
|
+
* renderers. The three output targets (payload, terminal, Markdown) share this one dispatch.
|
|
41
|
+
* After the string and task-rows branches a part is a {@link RecLink}, so `render.link`
|
|
42
|
+
* takes it directly — and a new {@link RecPart} member that is neither would fail to satisfy
|
|
43
|
+
* that `RecLink` parameter, turning "forgot to handle it" into a compile error right here.
|
|
44
|
+
*/
|
|
45
|
+
function renderRecommendation(rec, render) {
|
|
46
|
+
return rec
|
|
47
|
+
.map((part) => {
|
|
48
|
+
if (typeof part === 'string') {
|
|
49
|
+
return part;
|
|
50
|
+
}
|
|
51
|
+
if (isRecTaskRows(part)) {
|
|
52
|
+
return render.taskRows(part);
|
|
53
|
+
}
|
|
54
|
+
return render.link(part);
|
|
55
|
+
})
|
|
56
|
+
.join('');
|
|
30
57
|
}
|
|
31
58
|
/**
|
|
32
59
|
* The recommendation string the napi payload ships and the Rust popup matches against.
|
|
33
60
|
* Links are URL-less (the popup re-links them from {@link PerformanceSummaryPayload.links}).
|
|
34
61
|
*/
|
|
35
62
|
function recommendationToPayloadString(rec) {
|
|
36
|
-
return rec
|
|
63
|
+
return renderRecommendation(rec, {
|
|
64
|
+
link: (link) => link.visible,
|
|
65
|
+
taskRows: taskRowsToText,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Task rows as the text block the terminal and payload embed: newline-led, space-aligned columns. */
|
|
69
|
+
function taskRowsToText(tasks) {
|
|
70
|
+
return ['', ...formatTopTaskRows(tasks)].join('\n');
|
|
37
71
|
}
|
|
38
72
|
/**
|
|
39
73
|
* The recommendation as a terminal string. With OSC 8 the phrase becomes a hyperlink
|
|
@@ -42,16 +76,12 @@ function recommendationToPayloadString(rec) {
|
|
|
42
76
|
* are off.
|
|
43
77
|
*/
|
|
44
78
|
function recommendationToTerminalString(rec, hyperlinks) {
|
|
45
|
-
return rec
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
? (0, terminal_link_1.terminalLink)(part.visible, part.href)
|
|
52
|
-
: `${part.visible} → ${part.href}`;
|
|
53
|
-
})
|
|
54
|
-
.join('');
|
|
79
|
+
return renderRecommendation(rec, {
|
|
80
|
+
link: (link) => hyperlinks
|
|
81
|
+
? (0, terminal_link_1.terminalLink)(link.visible, link.href)
|
|
82
|
+
: `${link.visible} → ${link.href}`,
|
|
83
|
+
taskRows: taskRowsToText,
|
|
84
|
+
});
|
|
55
85
|
}
|
|
56
86
|
/** The popup links (phrase + href) for every link in a recommendation list, for OSC 8 re-linking. */
|
|
57
87
|
function recommendationLinks(recommendations) {
|
|
@@ -59,6 +89,8 @@ function recommendationLinks(recommendations) {
|
|
|
59
89
|
.filter(isRecLink)
|
|
60
90
|
.map((part) => ({ text: part.visible, href: part.href })));
|
|
61
91
|
}
|
|
92
|
+
/** Below this run duration (ms), the run is already fast — recommend nothing. */
|
|
93
|
+
exports.MIN_RECOMMENDATION_RUN_DURATION = 30_000;
|
|
62
94
|
/** At/below this hit rate, recommend remote cache (if off); above it caching works. */
|
|
63
95
|
const LOW_CACHE_HIT_RATE = 0.1;
|
|
64
96
|
/** Below this (ms) overhead is noise, not worth a recommendation. */
|
|
@@ -75,7 +107,8 @@ function recoverableTime(s) {
|
|
|
75
107
|
}
|
|
76
108
|
/** Render the longest critical-path tasks as aligned columns: task (left), duration (right). */
|
|
77
109
|
function formatTopTaskRows(tasks) {
|
|
78
|
-
//
|
|
110
|
+
// Non-empty by construction: the only recommendation carrying task rows requires
|
|
111
|
+
// `criticalPathTop.length > 0` to apply, so no empty array reaches the widths below.
|
|
79
112
|
const idWidth = Math.max(...tasks.map((t) => t.id.length));
|
|
80
113
|
const durations = tasks.map((t) => (0, native_1.formatDuration)(t.duration));
|
|
81
114
|
const durWidth = Math.max(...durations.map((d) => d.length));
|
|
@@ -136,8 +169,10 @@ const RECOMMENDATIONS = [
|
|
|
136
169
|
},
|
|
137
170
|
{
|
|
138
171
|
// Barely-used cache with no remote: set up Nx Cloud. Whole-phrase link; the payload
|
|
139
|
-
// string stays URL-less (the popup re-links the phrase).
|
|
172
|
+
// string stays URL-less (the popup re-links the phrase). Never pushed at a
|
|
173
|
+
// workspace that opted out of Nx Cloud.
|
|
140
174
|
isApplicable: (c) => !c.cacheSkipped &&
|
|
175
|
+
!c.cloudOptedOut &&
|
|
141
176
|
c.cacheableCount > 0 &&
|
|
142
177
|
!c.remoteCacheEnabled &&
|
|
143
178
|
c.cacheHits / c.cacheableCount <= LOW_CACHE_HIT_RATE,
|
|
@@ -168,10 +203,8 @@ const RECOMMENDATIONS = [
|
|
|
168
203
|
// only multi-line rec). Nothing ran (fully cached) → it doesn't apply.
|
|
169
204
|
isApplicable: (c) => criticalPathBound(c) && c.criticalPathTop.length > 0,
|
|
170
205
|
build: (c) => [
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
...formatTopTaskRows(c.criticalPathTop),
|
|
174
|
-
].join('\n'),
|
|
206
|
+
`Speed up or split the longest tasks on the critical path:`,
|
|
207
|
+
c.criticalPathTop,
|
|
175
208
|
],
|
|
176
209
|
},
|
|
177
210
|
];
|
|
@@ -181,6 +214,10 @@ const RECOMMENDATIONS = [
|
|
|
181
214
|
* the GitHub-summary Markdown, and the TUI payload.
|
|
182
215
|
*/
|
|
183
216
|
function buildRecommendations(s) {
|
|
217
|
+
// A fast run has nothing worth optimizing — stats only, no advice.
|
|
218
|
+
if (s.runDuration < exports.MIN_RECOMMENDATION_RUN_DURATION) {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
184
221
|
const c = {
|
|
185
222
|
recoverableByParallel: s.recoverableByParallel,
|
|
186
223
|
recoverableByMachines: s.recoverableByMachines,
|
|
@@ -194,6 +231,7 @@ function buildRecommendations(s) {
|
|
|
194
231
|
cacheableCount: s.cacheableCount,
|
|
195
232
|
cacheSkipped: s.cacheSkipped,
|
|
196
233
|
remoteCacheEnabled: s.remoteCacheEnabled,
|
|
234
|
+
cloudOptedOut: s.cloudOptedOut,
|
|
197
235
|
};
|
|
198
236
|
return RECOMMENDATIONS.filter((r) => r.isApplicable(c)).map((r) => r.build(c));
|
|
199
237
|
}
|
|
@@ -252,18 +290,17 @@ function formatReport(s) {
|
|
|
252
290
|
}
|
|
253
291
|
/**
|
|
254
292
|
* A recommendation as Markdown: every link becomes `[phrase](href)` (no OSC 8, unlike the
|
|
255
|
-
* terminal renderer) — the whole sentence reads as prose and is the link text.
|
|
256
|
-
*
|
|
257
|
-
*
|
|
293
|
+
* terminal renderer) — the whole sentence reads as prose and is the link text. Task rows
|
|
294
|
+
* become a nested list under the recommendation's bullet (space-aligned columns don't
|
|
295
|
+
* survive HTML's whitespace collapsing).
|
|
258
296
|
*/
|
|
259
297
|
function recommendationToMarkdownString(rec) {
|
|
260
|
-
return rec
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
.join('<br>');
|
|
298
|
+
return renderRecommendation(rec, {
|
|
299
|
+
link: (link) => `[${link.visible}](${link.href})`,
|
|
300
|
+
taskRows: (rows) => rows
|
|
301
|
+
.map((t) => `\n - \`${t.id}\` — ${(0, native_1.formatDuration)(t.duration)}`)
|
|
302
|
+
.join(''),
|
|
303
|
+
});
|
|
267
304
|
}
|
|
268
305
|
/**
|
|
269
306
|
* The performance report as GitHub-flavored Markdown for the Actions job summary
|
|
@@ -25,6 +25,7 @@ const update_manager_1 = require("../nx-cloud/update-manager");
|
|
|
25
25
|
const logger_1 = require("../utils/logger");
|
|
26
26
|
const nx_key_1 = require("../utils/nx-key");
|
|
27
27
|
const output_1 = require("../utils/output");
|
|
28
|
+
const configure_ai_agents_disclaimer_1 = require("../ai/configure-ai-agents-disclaimer");
|
|
28
29
|
const sync_generators_1 = require("../utils/sync-generators");
|
|
29
30
|
const workspace_root_1 = require("../utils/workspace-root");
|
|
30
31
|
const create_task_graph_1 = require("./create-task-graph");
|
|
@@ -410,9 +411,10 @@ async function printConfigureAiAgentsDisclaimer() {
|
|
|
410
411
|
return;
|
|
411
412
|
}
|
|
412
413
|
const { outdatedAgents } = await client_1.daemonClient.getConfigureAiAgentsStatus();
|
|
413
|
-
if (outdatedAgents.
|
|
414
|
-
|
|
414
|
+
if (!(0, configure_ai_agents_disclaimer_1.shouldPrintConfigureAiAgentsDisclaimer)(outdatedAgents, workspace_root_1.workspaceRoot)) {
|
|
415
|
+
return;
|
|
415
416
|
}
|
|
417
|
+
output_1.output.logRawLine(output_1.output.dim('Your AI agent configuration is outdated. Run "nx configure-ai-agents" to update.'));
|
|
416
418
|
}
|
|
417
419
|
catch {
|
|
418
420
|
// Silently ignore errors
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { ProjectGraph } from '../config/project-graph';
|
|
2
2
|
import { Task } from '../config/task-graph';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the FORCE_COLOR value for forked child processes.
|
|
5
|
+
*
|
|
6
|
+
* When the user sets FORCE_COLOR=0, bin/nx.ts deletes it from process.env
|
|
7
|
+
* (workaround for picocolors treating "0" as truthy) and saves the original
|
|
8
|
+
* value in NX_ORIGINAL_FORCE_COLOR. Without this check, the undefined
|
|
9
|
+
* FORCE_COLOR would default to 'true', re-enabling colors in all children.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getForceColorForChild(): string;
|
|
3
12
|
export declare function getEnvVariablesForBatchProcess(skipNxCache: boolean, captureStderr: boolean): NodeJS.ProcessEnv;
|
|
4
13
|
export declare function getTaskSpecificEnv(task: Task, graph: ProjectGraph): NodeJS.ProcessEnv;
|
|
5
14
|
export declare function getEnvVariablesForTask(task: Task, taskSpecificEnv: NodeJS.ProcessEnv, forceColor: string, skipNxCache: boolean, captureStderr: boolean, outputPath: string, streamOutput: boolean): NodeJS.ProcessEnv;
|