nx 19.6.0-canary.20240808-333ab77 → 19.6.0-canary.20240813-c72ba9b

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 (107) hide show
  1. package/bin/post-install.js +8 -0
  2. package/package.json +12 -12
  3. package/schemas/nx-schema.json +55 -4
  4. package/schemas/project-schema.json +7 -0
  5. package/src/adapter/compat.d.ts +1 -1
  6. package/src/adapter/compat.js +1 -0
  7. package/src/command-line/import/command-object.d.ts +2 -0
  8. package/src/command-line/import/command-object.js +38 -0
  9. package/src/command-line/import/import.d.ts +21 -0
  10. package/src/command-line/import/import.js +173 -0
  11. package/src/command-line/import/utils/merge-remote-source.d.ts +2 -0
  12. package/src/command-line/import/utils/merge-remote-source.js +14 -0
  13. package/src/command-line/import/utils/needs-install.d.ts +3 -0
  14. package/src/command-line/import/utils/needs-install.js +31 -0
  15. package/src/command-line/import/utils/prepare-source-repo.d.ts +2 -0
  16. package/src/command-line/import/utils/prepare-source-repo.js +104 -0
  17. package/src/command-line/init/init-v2.d.ts +7 -0
  18. package/src/command-line/init/init-v2.js +49 -16
  19. package/src/command-line/nx-commands.js +33 -28
  20. package/src/command-line/release/changelog.js +9 -9
  21. package/src/command-line/release/command-object.d.ts +12 -3
  22. package/src/command-line/release/command-object.js +16 -1
  23. package/src/command-line/release/config/config.js +4 -2
  24. package/src/command-line/release/config/filter-release-groups.d.ts +2 -2
  25. package/src/command-line/release/config/filter-release-groups.js +1 -1
  26. package/src/command-line/release/config/version-plans.d.ts +1 -1
  27. package/src/command-line/release/config/version-plans.js +12 -12
  28. package/src/command-line/release/plan-check.d.ts +4 -0
  29. package/src/command-line/release/plan-check.js +225 -0
  30. package/src/command-line/release/plan.js +1 -1
  31. package/src/command-line/release/release.js +3 -3
  32. package/src/command-line/release/version.js +1 -1
  33. package/src/command-line/sync/command-object.d.ts +6 -0
  34. package/src/command-line/sync/command-object.js +25 -0
  35. package/src/command-line/sync/sync.d.ts +6 -0
  36. package/src/command-line/sync/sync.js +30 -0
  37. package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  38. package/src/config/nx-json.d.ts +32 -2
  39. package/src/config/workspace-json-project-json.d.ts +5 -0
  40. package/src/core/graph/main.js +1 -1
  41. package/src/core/graph/styles.css +1 -1
  42. package/src/daemon/cache.d.ts +1 -0
  43. package/src/daemon/cache.js +25 -18
  44. package/src/daemon/client/client.d.ts +5 -0
  45. package/src/daemon/client/client.js +42 -1
  46. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.d.ts +6 -0
  47. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.js +11 -0
  48. package/src/daemon/message-types/force-shutdown.d.ts +5 -0
  49. package/src/daemon/message-types/force-shutdown.js +11 -0
  50. package/src/daemon/message-types/get-registered-sync-generators.d.ts +5 -0
  51. package/src/daemon/message-types/get-registered-sync-generators.js +11 -0
  52. package/src/daemon/message-types/get-sync-generator-changes.d.ts +6 -0
  53. package/src/daemon/message-types/get-sync-generator-changes.js +11 -0
  54. package/src/daemon/message-types/update-workspace-context.d.ts +8 -0
  55. package/src/daemon/message-types/update-workspace-context.js +11 -0
  56. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.d.ts +2 -0
  57. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.js +11 -0
  58. package/src/daemon/server/handle-force-shutdown.d.ts +5 -0
  59. package/src/daemon/server/handle-force-shutdown.js +18 -0
  60. package/src/daemon/server/handle-get-registered-sync-generators.d.ts +2 -0
  61. package/src/daemon/server/handle-get-registered-sync-generators.js +11 -0
  62. package/src/daemon/server/handle-get-sync-generator-changes.d.ts +2 -0
  63. package/src/daemon/server/handle-get-sync-generator-changes.js +17 -0
  64. package/src/daemon/server/handle-request-shutdown.js +2 -0
  65. package/src/daemon/server/handle-update-workspace-context.d.ts +2 -0
  66. package/src/daemon/server/handle-update-workspace-context.js +11 -0
  67. package/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -0
  68. package/src/daemon/server/project-graph-incremental-recomputation.js +19 -2
  69. package/src/daemon/server/server.d.ts +1 -0
  70. package/src/daemon/server/server.js +39 -0
  71. package/src/daemon/server/shutdown-utils.d.ts +2 -1
  72. package/src/daemon/server/shutdown-utils.js +11 -4
  73. package/src/daemon/server/sync-generators.d.ts +6 -0
  74. package/src/daemon/server/sync-generators.js +202 -0
  75. package/src/daemon/server/watcher.js +3 -0
  76. package/src/daemon/socket-utils.js +18 -5
  77. package/src/daemon/tmp-dir.js +2 -1
  78. package/src/native/nx.wasm32-wasi.wasm +0 -0
  79. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +1 -1
  80. package/src/nx-cloud/models/onboarding-status.d.ts +1 -0
  81. package/src/nx-cloud/models/onboarding-status.js +2 -0
  82. package/src/nx-cloud/utilities/is-workspace-claimed.d.ts +1 -0
  83. package/src/nx-cloud/utilities/is-workspace-claimed.js +24 -0
  84. package/src/nx-cloud/utilities/onboarding.d.ts +5 -0
  85. package/src/nx-cloud/utilities/onboarding.js +28 -0
  86. package/src/project-graph/plugins/internal-api.js +16 -5
  87. package/src/project-graph/plugins/isolation/messaging.d.ts +5 -1
  88. package/src/project-graph/plugins/isolation/messaging.js +1 -0
  89. package/src/project-graph/plugins/isolation/plugin-pool.js +4 -6
  90. package/src/project-graph/plugins/isolation/plugin-worker.js +15 -0
  91. package/src/project-graph/utils/project-configuration-utils.js +5 -2
  92. package/src/tasks-runner/run-command.d.ts +1 -1
  93. package/src/tasks-runner/run-command.js +120 -2
  94. package/src/utils/command-line-utils.d.ts +1 -0
  95. package/src/utils/command-line-utils.js +6 -3
  96. package/src/utils/git-utils.d.ts +35 -0
  97. package/src/utils/git-utils.js +111 -0
  98. package/src/utils/package-manager.js +1 -1
  99. package/src/utils/plugins/output.js +1 -1
  100. package/src/utils/squash.d.ts +1 -0
  101. package/src/utils/squash.js +12 -0
  102. package/src/utils/sync-generators.d.ts +22 -0
  103. package/src/utils/sync-generators.js +161 -0
  104. package/src/utils/workspace-context.d.ts +1 -0
  105. package/src/utils/workspace-context.js +16 -0
  106. package/src/daemon/message-types/update-context-files.d.ts +0 -7
  107. package/src/daemon/message-types/update-context-files.js +0 -11
