nx 19.7.2 → 19.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. package/package.json +12 -12
  2. package/schemas/nx-schema.json +2 -2
  3. package/src/command-line/add/add.js +2 -2
  4. package/src/command-line/affected/command-object.js +6 -6
  5. package/src/command-line/deprecated/command-objects.js +3 -3
  6. package/src/command-line/generate/generate.js +2 -1
  7. package/src/command-line/import/command-object.js +8 -6
  8. package/src/command-line/import/import.d.ts +1 -1
  9. package/src/command-line/import/import.js +45 -29
  10. package/src/command-line/import/utils/prepare-source-repo.js +7 -35
  11. package/src/command-line/init/init-v2.js +6 -2
  12. package/src/command-line/login/login.js +2 -2
  13. package/src/command-line/logout/logout.js +2 -2
  14. package/src/command-line/migrate/migrate.js +2 -2
  15. package/src/command-line/new/new.js +2 -1
  16. package/src/command-line/release/changelog.js +2 -2
  17. package/src/command-line/release/command-object.d.ts +2 -2
  18. package/src/command-line/release/config/config.js +10 -3
  19. package/src/command-line/release/plan-check.js +2 -2
  20. package/src/command-line/release/plan.js +2 -2
  21. package/src/command-line/release/publish.js +2 -2
  22. package/src/command-line/release/release.js +2 -2
  23. package/src/command-line/release/utils/git.d.ts +2 -2
  24. package/src/command-line/release/utils/git.js +12 -2
  25. package/src/command-line/release/utils/shared.d.ts +1 -1
  26. package/src/command-line/release/version.js +6 -1
  27. package/src/command-line/repair/repair.js +2 -2
  28. package/src/command-line/run/command-object.js +3 -3
  29. package/src/command-line/run/run.js +3 -2
  30. package/src/command-line/run-many/command-object.js +2 -2
  31. package/src/command-line/show/command-object.js +3 -3
  32. package/src/command-line/sync/sync.js +69 -11
  33. package/src/config/nx-json.d.ts +13 -5
  34. package/src/daemon/client/client.d.ts +3 -3
  35. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.js +2 -2
  36. package/src/daemon/server/handle-get-sync-generator-changes.js +8 -6
  37. package/src/daemon/server/sync-generators.d.ts +4 -4
  38. package/src/daemon/server/sync-generators.js +11 -2
  39. package/src/hasher/hash-task.js +2 -2
  40. package/src/native/nx.wasi-browser.js +42 -54
  41. package/src/native/nx.wasi.cjs +42 -54
  42. package/src/native/nx.wasm32-wasi.wasm +0 -0
  43. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +0 -1
  44. package/src/nx-cloud/utilities/get-cloud-options.d.ts +1 -0
  45. package/src/nx-cloud/utilities/get-cloud-options.js +4 -0
  46. package/src/nx-cloud/utilities/is-workspace-claimed.d.ts +1 -1
  47. package/src/nx-cloud/utilities/is-workspace-claimed.js +6 -5
  48. package/src/nx-cloud/utilities/onboarding.js +2 -2
  49. package/src/plugins/js/utils/register.js +7 -0
  50. package/src/project-graph/error-types.d.ts +1 -1
  51. package/src/project-graph/error-types.js +19 -5
  52. package/src/tasks-runner/cache.js +2 -1
  53. package/src/tasks-runner/run-command.js +142 -30
  54. package/src/tasks-runner/task-orchestrator.d.ts +0 -1
  55. package/src/tasks-runner/task-orchestrator.js +3 -6
  56. package/src/utils/git-utils.d.ts +3 -2
  57. package/src/utils/git-utils.index-filter.d.ts +0 -0
  58. package/src/utils/git-utils.index-filter.js +20 -0
  59. package/src/utils/git-utils.js +44 -13
  60. package/src/utils/git-utils.tree-filter.d.ts +11 -0
  61. package/src/utils/git-utils.tree-filter.js +43 -0
  62. package/src/utils/handle-errors.d.ts +1 -0
  63. package/src/utils/handle-errors.js +71 -0
  64. package/src/utils/nx-cloud-utils.d.ts +0 -1
  65. package/src/utils/nx-cloud-utils.js +0 -10
  66. package/src/utils/params.d.ts +0 -1
  67. package/src/utils/params.js +0 -50
  68. package/src/utils/plugins/plugin-capabilities.js +4 -1
  69. package/src/utils/sync-generators.d.ts +35 -6
  70. package/src/utils/sync-generators.js +144 -47
