@depup/nx 23.1.2-depup.1 → 23.2.0-depup.0
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/README.md +7 -6
- package/changes.json +12 -8
- package/dist/bin/init-local.js +3 -5
- package/dist/bin/nx.js +1 -0
- package/dist/src/adapter/ngcli-adapter.js +60 -1
- package/dist/src/ai/constants.d.ts +15 -0
- package/dist/src/ai/constants.js +17 -1
- package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +57 -9
- package/dist/src/ai/utils.d.ts +13 -0
- package/dist/src/ai/utils.js +29 -0
- package/dist/src/analytics/analytics.js +2 -4
- package/dist/src/command-line/completion/command-object.js +7 -12
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +42 -31
- package/dist/src/command-line/format/format.js +84 -101
- package/dist/src/command-line/generate/generate.js +35 -35
- package/dist/src/command-line/import/import.js +29 -38
- package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
- package/dist/src/command-line/init/command-object.js +4 -2
- package/dist/src/command-line/init/configure-plugins.js +4 -1
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +17 -21
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
- package/dist/src/command-line/init/implementation/angular/index.js +10 -15
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +2 -0
- package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
- package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -0
- package/dist/src/command-line/init/implementation/format.d.ts +18 -0
- package/dist/src/command-line/init/implementation/format.js +114 -0
- package/dist/src/command-line/init/implementation/utils.js +8 -8
- package/dist/src/command-line/init/init-v1.js +15 -18
- package/dist/src/command-line/init/init-v2.js +77 -66
- package/dist/src/command-line/migrate/agentic/definitions.js +36 -9
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +37 -22
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +30 -39
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +7 -7
- package/dist/src/command-line/migrate/agentic/handoff.js +13 -10
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +7 -12
- package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +7 -0
- package/dist/src/command-line/migrate/agentic/run-step.d.ts +10 -0
- package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
- package/dist/src/command-line/migrate/agentic/runner.js +24 -24
- package/dist/src/command-line/migrate/agentic/select.d.ts +10 -2
- package/dist/src/command-line/migrate/agentic/select.js +30 -32
- package/dist/src/command-line/migrate/agentic/types.d.ts +33 -3
- package/dist/src/command-line/migrate/agentic/types.js +35 -0
- package/dist/src/command-line/migrate/command-object.d.ts +6 -0
- package/dist/src/command-line/migrate/command-object.js +19 -1
- package/dist/src/command-line/migrate/execute-migration.d.ts +28 -9
- package/dist/src/command-line/migrate/execute-migration.js +112 -27
- package/dist/src/command-line/migrate/migrate-analytics.d.ts +35 -0
- package/dist/src/command-line/migrate/migrate-analytics.js +64 -0
- package/dist/src/command-line/migrate/migrate-commits.d.ts +38 -8
- package/dist/src/command-line/migrate/migrate-commits.js +130 -15
- package/dist/src/command-line/migrate/migrate-config.d.ts +13 -12
- package/dist/src/command-line/migrate/migrate-config.js +22 -14
- package/dist/src/command-line/migrate/migrate-output.d.ts +45 -7
- package/dist/src/command-line/migrate/migrate-output.js +52 -8
- package/dist/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
- package/dist/src/command-line/migrate/migrate-ui-api.js +16 -7
- package/dist/src/command-line/migrate/migrate.d.ts +24 -55
- package/dist/src/command-line/migrate/migrate.js +553 -226
- package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
- package/dist/src/command-line/migrate/multi-major.js +7 -10
- package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
- package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
- package/dist/src/command-line/migrate/run/agent-output.js +65 -0
- package/dist/src/command-line/migrate/run/index.d.ts +9 -0
- package/dist/src/command-line/migrate/run/index.js +23 -0
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
- package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
- package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
- package/dist/src/command-line/migrate/run/run-id.js +56 -0
- package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
- package/dist/src/command-line/migrate/run/run-state.js +438 -0
- package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
- package/dist/src/command-line/migrate/run/state-lock.js +76 -0
- package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
- package/dist/src/command-line/migrate/run/state-machine.js +315 -0
- package/dist/src/command-line/migrate/run/util.d.ts +59 -0
- package/dist/src/command-line/migrate/run/util.js +148 -0
- package/dist/src/command-line/migrate/run/worker.d.ts +16 -0
- package/dist/src/command-line/migrate/run/worker.js +682 -0
- package/dist/src/command-line/migrate/run-migration-process.js +6 -5
- package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
- package/dist/src/command-line/migrate/safe-prompt.js +32 -43
- package/dist/src/command-line/migrate/sort-migrations.d.ts +16 -0
- package/dist/src/command-line/migrate/sort-migrations.js +32 -0
- package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
- package/dist/src/command-line/migrate/step-actions.js +12 -0
- package/dist/src/command-line/migrate/text.d.ts +18 -0
- package/dist/src/command-line/migrate/text.js +26 -0
- package/dist/src/command-line/migrate/version-skew-guard.d.ts +60 -0
- package/dist/src/command-line/migrate/version-skew-guard.js +175 -0
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.d.ts +2 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/command-object.js +16 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.d.ts +4 -0
- package/dist/src/command-line/nx-cloud/start-nx-agents/start-nx-agents.js +13 -0
- package/dist/src/command-line/nx-commands.js +26 -24
- package/dist/src/command-line/release/changelog.js +6 -17
- package/dist/src/command-line/release/plan.js +15 -28
- package/dist/src/command-line/release/publish.js +5 -0
- package/dist/src/command-line/release/release.js +6 -17
- package/dist/src/command-line/release/utils/release-graph.d.ts +1 -0
- package/dist/src/command-line/release/utils/release-graph.js +10 -2
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +10 -22
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
- package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
- package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
- package/dist/src/command-line/release/version.js +2 -2
- package/dist/src/command-line/reset/reset.js +17 -15
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/command-line/yargs-utils/shared-options.js +3 -1
- package/dist/src/config/misc-interfaces.d.ts +19 -7
- 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 +2 -7
- package/dist/src/daemon/client/client.js +113 -28
- package/dist/src/daemon/client/daemon-environment.d.ts +35 -0
- package/dist/src/daemon/client/daemon-environment.js +106 -6
- package/dist/src/daemon/client/daemon-socket-messenger.d.ts +1 -1
- package/dist/src/daemon/client/daemon-socket-messenger.js +8 -3
- package/dist/src/daemon/is-v8-serializer-enabled.d.ts +2 -2
- package/dist/src/daemon/is-v8-serializer-enabled.js +2 -2
- package/dist/src/daemon/message-types/daemon-message.d.ts +2 -1
- package/dist/src/daemon/message-types/daemon-message.js +25 -2
- package/dist/src/daemon/sandbox-socket-hint.d.ts +27 -0
- package/dist/src/daemon/sandbox-socket-hint.js +136 -0
- package/dist/src/daemon/server/client-socket-context.d.ts +1 -1
- package/dist/src/daemon/server/client-socket-context.js +2 -3
- package/dist/src/daemon/server/dotenv-graph-changes.d.ts +97 -0
- package/dist/src/daemon/server/dotenv-graph-changes.js +284 -0
- package/dist/src/daemon/server/handle-client-env.d.ts +8 -0
- package/dist/src/daemon/server/handle-client-env.js +92 -0
- package/dist/src/daemon/server/handle-outputs-changes.d.ts +10 -0
- package/dist/src/daemon/server/handle-outputs-changes.js +86 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +21 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +159 -6
- package/dist/src/daemon/server/server.js +36 -72
- package/dist/src/daemon/server/shutdown-utils.d.ts +1 -1
- package/dist/src/daemon/server/shutdown-utils.js +2 -2
- package/dist/src/daemon/socket-utils.d.ts +26 -7
- package/dist/src/daemon/socket-utils.js +45 -31
- package/dist/src/daemon/tmp-dir.d.ts +10 -0
- package/dist/src/daemon/tmp-dir.js +21 -37
- package/dist/src/devkit-internals.d.ts +20 -9
- package/dist/src/devkit-internals.js +49 -6
- package/dist/src/executors/run-commands/running-tasks.js +46 -29
- package/dist/src/generators/internal-utils/{format-changed-files-with-prettier-if-available.d.ts → format-changed-files.d.ts} +6 -6
- package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
- package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
- package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
- package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
- package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
- package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
- package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
- package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
- package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
- package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
- package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
- package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
- package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
- package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
- package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
- package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
- package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
- package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
- package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
- package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
- package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
- package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
- package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +2 -2
- package/dist/src/native/index.d.ts +7 -3
- 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/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
- package/dist/src/nx-cloud/utilities/url-shorten.d.ts +1 -4
- package/dist/src/nx-cloud/utilities/url-shorten.js +9 -8
- package/dist/src/plugins/js/lock-file/lock-file.d.ts +46 -4
- package/dist/src/plugins/js/lock-file/lock-file.js +192 -15
- package/dist/src/plugins/js/lock-file/npm-parser.js +10 -3
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +356 -62
- package/dist/src/plugins/js/lock-file/project-graph-pruning.d.ts +25 -1
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +78 -4
- package/dist/src/plugins/js/lock-file/pruned-output.d.ts +330 -0
- package/dist/src/plugins/js/lock-file/pruned-output.js +1441 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.d.ts +1 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +6 -5
- package/dist/src/plugins/js/utils/register.d.ts +11 -0
- package/dist/src/plugins/js/utils/register.js +40 -6
- package/dist/src/project-graph/plugins/get-plugins.d.ts +27 -1
- package/dist/src/project-graph/plugins/get-plugins.js +110 -5
- package/dist/src/project-graph/plugins/isolation/enabled.js +1 -4
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +16 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +69 -11
- package/dist/src/project-graph/plugins/isolation/messaging.js +1 -3
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +23 -2
- package/dist/src/project-graph/project-graph.js +27 -2
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +7 -0
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +14 -6
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +47 -21
- package/dist/src/tasks-runner/is-tui-enabled.js +3 -1
- package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
- package/dist/src/tasks-runner/life-cycle.js +2 -2
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +12 -0
- package/dist/src/tasks-runner/life-cycles/performance-report.js +62 -3
- package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +26 -1
- package/dist/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.js +99 -5
- package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +26 -0
- package/dist/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.js +113 -17
- package/dist/src/tasks-runner/pseudo-ipc.js +14 -13
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +17 -3
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/run-command.js +32 -39
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +55 -0
- package/dist/src/tasks-runner/running-tasks/batch-process.js +161 -8
- package/dist/src/tasks-runner/task-env.d.ts +25 -0
- package/dist/src/tasks-runner/task-env.js +39 -0
- package/dist/src/tasks-runner/task-orchestrator.d.ts +68 -0
- package/dist/src/tasks-runner/task-orchestrator.js +159 -8
- package/dist/src/utils/analytics-enabled.d.ts +7 -0
- package/dist/src/utils/analytics-enabled.js +11 -0
- package/dist/src/utils/analytics-prompt.js +4 -7
- package/dist/src/utils/cache-directory.d.ts +62 -3
- package/dist/src/utils/cache-directory.js +276 -25
- package/dist/src/utils/catalog/bun-manager-utils.d.ts +8 -0
- package/dist/src/utils/catalog/bun-manager-utils.js +174 -0
- package/dist/src/utils/catalog/bun-manager.d.ts +28 -0
- package/dist/src/utils/catalog/bun-manager.js +130 -0
- package/dist/src/utils/catalog/index.d.ts +1 -1
- package/dist/src/utils/catalog/index.js +1 -1
- package/dist/src/utils/catalog/manager-factory.js +3 -0
- package/dist/src/utils/catalog/manager-utils.d.ts +8 -1
- package/dist/src/utils/catalog/manager-utils.js +9 -4
- package/dist/src/utils/catalog/manager.d.ts +13 -1
- package/dist/src/utils/catalog/manager.js +30 -0
- package/dist/src/utils/catalog/pnpm-manager.d.ts +2 -1
- package/dist/src/utils/catalog/pnpm-manager.js +3 -0
- package/dist/src/utils/catalog/types.d.ts +4 -0
- package/dist/src/utils/catalog/yarn-manager.d.ts +6 -2
- package/dist/src/utils/catalog/yarn-manager.js +23 -32
- package/dist/src/utils/child-process.d.ts +31 -1
- package/dist/src/utils/child-process.js +103 -0
- package/dist/src/utils/chunkify.d.ts +7 -1
- package/dist/src/utils/chunkify.js +10 -3
- package/dist/src/utils/consume-messages-from-socket.d.ts +42 -7
- package/dist/src/utils/consume-messages-from-socket.js +273 -38
- package/dist/src/utils/db-connection.js +8 -16
- package/dist/src/utils/exit-codes.d.ts +9 -0
- package/dist/src/utils/exit-codes.js +19 -0
- package/dist/src/utils/formatters/index.d.ts +13 -0
- package/dist/src/utils/formatters/index.js +74 -0
- package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
- package/dist/src/utils/formatters/oxfmt.js +764 -0
- package/dist/src/utils/formatters/prettier.d.ts +26 -0
- package/dist/src/utils/formatters/prettier.js +201 -0
- package/dist/src/utils/formatters/shared.d.ts +5 -0
- package/dist/src/utils/formatters/shared.js +8 -0
- package/dist/src/utils/git-utils.d.ts +38 -2
- package/dist/src/utils/git-utils.js +422 -19
- package/dist/src/utils/has-nx-js-plugin.d.ts +1 -1
- package/dist/src/utils/has-nx-js-plugin.js +1 -1
- package/dist/src/utils/ignore.d.ts +47 -5
- package/dist/src/utils/ignore.js +93 -11
- package/dist/src/utils/kill-child-on-host-exit.d.ts +7 -0
- package/dist/src/utils/kill-child-on-host-exit.js +42 -0
- package/dist/src/utils/nx-console-prompt.js +3 -6
- package/dist/src/utils/nx-tmp-dir.d.ts +5 -0
- package/dist/src/utils/nx-tmp-dir.js +7 -2
- package/dist/src/utils/output.d.ts +153 -0
- package/dist/src/utils/output.js +289 -5
- package/dist/src/utils/owned-private-dir.d.ts +13 -0
- package/dist/src/utils/owned-private-dir.js +39 -0
- package/dist/src/utils/package-json.d.ts +2 -0
- package/dist/src/utils/package-manager.js +17 -7
- package/dist/src/utils/params.d.ts +7 -1
- package/dist/src/utils/params.js +64 -6
- package/dist/src/utils/permission-errors.d.ts +11 -0
- package/dist/src/utils/permission-errors.js +17 -0
- package/dist/src/utils/plugins/core-plugins.js +4 -0
- package/dist/src/utils/prompt-helpers.d.ts +53 -0
- package/dist/src/utils/prompt-helpers.js +111 -0
- package/dist/src/utils/socket-refused-exit-code.d.ts +15 -0
- package/dist/src/utils/socket-refused-exit-code.js +18 -0
- package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
- package/dist/src/utils/write-formatted-json-file.js +5 -4
- package/package.json +33 -24
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -88
- package/dist/src/utils/is-using-prettier.d.ts +0 -3
- package/dist/src/utils/is-using-prettier.js +0 -62
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BatchProcess = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
4
6
|
const native_1 = require("../../native");
|
|
7
|
+
const cache_directory_1 = require("../../utils/cache-directory");
|
|
5
8
|
const exit_codes_1 = require("../../utils/exit-codes");
|
|
9
|
+
const output_1 = require("../../utils/output");
|
|
6
10
|
const batch_messages_1 = require("../batch/batch-messages");
|
|
7
11
|
class BatchProcess {
|
|
8
12
|
constructor(childProcess, executorName) {
|
|
@@ -12,6 +16,18 @@ class BatchProcess {
|
|
|
12
16
|
this.batchResultsCallbacks = [];
|
|
13
17
|
this.taskResultsCallbacks = [];
|
|
14
18
|
this.outputCallbacks = [];
|
|
19
|
+
/**
|
|
20
|
+
* Set once the capture is released. A chunk can still arrive after that —
|
|
21
|
+
* stdout delivers past the exit event — and reopening then would mint a
|
|
22
|
+
* second numbered file that nothing ever cleans up.
|
|
23
|
+
*/
|
|
24
|
+
this.capturedOutputDiscarded = false;
|
|
25
|
+
/**
|
|
26
|
+
* Set when writing the capture failed. Distinct from discarded: the bytes
|
|
27
|
+
* already on disk are still the best record of the batch, so the file is kept
|
|
28
|
+
* and rendered, while everything after the failure goes live to the terminal.
|
|
29
|
+
*/
|
|
30
|
+
this.capturedOutputFailed = false;
|
|
15
31
|
this.childProcess.on('message', (message) => {
|
|
16
32
|
switch (message.type) {
|
|
17
33
|
case batch_messages_1.BatchMessageType.CompleteTask: {
|
|
@@ -47,24 +63,39 @@ class BatchProcess {
|
|
|
47
63
|
// Capture stdout output
|
|
48
64
|
if (this.childProcess.stdout) {
|
|
49
65
|
this.childProcess.stdout.on('data', (chunk) => {
|
|
50
|
-
const
|
|
51
|
-
//
|
|
52
|
-
|
|
66
|
+
const text = chunk.toString();
|
|
67
|
+
// When batch output is being folded, the live copy is suppressed to
|
|
68
|
+
// keep each group contiguous; it is retained (see capturedOutputPath)
|
|
69
|
+
// for the renderings that need it. Otherwise, maintain
|
|
70
|
+
// current terminal output behavior. These chunks are forwarded raw and
|
|
71
|
+
// routinely end mid-line, so they go through `output` to keep its line
|
|
72
|
+
// tracking accurate for whatever prints next.
|
|
73
|
+
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
74
|
+
this.capture(chunk);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
output_1.output.writeTaskOutputChunk(chunk);
|
|
78
|
+
}
|
|
53
79
|
// Notify callbacks for TUI
|
|
54
80
|
for (const cb of this.outputCallbacks) {
|
|
55
|
-
cb(
|
|
81
|
+
cb(text);
|
|
56
82
|
}
|
|
57
83
|
});
|
|
58
84
|
}
|
|
59
85
|
// Capture stderr output
|
|
60
86
|
if (this.childProcess.stderr) {
|
|
61
87
|
this.childProcess.stderr.on('data', (chunk) => {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
const text = chunk.toString();
|
|
89
|
+
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
90
|
+
this.capture(chunk, process.stderr);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Maintain current terminal output behavior
|
|
94
|
+
output_1.output.writeTaskOutputChunk(chunk, process.stderr);
|
|
95
|
+
}
|
|
65
96
|
// Notify callbacks for TUI
|
|
66
97
|
for (const cb of this.outputCallbacks) {
|
|
67
|
-
cb(
|
|
98
|
+
cb(text);
|
|
68
99
|
}
|
|
69
100
|
});
|
|
70
101
|
}
|
|
@@ -81,6 +112,127 @@ class BatchProcess {
|
|
|
81
112
|
onOutput(cb) {
|
|
82
113
|
this.outputCallbacks.push(cb);
|
|
83
114
|
}
|
|
115
|
+
capture(chunk, stream = process.stdout) {
|
|
116
|
+
// Only a released capture stops recording; a handed-over one keeps
|
|
117
|
+
// appending until the fold is rendered.
|
|
118
|
+
if (this.capturedOutputDiscarded) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (this.capturedOutputFailed) {
|
|
122
|
+
// Capture is over, but the output is not optional. Everything from here
|
|
123
|
+
// goes straight to the terminal, on the stream it arrived on.
|
|
124
|
+
output_1.output.writeTaskOutputChunk(chunk, stream);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// Hoisted so the catch can tell how much of this chunk reached the file: a
|
|
128
|
+
// `writeSync` that fails partway leaves a prefix on disk, and replaying the
|
|
129
|
+
// whole chunk live would print that prefix twice - once now, once when the
|
|
130
|
+
// fold reads the file.
|
|
131
|
+
const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
132
|
+
let written = 0;
|
|
133
|
+
try {
|
|
134
|
+
if (this.capturedOutputFd === undefined) {
|
|
135
|
+
const dir = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'batch-outputs');
|
|
136
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
137
|
+
const name = `${this.executorName.replace(/[^a-zA-Z0-9]+/g, '-')}-${process.pid}-${++BatchProcess.capturedOutputCount}.log`;
|
|
138
|
+
const path = (0, path_1.join)(dir, name);
|
|
139
|
+
// Assigned only once the file is actually open, so a path always names
|
|
140
|
+
// an fd rather than a file that failed to open.
|
|
141
|
+
const fd = (0, fs_1.openSync)(path, 'w');
|
|
142
|
+
this.capturedOutputPath = path;
|
|
143
|
+
this.capturedOutputFd = fd;
|
|
144
|
+
}
|
|
145
|
+
// Written synchronously so the file is complete the moment the batch ends,
|
|
146
|
+
// with no flush to sequence against the read that renders the fold.
|
|
147
|
+
while (written < bytes.length) {
|
|
148
|
+
written += (0, fs_1.writeSync)(this.capturedOutputFd, bytes, written);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
// This runs inside a stream 'data' handler, where a throw is an uncaught
|
|
153
|
+
// exception rather than something the orchestrator's try can see - so a
|
|
154
|
+
// full disk or a read-only data directory would take down a run that
|
|
155
|
+
// otherwise had nothing wrong with it. The capture is an optimization
|
|
156
|
+
// that the common path discards anyway, so give it up and put the bytes
|
|
157
|
+
// back on the terminal instead of losing both them and the run.
|
|
158
|
+
// Latch on a flag of its own rather than reusing the discard flag: that
|
|
159
|
+
// one makes `capture` return early, which would drop every later chunk
|
|
160
|
+
// on the floor - captured nowhere and printed nowhere.
|
|
161
|
+
this.capturedOutputFailed = true;
|
|
162
|
+
// Close the fd but keep the file. Whatever was written before the failure
|
|
163
|
+
// is still the head of the batch's log, which is where a compiler's first
|
|
164
|
+
// non-cascading errors live; unlinking it here would throw away the most
|
|
165
|
+
// useful bytes precisely when the disk is in trouble.
|
|
166
|
+
this.closeCapturedOutput();
|
|
167
|
+
// Forward only what did not reach the file, and do it before warning.
|
|
168
|
+
// `output.warn` writes to the terminal as well, so if that is the thing
|
|
169
|
+
// failing, the bytes this handler was handed must already be out - losing
|
|
170
|
+
// the warning is survivable, losing task output is what this path exists
|
|
171
|
+
// to prevent.
|
|
172
|
+
const unwritten = bytes.subarray(written);
|
|
173
|
+
if (unwritten.length > 0) {
|
|
174
|
+
output_1.output.writeTaskOutputChunk(unwritten, stream);
|
|
175
|
+
}
|
|
176
|
+
output_1.output.warn({
|
|
177
|
+
title: `Could not capture batch output for ${this.executorName}`,
|
|
178
|
+
bodyLines: [
|
|
179
|
+
e.message,
|
|
180
|
+
'Streaming the rest of it live instead; the fold holds what was captured first.',
|
|
181
|
+
],
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Path to the file holding everything held back from the live stream under
|
|
187
|
+
* log grouping, or undefined if nothing was captured. Used to render the whole
|
|
188
|
+
* batch as one fold, so output no task claimed is not lost.
|
|
189
|
+
*
|
|
190
|
+
* The file is deliberately left open rather than closed here. A worker's
|
|
191
|
+
* stdout can deliver after its exit event — which is what `getResults()`
|
|
192
|
+
* settles on — and leaving the fd open keeps such a chunk appending to this
|
|
193
|
+
* same file instead of minting a second numbered one that nothing cleans up.
|
|
194
|
+
* The caller reads the file once, synchronously, while rendering the fold, so
|
|
195
|
+
* anything arriving after that read is not shown; writes are unbuffered, so
|
|
196
|
+
* the read always sees a complete prefix of what has arrived by then.
|
|
197
|
+
*/
|
|
198
|
+
getCapturedOutputPath() {
|
|
199
|
+
return this.capturedOutputPath;
|
|
200
|
+
}
|
|
201
|
+
/** Releases the capture file. Safe to call more than once. */
|
|
202
|
+
discardCapturedOutput() {
|
|
203
|
+
this.capturedOutputDiscarded = true;
|
|
204
|
+
this.releaseCapturedOutput();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Closes the fd and unlinks the file, leaving no path behind for a caller to
|
|
208
|
+
* read. Tolerates a partially-initialized capture, since it also runs when
|
|
209
|
+
* opening or writing the file is what failed.
|
|
210
|
+
*/
|
|
211
|
+
releaseCapturedOutput() {
|
|
212
|
+
this.closeCapturedOutput();
|
|
213
|
+
if (this.capturedOutputPath) {
|
|
214
|
+
try {
|
|
215
|
+
(0, fs_1.rmSync)(this.capturedOutputPath, { force: true });
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// `force` covers a missing file but not a locked one: on Windows an fd
|
|
219
|
+
// that failed to close still holds a share lock. This runs from
|
|
220
|
+
// `runBatch`'s finally, where throwing would replace the batch's real
|
|
221
|
+
// result with a cleanup error, so a stale file is the lesser outcome.
|
|
222
|
+
}
|
|
223
|
+
this.capturedOutputPath = undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/** Closes the fd, keeping the file and its path readable. */
|
|
227
|
+
closeCapturedOutput() {
|
|
228
|
+
if (this.capturedOutputFd !== undefined) {
|
|
229
|
+
try {
|
|
230
|
+
(0, fs_1.closeSync)(this.capturedOutputFd);
|
|
231
|
+
}
|
|
232
|
+
catch { }
|
|
233
|
+
this.capturedOutputFd = undefined;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
84
236
|
async getResults() {
|
|
85
237
|
return Promise.race([
|
|
86
238
|
new Promise((_, rej) => {
|
|
@@ -108,3 +260,4 @@ class BatchProcess {
|
|
|
108
260
|
}
|
|
109
261
|
}
|
|
110
262
|
exports.BatchProcess = BatchProcess;
|
|
263
|
+
BatchProcess.capturedOutputCount = 0;
|
|
@@ -11,6 +11,31 @@ import { Task } from '../config/task-graph';
|
|
|
11
11
|
export declare function getForceColorForChild(): string;
|
|
12
12
|
export declare function getEnvVariablesForBatchProcess(skipNxCache: boolean, captureStderr: boolean): NodeJS.ProcessEnv;
|
|
13
13
|
export declare function getTaskSpecificEnv(task: Task, graph: ProjectGraph): NodeJS.ProcessEnv;
|
|
14
|
+
/**
|
|
15
|
+
* Reconstructs, at graph-construction time, the env a task would see: the
|
|
16
|
+
* root dotenv files Nx loaded at init are unloaded from the ambient env, then
|
|
17
|
+
* the dotenv files the task would load (`.env.<target>`, project-scoped
|
|
18
|
+
* `.env`, ...) are applied, so a task-scoped file wins over an init-time root
|
|
19
|
+
* load. The unload compares values, not provenance: a variable whose value
|
|
20
|
+
* differs from the root file's is kept and wins over the task files, while a
|
|
21
|
+
* shell-set value equal to the root file's is unloaded like the file's own.
|
|
22
|
+
*
|
|
23
|
+
* `createNodes` runs before any task, so the per-task dotenv files that
|
|
24
|
+
* `getTaskSpecificEnv` loads at run time are not in `process.env` yet. A plugin
|
|
25
|
+
* inferring targets from a config that reads `process.env` needs those values
|
|
26
|
+
* to resolve the config the way the task will. This mirrors
|
|
27
|
+
* `loadDotEnvFilesForTask` but takes the target coordinates directly (there is
|
|
28
|
+
* no `Task`/graph yet) and gates on `!== 'false'` rather than `=== 'true'`: the
|
|
29
|
+
* `'true'` marker is only stamped once the graph exists (`run-command.ts`),
|
|
30
|
+
* which is after this runs. Only the dotenv overlay is reconstructed: run-time
|
|
31
|
+
* env like `NX_TASK_TARGET_*` or `NX_TASK_HASH` is not included.
|
|
32
|
+
*
|
|
33
|
+
* `baseEnv` is the ambient env the overlay applies to, defaulting to the live
|
|
34
|
+
* `process.env`. A caller that runs config files in-process passes a snapshot
|
|
35
|
+
* taken under its load lock instead: a concurrent load's transient env writes
|
|
36
|
+
* would otherwise be read as ambient and mask the task files' values.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getGraphTimeDotEnvForTask(projectRoot: string, target: string, configuration?: string, nonAtomizedTarget?: string, baseEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
14
39
|
export declare function getEnvVariablesForTask(task: Task, taskSpecificEnv: NodeJS.ProcessEnv, forceColor: string, skipNxCache: boolean, captureStderr: boolean, outputPath: string, streamOutput: boolean): NodeJS.ProcessEnv;
|
|
15
40
|
/**
|
|
16
41
|
* This function loads one or more .env files and expands the variables in them.
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getForceColorForChild = getForceColorForChild;
|
|
4
4
|
exports.getEnvVariablesForBatchProcess = getEnvVariablesForBatchProcess;
|
|
5
5
|
exports.getTaskSpecificEnv = getTaskSpecificEnv;
|
|
6
|
+
exports.getGraphTimeDotEnvForTask = getGraphTimeDotEnvForTask;
|
|
6
7
|
exports.getEnvVariablesForTask = getEnvVariablesForTask;
|
|
7
8
|
exports.loadAndExpandDotEnvFile = loadAndExpandDotEnvFile;
|
|
8
9
|
exports.unloadDotEnvFile = unloadDotEnvFile;
|
|
@@ -64,6 +65,44 @@ function getTaskSpecificEnv(task, graph) {
|
|
|
64
65
|
taskSpecificEnvCache.set(task.id, env);
|
|
65
66
|
return env;
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Reconstructs, at graph-construction time, the env a task would see: the
|
|
70
|
+
* root dotenv files Nx loaded at init are unloaded from the ambient env, then
|
|
71
|
+
* the dotenv files the task would load (`.env.<target>`, project-scoped
|
|
72
|
+
* `.env`, ...) are applied, so a task-scoped file wins over an init-time root
|
|
73
|
+
* load. The unload compares values, not provenance: a variable whose value
|
|
74
|
+
* differs from the root file's is kept and wins over the task files, while a
|
|
75
|
+
* shell-set value equal to the root file's is unloaded like the file's own.
|
|
76
|
+
*
|
|
77
|
+
* `createNodes` runs before any task, so the per-task dotenv files that
|
|
78
|
+
* `getTaskSpecificEnv` loads at run time are not in `process.env` yet. A plugin
|
|
79
|
+
* inferring targets from a config that reads `process.env` needs those values
|
|
80
|
+
* to resolve the config the way the task will. This mirrors
|
|
81
|
+
* `loadDotEnvFilesForTask` but takes the target coordinates directly (there is
|
|
82
|
+
* no `Task`/graph yet) and gates on `!== 'false'` rather than `=== 'true'`: the
|
|
83
|
+
* `'true'` marker is only stamped once the graph exists (`run-command.ts`),
|
|
84
|
+
* which is after this runs. Only the dotenv overlay is reconstructed: run-time
|
|
85
|
+
* env like `NX_TASK_TARGET_*` or `NX_TASK_HASH` is not included.
|
|
86
|
+
*
|
|
87
|
+
* `baseEnv` is the ambient env the overlay applies to, defaulting to the live
|
|
88
|
+
* `process.env`. A caller that runs config files in-process passes a snapshot
|
|
89
|
+
* taken under its load lock instead: a concurrent load's transient env writes
|
|
90
|
+
* would otherwise be read as ambient and mask the task files' values.
|
|
91
|
+
*/
|
|
92
|
+
function getGraphTimeDotEnvForTask(projectRoot, target, configuration, nonAtomizedTarget, baseEnv = process.env) {
|
|
93
|
+
// Unload the root dotenv files loaded on init of Nx so the task-scoped files win.
|
|
94
|
+
const env = unloadDotEnvFiles({ ...baseEnv });
|
|
95
|
+
// Fall back to the live env when the snapshot has no entry: Windows resolves
|
|
96
|
+
// `process.env` case-insensitively but a plain snapshot keeps whichever
|
|
97
|
+
// spelling was exported, so a lowercase opt-out is invisible here otherwise.
|
|
98
|
+
if ((baseEnv.NX_LOAD_DOT_ENV_FILES ?? process.env.NX_LOAD_DOT_ENV_FILES) ===
|
|
99
|
+
'false') {
|
|
100
|
+
return env;
|
|
101
|
+
}
|
|
102
|
+
const dotEnvFiles = (0, task_env_paths_1.getEnvPathsForTask)(projectRoot, target, configuration, nonAtomizedTarget);
|
|
103
|
+
loadAndExpandDotEnvFile(dotEnvFiles.map((file) => (0, node_path_1.join)(workspace_root_1.workspaceRoot, file)), env);
|
|
104
|
+
return env;
|
|
105
|
+
}
|
|
67
106
|
function getEnvVariablesForTask(task, taskSpecificEnv, forceColor, skipNxCache, captureStderr, outputPath, streamOutput) {
|
|
68
107
|
const res = {
|
|
69
108
|
// Start With Dotenv Variables
|
|
@@ -41,6 +41,12 @@ export declare class TaskOrchestrator {
|
|
|
41
41
|
private pendingDiscreteWorkers;
|
|
42
42
|
private groups;
|
|
43
43
|
private continuousTasksStarted;
|
|
44
|
+
/**
|
|
45
|
+
* How many folds each batch id has rendered. A batch that reports a strict
|
|
46
|
+
* subset of its tasks is re-run under the same id, so one id can produce more
|
|
47
|
+
* than one fold and the redirect lines have to point at the right one.
|
|
48
|
+
*/
|
|
49
|
+
private batchFoldRenders;
|
|
44
50
|
private bailed;
|
|
45
51
|
private resolveStopPromise;
|
|
46
52
|
private stopRequested;
|
|
@@ -118,6 +124,68 @@ export declare class TaskOrchestrator {
|
|
|
118
124
|
private hashBatchTasks;
|
|
119
125
|
applyFromCacheOrRunBatch(doNotSkipCache: boolean, batch: Batch, groupId: number): Promise<TaskResult[]>;
|
|
120
126
|
private runBatch;
|
|
127
|
+
/**
|
|
128
|
+
* Rendering a batch's output must never change the batch's results. A throw
|
|
129
|
+
* from the printer would otherwise land in `runBatch`'s own error handling:
|
|
130
|
+
* on the resolved path it rewrites every task to `failure` with the printer's
|
|
131
|
+
* stack as its output — reporting a green build red to the life cycles and Nx
|
|
132
|
+
* Cloud — and on the crash path it escapes `runBatch`, replacing the built
|
|
133
|
+
* failure results with the printer's error. Both call sites degrade to a
|
|
134
|
+
* warning here instead.
|
|
135
|
+
*/
|
|
136
|
+
private renderBatchOutputSafely;
|
|
137
|
+
/**
|
|
138
|
+
* Prints a completed batch's output once, under log grouping. Live forwarding
|
|
139
|
+
* was suppressed while grouping, so this is the only copy — which is why the
|
|
140
|
+
* requested output style has to reach this path rather than stopping at the
|
|
141
|
+
* life cycle.
|
|
142
|
+
*
|
|
143
|
+
* Two things are rendered, and they answer different questions.
|
|
144
|
+
*
|
|
145
|
+
* Every task always renders through the life cycle, exactly as in a non-batch
|
|
146
|
+
* run - failures in full, successes collapsed to a line for run-many, plus the
|
|
147
|
+
* initiating project in full for run-one. That is what attributes output to a
|
|
148
|
+
* task, and it is the only place some of it exists: `@nx/jest` synthesizes
|
|
149
|
+
* each task's `terminalOutput` from an aggregated result and never writes
|
|
150
|
+
* those per-project summaries to the worker's stdio at all.
|
|
151
|
+
*
|
|
152
|
+
* The worker's whole captured log is rendered as a fold above them when the
|
|
153
|
+
* run asked for full output, or when any task failed or was stopped. A
|
|
154
|
+
* diagnostic that explains a failure is routinely one no task claimed:
|
|
155
|
+
* `@nx/maven`'s batch impl writes its exit-code dump and failed-task outputs
|
|
156
|
+
* to the worker's stderr via `console.error`, and the Maven JVM it spawns
|
|
157
|
+
* points slf4j at `System.out` because its own stderr carries the result
|
|
158
|
+
* protocol - two layers, two streams, both captured and neither attributed to
|
|
159
|
+
* a task - and `@nx/gradle` emits configuration-phase errors before the first
|
|
160
|
+
* `> Task :x:y` header tells it which task to attribute to. Both catch their
|
|
161
|
+
* own crash and backfill task results, so the batch resolves and lands here
|
|
162
|
+
* rather than in the caller's failure path.
|
|
163
|
+
*
|
|
164
|
+
* Rendering both duplicates some bytes, deliberately. `@nx/maven` and
|
|
165
|
+
* `@nx/gradle` tee each task's output into the worker's stdio on the way to
|
|
166
|
+
* `terminalOutput`, so a failing task's body appears in the fold and again in
|
|
167
|
+
* its own block. That is bounded on the default style, where successes
|
|
168
|
+
* collapse to a line each and a crashed batch backfills a short
|
|
169
|
+
* `e.toString()` rather than a body, so the case with the largest fold
|
|
170
|
+
* duplicates the least. Under a full-output style it is not bounded: every
|
|
171
|
+
* task prints in full beside a log that already contains it, which is the
|
|
172
|
+
* price of that style asking for everything. What it buys either way is
|
|
173
|
+
* attribution the fold cannot express. The
|
|
174
|
+
* alternative, letting the fold replace per-task rendering, silently dropped
|
|
175
|
+
* `@nx/jest`'s summaries and is what this shape exists to avoid.
|
|
176
|
+
*
|
|
177
|
+
* A batch that never reported results is handled by the caller instead.
|
|
178
|
+
*/
|
|
179
|
+
private printGroupedBatchOutput;
|
|
180
|
+
/**
|
|
181
|
+
* Renders a batch's whole output as one fold, plus — unless `redirectLines`
|
|
182
|
+
* is off — a line per task pointing at it. The fold is labelled with the
|
|
183
|
+
* executor and a run-unique id (the same
|
|
184
|
+
* executor can run more than one batch), rather than an arbitrary task. Safe
|
|
185
|
+
* to write to `output` directly: grouping implies GitHub Actions implies a
|
|
186
|
+
* non-TTY, static lifecycle.
|
|
187
|
+
*/
|
|
188
|
+
private printBatchFold;
|
|
121
189
|
/**
|
|
122
190
|
* Bulk-resolve cache hits for a set of tasks: fetch cached entries,
|
|
123
191
|
* copy outputs as needed, fire lifecycle, and return the TaskResults
|
|
@@ -90,6 +90,12 @@ class TaskOrchestrator {
|
|
|
90
90
|
this.pendingDiscreteWorkers = new Set();
|
|
91
91
|
this.groups = [];
|
|
92
92
|
this.continuousTasksStarted = 0;
|
|
93
|
+
/**
|
|
94
|
+
* How many folds each batch id has rendered. A batch that reports a strict
|
|
95
|
+
* subset of its tasks is re-run under the same id, so one id can produce more
|
|
96
|
+
* than one fold and the redirect lines have to point at the right one.
|
|
97
|
+
*/
|
|
98
|
+
this.batchFoldRenders = new Map();
|
|
93
99
|
this.bailed = false;
|
|
94
100
|
this.resolveStopPromise = null;
|
|
95
101
|
this.stopRequested = false;
|
|
@@ -576,8 +582,9 @@ class TaskOrchestrator {
|
|
|
576
582
|
}
|
|
577
583
|
async runBatch(batch, env, groupId) {
|
|
578
584
|
const runBatchStart = perf_hooks_1.performance.mark('TaskOrchestrator-run-batch:start');
|
|
585
|
+
let batchProcess;
|
|
579
586
|
try {
|
|
580
|
-
|
|
587
|
+
batchProcess = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.projectGraph, this.fullTaskGraph, env);
|
|
581
588
|
// Stream output from batch process to the batch
|
|
582
589
|
batchProcess.onOutput((output) => {
|
|
583
590
|
this.options.lifeCycle.appendBatchOutput?.(batch.id, output);
|
|
@@ -595,7 +602,12 @@ class TaskOrchestrator {
|
|
|
595
602
|
// Skipped tasks didn't run, so they have no terminal output and don't
|
|
596
603
|
// need a per-task PTY — calling printTaskTerminalOutput would otherwise
|
|
597
604
|
// allocate one just to write a cursor-hide escape.
|
|
598
|
-
|
|
605
|
+
//
|
|
606
|
+
// When the batch is being folded, printing is deferred to batch end
|
|
607
|
+
// (printGroupedBatchOutput), which always renders each task through the
|
|
608
|
+
// life cycle and adds the worker's whole log as a fold when the run
|
|
609
|
+
// asked for full output or any task failed or was stopped.
|
|
610
|
+
if (status !== 'skipped' && !(0, output_1.shouldGroupBatchOutput)()) {
|
|
599
611
|
this.options.lifeCycle.printTaskTerminalOutput(task, status, result.terminalOutput ?? '');
|
|
600
612
|
}
|
|
601
613
|
task.startTime = result.startTime;
|
|
@@ -607,7 +619,7 @@ class TaskOrchestrator {
|
|
|
607
619
|
});
|
|
608
620
|
const results = await batchProcess.getResults();
|
|
609
621
|
const batchResultEntries = Object.entries(results);
|
|
610
|
-
|
|
622
|
+
const taskResults = batchResultEntries.map(([taskId, result]) => {
|
|
611
623
|
const task = this.taskGraph.tasks[taskId];
|
|
612
624
|
task.startTime = result.startTime;
|
|
613
625
|
task.endTime = result.endTime;
|
|
@@ -619,10 +631,14 @@ class TaskOrchestrator {
|
|
|
619
631
|
terminalOutput: result.terminalOutput,
|
|
620
632
|
};
|
|
621
633
|
});
|
|
634
|
+
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
635
|
+
this.renderBatchOutputSafely(batch.id, () => this.printGroupedBatchOutput(batch, taskResults, batchProcess.getCapturedOutputPath()));
|
|
636
|
+
}
|
|
637
|
+
return taskResults;
|
|
622
638
|
}
|
|
623
639
|
catch (e) {
|
|
624
640
|
const isBatchStopping = this.stopRequested;
|
|
625
|
-
|
|
641
|
+
const taskResults = Object.keys(batch.taskGraph.tasks).map((taskId) => {
|
|
626
642
|
const task = this.taskGraph.tasks[taskId];
|
|
627
643
|
if (isBatchStopping) {
|
|
628
644
|
task.endTime = Date.now();
|
|
@@ -634,12 +650,147 @@ class TaskOrchestrator {
|
|
|
634
650
|
terminalOutput: isBatchStopping ? '' : (e.stack ?? e.message ?? ''),
|
|
635
651
|
};
|
|
636
652
|
});
|
|
653
|
+
// The worker died without reporting results, so nothing was attributed to
|
|
654
|
+
// a task and no per-task output ran. Everything it wrote went to
|
|
655
|
+
// stdout/stderr, held back under log grouping — surface it as one fold.
|
|
656
|
+
// Outside grouping it already streamed live. This matters just as much
|
|
657
|
+
// when the batch was stopped: every task is marked stopped whether or not
|
|
658
|
+
// it finished, so the log is the only record of what got through. Only
|
|
659
|
+
// the exit-code error is dropped there, since it restates the
|
|
660
|
+
// cancellation.
|
|
661
|
+
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
662
|
+
const capturedOutputPath = batchProcess?.getCapturedOutputPath();
|
|
663
|
+
const trailer = isBatchStopping ? undefined : e.message;
|
|
664
|
+
if (capturedOutputPath || trailer) {
|
|
665
|
+
this.renderBatchOutputSafely(batch.id, () => this.printBatchFold(batch, taskResults, {
|
|
666
|
+
capturedOutputPath,
|
|
667
|
+
trailer,
|
|
668
|
+
}));
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return taskResults;
|
|
637
672
|
}
|
|
638
673
|
finally {
|
|
674
|
+
batchProcess?.discardCapturedOutput();
|
|
639
675
|
const runBatchEnd = perf_hooks_1.performance.mark('TaskOrchestrator-run-batch:end');
|
|
640
676
|
perf_hooks_1.performance.measure('TaskOrchestrator-run-batch', runBatchStart.name, runBatchEnd.name);
|
|
641
677
|
}
|
|
642
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* Rendering a batch's output must never change the batch's results. A throw
|
|
681
|
+
* from the printer would otherwise land in `runBatch`'s own error handling:
|
|
682
|
+
* on the resolved path it rewrites every task to `failure` with the printer's
|
|
683
|
+
* stack as its output — reporting a green build red to the life cycles and Nx
|
|
684
|
+
* Cloud — and on the crash path it escapes `runBatch`, replacing the built
|
|
685
|
+
* failure results with the printer's error. Both call sites degrade to a
|
|
686
|
+
* warning here instead.
|
|
687
|
+
*/
|
|
688
|
+
renderBatchOutputSafely(batchId, render) {
|
|
689
|
+
try {
|
|
690
|
+
render();
|
|
691
|
+
}
|
|
692
|
+
catch (e) {
|
|
693
|
+
output_1.output.warn({
|
|
694
|
+
title: `Could not render output for batch ${batchId}`,
|
|
695
|
+
bodyLines: [e.message],
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Prints a completed batch's output once, under log grouping. Live forwarding
|
|
701
|
+
* was suppressed while grouping, so this is the only copy — which is why the
|
|
702
|
+
* requested output style has to reach this path rather than stopping at the
|
|
703
|
+
* life cycle.
|
|
704
|
+
*
|
|
705
|
+
* Two things are rendered, and they answer different questions.
|
|
706
|
+
*
|
|
707
|
+
* Every task always renders through the life cycle, exactly as in a non-batch
|
|
708
|
+
* run - failures in full, successes collapsed to a line for run-many, plus the
|
|
709
|
+
* initiating project in full for run-one. That is what attributes output to a
|
|
710
|
+
* task, and it is the only place some of it exists: `@nx/jest` synthesizes
|
|
711
|
+
* each task's `terminalOutput` from an aggregated result and never writes
|
|
712
|
+
* those per-project summaries to the worker's stdio at all.
|
|
713
|
+
*
|
|
714
|
+
* The worker's whole captured log is rendered as a fold above them when the
|
|
715
|
+
* run asked for full output, or when any task failed or was stopped. A
|
|
716
|
+
* diagnostic that explains a failure is routinely one no task claimed:
|
|
717
|
+
* `@nx/maven`'s batch impl writes its exit-code dump and failed-task outputs
|
|
718
|
+
* to the worker's stderr via `console.error`, and the Maven JVM it spawns
|
|
719
|
+
* points slf4j at `System.out` because its own stderr carries the result
|
|
720
|
+
* protocol - two layers, two streams, both captured and neither attributed to
|
|
721
|
+
* a task - and `@nx/gradle` emits configuration-phase errors before the first
|
|
722
|
+
* `> Task :x:y` header tells it which task to attribute to. Both catch their
|
|
723
|
+
* own crash and backfill task results, so the batch resolves and lands here
|
|
724
|
+
* rather than in the caller's failure path.
|
|
725
|
+
*
|
|
726
|
+
* Rendering both duplicates some bytes, deliberately. `@nx/maven` and
|
|
727
|
+
* `@nx/gradle` tee each task's output into the worker's stdio on the way to
|
|
728
|
+
* `terminalOutput`, so a failing task's body appears in the fold and again in
|
|
729
|
+
* its own block. That is bounded on the default style, where successes
|
|
730
|
+
* collapse to a line each and a crashed batch backfills a short
|
|
731
|
+
* `e.toString()` rather than a body, so the case with the largest fold
|
|
732
|
+
* duplicates the least. Under a full-output style it is not bounded: every
|
|
733
|
+
* task prints in full beside a log that already contains it, which is the
|
|
734
|
+
* price of that style asking for everything. What it buys either way is
|
|
735
|
+
* attribution the fold cannot express. The
|
|
736
|
+
* alternative, letting the fold replace per-task rendering, silently dropped
|
|
737
|
+
* `@nx/jest`'s summaries and is what this shape exists to avoid.
|
|
738
|
+
*
|
|
739
|
+
* A batch that never reported results is handled by the caller instead.
|
|
740
|
+
*/
|
|
741
|
+
printGroupedBatchOutput(batch, taskResults, capturedOutputPath) {
|
|
742
|
+
// Read from the same field the streaming decision uses. `this.options` has
|
|
743
|
+
// its own `outputStyle`, merged from `nx.json`'s tasksRunnerOptions, so the
|
|
744
|
+
// two disagree whenever a style is configured there but not named on the
|
|
745
|
+
// command line - and `init-tasks-runner` passes a populated `options` with
|
|
746
|
+
// no style argument at all, so on that path only `options` can carry one.
|
|
747
|
+
const printsFullOutput = (0, output_1.printsFullTaskOutput)({
|
|
748
|
+
verbose: this.options.verbose,
|
|
749
|
+
outputStyle: this.outputStyle,
|
|
750
|
+
});
|
|
751
|
+
const batchOwnsTheDiagnostic = taskResults.some((r) => r.status === 'failure' || r.status === 'stopped');
|
|
752
|
+
if ((printsFullOutput || batchOwnsTheDiagnostic) && capturedOutputPath) {
|
|
753
|
+
// No redirect lines: every task renders itself below, so there is nothing
|
|
754
|
+
// to redirect anyone to.
|
|
755
|
+
this.printBatchFold(batch, taskResults, { capturedOutputPath }, { redirectLines: false });
|
|
756
|
+
}
|
|
757
|
+
for (const { task, status, terminalOutput } of taskResults) {
|
|
758
|
+
if (status !== 'skipped') {
|
|
759
|
+
this.options.lifeCycle.printTaskTerminalOutput(task, status, terminalOutput ?? '');
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Renders a batch's whole output as one fold, plus — unless `redirectLines`
|
|
765
|
+
* is off — a line per task pointing at it. The fold is labelled with the
|
|
766
|
+
* executor and a run-unique id (the same
|
|
767
|
+
* executor can run more than one batch), rather than an arbitrary task. Safe
|
|
768
|
+
* to write to `output` directly: grouping implies GitHub Actions implies a
|
|
769
|
+
* non-TTY, static lifecycle.
|
|
770
|
+
*/
|
|
771
|
+
printBatchFold(batch, taskResults, body, { redirectLines = true } = {}) {
|
|
772
|
+
// batch.id is already `<executor> <n>`, numbered per executor when the batch
|
|
773
|
+
// was scheduled. Deriving a second number here would drift from it, since
|
|
774
|
+
// only batches that render a fold would be counted. The suffix disambiguates
|
|
775
|
+
// re-runs of the same batch rather than replacing the id, so it cannot.
|
|
776
|
+
const renders = (this.batchFoldRenders.get(batch.id) ?? 0) + 1;
|
|
777
|
+
this.batchFoldRenders.set(batch.id, renders);
|
|
778
|
+
const label = renders === 1 ? `batch ${batch.id}` : `batch ${batch.id}:${renders}`;
|
|
779
|
+
const worst = taskResults.some((r) => r.status === 'failure')
|
|
780
|
+
? 'failure'
|
|
781
|
+
: taskResults.some((r) => r.status === 'stopped')
|
|
782
|
+
? 'stopped'
|
|
783
|
+
: 'success';
|
|
784
|
+
output_1.output.logBatchGroup(label, body, worst);
|
|
785
|
+
if (!redirectLines) {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
for (const { task, status } of taskResults) {
|
|
789
|
+
if (status !== 'skipped') {
|
|
790
|
+
output_1.output.logCommandRedirect((0, utils_1.getPrintableCommandArgsForTask)(task).join(' '), status, `(output in "${label}" above)`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
643
794
|
// endregion Batch
|
|
644
795
|
// region Single Task
|
|
645
796
|
/**
|
|
@@ -727,7 +878,7 @@ class TaskOrchestrator {
|
|
|
727
878
|
await this.preRunSteps([task], { groupId });
|
|
728
879
|
const pipeOutput = await this.pipeOutputCapture(task);
|
|
729
880
|
const temporaryOutputPath = this.cache.temporaryOutputPath(task);
|
|
730
|
-
const streamOutput = this.outputStyle
|
|
881
|
+
const streamOutput = (0, output_1.isStaticOutputStyle)(this.outputStyle)
|
|
731
882
|
? false
|
|
732
883
|
: (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
|
|
733
884
|
const env = pipeOutput
|
|
@@ -805,7 +956,7 @@ class TaskOrchestrator {
|
|
|
805
956
|
else if (this.tuiEnabled) {
|
|
806
957
|
if (runningTask instanceof pseudo_terminal_1.PseudoTtyProcess) {
|
|
807
958
|
// This is an external of a the pseudo terminal where a task is running and can be passed to the TUI
|
|
808
|
-
this.options.lifeCycle.registerRunningTask(task.id, runningTask.
|
|
959
|
+
this.options.lifeCycle.registerRunningTask(task.id, runningTask.getPtyHandles());
|
|
809
960
|
runningTask.onOutput((output) => {
|
|
810
961
|
this.options.lifeCycle.appendTaskOutput(task.id, output, true);
|
|
811
962
|
});
|
|
@@ -854,7 +1005,7 @@ class TaskOrchestrator {
|
|
|
854
1005
|
if (this.tuiEnabled) {
|
|
855
1006
|
if (runningTask instanceof pseudo_terminal_1.PseudoTtyProcess) {
|
|
856
1007
|
// This is an external of a the pseudo terminal where a task is running and can be passed to the TUI
|
|
857
|
-
this.options.lifeCycle.registerRunningTask(task.id, runningTask.
|
|
1008
|
+
this.options.lifeCycle.registerRunningTask(task.id, runningTask.getPtyHandles());
|
|
858
1009
|
runningTask.onOutput((output) => {
|
|
859
1010
|
this.options.lifeCycle.appendTaskOutput(task.id, output, true);
|
|
860
1011
|
});
|
|
@@ -938,7 +1089,7 @@ class TaskOrchestrator {
|
|
|
938
1089
|
const pipeOutput = await this.pipeOutputCapture(task);
|
|
939
1090
|
// obtain metadata
|
|
940
1091
|
const temporaryOutputPath = this.cache.temporaryOutputPath(task);
|
|
941
|
-
const streamOutput = this.outputStyle
|
|
1092
|
+
const streamOutput = (0, output_1.isStaticOutputStyle)(this.outputStyle)
|
|
942
1093
|
? false
|
|
943
1094
|
: (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
|
|
944
1095
|
let env = pipeOutput
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NxJsonConfiguration } from '../config/nx-json';
|
|
2
|
+
/**
|
|
3
|
+
* Analytics are opt-in: both `"analytics": false` and an unset flag mean no
|
|
4
|
+
* event is ever sent. Anything enabled for the sake of analytics (network
|
|
5
|
+
* allowlists, endpoints) gates on this, not on an explicit opt-out alone.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isAnalyticsEnabled(nxJson: NxJsonConfiguration | null): boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isAnalyticsEnabled = isAnalyticsEnabled;
|
|
4
|
+
/**
|
|
5
|
+
* Analytics are opt-in: both `"analytics": false` and an unset flag mean no
|
|
6
|
+
* event is ever sent. Anything enabled for the sake of analytics (network
|
|
7
|
+
* allowlists, endpoints) gates on this, not on an explicit opt-out alone.
|
|
8
|
+
*/
|
|
9
|
+
function isAnalyticsEnabled(nxJson) {
|
|
10
|
+
return nxJson?.analytics === true;
|
|
11
|
+
}
|