@@ -446,7 +446,7 @@ function normalizeTargets(project, sourceMaps, nxJsonConfiguration) {
446
446
  project.targets[targetName] = normalizeTarget(project.targets[targetName], project);
447
447
  const projectSourceMaps = sourceMaps[project.root];
448
448
  const targetConfig = project.targets[targetName];
449
- const targetDefaults = readTargetDefaultsForTarget(targetName, nxJsonConfiguration.targetDefaults, targetConfig.executor);
449
+ const targetDefaults = deepClone(readTargetDefaultsForTarget(targetName, nxJsonConfiguration.targetDefaults, targetConfig.executor));
450
450
  // We only apply defaults if they exist
451
451
  if (targetDefaults && isCompatibleTarget(targetConfig, targetDefaults)) {
452
452
  project.targets[targetName] = mergeTargetDefaultWithTargetDefinition(targetName, project, normalizeTarget(targetDefaults, project), projectSourceMaps);
@@ -499,9 +499,12 @@ function targetDefaultShouldBeApplied(key, sourceMap) {
499
499
  const [, plugin] = sourceInfo;
500
500
  return !plugin?.startsWith('nx/');
501
501
  }
502
+ function deepClone(obj) {
503
+ return JSON.parse(JSON.stringify(obj));
504
+ }
502
505
  function mergeTargetDefaultWithTargetDefinition(targetName, project, targetDefault, sourceMap) {
503
506
  const targetDefinition = project.targets[targetName] ?? {};
504
- const result = JSON.parse(JSON.stringify(targetDefinition));
507
+ const result = deepClone(targetDefinition);
505
508
  for (const key in targetDefault) {
506
509
  switch (key) {
507
510
  case 'options': {
@@ -5,7 +5,7 @@ import { TargetDependencyConfig } from '../config/workspace-json-project-json';
5
5
  import { NxArgs } from '../utils/command-line-utils';
6
6
  import { LifeCycle } from './life-cycle';
7
7
  import { TasksRunner } from './tasks-runner';
8
- export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], projectGraph: ProjectGraph, { nxJson }: {
8
+ export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
9
9
  nxJson: NxJsonConfiguration;
10
10
  }, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
11
11
  excludeTaskDependencies: boolean;
@@ -4,16 +4,20 @@ exports.runCommand = runCommand;
4
4
  exports.invokeTasksRunner = invokeTasksRunner;
5
5
  exports.getRunner = getRunner;
6
6
  exports.getRunnerOptions = getRunnerOptions;
7
+ const enquirer_1 = require("enquirer");
8
+ const ora = require("ora");
7
9
  const path_1 = require("path");
8
10
  const nx_json_1 = require("../config/nx-json");
9
11
  const client_1 = require("../daemon/client/client");
10
12
  const create_task_hasher_1 = require("../hasher/create-task-hasher");
11
13
  const hash_task_1 = require("../hasher/hash-task");
14
+ const project_graph_1 = require("../project-graph/project-graph");
12
15
  const fileutils_1 = require("../utils/fileutils");
13
16
  const is_ci_1 = require("../utils/is-ci");
14
17
  const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
15
18
  const output_1 = require("../utils/output");
16
19
  const params_1 = require("../utils/params");
20
+ const sync_generators_1 = require("../utils/sync-generators");
17
21
  const workspace_root_1 = require("../utils/workspace-root");
18
22
  const create_task_graph_1 = require("./create-task-graph");
19
23
  const life_cycle_1 = require("./life-cycle");
@@ -27,6 +31,7 @@ const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-c
27
31
  const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle");
28
32
  const task_graph_utils_1 = require("./task-graph-utils");
29
33
  const utils_1 = require("./utils");
34
+ const chalk = require("chalk");
30
35
  async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {
31
36
  const { runnerOptions } = getRunner(nxArgs, nxJson);
32
37
  const isRunOne = initiatingProject != null;
@@ -90,10 +95,10 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
90
95
  }
91
96
  return taskGraph;
92
97
  }
93
- async function runCommand(projectsToRun, projectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
98
+ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
94
99
  const status = await (0, params_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
95
100
  const projectNames = projectsToRun.map((t) => t.name);
96
- const taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
101
+ const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
97
102
  const tasks = Object.values(taskGraph.tasks);
98
103
  const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
99
104
  const status = await invokeTasksRunner({
@@ -111,6 +116,119 @@ async function runCommand(projectsToRun, projectGraph, { nxJson }, nxArgs, overr
111
116
  });
112
117
  return status;
113
118
  }
119
+ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
120
+ let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
121
+ if (process.env.NX_ENABLE_SYNC_GENERATORS !== 'true') {
122
+ return { projectGraph, taskGraph };
123
+ }
124
+ // collect unique syncGenerators from the tasks
125
+ const uniqueSyncGenerators = new Set();
126
+ for (const { target } of Object.values(taskGraph.tasks)) {
127
+ const { syncGenerators } = projectGraph.nodes[target.project].data.targets[target.target];
128
+ if (!syncGenerators) {
129
+ continue;
130
+ }
131
+ for (const generator of syncGenerators) {
132
+ uniqueSyncGenerators.add(generator);
133
+ }
134
+ }
135
+ if (!uniqueSyncGenerators.size) {
136
+ // There are no sync generators registered in the tasks to run
137
+ return { projectGraph, taskGraph };
138
+ }
139
+ const syncGenerators = Array.from(uniqueSyncGenerators);
140
+ const results = await (0, sync_generators_1.getSyncGeneratorChanges)(syncGenerators);
141
+ if (!results.length) {
142
+ // There are no changes to sync, workspace is up to date
143
+ return { projectGraph, taskGraph };
144
+ }
145
+ const outOfSyncTitle = 'The workspace is out of sync';
146
+ const resultBodyLines = (0, sync_generators_1.syncGeneratorResultsToMessageLines)(results);
147
+ 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.';
148
+ const willErrorOnCiMessage = 'Please note that this will be an error on CI.';
149
+ if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
150
+ // If the user is running in CI or is running in a non-TTY environment we
151
+ // throw an error to stop the execution of the tasks.
152
+ throw new Error(`${outOfSyncTitle}\n${resultBodyLines.join('\n')}\n${fixMessage}`);
153
+ }
154
+ if (nxJson.sync?.applyChanges === false) {
155
+ // If the user has set `sync.applyChanges` to `false` in their `nx.json`
156
+ // we don't prompt the them and just log a warning informing them that
157
+ // the workspace is out of sync and they have it set to not apply changes
158
+ // automatically.
159
+ output_1.output.warn({
160
+ title: outOfSyncTitle,
161
+ bodyLines: [
162
+ ...resultBodyLines,
163
+ 'Your workspace is set to not apply changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
164
+ willErrorOnCiMessage,
165
+ fixMessage,
166
+ ],
167
+ });
168
+ return { projectGraph, taskGraph };
169
+ }
170
+ output_1.output.warn({
171
+ title: outOfSyncTitle,
172
+ bodyLines: [
173
+ ...resultBodyLines,
174
+ nxJson.sync?.applyChanges === true
175
+ ? 'Proceeding to sync the changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
176
+ : willErrorOnCiMessage,
177
+ ],
178
+ });
179
+ const applyChanges = nxJson.sync?.applyChanges === true ||
180
+ (await promptForApplyingSyncGeneratorChanges());
181
+ if (applyChanges) {
182
+ const spinner = ora('Syncing the workspace...');
183
+ spinner.start();
184
+ // Flush sync generator changes to disk
185
+ await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
186
+ // Re-create project graph and task graph
187
+ projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
188
+ taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
189
+ if (nxJson.sync?.applyChanges === true) {
190
+ spinner.succeed(`The workspace was synced successfully!
191
+
192
+ Please make sure to commit the changes to your repository or this will error on CI.`);
193
+ }
194
+ else {
195
+ // The user was prompted and we already logged a message about erroring on CI
196
+ // so here we just tell them to commit the changes.
197
+ spinner.succeed(`The workspace was synced successfully!
198
+
199
+ Please make sure to commit the changes to your repository.`);
200
+ }
201
+ }
202
+ else {
203
+ output_1.output.warn({
204
+ title: 'Syncing the workspace was skipped',
205
+ bodyLines: [
206
+ 'This could lead to unexpected results or errors when running tasks.',
207
+ fixMessage,
208
+ ],
209
+ });
210
+ }
211
+ return { projectGraph, taskGraph };
212
+ }
213
+ async function promptForApplyingSyncGeneratorChanges() {
214
+ const promptConfig = {
215
+ name: 'applyChanges',
216
+ type: 'select',
217
+ message: 'Would you like to sync the changes to get your worskpace up to date?',
218
+ choices: [
219
+ {
220
+ name: 'yes',
221
+ message: 'Yes, sync the changes and run the tasks',
222
+ },
223
+ {
224
+ name: 'no',
225
+ message: 'No, run the tasks without syncing the changes',
226
+ },
227
+ ],
228
+ footer: () => chalk.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option in your `nx.json`.'),
229
+ };
230
+ return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
231
+ }
114
232
  function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
115
233
  if (nxArgs.outputStyle == 'stream' ||
116
234
  process.env.NX_BATCH_MODE === 'true' ||
@@ -32,6 +32,7 @@ export interface NxArgs {
32
32
  excludeTaskDependencies?: boolean;
33
33
  }
34
34
  export declare function createOverrides(__overrides_unparsed__?: string[]): Record<string, any>;
35
+ export declare function getBaseRef(nxJson: NxJsonConfiguration): string;
35
36
  export declare function splitArgsIntoNxArgsAndOverrides(args: {
36
37
  [k: string]: any;
37
38
  }, mode: 'run-one' | 'run-many' | 'affected' | 'print-affected', options: {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createOverrides = createOverrides;
4
+ exports.getBaseRef = getBaseRef;
4
5
  exports.splitArgsIntoNxArgsAndOverrides = splitArgsIntoNxArgsAndOverrides;
5
6
  exports.readParallelFromArgsAndEnv = readParallelFromArgsAndEnv;
6
7
  exports.parseFiles = parseFiles;
@@ -24,6 +25,9 @@ function createOverrides(__overrides_unparsed__ = []) {
24
25
  overrides.__overrides_unparsed__ = __overrides_unparsed__;
25
26
  return overrides;
26
27
  }
28
+ function getBaseRef(nxJson) {
29
+ return nxJson.defaultBase ?? nxJson.affected?.defaultBase ?? 'main';
30
+ }
27
31
  function splitArgsIntoNxArgsAndOverrides(args, mode, options = { printWarnings: true }, nxJson) {
28
32
  // this is to lerna case when this function is invoked imperatively
29
33
  if (args['target'] && !args['targets']) {
@@ -70,7 +74,7 @@ function splitArgsIntoNxArgsAndOverrides(args, mode, options = { printWarnings:
70
74
  ],
71
75
  });
72
76
  }
73
- // Allow setting base and head via environment variables (lower priority then direct command arguments)
77
+ // Allow setting base and head via environment variables (lower priority than direct command arguments)
74
78
  if (!nxArgs.base && process.env.NX_BASE) {
75
79
  nxArgs.base = process.env.NX_BASE;
76
80
  if (options.printWarnings) {
@@ -88,8 +92,7 @@ function splitArgsIntoNxArgsAndOverrides(args, mode, options = { printWarnings:
88
92
  }
89
93
  }
90
94
  if (!nxArgs.base) {
91
- nxArgs.base =
92
- nxJson.defaultBase ?? nxJson.affected?.defaultBase ?? 'main';
95
+ nxArgs.base = getBaseRef(nxJson);
93
96
  // No user-provided arguments to set the affected criteria, so inform the user of the defaults being used
94
97
  if (options.printWarnings &&
95
98
  !nxArgs.head &&
@@ -1,3 +1,38 @@
1
+ import { ExecSyncOptions } from 'child_process';
2
+ export declare function cloneFromUpstream(url: string, destination: string, { originName }?: {
3
+ originName: string;
4
+ }): Promise<GitRepository>;
5
+ export declare class GitRepository {
6
+ private directory;
7
+ root: string;
8
+ constructor(directory: string);
9
+ getGitRootPath(cwd: string): string;
10
+ addFetchRemote(remoteName: string, branch: string): Promise<string>;
11
+ private execAsync;
12
+ showStat(): Promise<string>;
13
+ listBranches(): Promise<string[]>;
14
+ getGitFiles(path: string): Promise<string[]>;
15
+ reset(ref: string): Promise<string>;
16
+ squashLastTwoCommits(): Promise<string>;
17
+ mergeUnrelatedHistories(ref: string, message: string): Promise<string>;
18
+ fetch(remote: string, ref?: string): Promise<string>;
19
+ checkout(branch: string, opts: {
20
+ new: boolean;
21
+ base: string;
22
+ }): Promise<string>;
23
+ move(path: string, destination: string): Promise<string>;
24
+ push(ref: string, remoteName: string): Promise<string>;
25
+ commit(message: string): Promise<string>;
26
+ amendCommit(): Promise<string>;
27
+ deleteGitRemote(name: string): Promise<string>;
28
+ deleteBranch(branch: string): Promise<string>;
29
+ addGitRemote(name: string, url: string): Promise<string>;
30
+ }
31
+ /**
32
+ * This is used by the squash editor script to update the rebase file.
33
+ */
34
+ export declare function updateRebaseFile(contents: string): string;
35
+ export declare function fetchGitRemote(name: string, branch: string, execOptions: ExecSyncOptions): string | Buffer;
1
36
  export declare function getGithubSlugOrNull(): string | null;
2
37
  export declare function extractUserAndRepoFromGitHubUrl(gitRemotes: string): string | null;
3
38
  export declare function commitChanges(commitMessage: string, directory?: string): string | null;
@@ -1,11 +1,122 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitRepository = void 0;
4
+ exports.cloneFromUpstream = cloneFromUpstream;
5
+ exports.updateRebaseFile = updateRebaseFile;
6
+ exports.fetchGitRemote = fetchGitRemote;
3
7
  exports.getGithubSlugOrNull = getGithubSlugOrNull;
4
8
  exports.extractUserAndRepoFromGitHubUrl = extractUserAndRepoFromGitHubUrl;
5
9
  exports.commitChanges = commitChanges;
6
10
  exports.getLatestCommitSha = getLatestCommitSha;
7
11
  const child_process_1 = require("child_process");
8
12
  const devkit_exports_1 = require("../devkit-exports");
13
+ const path_1 = require("path");
14
+ const SQUASH_EDITOR = (0, path_1.join)(__dirname, 'squash.js');
15
+ function execAsync(command, execOptions) {
16
+ return new Promise((res, rej) => {
17
+ (0, child_process_1.exec)(command, execOptions, (err, stdout, stderr) => {
18
+ if (err) {
19
+ return rej(err);
20
+ }
21
+ res(stdout);
22
+ });
23
+ });
24
+ }
25
+ async function cloneFromUpstream(url, destination, { originName } = { originName: 'origin' }) {
26
+ await execAsync(`git clone ${url} ${destination} --depth 1 --origin ${originName}`, {
27
+ cwd: (0, path_1.dirname)(destination),
28
+ });
29
+ return new GitRepository(destination);
30
+ }
31
+ class GitRepository {
32
+ constructor(directory) {
33
+ this.directory = directory;
34
+ this.root = this.getGitRootPath(this.directory);
35
+ }
36
+ getGitRootPath(cwd) {
37
+ return (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
38
+ cwd,
39
+ })
40
+ .toString()
41
+ .trim();
42
+ }
43
+ addFetchRemote(remoteName, branch) {
44
+ return this.execAsync(`git config --add remote.${remoteName}.fetch "+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}"`);
45
+ }
46
+ execAsync(command) {
47
+ return execAsync(command, {
48
+ cwd: this.root,
49
+ });
50
+ }
51
+ async showStat() {
52
+ return await this.execAsync(`git show --stat`);
53
+ }
54
+ async listBranches() {
55
+ return (await this.execAsync(`git ls-remote --heads --quiet`))
56
+ .trim()
57
+ .split('\n')
58
+ .map((s) => s
59
+ .trim()
60
+ .substring(s.indexOf('\t') + 1)
61
+ .replace('refs/heads/', ''));
62
+ }
63
+ async getGitFiles(path) {
64
+ return (await this.execAsync(`git ls-files ${path}`))
65
+ .trim()
66
+ .split('\n')
67
+ .map((s) => s.trim())
68
+ .filter(Boolean);
69
+ }
70
+ async reset(ref) {
71
+ return this.execAsync(`git reset ${ref} --hard`);
72
+ }
73
+ async squashLastTwoCommits() {
74
+ return this.execAsync(`git -c core.editor="node ${SQUASH_EDITOR}" rebase --interactive --no-autosquash HEAD~2`);
75
+ }
76
+ async mergeUnrelatedHistories(ref, message) {
77
+ return this.execAsync(`git merge ${ref} -X ours --allow-unrelated-histories -m "${message}"`);
78
+ }
79
+ async fetch(remote, ref) {
80
+ return this.execAsync(`git fetch ${remote}${ref ? ` ${ref}` : ''}`);
81
+ }
82
+ async checkout(branch, opts) {
83
+ return this.execAsync(`git checkout ${opts.new ? '-b ' : ' '}${branch}${opts.base ? ' ' + opts.base : ''}`);
84
+ }
85
+ async move(path, destination) {
86
+ return this.execAsync(`git mv ${path} ${destination}`);
87
+ }
88
+ async push(ref, remoteName) {
89
+ return this.execAsync(`git push -u -f ${remoteName} ${ref}`);
90
+ }
91
+ async commit(message) {
92
+ return this.execAsync(`git commit -am "${message}"`);
93
+ }
94
+ async amendCommit() {
95
+ return this.execAsync(`git commit --amend -a --no-edit`);
96
+ }
97
+ deleteGitRemote(name) {
98
+ return this.execAsync(`git remote rm ${name}`);
99
+ }
100
+ deleteBranch(branch) {
101
+ return this.execAsync(`git branch -D ${branch}`);
102
+ }
103
+ addGitRemote(name, url) {
104
+ return this.execAsync(`git remote add ${name} ${url}`);
105
+ }
106
+ }
107
+ exports.GitRepository = GitRepository;
108
+ /**
109
+ * This is used by the squash editor script to update the rebase file.
110
+ */
111
+ function updateRebaseFile(contents) {
112
+ const lines = contents.split('\n');
113
+ const lastCommitIndex = lines.findIndex((line) => line === '') - 1;
114
+ lines[lastCommitIndex] = lines[lastCommitIndex].replace('pick', 'fixup');
115
+ return lines.join('\n');
116
+ }
117
+ function fetchGitRemote(name, branch, execOptions) {
118
+ return (0, child_process_1.execSync)(`git fetch ${name} ${branch} --depth 1`, execOptions);
119
+ }
9
120
  function getGithubSlugOrNull() {
10
121
  try {
11
122
  const gitRemote = (0, child_process_1.execSync)('git remote -v', {
@@ -49,7 +49,7 @@ function isWorkspacesEnabled(packageManager = detectPackageManager(), root = wor
49
49
  if (packageManager === 'pnpm') {
50
50
  return (0, fs_1.existsSync)((0, path_1.join)(root, 'pnpm-workspace.yaml'));
51
51
  }
52
- // yarn and pnpm both use the same 'workspaces' property in package.json
52
+ // yarn and npm both use the same 'workspaces' property in package.json
53
53
  const packageJson = (0, file_utils_1.readPackageJson)();
54
54
  return !!packageJson?.workspaces;
55
55
  }
@@ -27,7 +27,7 @@ function listPlugins(plugins, title) {
27
27
  if (p.projectInference) {
28
28
  capabilities.push('project-inference');
29
29
  }
30
- bodyLines.push(`${chalk.bold(p.name)} (${capabilities.join()})`);
30
+ bodyLines.push(`${chalk.bold(p.name)} ${capabilities.length >= 1 ? `(${capabilities.join()})` : ''}`);
31
31
  }
32
32
  output_1.output.log({
33
33
  title: title,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const git_utils_1 = require("./git-utils");
5
+ // This script is used as an editor for git rebase -i
6
+ // This is the file which git creates. When this script exits, the updates should be written to this file.
7
+ const filePath = process.argv[2];
8
+ // Change the second commit from pick to fixup
9
+ const contents = (0, fs_1.readFileSync)(filePath).toString();
10
+ const newContents = (0, git_utils_1.updateRebaseFile)(contents);
11
+ // Write the updated contents back to the file
12
+ (0, fs_1.writeFileSync)(filePath, newContents);
@@ -0,0 +1,22 @@
1
+ import type { GeneratorCallback } from '../config/misc-interfaces';
2
+ import type { ProjectGraph } from '../config/project-graph';
3
+ import type { ProjectConfiguration } from '../config/workspace-json-project-json';
4
+ import { FsTree, type FileChange, type Tree } from '../generators/tree';
5
+ export type SyncGeneratorResult = void | {
6
+ callback?: GeneratorCallback;
7
+ outOfSyncMessage?: string;
8
+ };
9
+ export type SyncGenerator = (tree: Tree) => SyncGeneratorResult | Promise<SyncGeneratorResult>;
10
+ export type SyncGeneratorChangesResult = {
11
+ changes: FileChange[];
12
+ generatorName: string;
13
+ callback?: GeneratorCallback;
14
+ outOfSyncMessage?: string;
15
+ };
16
+ export declare function getSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorChangesResult[]>;
17
+ export declare function flushSyncGeneratorChanges(results: SyncGeneratorChangesResult[]): Promise<void>;
18
+ export declare function collectAllRegisteredSyncGenerators(projectGraph: ProjectGraph): Promise<string[]>;
19
+ export declare function runSyncGenerator(tree: FsTree, generatorSpecifier: string, projects: Record<string, ProjectConfiguration>): Promise<SyncGeneratorChangesResult>;
20
+ export declare function collectRegisteredTaskSyncGenerators(projectGraph: ProjectGraph): Set<string>;
21
+ export declare function collectRegisteredGlobalSyncGenerators(nxJson?: import("../config/nx-json").NxJsonConfiguration<string[] | "*">): Set<string>;
22
+ export declare function syncGeneratorResultsToMessageLines(results: SyncGeneratorChangesResult[]): string[];
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSyncGeneratorChanges = getSyncGeneratorChanges;
4
+ exports.flushSyncGeneratorChanges = flushSyncGeneratorChanges;
5
+ exports.collectAllRegisteredSyncGenerators = collectAllRegisteredSyncGenerators;
6
+ exports.runSyncGenerator = runSyncGenerator;
7
+ exports.collectRegisteredTaskSyncGenerators = collectRegisteredTaskSyncGenerators;
8
+ exports.collectRegisteredGlobalSyncGenerators = collectRegisteredGlobalSyncGenerators;
9
+ exports.syncGeneratorResultsToMessageLines = syncGeneratorResultsToMessageLines;
10
+ const perf_hooks_1 = require("perf_hooks");
11
+ const generate_1 = require("../command-line/generate/generate");
12
+ const generator_utils_1 = require("../command-line/generate/generator-utils");
13
+ const nx_json_1 = require("../config/nx-json");
14
+ const client_1 = require("../daemon/client/client");
15
+ const is_on_daemon_1 = require("../daemon/is-on-daemon");
16
+ const tree_1 = require("../generators/tree");
17
+ const project_graph_1 = require("../project-graph/project-graph");
18
+ const workspace_context_1 = require("./workspace-context");
19
+ const workspace_root_1 = require("./workspace-root");
20
+ const chalk = require("chalk");
21
+ async function getSyncGeneratorChanges(generators) {
22
+ perf_hooks_1.performance.mark('get-sync-generators-changes:start');
23
+ let results;
24
+ if (!client_1.daemonClient.enabled()) {
25
+ results = await runSyncGenerators(generators);
26
+ }
27
+ else {
28
+ results = await client_1.daemonClient.getSyncGeneratorChanges(generators);
29
+ }
30
+ perf_hooks_1.performance.mark('get-sync-generators-changes:end');
31
+ perf_hooks_1.performance.measure('get-sync-generators-changes', 'get-sync-generators-changes:start', 'get-sync-generators-changes:end');
32
+ return results.filter((r) => r.changes.length > 0);
33
+ }
34
+ async function flushSyncGeneratorChanges(results) {
35
+ if ((0, is_on_daemon_1.isOnDaemon)() || !client_1.daemonClient.enabled()) {
36
+ await flushSyncGeneratorChangesToDisk(results);
37
+ }
38
+ else {
39
+ await client_1.daemonClient.flushSyncGeneratorChangesToDisk(results.map((r) => r.generatorName));
40
+ }
41
+ }
42
+ async function collectAllRegisteredSyncGenerators(projectGraph) {
43
+ if (!client_1.daemonClient.enabled()) {
44
+ return [
45
+ ...collectRegisteredTaskSyncGenerators(projectGraph),
46
+ ...collectRegisteredGlobalSyncGenerators(),
47
+ ];
48
+ }
49
+ return await client_1.daemonClient.getRegisteredSyncGenerators();
50
+ }
51
+ async function runSyncGenerator(tree, generatorSpecifier, projects) {
52
+ perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:start`);
53
+ const { collection, generator } = (0, generate_1.parseGeneratorString)(generatorSpecifier);
54
+ const { implementationFactory } = (0, generator_utils_1.getGeneratorInformation)(collection, generator, workspace_root_1.workspaceRoot, projects);
55
+ const implementation = implementationFactory();
56
+ const result = await implementation(tree);
57
+ let callback;
58
+ let outOfSyncMessage;
59
+ if (result && typeof result === 'object') {
60
+ callback = result.callback;
61
+ outOfSyncMessage = result.outOfSyncMessage;
62
+ }
63
+ perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:end`);
64
+ perf_hooks_1.performance.measure(`run-sync-generator:${generatorSpecifier}`, `run-sync-generator:${generatorSpecifier}:start`, `run-sync-generator:${generatorSpecifier}:end`);
65
+ return {
66
+ changes: tree.listChanges(),
67
+ generatorName: generatorSpecifier,
68
+ callback,
69
+ outOfSyncMessage,
70
+ };
71
+ }
72
+ function collectRegisteredTaskSyncGenerators(projectGraph) {
73
+ const taskSyncGenerators = new Set();
74
+ for (const { data: { targets }, } of Object.values(projectGraph.nodes)) {
75
+ if (!targets) {
76
+ continue;
77
+ }
78
+ for (const target of Object.values(targets)) {
79
+ if (!target.syncGenerators) {
80
+ continue;
81
+ }
82
+ for (const generator of target.syncGenerators) {
83
+ taskSyncGenerators.add(generator);
84
+ }
85
+ }
86
+ }
87
+ return taskSyncGenerators;
88
+ }
89
+ function collectRegisteredGlobalSyncGenerators(nxJson = (0, nx_json_1.readNxJson)()) {
90
+ const globalSyncGenerators = new Set();
91
+ if (!nxJson.sync?.globalGenerators?.length) {
92
+ return globalSyncGenerators;
93
+ }
94
+ for (const generator of nxJson.sync.globalGenerators) {
95
+ globalSyncGenerators.add(generator);
96
+ }
97
+ return globalSyncGenerators;
98
+ }
99
+ function syncGeneratorResultsToMessageLines(results) {
100
+ const messageLines = [];
101
+ for (const result of results) {
102
+ messageLines.push(`The ${chalk.bold(result.generatorName)} sync generator identified ${chalk.bold(result.changes.length)} file${result.changes.length === 1 ? '' : 's'} in the workspace that ${result.changes.length === 1 ? 'is' : 'are'} out of sync${result.outOfSyncMessage ? ':' : '.'}`);
103
+ if (result.outOfSyncMessage) {
104
+ messageLines.push(result.outOfSyncMessage);
105
+ }
106
+ messageLines.push('');
107
+ }
108
+ return messageLines;
109
+ }
110
+ async function runSyncGenerators(generators) {
111
+ const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, 'running sync generators');
112
+ const projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
113
+ const { projects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
114
+ const results = [];
115
+ for (const generator of generators) {
116
+ const result = await runSyncGenerator(tree, generator, projects);
117
+ results.push(result);
118
+ }
119
+ return results;
120
+ }
121
+ async function flushSyncGeneratorChangesToDisk(results) {
122
+ perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:start');
123
+ const { changes, createdFiles, updatedFiles, deletedFiles, callbacks } = processSyncGeneratorResults(results);
124
+ // Write changes to disk
125
+ (0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, changes);
126
+ // Run the callbacks
127
+ if (callbacks.length) {
128
+ for (const callback of callbacks) {
129
+ await callback();
130
+ }
131
+ }
132
+ // Update the context files
133
+ await (0, workspace_context_1.updateContextWithChangedFiles)(createdFiles, updatedFiles, deletedFiles);
134
+ perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:end');
135
+ perf_hooks_1.performance.measure('flush sync generator changes to disk', 'flush-sync-generator-changes-to-disk:start', 'flush-sync-generator-changes-to-disk:end');
136
+ }
137
+ function processSyncGeneratorResults(results) {
138
+ const changes = [];
139
+ const createdFiles = [];
140
+ const updatedFiles = [];
141
+ const deletedFiles = [];
142
+ const callbacks = [];
143
+ for (const result of results) {
144
+ if (result.callback) {
145
+ callbacks.push(result.callback);
146
+ }
147
+ for (const change of result.changes) {
148
+ changes.push(change);
149
+ if (change.type === 'CREATE') {
150
+ createdFiles.push(change.path);
151
+ }
152
+ else if (change.type === 'UPDATE') {
153
+ updatedFiles.push(change.path);
154
+ }
155
+ else if (change.type === 'DELETE') {
156
+ deletedFiles.push(change.path);
157
+ }
158
+ }
159
+ }
160
+ return { changes, createdFiles, updatedFiles, deletedFiles, callbacks };
161
+ }
@@ -11,6 +11,7 @@ export declare function getNxWorkspaceFilesFromContext(workspaceRoot: string, pr
11
11
  export declare function globWithWorkspaceContextSync(workspaceRoot: string, globs: string[], exclude?: string[]): string[];
12
12
  export declare function globWithWorkspaceContext(workspaceRoot: string, globs: string[], exclude?: string[]): Promise<string[]>;
13
13
  export declare function hashWithWorkspaceContext(workspaceRoot: string, globs: string[], exclude?: string[]): Promise<string>;
14
+ export declare function updateContextWithChangedFiles(createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): Promise<void>;
14
15
  export declare function updateFilesInContext(updatedFiles: string[], deletedFiles: string[]): Record<string, string>;
15
16
  export declare function getAllFileDataInContext(workspaceRoot: string): Promise<import("../native").FileData[]>;
16
17
  export declare function getFilesInDirectoryUsingContext(workspaceRoot: string, dir: string): Promise<string[]>;
@@ -5,6 +5,7 @@ exports.getNxWorkspaceFilesFromContext = getNxWorkspaceFilesFromContext;
5
5
  exports.globWithWorkspaceContextSync = globWithWorkspaceContextSync;
6
6
  exports.globWithWorkspaceContext = globWithWorkspaceContext;
7
7
  exports.hashWithWorkspaceContext = hashWithWorkspaceContext;
8
+ exports.updateContextWithChangedFiles = updateContextWithChangedFiles;
8
9
  exports.updateFilesInContext = updateFilesInContext;
9
10
  exports.getAllFileDataInContext = getAllFileDataInContext;
10
11
  exports.getFilesInDirectoryUsingContext = getFilesInDirectoryUsingContext;
@@ -56,6 +57,21 @@ async function hashWithWorkspaceContext(workspaceRoot, globs, exclude) {
56
57
  }
57
58
  return client_1.daemonClient.hashGlob(globs, exclude);
58
59
  }
60
+ async function updateContextWithChangedFiles(createdFiles, updatedFiles, deletedFiles) {
61
+ if (!client_1.daemonClient.enabled()) {
62
+ updateFilesInContext([...createdFiles, ...updatedFiles], deletedFiles);
63
+ }
64
+ else if ((0, is_on_daemon_1.isOnDaemon)()) {
65
+ // make sure to only import this when running on the daemon
66
+ const { addUpdatedAndDeletedFiles } = await Promise.resolve().then(() => require('../daemon/server/project-graph-incremental-recomputation'));
67
+ // update files for the incremental graph recomputation on the daemon
68
+ addUpdatedAndDeletedFiles(createdFiles, updatedFiles, deletedFiles);
69
+ }
70
+ else {
71
+ // daemon is enabled but we are not running on it, ask the daemon to update the context
72
+ await client_1.daemonClient.updateWorkspaceContext(createdFiles, updatedFiles, deletedFiles);
73
+ }
74
+ }
59
75
  function updateFilesInContext(updatedFiles, deletedFiles) {
60
76
  return workspaceContext?.incrementalUpdate(updatedFiles, deletedFiles);
61
77
  }