@@ -11,12 +11,13 @@ const nx_json_1 = require("../config/nx-json");
11
11
  const client_1 = require("../daemon/client/client");
12
12
  const create_task_hasher_1 = require("../hasher/create-task-hasher");
13
13
  const hash_task_1 = require("../hasher/hash-task");
14
+ const native_1 = require("../native");
14
15
  const project_graph_1 = require("../project-graph/project-graph");
15
16
  const fileutils_1 = require("../utils/fileutils");
16
17
  const is_ci_1 = require("../utils/is-ci");
17
18
  const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
18
19
  const output_1 = require("../utils/output");
19
- const params_1 = require("../utils/params");
20
+ const handle_errors_1 = require("../utils/handle-errors");
20
21
  const sync_generators_1 = require("../utils/sync-generators");
21
22
  const workspace_root_1 = require("../utils/workspace-root");
22
23
  const create_task_graph_1 = require("./create-task-graph");
@@ -33,7 +34,6 @@ const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle
33
34
  const task_graph_utils_1 = require("./task-graph-utils");
34
35
  const utils_1 = require("./utils");
35
36
  const chalk = require("chalk");
36
- const native_1 = require("../native");
37
37
  async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {
38
38
  const { runnerOptions } = getRunner(nxArgs, nxJson);
39
39
  const isRunOne = initiatingProject != null;
@@ -98,7 +98,7 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
98
98
  return taskGraph;
99
99
  }
100
100
  async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
101
- const status = await (0, params_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
101
+ const status = await (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
102
102
  const projectNames = projectsToRun.map((t) => t.name);
103
103
  const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
104
104
  const tasks = Object.values(taskGraph.tasks);
@@ -135,14 +135,49 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
135
135
  // There are no changes to sync, workspace is up to date
136
136
  return { projectGraph, taskGraph };
137
137
  }
138
+ const { failedGeneratorsCount, areAllResultsFailures, anySyncGeneratorsFailed, } = (0, sync_generators_1.processSyncGeneratorResultErrors)(results);
139
+ const failedSyncGeneratorsFixMessageLines = (0, sync_generators_1.getFailedSyncGeneratorsFixMessageLines)(results, nxArgs.verbose);
138
140
  const outOfSyncTitle = 'The workspace is out of sync';
139
- const resultBodyLines = [...(0, sync_generators_1.syncGeneratorResultsToMessageLines)(results), ''];
140
- const fixMessage = 'You can manually run `nx sync` to update your workspace or you can set `sync.applyChanges` to `true` in your `nx.json` to apply the changes automatically when running tasks in interactive environments.';
141
- const willErrorOnCiMessage = 'Please note that this will be an error on CI.';
141
+ const resultBodyLines = (0, sync_generators_1.getSyncGeneratorSuccessResultsMessageLines)(results);
142
+ const fixMessage = 'You can manually run `nx sync` to update your workspace with the identified changes or you can set `sync.applyChanges` to `true` in your `nx.json` to apply the changes automatically when running tasks in interactive environments.';
143
+ const willErrorOnCiMessage = 'Please note that having the workspace out of sync will result in an error in CI.';
142
144
  if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
143
145
  // If the user is running in CI or is running in a non-TTY environment we
144
146
  // throw an error to stop the execution of the tasks.
145
- throw new Error(`${outOfSyncTitle}\n${resultBodyLines.join('\n')}\n${fixMessage}`);
147
+ if (areAllResultsFailures) {
148
+ output_1.output.error({
149
+ title: `The workspace is probably out of sync because ${failedGeneratorsCount === 1
150
+ ? 'a sync generator'
151
+ : 'some sync generators'} failed to run`,
152
+ bodyLines: failedSyncGeneratorsFixMessageLines,
153
+ });
154
+ }
155
+ else {
156
+ output_1.output.error({
157
+ title: outOfSyncTitle,
158
+ bodyLines: [...resultBodyLines, '', fixMessage],
159
+ });
160
+ if (anySyncGeneratorsFailed) {
161
+ output_1.output.error({
162
+ title: failedGeneratorsCount === 1
163
+ ? 'A sync generator failed to run'
164
+ : 'Some sync generators failed to run',
165
+ bodyLines: failedSyncGeneratorsFixMessageLines,
166
+ });
167
+ }
168
+ }
169
+ process.exit(1);
170
+ }
171
+ if (areAllResultsFailures) {
172
+ output_1.output.warn({
173
+ title: `The workspace is probably out of sync because ${failedGeneratorsCount === 1
174
+ ? 'a sync generator'
175
+ : 'some sync generators'} failed to run`,
176
+ bodyLines: failedSyncGeneratorsFixMessageLines,
177
+ });
178
+ await confirmRunningTasksWithSyncFailures();
179
+ // if all sync generators failed to run there's nothing to sync, we just let the tasks run
180
+ return { projectGraph, taskGraph };
146
181
  }
