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.
Files changed (223) hide show
  1. package/dist/bin/nx.js +2 -1
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/release/index.d.ts +1 -1
  4. package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
  5. package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
  6. package/dist/src/analytics/analytics.d.ts +6 -0
  7. package/dist/src/analytics/analytics.js +16 -8
  8. package/dist/src/analytics/index.d.ts +1 -1
  9. package/dist/src/analytics/index.js +2 -1
  10. package/dist/src/command-line/add/add.js +13 -1
  11. package/dist/src/command-line/affected/affected.js +1 -0
  12. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  13. package/dist/src/command-line/graph/graph.d.ts +1 -0
  14. package/dist/src/command-line/graph/graph.js +15 -6
  15. package/dist/src/command-line/import/import.js +2 -3
  16. package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
  17. package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
  18. package/dist/src/command-line/init/command-object.js +10 -2
  19. package/dist/src/command-line/init/configure-plugins.js +3 -2
  20. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
  21. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
  22. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
  23. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
  24. package/dist/src/command-line/init/implementation/angular/index.js +4 -2
  25. package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
  26. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
  27. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
  28. package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
  29. package/dist/src/command-line/init/implementation/utils.js +22 -3
  30. package/dist/src/command-line/init/init-v2.js +4 -5
  31. package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
  32. package/dist/src/command-line/migrate/execute-migration.js +389 -0
  33. package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
  34. package/dist/src/command-line/migrate/migrate.d.ts +5 -45
  35. package/dist/src/command-line/migrate/migrate.js +122 -402
  36. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
  37. package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
  38. package/dist/src/command-line/release/changelog.js +5 -0
  39. package/dist/src/command-line/release/index.d.ts +1 -1
  40. package/dist/src/command-line/release/utils/git.js +7 -3
  41. package/dist/src/command-line/release/utils/release-graph.d.ts +19 -2
  42. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  43. package/dist/src/command-line/release/utils/remote-release-clients/github.js +7 -1
  44. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
  45. package/dist/src/command-line/release/utils/shared.d.ts +2 -2
  46. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  47. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  48. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  49. package/dist/src/command-line/release/version/version-actions.js +9 -1
  50. package/dist/src/command-line/release/version.js +9 -5
  51. package/dist/src/command-line/reset/reset.js +6 -1
  52. package/dist/src/command-line/run/run-one.js +1 -0
  53. package/dist/src/command-line/run-many/run-many.js +1 -0
  54. package/dist/src/command-line/show/show-target/info.js +11 -2
  55. package/dist/src/command-line/show/show-target/inputs.js +50 -153
  56. package/dist/src/command-line/show/show-target/outputs.js +48 -173
  57. package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
  58. package/dist/src/command-line/show/show-target/utils.js +83 -3
  59. package/dist/src/command-line/watch/watch.js +13 -0
  60. package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  61. package/dist/src/commands-runner/create-command-graph.js +5 -0
  62. package/dist/src/config/nx-json.d.ts +5 -3
  63. package/dist/src/core/graph/main.js +1 -1
  64. package/dist/src/core/graph/styles.js +1 -1
  65. package/dist/src/daemon/client/client.d.ts +52 -3
  66. package/dist/src/daemon/client/client.js +177 -55
  67. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  68. package/dist/src/daemon/client/daemon-environment.js +110 -2
  69. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  70. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  71. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  72. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  73. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  74. package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
  75. package/dist/src/daemon/server/latest-nx.js +5 -2
  76. package/dist/src/daemon/server/server.js +31 -4
  77. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  78. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  79. package/dist/src/daemon/socket-utils.d.ts +1 -0
  80. package/dist/src/daemon/socket-utils.js +24 -3
  81. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  82. package/dist/src/daemon/tmp-dir.js +437 -15
  83. package/dist/src/devkit-internals.d.ts +96 -3
  84. package/dist/src/devkit-internals.js +200 -4
  85. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  86. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  87. package/dist/src/generators/tree.d.ts +4 -2
  88. package/dist/src/generators/utils/nx-json.js +13 -3
  89. package/dist/src/hasher/check-task-files.d.ts +86 -0
  90. package/dist/src/hasher/check-task-files.js +378 -0
  91. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  92. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  93. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  94. package/dist/src/native/index.d.ts +31 -2
  95. package/dist/src/native/index.js +71 -28
  96. package/dist/src/native/native-bindings.js +3 -0
  97. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  98. package/dist/src/native/native-file-cache-location.js +86 -12
  99. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  100. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  101. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  102. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  103. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  104. package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
  105. package/dist/src/plugins/js/lock-file/pnpm-parser.js +110 -17
  106. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +15 -9
  107. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
  108. package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
  109. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  110. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
  111. package/dist/src/plugins/js/utils/register.d.ts +18 -0
  112. package/dist/src/plugins/js/utils/register.js +81 -0
  113. package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
  114. package/dist/src/plugins/js/utils/typescript.js +15 -0
  115. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  116. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  117. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  118. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  119. package/dist/src/project-graph/build-project-graph.js +7 -1
  120. package/dist/src/project-graph/error-types.d.ts +12 -1
  121. package/dist/src/project-graph/error-types.js +68 -3
  122. package/dist/src/project-graph/file-utils.js +6 -1
  123. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  124. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +22 -1
  125. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  126. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  127. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  128. package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
  129. package/dist/src/project-graph/plugins/transpiler.js +4 -0
  130. package/dist/src/project-graph/project-graph.js +23 -0
  131. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
  132. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
  133. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
  134. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +16 -15
  135. package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
  136. package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
  137. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
  138. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
  139. package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
  140. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
  141. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
  142. package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
  143. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
  144. package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
  145. package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
  146. package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
  147. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
  148. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
  149. package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
  150. package/dist/src/tasks-runner/run-command.js +4 -2
  151. package/dist/src/tasks-runner/task-env.d.ts +9 -0
  152. package/dist/src/tasks-runner/task-env.js +31 -4
  153. package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
  154. package/dist/src/tasks-runner/task-orchestrator.js +23 -10
  155. package/dist/src/tasks-runner/utils.js +2 -6
  156. package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
  157. package/dist/src/utils/acknowledge-build-scripts.js +102 -0
  158. package/dist/src/utils/analytics-prompt.d.ts +0 -6
  159. package/dist/src/utils/analytics-prompt.js +0 -51
  160. package/dist/src/utils/assert-workspace-validity.js +7 -2
  161. package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
  162. package/dist/src/utils/catalog/manager-utils.js +22 -5
  163. package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
  164. package/dist/src/utils/catalog/pnpm-manager.js +3 -15
  165. package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
  166. package/dist/src/utils/catalog/yarn-manager.js +3 -15
  167. package/dist/src/utils/command-line-utils.js +30 -20
  168. package/dist/src/utils/fileutils.d.ts +5 -0
  169. package/dist/src/utils/fileutils.js +7 -2
  170. package/dist/src/utils/git-revision.d.ts +12 -0
  171. package/dist/src/utils/git-revision.js +25 -0
  172. package/dist/src/utils/git-utils.d.ts +16 -3
  173. package/dist/src/utils/git-utils.js +146 -52
  174. package/dist/src/utils/git-worktrees.d.ts +30 -0
  175. package/dist/src/utils/git-worktrees.js +212 -0
  176. package/dist/src/utils/ignore.d.ts +128 -1
  177. package/dist/src/utils/ignore.js +182 -12
  178. package/dist/src/utils/long-running-target.d.ts +10 -0
  179. package/dist/src/utils/long-running-target.js +19 -0
  180. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  181. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  182. package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
  183. package/dist/src/utils/min-release-age/packument.js +1 -1
  184. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  185. package/dist/src/utils/nx-tmp-dir.js +40 -0
  186. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  187. package/dist/src/utils/owned-private-dir.js +323 -0
  188. package/dist/src/utils/package-json.js +11 -7
  189. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  190. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  191. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  192. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  193. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  194. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  195. package/dist/src/utils/package-manager.d.ts +23 -2
  196. package/dist/src/utils/package-manager.js +264 -43
  197. package/dist/src/utils/provenance.js +18 -16
  198. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  199. package/dist/src/utils/registry-config/bun.js +257 -0
  200. package/dist/src/utils/registry-config/index.d.ts +13 -0
  201. package/dist/src/utils/registry-config/index.js +102 -0
  202. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  203. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  204. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  205. package/dist/src/utils/registry-config/utils.js +496 -0
  206. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  207. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  208. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  209. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  210. package/dist/src/utils/safe-spawn.d.ts +24 -0
  211. package/dist/src/utils/safe-spawn.js +104 -0
  212. package/dist/src/utils/shell-quoting.d.ts +15 -0
  213. package/dist/src/utils/shell-quoting.js +35 -0
  214. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  215. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  216. package/dist/src/utils/workspace-id.d.ts +20 -0
  217. package/dist/src/utils/workspace-id.js +54 -0
  218. package/migrations.json +13 -1
  219. package/package.json +22 -17
  220. package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
  221. package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
  222. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  223. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getForceColorForChild = getForceColorForChild;