147
182
  if (nxJson.sync?.applyChanges === false) {
148
183
  // If the user has set `sync.applyChanges` to `false` in their `nx.json`
@@ -153,19 +188,30 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
153
188
  title: outOfSyncTitle,
154
189
  bodyLines: [
155
190
  ...resultBodyLines,
156
- 'Your workspace is set to not apply changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
191
+ '',
192
+ 'Your workspace is set to not apply the identified changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
157
193
  willErrorOnCiMessage,
158
194
  fixMessage,
159
195
  ],
160
196
  });
197
+ if (anySyncGeneratorsFailed) {
198
+ output_1.output.warn({
199
+ title: failedGeneratorsCount === 1
200
+ ? 'A sync generator failed to run'
201
+ : 'Some sync generators failed to run',
202
+ bodyLines: failedSyncGeneratorsFixMessageLines,
203
+ });
204
+ await confirmRunningTasksWithSyncFailures();
205
+ }
161
206
  return { projectGraph, taskGraph };
162
207
  }
163
208
  output_1.output.warn({
164
209
  title: outOfSyncTitle,
165
210
  bodyLines: [
166
211
  ...resultBodyLines,
212
+ '',
167
213
  nxJson.sync?.applyChanges === true
168
- ? 'Proceeding to sync the changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
214
+ ? 'Proceeding to sync the identified changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
169
215
  : willErrorOnCiMessage,
170
216
  ],
171
217
  });
@@ -175,31 +221,66 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
175
221
  const spinner = ora('Syncing the workspace...');
176
222
  spinner.start();
177
223
  // Flush sync generator changes to disk
178
- await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
224
+ const flushResult = await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
225
+ if ('generatorFailures' in flushResult) {
226
+ spinner.fail();
227
+ output_1.output.error({
228
+ title: 'Failed to sync the workspace',
229
+ bodyLines: [
230
+ ...(0, sync_generators_1.getFlushFailureMessageLines)(flushResult, nxArgs.verbose),
231
+ ...(flushResult.generalFailure
232
+ ? [
233
+ 'If needed, you can run the tasks with the `--skip-sync` flag to disable syncing.',
234
+ ]
235
+ : []),
236
+ ],
237
+ });
238
+ await confirmRunningTasksWithSyncFailures();
239
+ }
179
240
  // Re-create project graph and task graph
180
241
  projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
181
242
  taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
182
- if (nxJson.sync?.applyChanges === true) {
183
- spinner.succeed(`The workspace was synced successfully!
184
-
185
- Please make sure to commit the changes to your repository or this will error on CI.`);
186
- }
187
- else {
188
- // The user was prompted and we already logged a message about erroring on CI
189
- // so here we just tell them to commit the changes.
190
- spinner.succeed(`The workspace was synced successfully!
191
-
192
- Please make sure to commit the changes to your repository.`);
243
+ const successTitle = anySyncGeneratorsFailed
244
+ ? // the identified changes were synced successfully, but the workspace
245
+ // is still not up to date, which we'll mention next
246
+ 'The identified changes were synced successfully!'
247
+ : // the workspace is fully up to date
248
+ 'The workspace was synced successfully!';
249
+ const successSubtitle = nxJson.sync?.applyChanges === true
250
+ ? 'Please make sure to commit the changes to your repository or this will error in CI.'
251
+ : // The user was prompted and we already logged a message about erroring in CI
252
+ // so here we just tell them to commit the changes.
253
+ 'Please make sure to commit the changes to your repository.';
254
+ spinner.succeed(`${successTitle}\n\n${successSubtitle}`);
255
+ if (anySyncGeneratorsFailed) {
256
+ output_1.output.warn({
257
+ title: `The workspace is probably still out of sync because ${failedGeneratorsCount === 1
258
+ ? 'a sync generator'
259
+ : 'some sync generators'} failed to run`,
260
+ bodyLines: failedSyncGeneratorsFixMessageLines,
261
+ });
262
+ await confirmRunningTasksWithSyncFailures();
193
263
  }
194
264
  }
195
265
  else {
196
- output_1.output.warn({
197
- title: 'Syncing the workspace was skipped',
198
- bodyLines: [
199
- 'This could lead to unexpected results or errors when running tasks.',
200
- fixMessage,
201
- ],
202
- });
266
+ if (anySyncGeneratorsFailed) {
267
+ output_1.output.warn({
268
+ title: failedGeneratorsCount === 1
269
+ ? 'A sync generator failed to report the sync status'
270
+ : 'Some sync generators failed to report the sync status',
271
+ bodyLines: failedSyncGeneratorsFixMessageLines,
272
+ });
273
+ await confirmRunningTasksWithSyncFailures();
274
+ }
275
+ else {
276
+ output_1.output.warn({
277
+ title: 'Syncing the workspace was skipped',
278
+ bodyLines: [
279
+ 'This could lead to unexpected results or errors when running tasks.',
280
+ fixMessage,
281
+ ],
282
+ });
283
+ }
203
284
  }
204
285
  return { projectGraph, taskGraph };
205
286
  }
@@ -208,7 +289,7 @@ async function promptForApplyingSyncGeneratorChanges() {
208
289
  const promptConfig = {
209
290
  name: 'applyChanges',
210
291
  type: 'select',
211
- message: 'Would you like to sync the changes to get your worskpace up to date?',
292
+ message: 'Would you like to sync the identified changes to get your worskpace up to date?',
212
293
  choices: [
213
294
  {
214
295
  name: 'yes',
@@ -227,6 +308,35 @@ async function promptForApplyingSyncGeneratorChanges() {
227
308
  process.exit(1);
228
309
  }
229
310
  }
311
+ async function confirmRunningTasksWithSyncFailures() {
312
+ try {
313
+ const promptConfig = {
314
+ name: 'runTasks',
315
+ type: 'select',
316
+ message: 'Would you like to ignore the sync failures and continue running the tasks?',
317
+ choices: [
318
+ {
319
+ name: 'yes',
320
+ message: 'Yes, ignore the failures and run the tasks',
321
+ },
322
+ {
323
+ name: 'no',
324
+ message: `No, don't run the tasks`,
325
+ },
326
+ ],
327
+ footer: () => chalk.dim(`\nWhen running in CI and there are sync failures, the tasks won't run. Addressing the errors above is highly recommended to prevent failures in CI.`),
328
+ };
329
+ const runTasks = await (0, enquirer_1.prompt)([
330
+ promptConfig,
331
+ ]).then(({ runTasks }) => runTasks === 'yes');
332
+ if (!runTasks) {
333
+ process.exit(1);
334
+ }
335
+ }
336
+ catch {
337
+ process.exit(1);
338
+ }
339
+ }
230
340
  function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
231
341
  if (nxArgs.outputStyle == 'stream' ||
232
342
  process.env.NX_BATCH_MODE === 'true' ||
@@ -329,7 +439,9 @@ function constructLifeCycles(lifeCycle) {
329
439
  lifeCycles.push(new task_profiling_life_cycle_1.TaskProfilingLifeCycle(process.env.NX_PROFILE));
330
440
  }
331
441
  if (!(0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)())) {
332
- lifeCycles.push(!native_1.IS_WASM ? new task_history_life_cycle_1.TaskHistoryLifeCycle() : new task_history_life_cycle_old_1.LegacyTaskHistoryLifeCycle());
442
+ lifeCycles.push(process.env.NX_DISABLE_DB !== 'true' && !native_1.IS_WASM
443
+ ? new task_history_life_cycle_1.TaskHistoryLifeCycle()
444
+ : new task_history_life_cycle_old_1.LegacyTaskHistoryLifeCycle());
333
445
  }
334
446
  return lifeCycles;
335
447
  }
@@ -40,7 +40,6 @@ export declare class TaskOrchestrator {
40
40
  private runTaskInForkedProcess;
41
41
  private preRunSteps;
42
42
  private postRunSteps;
43
- private scheduleNextTasks;
44
43
  private complete;
45
44
  private pipeOutputCapture;
46
45
  private shouldCacheTaskResult;
@@ -43,7 +43,7 @@ class TaskOrchestrator {
43
43
  // Init the ForkedProcessTaskRunner
44
44
  await this.forkedProcessTaskRunner.init();
45
45
  // initial scheduling
46
- await this.scheduleNextTasks();
46
+ await this.tasksSchedule.scheduleNextTasks();
47
47
  perf_hooks_1.performance.mark('task-execution:start');
48
48
  const threads = [];
49
49
  process.stdout.setMaxListeners(this.options.parallel + events_1.defaultMaxListeners);
@@ -65,6 +65,7 @@ class TaskOrchestrator {
65
65
  }
66
66
  const doNotSkipCache = this.options.skipNxCache === false ||
67
67
  this.options.skipNxCache === undefined;
68
+ this.processAllScheduledTasks();
68
69
  const batch = this.tasksSchedule.nextBatch();
69
70
  if (batch) {
70
71
  const groupId = this.closeGroup();
@@ -373,15 +374,11 @@ class TaskOrchestrator {
373
374
  status,
374
375
  };
375
376
  }));
376
- await this.scheduleNextTasks();
377
+ await this.tasksSchedule.scheduleNextTasks();
377
378
  // release blocked threads
378
379
  this.waitingForTasks.forEach((f) => f(null));
379
380
  this.waitingForTasks.length = 0;
380
381
  }
381
- async scheduleNextTasks() {
382
- await this.tasksSchedule.scheduleNextTasks();
383
- this.processAllScheduledTasks();
384
- }
385
382
  complete(taskResults) {
386
383
  this.tasksSchedule.complete(taskResults.map(({ taskId }) => taskId));
387
384
  for (const { taskId, status } of taskResults) {
@@ -25,10 +25,11 @@ export declare class GitRepository {
25
25
  deleteGitRemote(name: string): Promise<string>;
26
26
  addGitRemote(name: string, url: string): Promise<string>;
27
27
  hasFilterRepoInstalled(): Promise<boolean>;
28
- filterRepo(subdirectory: string): Promise<string>;
29
- filterBranch(subdirectory: string, branchName: string): Promise<string>;
28
+ filterRepo(source: string, destination: string): Promise<void>;
29
+ filterBranch(source: string, destination: string, branchName: string): Promise<void>;
30
30
  private execAsync;
31
31
  private quotePath;
32
+ private quoteArg;
32
33
  }
33
34
  /**
34
35
  * This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
File without changes
@@ -0,0 +1,20 @@
1
+ /**
2
+ * This is meant to be used with `git filter-branch --index-filter` to rewrite
3
+ * history such that only commits related to the subdirectory is kept.
4
+ *
5
+ * Example:
6
+ * NX_IMPORT_SOURCE=<source> git filter-branch --index-filter 'node git-utils.index-filter.js' --prune-empty -- --all
7
+ */
8
+ try {
9
+ const { execSync } = require('child_process');
10
+ // NOTE: Using env vars because Windows PowerShell has its own handling of quotes (") messes up quotes in args, even if escaped.
11
+ const src = process.env.NX_IMPORT_SOURCE;
12
+ execSync('git read-tree --empty', { stdio: 'inherit' });
13
+ execSync(`git reset ${process.env.GIT_COMMIT} -- "${src}"`, {
14
+ stdio: 'inherit',
15
+ });
16
+ }
17
+ catch (error) {
18
+ console.error(`Error executing Git commands: ${error}`);
19
+ process.exit(1);
20
+ }
@@ -105,32 +105,63 @@ class GitRepository {
105
105
  }
106
106
  // git-filter-repo is much faster than filter-branch, but needs to be installed by user
107
107
  // Use `hasFilterRepoInstalled` to check if it's installed
108
- async filterRepo(subdirectory) {
109
- // filter-repo requires POSIX path to work
110
- const posixPath = subdirectory.split(path_1.sep).join(path_1.posix.sep);
111
- return await this.execAsync(`git filter-repo -f --subdirectory-filter ${this.quotePath(posixPath)}`);
112
- }
113
- async filterBranch(subdirectory, branchName) {
114
- // filter-repo requires POSIX path to work
115
- const posixPath = subdirectory.split(path_1.sep).join(path_1.posix.sep);
108
+ async filterRepo(source, destination) {
109
+ // NOTE: filter-repo requires POSIX path to work
110
+ const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
111
+ const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
112
+ await this.execAsync(`git filter-repo -f ${source !== '' ? `--path ${this.quotePath(sourcePosixPath)}` : ''} ${source !== destination
113
+ ? `--path-rename ${this.quotePath(sourcePosixPath, true)}:${this.quotePath(destinationPosixPath, true)}`
114
+ : ''}`);
115
+ }
116
+ async filterBranch(source, destination, branchName) {
116
117
  // We need non-ASCII file names to not be quoted, or else filter-branch will exclude them.
117
118
  await this.execAsync(`git config core.quotepath false`);
118
- return await this.execAsync(`git filter-branch --subdirectory-filter ${this.quotePath(posixPath)} -- ${branchName}`);
119
+ // NOTE: filter-repo requires POSIX path to work
120
+ const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
121
+ const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
122
+ // First, if the source is not a root project, then only include commits relevant to the subdirectory.
123
+ if (source !== '') {
124
+ const indexFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.index-filter.js')}`);
125
+ await this.execAsync(`git filter-branch -f --index-filter ${indexFilterCommand} --prune-empty -- ${branchName}`, {
126
+ NX_IMPORT_SOURCE: sourcePosixPath,
127
+ NX_IMPORT_DESTINATION: destinationPosixPath,
128
+ });
129
+ }
130
+ // Then, move files to their new location if necessary.
131
+ if (source === '' || source !== destination) {
132
+ const treeFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.tree-filter.js')}`);
133
+ await this.execAsync(`git filter-branch -f --tree-filter ${treeFilterCommand} -- ${branchName}`, {
134
+ NX_IMPORT_SOURCE: sourcePosixPath,
135
+ NX_IMPORT_DESTINATION: destinationPosixPath,
136
+ });
137
+ }
119
138
  }
120
- execAsync(command) {
139
+ execAsync(command, env) {
121
140
  return execAsync(command, {
122
141
  cwd: this.root,
123
142
  maxBuffer: 10 * 1024 * 1024,
143
+ env: {
144
+ ...process.env,
145
+ ...env,
146
+ },
124
147
  });
125
148
  }
126
- quotePath(path) {
149
+ quotePath(path, ensureTrailingSlash) {
150
+ return this.quoteArg(ensureTrailingSlash && path !== '' && !path.endsWith('/')
151
+ ? `${path}/`
152
+ : path);
153
+ }
154
+ quoteArg(arg) {
127
155
  return process.platform === 'win32'
128
156
  ? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name
129
157
  // Bash and other shells will substitute `$` in file names with a variable value.
130
- `"${path}"`
158
+ `"${arg
159
+ // Need to keep two slashes for Windows or else the path will be invalid.
160
+ // e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid
161
+ .replaceAll('\\', '\\\\')}"`
131
162
  : // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process.
132
163
  // Using single-quotes prevents this substitution.
133
- `'${path}'`;
164
+ `'${arg}'`;
134
165
  }
135
166
  }
136
167
  exports.GitRepository = GitRepository;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This is meant to be used with `git filter-branch --tree-filter` to rewrite
3
+ * history to only include commits related to the source project folder. If the
4
+ * destination folder is different, this script also moves the files over.
5
+ *
6
+ * Example:
7
+ * NX_IMPORT_SOURCE=<source> NX_IMPORT_DESTINATION=<destination> git filter-branch --tree-filter 'node git-utils.tree-filter.js' --prune-empty -- --all
8
+ */
9
+ declare const execSync: any;
10
+ declare const existsSync: any, mkdirSync: any, renameSync: any, rmSync: any;
11
+ declare const posix: any;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * This is meant to be used with `git filter-branch --tree-filter` to rewrite
3
+ * history to only include commits related to the source project folder. If the
4
+ * destination folder is different, this script also moves the files over.
5
+ *
6
+ * Example:
7
+ * NX_IMPORT_SOURCE=<source> NX_IMPORT_DESTINATION=<destination> git filter-branch --tree-filter 'node git-utils.tree-filter.js' --prune-empty -- --all
8
+ */
9
+ const { execSync } = require('child_process');
10
+ const { existsSync, mkdirSync, renameSync, rmSync } = require('fs');
11
+ // NOTE: The path passed to `git filter-branch` is POSIX, so we need to use the `posix` module.
12
+ const { posix } = require('path');
13
+ try {
14
+ // NOTE: Using env vars because Windows PowerShell has its own handling of quotes (") messes up quotes in args, even if escaped.
15
+ const src = process.env.NX_IMPORT_SOURCE;
16
+ const dest = process.env.NX_IMPORT_DESTINATION;
17
+ const files = execSync(`git ls-files -z ${src}`)
18
+ .toString()
19
+ .trim()
20
+ .split('\x00')
21
+ .map((s) => s.trim())
22
+ .filter(Boolean);
23
+ for (const file of files) {
24
+ if (src === '' || file.startsWith(src)) {
25
+ // If source and destination are the same, then keep the file as is.
26
+ if (src === dest)
27
+ continue;
28
+ const destFile = posix.join(dest, file.replace(src, ''));
29
+ const dir = posix.dirname(destFile);
30
+ if (!existsSync(dir))
31
+ mkdirSync(dir, { recursive: true });
32
+ renameSync(file, destFile);
33
+ }
34
+ else {
35
+ // If not matching the source we are filtering, remove it.
36
+ rmSync(file);
37
+ }
38
+ }
39
+ }
40
+ catch (error) {
41
+ console.error(`Error executing Git commands: ${error}`);
42
+ process.exit(1);
43
+ }
@@ -0,0 +1 @@
1
+ export declare function handleErrors(isVerbose: boolean, fn: Function): Promise<number>;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleErrors = handleErrors;
4
+ const client_1 = require("../daemon/client/client");
5
+ const logger_1 = require("./logger");
6
+ const output_1 = require("./output");
7
+ async function handleErrors(isVerbose, fn) {
8
+ try {
9
+ const result = await fn();
10
+ if (typeof result === 'number') {
11
+ return result;
12
+ }
13
+ return 0;
14
+ }
15
+ catch (err) {
16
+ err ||= new Error('Unknown error caught');
17
+ if (err.constructor.name === 'UnsuccessfulWorkflowExecution') {
18
+ logger_1.logger.error('The generator workflow failed. See above.');
19
+ }
20
+ else if (err.name === 'ProjectGraphError') {
21
+ const projectGraphError = err;
22
+ let title = projectGraphError.message;
23
+ if (projectGraphError.cause &&
24
+ typeof projectGraphError.cause === 'object' &&
25
+ 'message' in projectGraphError.cause) {
26
+ title += ' ' + projectGraphError.cause.message + '.';
27
+ }
28
+ if (isVerbose) {
29
+ title += ' See errors below.';
30
+ }
31
+ const bodyLines = isVerbose
32
+ ? formatErrorStackAndCause(projectGraphError)
33
+ : ['Pass --verbose to see the stacktraces.'];
34
+ output_1.output.error({
35
+ title,
36
+ bodyLines: bodyLines,
37
+ });
38
+ }
39
+ else {
40
+ const lines = (err.message ? err.message : err.toString()).split('\n');
41
+ const bodyLines = lines.slice(1);
42
+ if (isVerbose) {
43
+ bodyLines.push(...formatErrorStackAndCause(err));
44
+ }
45
+ else if (err.stack) {
46
+ bodyLines.push('Pass --verbose to see the stacktrace.');
47
+ }
48
+ output_1.output.error({
49
+ title: lines[0],
50
+ bodyLines,
51
+ });
52
+ }
53
+ if (client_1.daemonClient.enabled()) {
54
+ client_1.daemonClient.reset();
55
+ }
56
+ return 1;
57
+ }
58
+ }
59
+ function formatErrorStackAndCause(error) {
60
+ return [
61
+ error.stack || error.message,
62
+ ...(error.cause && typeof error.cause === 'object'
63
+ ? [
64
+ 'Caused by:',
65
+ 'stack' in error.cause
66
+ ? error.cause.stack.toString()
67
+ : error.cause.toString(),
68
+ ]
69
+ : []),
70
+ ];
71
+ }
@@ -1,4 +1,3 @@
1
1
  import { NxJsonConfiguration } from '../config/nx-json';
2
2
  export declare function isNxCloudUsed(nxJson: NxJsonConfiguration): boolean;
3
3
  export declare function getNxCloudUrl(nxJson: NxJsonConfiguration): string;
4
- export declare function getNxCloudToken(nxJson: NxJsonConfiguration): string;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isNxCloudUsed = isNxCloudUsed;
4
4
  exports.getNxCloudUrl = getNxCloudUrl;
5
- exports.getNxCloudToken = getNxCloudToken;
6
5
  function isNxCloudUsed(nxJson) {
7
6
  return (!!process.env.NX_CLOUD_ACCESS_TOKEN ||
8
7
  !!nxJson.nxCloudAccessToken ||
@@ -17,12 +16,3 @@ function getNxCloudUrl(nxJson) {
17
16
  throw new Error('nx-cloud runner not found in nx.json');
18
17
  return cloudRunner?.options?.url ?? nxJson.nxCloudUrl ?? 'https://nx.app';
19
18
  }
20
- function getNxCloudToken(nxJson) {
21
- const cloudRunner = Object.values(nxJson.tasksRunnerOptions ?? {}).find((r) => r.runner == '@nrwl/nx-cloud' || r.runner == 'nx-cloud');
22
- if (!cloudRunner &&
23
- !(nxJson.nxCloudAccessToken || process.env.NX_CLOUD_ACCESS_TOKEN))
24
- throw new Error('nx-cloud runner not found in nx.json');
25
- return (process.env.NX_CLOUD_ACCESS_TOKEN ??
26
- cloudRunner?.options.accessToken ??
27
- nxJson.nxCloudAccessToken);
28
- }
@@ -79,7 +79,6 @@ export type Options = {
79
79
  '--'?: Unmatched[];
80
80
  [k: string]: string | number | boolean | string[] | Unmatched[] | undefined;
81
81
  };
82
- export declare function handleErrors(isVerbose: boolean, fn: Function): Promise<number>;
83
82
  export declare function convertToCamelCase(parsed: {
84
83
  [k: string]: any;
85
84
  }, schema: Schema): Options;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SchemaError = void 0;
4
- exports.handleErrors = handleErrors;
5
4
  exports.convertToCamelCase = convertToCamelCase;
6
5
  exports.coerceTypesInOptions = coerceTypesInOptions;
7
6
  exports.convertAliases = convertAliases;
@@ -15,55 +14,6 @@ exports.warnDeprecations = warnDeprecations;
15
14
  exports.convertSmartDefaultsIntoNamedParams = convertSmartDefaultsIntoNamedParams;
16
15
  exports.getPromptsForSchema = getPromptsForSchema;
17
16
  const logger_1 = require("./logger");
18
- const output_1 = require("./output");
19
- const client_1 = require("../daemon/client/client");
20
- async function handleErrors(isVerbose, fn) {
21
- try {
22
- const result = await fn();
23
- if (typeof result === 'number') {
24
- return result;
25
- }
26
- return 0;
27
- }
28
- catch (err) {
29
- err ||= new Error('Unknown error caught');
30
- if (err.constructor.name === 'UnsuccessfulWorkflowExecution') {
31
- logger_1.logger.error('The generator workflow failed. See above.');
32
- }
33
- else if (err.name === 'ProjectGraphError') {
34
- const projectGraphError = err;
35
- let title = projectGraphError.message;
36
- if (isVerbose) {
37
- title += ' See errors below.';
38
- }
39
- const bodyLines = isVerbose
40
- ? [projectGraphError.stack]
41
- : ['Pass --verbose to see the stacktraces.'];
42
- output_1.output.error({
43
- title,
44
- bodyLines: bodyLines,
45
- });
46
- }
47
- else {
48
- const lines = (err.message ? err.message : err.toString()).split('\n');
49
- const bodyLines = lines.slice(1);
50
- if (err.stack && !isVerbose) {
51
- bodyLines.push('Pass --verbose to see the stacktrace.');
52
- }
53
- output_1.output.error({
54
- title: lines[0],
55
- bodyLines,
56
- });
57
- if (err.stack && isVerbose) {
58
- logger_1.logger.info(err.stack);
59
- }
60
- }
61
- if (client_1.daemonClient.enabled()) {
62
- client_1.daemonClient.reset();
63
- }
64
- return 1;
65
- }
66
- }
67
17
  function camelCase(input) {
68
18
  if (input.indexOf('-') > 1) {
69
19
  return input