3
4
  exports.getEnvVariablesForBatchProcess = getEnvVariablesForBatchProcess;
4
5
  exports.getTaskSpecificEnv = getTaskSpecificEnv;
5
6
  exports.getEnvVariablesForTask = getEnvVariablesForTask;
@@ -11,13 +12,33 @@ const dotenv_expand_1 = require("dotenv-expand");
11
12
  const node_path_1 = require("node:path");
12
13
  const workspace_root_1 = require("../utils/workspace-root");
13
14
  const task_env_paths_1 = require("./task-env-paths");
15
+ /**
16
+ * Resolves the FORCE_COLOR value for forked child processes.
17
+ *
18
+ * When the user sets FORCE_COLOR=0, bin/nx.ts deletes it from process.env
19
+ * (workaround for picocolors treating "0" as truthy) and saves the original
20
+ * value in NX_ORIGINAL_FORCE_COLOR. Without this check, the undefined
21
+ * FORCE_COLOR would default to 'true', re-enabling colors in all children.
22
+ */
23
+ function getForceColorForChild() {
24
+ if (process.env.FORCE_COLOR !== undefined) {
25
+ return process.env.FORCE_COLOR;
26
+ }
27
+ if (process.env.NX_ORIGINAL_FORCE_COLOR === '0') {
28
+ return '0';
29
+ }
30
+ return 'true';
31
+ }
14
32
  function getEnvVariablesForBatchProcess(skipNxCache, captureStderr) {
15
- return {
33
+ const res = {
16
34
  // User Process Env Variables override Dotenv Variables
17
35
  ...process.env,
18
36
  // Nx Env Variables overrides everything
19
- ...getNxEnvVariablesForForkedProcess(process.env.FORCE_COLOR === undefined ? 'true' : process.env.FORCE_COLOR, skipNxCache, captureStderr),
37
+ ...getNxEnvVariablesForForkedProcess(getForceColorForChild(), skipNxCache, captureStderr),
20
38
  };
39
+ // NX_ORIGINAL_FORCE_COLOR is an internal signal and should not leak into child processes
40
+ delete res.NX_ORIGINAL_FORCE_COLOR;
41
+ return res;
21
42
  }
22
43
  // The orchestrator now calls this eagerly during the coordinator pre-hash
23
44
  // in addition to processTask (and again in hashBatchTasks), so the same
@@ -58,6 +79,9 @@ function getEnvVariablesForTask(task, taskSpecificEnv, forceColor, skipNxCache,
58
79
  }
59
80
  // we don't reset NX_BASE or NX_HEAD because those are set by the user and should be preserved
60
81
  delete res.NX_SET_CLI;
82
+ // NX_ORIGINAL_FORCE_COLOR is an internal signal used by getForceColorForChild()
83
+ // and should not leak into child processes
84
+ delete res.NX_ORIGINAL_FORCE_COLOR;
61
85
  return res;
62
86
  }
63
87
  function getNxEnvVariablesForForkedProcess(forceColor, skipNxCache, captureStderr, outputPath, streamOutput) {
@@ -142,10 +166,13 @@ function getOwnerTargetForTask(task, graph) {
142
166
  for (const targets of Object.values(project.data.metadata.targetGroups)) {
143
167
  if (targets.includes(task.target.target)) {
144
168
  for (const target of targets) {
145
- if (project.data.targets[target].metadata?.nonAtomizedTarget) {
169
+ // a target group can name a target the project does not define —
170
+ // inference plugins build the group and the targets separately, so
171
+ // the two can disagree. skip the phantom rather than dereferencing it.
172
+ if (project.data.targets[target]?.metadata?.nonAtomizedTarget) {
146
173
  return [
147
174
  target,
148
- project.data.targets[target].metadata?.nonAtomizedTarget,
175
+ project.data.targets[target]?.metadata?.nonAtomizedTarget,
149
176
  ];
150
177
  }
151
178
  }
@@ -35,6 +35,7 @@ export declare class TaskOrchestrator {
35
35
  private reverseTaskDeps;
36
36
  private initializingTaskIds;
37
37
  private processedTasks;
38
+ private cacheMissedHashes;
38
39
  private completedTasks;
39
40
  private waitingForTasks;
40
41
  private pendingDiscreteWorkers;
@@ -100,7 +101,9 @@ export declare class TaskOrchestrator {
100
101
  * The coordinator relies on this running unconditionally (when cache
101
102
  * is enabled): tasks dispatched in step 5 via runTaskDirectly skip
102
103
  * their own cache lookup on the assumption that this has already
103
- * confirmed them as misses. Don't add length-based bails.
104
+ * confirmed them as misses. Excluding cacheMissedHashes preserves that
105
+ * invariant — every dispatched hash was queried exactly once — but
106
+ * don't add other length-based bails.
104
107
  */
105
108
  private resolveCachedTasksBulk;
106
109
  /**
@@ -79,6 +79,12 @@ class TaskOrchestrator {
79
79
  // underlying real tasks become the anchors.
80
80
  this.initializingTaskIds = (0, utils_1.expandInitiatingTasksThroughNoop)(this.initiatingTasks, this.taskGraph, this.projectGraph);
81
81
  this.processedTasks = new Map();
82
+ // Hashes confirmed absent from the cache this run. A confirmed miss can
83
+ // only become a hit when the task itself runs — and then it leaves the
84
+ // schedule — so a missed hash never needs re-querying. Without this, a
85
+ // miss waiting for a worker slot is re-queried (including the remote
86
+ // retrieval) on every coordinator cycle.
87
+ this.cacheMissedHashes = new Set();
82
88
  this.completedTasks = new Map();
83
89
  this.waitingForTasks = [];
84
90
  this.pendingDiscreteWorkers = new Set();
@@ -324,9 +330,12 @@ class TaskOrchestrator {
324
330
  * inside DbCache.getBatch.
325
331
  */
326
332
  async fetchCacheHits(tasks) {
327
- const batchResults = await this.cache.getBatch(tasks);
333
+ const tasksToQuery = tasks.filter((t) => t.hash && !this.cacheMissedHashes.has(t.hash));
334
+ if (tasksToQuery.length === 0)
335
+ return [];
336
+ const batchResults = await this.cache.getBatch(tasksToQuery);
328
337
  const cacheHits = [];
329
- for (const task of tasks) {
338
+ for (const task of tasksToQuery) {
330
339
  const cachedResult = batchResults.get(task.hash);
331
340
  // Replay a cached result only under the same condition it was cached
332
341
  // under (shouldCacheTaskResult): successes always, failures only when
@@ -335,6 +344,9 @@ class TaskOrchestrator {
335
344
  if (cachedResult && this.shouldCacheTaskResult(task, cachedResult.code)) {
336
345
  cacheHits.push({ task, cachedResult });
337
346
  }
347
+ else {
348
+ this.cacheMissedHashes.add(task.hash);
349
+ }
338
350
  }
339
351
  return cacheHits;
340
352
  }
@@ -396,14 +408,19 @@ class TaskOrchestrator {
396
408
  * The coordinator relies on this running unconditionally (when cache
397
409
  * is enabled): tasks dispatched in step 5 via runTaskDirectly skip
398
410
  * their own cache lookup on the assumption that this has already
399
- * confirmed them as misses. Don't add length-based bails.
411
+ * confirmed them as misses. Excluding cacheMissedHashes preserves that
412
+ * invariant — every dispatched hash was queried exactly once — but
413
+ * don't add other length-based bails.
400
414
  */
401
415
  async resolveCachedTasksBulk() {
402
416
  const { scheduledTasks } = this.tasksSchedule.getAllScheduledTasks();
403
417
  const candidates = [];
404
418
  for (const id of scheduledTasks) {
405
419
  const task = this.taskGraph.tasks[id];
406
- if (task.hash && !task.continuous && task.cache) {
420
+ if (task.hash &&
421
+ !this.cacheMissedHashes.has(task.hash) &&
422
+ !task.continuous &&
423
+ task.cache) {
407
424
  candidates.push(task);
408
425
  }
409
426
  }
@@ -714,9 +731,7 @@ class TaskOrchestrator {
714
731
  ? false
715
732
  : (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
716
733
  const env = pipeOutput
717
- ? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, process.env.FORCE_COLOR === undefined
718
- ? 'true'
719
- : process.env.FORCE_COLOR, this.options.skipNxCache, this.options.captureStderr, null, null)
734
+ ? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, (0, task_env_1.getForceColorForChild)(), this.options.skipNxCache, this.options.captureStderr, null, null)
720
735
  : (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, undefined, this.options.skipNxCache, this.options.captureStderr, temporaryOutputPath, streamOutput);
721
736
  let resolveDiscreteExit;
722
737
  const discreteExitHandled = new Promise((r) => (resolveDiscreteExit = r));
@@ -927,9 +942,7 @@ class TaskOrchestrator {
927
942
  ? false
928
943
  : (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
929
944
  let env = pipeOutput
930
- ? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, process.env.FORCE_COLOR === undefined
931
- ? 'true'
932
- : process.env.FORCE_COLOR, this.options.skipNxCache, this.options.captureStderr, null, null)
945
+ ? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, (0, task_env_1.getForceColorForChild)(), this.options.skipNxCache, this.options.captureStderr, null, null)
933
946
  : (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, undefined, this.options.skipNxCache, this.options.captureStderr, temporaryOutputPath, streamOutput);
934
947
  this.detectTaskInvocationLoop(task);
935
948
  const childProcess = await this.runTask(task, streamOutput, env, temporaryOutputPath, pipeOutput);
@@ -36,6 +36,7 @@ const fileutils_1 = require("../utils/fileutils");
36
36
  const find_matching_projects_1 = require("../utils/find-matching-projects");
37
37
  const legacy_depends_on_warning_1 = require("./legacy-depends-on-warning");
38
38
  const globs_1 = require("../utils/globs");
39
+ const long_running_target_1 = require("../utils/long-running-target");
39
40
  const path_1 = require("../utils/path");
40
41
  const serialize_overrides_into_command_line_1 = require("../utils/serialize-overrides-into-command-line");
41
42
  const split_target_1 = require("../utils/split-target");
@@ -429,14 +430,9 @@ function isCacheableTask(task) {
429
430
  return task.cache;
430
431
  }
431
432
  function longRunningTask(task) {
432
- const t = task.target.target;
433
433
  return (task.continuous ||
434
434
  (!!task.overrides['watch'] && task.overrides['watch'] !== 'false') ||
435
- t.endsWith(':watch') ||
436
- t.endsWith('-watch') ||
437
- t === 'serve' ||
438
- t === 'dev' ||
439
- t === 'start');
435
+ (0, long_running_target_1.isLongRunningTargetName)(task.target.target));
440
436
  }
441
437
  // TODO: vsavkin remove when nx-cloud doesn't depend on it
442
438
  function unparse(options) {
@@ -0,0 +1,13 @@
1
+ import type { Tree } from '../generators/tree';
2
+ import type { PackageManager } from './package-manager';
3
+ /**
4
+ * Records build-script decisions for dependencies that are about to be
5
+ * installed, in whatever form the given package manager understands.
6
+ *
7
+ * Only pnpm needs this today: pnpm 11+ refuses to install a dependency whose
8
+ * build scripts are neither allowed nor denied, so the generator or command
9
+ * that introduces such a dependency records the decision up front. Other
10
+ * package managers run build scripts unconditionally, so this is a no-op for
11
+ * them.
12
+ */
13
+ export declare function acknowledgeBuildScripts(treeOrRoot: Tree | string, packageManager: PackageManager, entries: Record<string, boolean>): void;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.acknowledgeBuildScripts = acknowledgeBuildScripts;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const yaml_1 = require("yaml");
7
+ const semver_1 = require("semver");
8
+ const package_manager_1 = require("./package-manager");
9
+ const fileutils_1 = require("./fileutils");
10
+ const json_1 = require("./json");
11
+ const PNPM_WORKSPACE_FILE = 'pnpm-workspace.yaml';
12
+ /**
13
+ * Records build-script decisions for dependencies that are about to be
14
+ * installed, in whatever form the given package manager understands.
15
+ *
16
+ * Only pnpm needs this today: pnpm 11+ refuses to install a dependency whose
17
+ * build scripts are neither allowed nor denied, so the generator or command
18
+ * that introduces such a dependency records the decision up front. Other
19
+ * package managers run build scripts unconditionally, so this is a no-op for
20
+ * them.
21
+ */
22
+ function acknowledgeBuildScripts(treeOrRoot, packageManager, entries) {
23
+ if (packageManager !== 'pnpm') {
24
+ return;
25
+ }
26
+ acknowledgePnpmBuildScripts(treeOrRoot, entries);
27
+ }
28
+ /**
29
+ * Records `allowBuilds` decisions in pnpm-workspace.yaml, creating the file
30
+ * when missing (mirroring `pnpm approve-builds` in single-package repos).
31
+ *
32
+ * Comment-preserving. Existing entries are never overwritten, so user
33
+ * decisions always win. No-op for pnpm < 11, which warns instead of erroring
34
+ * and does not read `allowBuilds`.
35
+ */
36
+ function acknowledgePnpmBuildScripts(treeOrRoot, entries) {
37
+ const host = createHost(treeOrRoot);
38
+ const pnpmVersion = getPnpmVersion(host);
39
+ if (!pnpmVersion || !(0, semver_1.gte)(pnpmVersion, '11.0.0')) {
40
+ return;
41
+ }
42
+ const parsed = (0, yaml_1.parseDocument)(host.exists(PNPM_WORKSPACE_FILE) ? host.read(PNPM_WORKSPACE_FILE) : '');
43
+ // A file that doesn't parse cleanly or whose root isn't a mapping is
44
+ // malformed for pnpm; leave it alone rather than crashing or replacing the
45
+ // user's content. pnpm's own error on the file is the actionable signal.
46
+ // Empty and comment-only files have no contents at all; setIn creates the
47
+ // mapping for them while keeping whatever comments they carry.
48
+ if (parsed.errors.length > 0 ||
49
+ (parsed.contents != null && !(parsed.contents instanceof yaml_1.YAMLMap))) {
50
+ return;
51
+ }
52
+ let changed = false;
53
+ for (const [pkg, allowed] of Object.entries(entries)) {
54
+ // Only a real boolean is a user decision. pnpm's non-strict installs stub
55
+ // undecided packages with a placeholder string ("set this to true or
56
+ // false"), which would fail the next strict install if left in place.
57
+ if (typeof parsed.getIn(['allowBuilds', pkg]) !== 'boolean') {
58
+ parsed.setIn(['allowBuilds', pkg], allowed);
59
+ changed = true;
60
+ }
61
+ }
62
+ if (changed) {
63
+ host.write(PNPM_WORKSPACE_FILE, parsed.toString());
64
+ }
65
+ }
66
+ function createHost(treeOrRoot) {
67
+ if (typeof treeOrRoot === 'string') {
68
+ return {
69
+ root: treeOrRoot,
70
+ exists: (p) => (0, fs_1.existsSync)((0, path_1.join)(treeOrRoot, p)),
71
+ read: (p) => (0, fs_1.readFileSync)((0, path_1.join)(treeOrRoot, p), 'utf-8'),
72
+ write: (p, c) => (0, fs_1.writeFileSync)((0, path_1.join)(treeOrRoot, p), c),
73
+ readJson: (p) => (0, fileutils_1.readJsonFile)((0, path_1.join)(treeOrRoot, p)),
74
+ };
75
+ }
76
+ return {
77
+ root: treeOrRoot.root,
78
+ exists: (p) => treeOrRoot.exists(p),
79
+ read: (p) => treeOrRoot.read(p, 'utf-8'),
80
+ write: (p, c) => treeOrRoot.write(p, c),
81
+ readJson: (p) => (0, json_1.parseJson)(treeOrRoot.read(p, 'utf-8')),
82
+ };
83
+ }
84
+ function getPnpmVersion(host) {
85
+ // The host's packageManager field wins: during workspace creation the
86
+ // in-flight package.json only exists in the tree, not on disk.
87
+ if (host.exists('package.json')) {
88
+ const { packageManager } = host.readJson('package.json');
89
+ const version = (0, package_manager_1.parseVersionFromPackageManagerField)('pnpm', typeof packageManager === 'string' ? packageManager : undefined);
90
+ if (version) {
91
+ return version;
92
+ }
93
+ }
94
+ try {
95
+ return (0, package_manager_1.getPackageManagerVersion)('pnpm', host.root);
96
+ }
97
+ catch {
98
+ // The version cannot be probed (e.g. pnpm is not on PATH). Leave the
99
+ // workspace file untouched; pnpm's own install error remains actionable.
100
+ return null;
101
+ }
102
+ }
@@ -7,9 +7,3 @@
7
7
  */
8
8
  export declare function ensureAnalyticsPreferenceSet(root?: string, interactive?: boolean): Promise<'yes' | 'no' | 'unset'>;
9
9
  export declare function promptForAnalyticsPreference(): Promise<boolean>;
10
- /**
11
- * Generates a deterministic workspace ID.
12
- * Priority: nxCloudId > git remote URL (hashed).
13
- * Returns null if neither is available (no telemetry).
14
- */
15
- export declare function generateWorkspaceId(cwd?: string): string | null;
@@ -2,9 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureAnalyticsPreferenceSet = ensureAnalyticsPreferenceSet;
4
4
  exports.promptForAnalyticsPreference = promptForAnalyticsPreference;
5
- exports.generateWorkspaceId = generateWorkspaceId;
6
- const crypto_1 = require("crypto");
7
- const child_process_1 = require("child_process");
8
5
  const fs_1 = require("fs");
9
6
  const enquirer_1 = require("enquirer");
10
7
  const path_1 = require("path");
@@ -85,51 +82,3 @@ async function saveAnalyticsPreference(root, enabled) {
85
82
  // Silently fail - don't block user's command
86
83
  }
87
84
  }
88
- /**
89
- * Generates a deterministic workspace ID.
90
- * Priority: nxCloudId > git remote URL (hashed).
91
- * Returns null if neither is available (no telemetry).
92
- */
93
- function generateWorkspaceId(cwd) {
94
- const root = cwd ?? workspace_root_1.workspaceRoot;
95
- // Use nxCloudId if available — most stable identifier
96
- const nxJson = (0, nx_json_1.readNxJson)(root);
97
- const nxCloudId = nxJson?.nxCloudId ?? nxJson?.nxCloudAccessToken;
98
- if (nxCloudId) {
99
- return nxCloudId;
100
- }
101
- // Fall back to git remote URL hash
102
- try {
103
- const remoteUrl = (0, child_process_1.execSync)('git remote get-url origin', {
104
- stdio: 'pipe',
105
- cwd: root,
106
- windowsHide: true,
107
- })
108
- .toString()
109
- .trim();
110
- if (remoteUrl) {
111
- return (0, crypto_1.createHash)('sha256').update(remoteUrl).digest('hex').slice(0, 32);
112
- }
113
- }
114
- catch {
115
- // No git remote available
116
- }
117
- // Fall back to first commit SHA — already a hash
118
- try {
119
- const firstCommit = (0, child_process_1.execSync)('git rev-list --max-parents=0 HEAD', {
120
- stdio: 'pipe',
121
- cwd: root,
122
- windowsHide: true,
123
- })
124
- .toString()
125
- .trim()
126
- .split('\n')[0];
127
- if (firstCommit) {
128
- return firstCommit;
129
- }
130
- }
131
- catch {
132
- // Not a git repo
133
- }
134
- return null;
135
- }
@@ -3,7 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertWorkspaceValidity = assertWorkspaceValidity;
4
4
  const find_matching_projects_1 = require("./find-matching-projects");
5
5
  const output_1 = require("./output");
6
- const devkit_internals_1 = require("../devkit-internals");
6
+ // Import from the defining module, not the devkit-internals barrel: this file
7
+ // is on the project-graph construction path, and the barrel now eagerly
8
+ // re-exports the project-graph modules, which would create a require cycle back
9
+ // through build-project-graph. (Release modules cross the barrel as erased
10
+ // types only — see the note in packages/devkit/internal.ts.)
11
+ const error_types_1 = require("../project-graph/error-types");
7
12
  function assertWorkspaceValidity(projects, nxJson) {
8
13
  const projectNames = Object.keys(projects);
9
14
  const projectGraphNodes = projectNames.reduce((graph, project) => {
@@ -65,7 +70,7 @@ function assertWorkspaceValidity(projects, nxJson) {
65
70
  })
66
71
  .join('\n\n');
67
72
  }
68
- throw new devkit_internals_1.WorkspaceValidityError(message);
73
+ throw new error_types_1.WorkspaceValidityError(message);
69
74
  }
70
75
  function detectAndSetInvalidProjectGlobValues(map, sourceName, desiredImplicitDeps, projectConfigurations, projects) {
71
76
  const invalidProjectsOrGlobs = desiredImplicitDeps.filter((implicit) => {
@@ -1,7 +1,6 @@
1
1
  import type { Tree } from '../../generators/tree';
2
2
  import type { CatalogDefinitions } from './types';
3
- export declare function readCatalogConfigFromFs(filename: string, fullPath: string): CatalogDefinitions | null;
4
- export declare function readCatalogConfigFromTree(filename: string, tree: Tree): CatalogDefinitions | null;
3
+ export declare function readCatalogDefinitions(filename: string, treeOrRoot: Tree | string, cache: Map<string, CatalogDefinitions | null>): CatalogDefinitions | null;
5
4
  export declare function updateCatalogVersionsInFile(filename: string, treeOrRoot: Tree | string, updates: Array<{
6
5
  packageName: string;
7
6
  version: string;
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readCatalogConfigFromFs = readCatalogConfigFromFs;
4
- exports.readCatalogConfigFromTree = readCatalogConfigFromTree;
3
+ exports.readCatalogDefinitions = readCatalogDefinitions;
5
4
  exports.updateCatalogVersionsInFile = updateCatalogVersionsInFile;
6
- // Keep in sync with packages/devkit/src/utils/catalog/manager-utils.ts; the body
7
- // below the imports is duplicated because @nx/devkit supports a range of nx majors
8
- // and this logic isn't part of the nx surface it can import across that range.
9
5
  const js_yaml_1 = require("@zkochan/js-yaml");
10
6
  const node_fs_1 = require("node:fs");
11
7
  const node_path_1 = require("node:path");
@@ -119,6 +115,27 @@ function readCatalogConfigFromTree(filename, tree) {
119
115
  return null;
120
116
  }
121
117
  }
118
+ // Managers are created per operation (getCatalogManager news one up), so the
119
+ // fs (string-root) branch is cached to read the file once per pass instead of
120
+ // once per catalog reference. The Tree branch stays live since the tree is
121
+ // mutable within a generator.
122
+ function readCatalogDefinitions(filename, treeOrRoot, cache) {
123
+ if (typeof treeOrRoot === 'string') {
124
+ if (cache.has(treeOrRoot)) {
125
+ return cache.get(treeOrRoot);
126
+ }
127
+ const configPath = (0, node_path_1.join)(treeOrRoot, filename);
128
+ const defs = (0, node_fs_1.existsSync)(configPath)
129
+ ? readCatalogConfigFromFs(filename, configPath)
130
+ : null;
131
+ cache.set(treeOrRoot, defs);
132
+ return defs;
133
+ }
134
+ if (!treeOrRoot.exists(filename)) {
135
+ return null;
136
+ }
137
+ return readCatalogConfigFromTree(filename, treeOrRoot);
138
+ }
122
139
  function updateCatalogVersionsInFile(filename, treeOrRoot, updates) {
123
140
  let checkExists;
124
141
  let readYaml;
@@ -7,6 +7,7 @@ import type { CatalogDefinitions, CatalogReference } from './types';
7
7
  export declare class PnpmCatalogManager implements CatalogManager {
8
8
  readonly name = "pnpm";
9
9
  readonly catalogProtocol = "catalog:";
10
+ private definitionsByRoot;
10
11
  isCatalogReference(version: string): boolean;
11
12
  parseCatalogReference(version: string): CatalogReference | null;
12
13
  getCatalogDefinitionFilePaths(): string[];
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PnpmCatalogManager = void 0;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
4
  const manager_1 = require("./manager");
7
5
  const manager_utils_1 = require("./manager-utils");
8
6
  const PNPM_WORKSPACE_FILENAME = 'pnpm-workspace.yaml';
@@ -13,6 +11,8 @@ class PnpmCatalogManager {
13
11
  constructor() {
14
12
  this.name = 'pnpm';
15
13
  this.catalogProtocol = 'catalog:';
14
+ // Parsed fs-root definitions, cached per pass. See readCatalogDefinitions.
15
+ this.definitionsByRoot = new Map();
16
16
  }
17
17
  isCatalogReference(version) {
18
18
  return version.startsWith(this.catalogProtocol);
@@ -33,19 +33,7 @@ class PnpmCatalogManager {
33
33
  return [PNPM_WORKSPACE_FILENAME];
34
34
  }
35
35
  getCatalogDefinitions(treeOrRoot) {
36
- if (typeof treeOrRoot === 'string') {
37
- const configPath = (0, node_path_1.join)(treeOrRoot, PNPM_WORKSPACE_FILENAME);
38
- if (!(0, node_fs_1.existsSync)(configPath)) {
39
- return null;
40
- }
41
- return (0, manager_utils_1.readCatalogConfigFromFs)(PNPM_WORKSPACE_FILENAME, configPath);
42
- }
43
- else {
44
- if (!treeOrRoot.exists(PNPM_WORKSPACE_FILENAME)) {
45
- return null;
46
- }
47
- return (0, manager_utils_1.readCatalogConfigFromTree)(PNPM_WORKSPACE_FILENAME, treeOrRoot);
48
- }
36
+ return (0, manager_utils_1.readCatalogDefinitions)(PNPM_WORKSPACE_FILENAME, treeOrRoot, this.definitionsByRoot);
49
37
  }
50
38
  resolveCatalogReference(treeOrRoot, packageName, version) {
51
39
  const catalogRef = this.parseCatalogReference(version);
@@ -7,6 +7,7 @@ import type { CatalogDefinitions, CatalogReference } from './types';
7
7
  export declare class YarnCatalogManager implements CatalogManager {
8
8
  readonly name = "yarn";
9
9
  readonly catalogProtocol = "catalog:";
10
+ private definitionsByRoot;
10
11
  isCatalogReference(version: string): boolean;
11
12
  parseCatalogReference(version: string): CatalogReference | null;
12
13
  getCatalogDefinitionFilePaths(): string[];
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.YarnCatalogManager = void 0;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
4
  const manager_1 = require("./manager");
7
5
  const manager_utils_1 = require("./manager-utils");
8
6
  const YARNRC_FILENAME = '.yarnrc.yml';
@@ -13,6 +11,8 @@ class YarnCatalogManager {
13
11
  constructor() {
14
12
  this.name = 'yarn';
15
13
  this.catalogProtocol = 'catalog:';
14
+ // Parsed fs-root definitions, cached per pass. See readCatalogDefinitions.
15
+ this.definitionsByRoot = new Map();
16
16
  }
17
17
  isCatalogReference(version) {
18
18
  return version.startsWith(this.catalogProtocol);
@@ -33,19 +33,7 @@ class YarnCatalogManager {
33
33
  return [YARNRC_FILENAME];
34
34
  }
35
35
  getCatalogDefinitions(treeOrRoot) {
36
- if (typeof treeOrRoot === 'string') {
37
- const configPath = (0, node_path_1.join)(treeOrRoot, YARNRC_FILENAME);
38
- if (!(0, node_fs_1.existsSync)(configPath)) {
39
- return null;
40
- }
41
- return (0, manager_utils_1.readCatalogConfigFromFs)(YARNRC_FILENAME, configPath);
42
- }
43
- else {
44
- if (!treeOrRoot.exists(YARNRC_FILENAME)) {
45
- return null;
46
- }
47
- return (0, manager_utils_1.readCatalogConfigFromTree)(YARNRC_FILENAME, treeOrRoot);
48
- }
36
+ return (0, manager_utils_1.readCatalogDefinitions)(YARNRC_FILENAME, treeOrRoot, this.definitionsByRoot);
49
37
  }
50
38
  resolveCatalogReference(treeOrRoot, packageName, version) {
51
39
  const catalogRef = this.parseCatalogReference(version);
@@ -11,6 +11,7 @@ const yargs_parser_1 = tslib_1.__importDefault(require("yargs-parser"));
11
11
  const file_utils_1 = require("../project-graph/file-utils");
12
12
  const output_1 = require("./output");
13
13
  const child_process_1 = require("child_process");
14
+ const git_revision_1 = require("./git-revision");
14
15
  const workspace_root_1 = require("./workspace-root");
15
16
  const shared_options_1 = require("../command-line/yargs-utils/shared-options");
16
17
  function createOverrides(__overrides_unparsed__ = []) {
@@ -192,30 +193,27 @@ function parseFiles(options) {
192
193
  }
193
194
  }
194
195
  function getUncommittedFiles() {
195
- return parseGitOutput(`git diff --name-only --no-renames --relative HEAD .`);
196
+ return parseGitOutput([
197
+ 'diff',
198
+ '--name-only',
199
+ '--no-renames',
200
+ '--relative',
201
+ 'HEAD',
202
+ '.',
203
+ ]);
196
204
  }
197
205
  function getUntrackedFiles() {
198
- return parseGitOutput(`git ls-files --others --exclude-standard`);
206
+ return parseGitOutput(['ls-files', '--others', '--exclude-standard']);
199
207
  }
200
208
  function getMergeBase(base, head = 'HEAD') {
209
+ (0, git_revision_1.assertValidGitRevision)(base);
210
+ (0, git_revision_1.assertValidGitRevision)(head);
201
211
  try {
202
- return (0, child_process_1.execSync)(`git merge-base "${base}" "${head}"`, {
203
- maxBuffer: file_utils_1.TEN_MEGABYTES,
204
- cwd: workspace_root_1.workspaceRoot,
205
- stdio: 'pipe',
206
- windowsHide: true,
207
- })
208
- .toString()
209
- .trim();
212
+ return runGit(['merge-base', base, head]).toString().trim();
210
213
  }
211
214
  catch {
212
215
  try {
213
- return (0, child_process_1.execSync)(`git merge-base --fork-point "${base}" "${head}"`, {
214
- maxBuffer: file_utils_1.TEN_MEGABYTES,
215
- cwd: workspace_root_1.workspaceRoot,
216
- stdio: 'pipe',
217
- windowsHide: true,
218
- })
216
+ return runGit(['merge-base', '--fork-point', base, head])
219
217
  .toString()
220
218
  .trim();
221
219
  }
@@ -225,15 +223,27 @@ function getMergeBase(base, head = 'HEAD') {
225
223
  }
226
224
  }
227
225
  function getFilesUsingBaseAndHead(base, head) {
228
- return parseGitOutput(`git diff --name-only --no-renames --relative "${base}" "${head}"`);
226
+ (0, git_revision_1.assertValidGitRevision)(base);
227
+ (0, git_revision_1.assertValidGitRevision)(head);
228
+ return parseGitOutput([
229
+ 'diff',
230
+ '--name-only',
231
+ '--no-renames',
232
+ '--relative',
233
+ base,
234
+ head,
235
+ ]);
229
236
  }
230
- function parseGitOutput(command) {
231
- return (0, child_process_1.execSync)(command, {
237
+ function runGit(args) {
238
+ return (0, child_process_1.execFileSync)('git', args, {
232
239
  maxBuffer: file_utils_1.TEN_MEGABYTES,
233
240
  cwd: workspace_root_1.workspaceRoot,
234
241
  stdio: 'pipe',
235
242
  windowsHide: true,
236
- })
243
+ });
244
+ }
245
+ function parseGitOutput(args) {
246
+ return runGit(args)
237
247
  .toString('utf-8')
238
248
  .split('\n')
239
249
  .map((a) => a.trim())
@@ -27,6 +27,11 @@ interface YamlReadOptions {
27
27
  * Compatibility with JSON.parse behaviour. If true, then duplicate keys in a mapping will override values rather than throwing an error.
28
28
  */
29
29
  json?: boolean;
30
+ /**
31
+ * Resolves only the tags every YAML parser must support, so every scalar stays
32
+ * a string instead of `true` or `12`.
33
+ */
34
+ failsafe?: boolean;
30
35
  }
31
36
  /**
32
37
  * Reads a YAML file and returns the object the YAML content represents.