nx 19.6.0-canary.20240809-d3747e0 → 19.6.0-canary.20240814-6d83ae2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. package/bin/post-install.js +9 -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/daemon/cache.d.ts +1 -0
  42. package/src/daemon/cache.js +25 -18
  43. package/src/daemon/client/client.d.ts +5 -0
  44. package/src/daemon/client/client.js +42 -1
  45. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.d.ts +6 -0
  46. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.js +11 -0
  47. package/src/daemon/message-types/force-shutdown.d.ts +5 -0
  48. package/src/daemon/message-types/force-shutdown.js +11 -0
  49. package/src/daemon/message-types/get-registered-sync-generators.d.ts +5 -0
  50. package/src/daemon/message-types/get-registered-sync-generators.js +11 -0
  51. package/src/daemon/message-types/get-sync-generator-changes.d.ts +6 -0
  52. package/src/daemon/message-types/get-sync-generator-changes.js +11 -0
  53. package/src/daemon/message-types/update-workspace-context.d.ts +8 -0
  54. package/src/daemon/message-types/update-workspace-context.js +11 -0
  55. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.d.ts +2 -0
  56. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.js +11 -0
  57. package/src/daemon/server/handle-force-shutdown.d.ts +5 -0
  58. package/src/daemon/server/handle-force-shutdown.js +18 -0
  59. package/src/daemon/server/handle-get-registered-sync-generators.d.ts +2 -0
  60. package/src/daemon/server/handle-get-registered-sync-generators.js +11 -0
  61. package/src/daemon/server/handle-get-sync-generator-changes.d.ts +2 -0
  62. package/src/daemon/server/handle-get-sync-generator-changes.js +17 -0
  63. package/src/daemon/server/handle-request-shutdown.js +2 -0
  64. package/src/daemon/server/handle-update-workspace-context.d.ts +2 -0
  65. package/src/daemon/server/handle-update-workspace-context.js +11 -0
  66. package/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -0
  67. package/src/daemon/server/project-graph-incremental-recomputation.js +20 -3
  68. package/src/daemon/server/server.d.ts +1 -0
  69. package/src/daemon/server/server.js +39 -0
  70. package/src/daemon/server/shutdown-utils.d.ts +2 -1
  71. package/src/daemon/server/shutdown-utils.js +11 -4
  72. package/src/daemon/server/sync-generators.d.ts +6 -0
  73. package/src/daemon/server/sync-generators.js +202 -0
  74. package/src/daemon/server/watcher.js +3 -0
  75. package/src/daemon/socket-utils.js +18 -5
  76. package/src/daemon/tmp-dir.js +2 -1
  77. package/src/native/nx.wasm32-wasi.wasm +0 -0
  78. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +1 -1
  79. package/src/nx-cloud/models/onboarding-status.d.ts +1 -0
  80. package/src/nx-cloud/models/onboarding-status.js +2 -0
  81. package/src/nx-cloud/utilities/is-workspace-claimed.d.ts +1 -0
  82. package/src/nx-cloud/utilities/is-workspace-claimed.js +24 -0
  83. package/src/nx-cloud/utilities/onboarding.d.ts +5 -0
  84. package/src/nx-cloud/utilities/onboarding.js +28 -0
  85. package/src/project-graph/plugins/internal-api.js +16 -5
  86. package/src/project-graph/plugins/isolation/messaging.d.ts +5 -1
  87. package/src/project-graph/plugins/isolation/messaging.js +1 -0
  88. package/src/project-graph/plugins/isolation/plugin-pool.js +4 -6
  89. package/src/project-graph/plugins/isolation/plugin-worker.js +15 -0
  90. package/src/project-graph/utils/project-configuration-utils.js +5 -2
  91. package/src/tasks-runner/run-command.d.ts +1 -1
  92. package/src/tasks-runner/run-command.js +117 -2
  93. package/src/utils/command-line-utils.d.ts +1 -0
  94. package/src/utils/command-line-utils.js +6 -3
  95. package/src/utils/git-utils.d.ts +35 -0
  96. package/src/utils/git-utils.js +111 -0
  97. package/src/utils/package-manager.js +1 -1
  98. package/src/utils/plugins/output.js +1 -1
  99. package/src/utils/squash.d.ts +1 -0
  100. package/src/utils/squash.js +12 -0
  101. package/src/utils/sync-generators.d.ts +22 -0
  102. package/src/utils/sync-generators.js +161 -0
  103. package/src/utils/workspace-context.d.ts +2 -1
  104. package/src/utils/workspace-context.js +18 -1
  105. package/src/daemon/message-types/update-context-files.d.ts +0 -7
  106. package/src/daemon/message-types/update-context-files.js +0 -11
@@ -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,116 @@ 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
+ // collect unique syncGenerators from the tasks
122
+ const uniqueSyncGenerators = new Set();
123
+ for (const { target } of Object.values(taskGraph.tasks)) {
124
+ const { syncGenerators } = projectGraph.nodes[target.project].data.targets[target.target];
125
+ if (!syncGenerators) {
126
+ continue;
127
+ }
128
+ for (const generator of syncGenerators) {
129
+ uniqueSyncGenerators.add(generator);
130
+ }
131
+ }
132
+ if (!uniqueSyncGenerators.size) {
133
+ // There are no sync generators registered in the tasks to run
134
+ return { projectGraph, taskGraph };
135
+ }
136
+ const syncGenerators = Array.from(uniqueSyncGenerators);
137
+ const results = await (0, sync_generators_1.getSyncGeneratorChanges)(syncGenerators);
138
+ if (!results.length) {
139
+ // There are no changes to sync, workspace is up to date
140
+ return { projectGraph, taskGraph };
141
+ }
142
+ const outOfSyncTitle = 'The workspace is out of sync';
143
+ const resultBodyLines = (0, sync_generators_1.syncGeneratorResultsToMessageLines)(results);
144
+ 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.';
145
+ const willErrorOnCiMessage = 'Please note that this will be an error on CI.';
146
+ if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
147
+ // If the user is running in CI or is running in a non-TTY environment we
148
+ // throw an error to stop the execution of the tasks.
149
+ throw new Error(`${outOfSyncTitle}\n${resultBodyLines.join('\n')}\n${fixMessage}`);
150
+ }
151
+ if (nxJson.sync?.applyChanges === false) {
152
+ // If the user has set `sync.applyChanges` to `false` in their `nx.json`
153
+ // we don't prompt the them and just log a warning informing them that
154
+ // the workspace is out of sync and they have it set to not apply changes
155
+ // automatically.
156
+ output_1.output.warn({
157
+ title: outOfSyncTitle,
158
+ bodyLines: [
159
+ ...resultBodyLines,
160
+ 'Your workspace is set to not apply changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
161
+ willErrorOnCiMessage,
162
+ fixMessage,
163
+ ],
164
+ });
165
+ return { projectGraph, taskGraph };
166
+ }
167
+ output_1.output.warn({
168
+ title: outOfSyncTitle,
169
+ bodyLines: [
170
+ ...resultBodyLines,
171
+ nxJson.sync?.applyChanges === true
172
+ ? 'Proceeding to sync the changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
173
+ : willErrorOnCiMessage,
174
+ ],
175
+ });
176
+ const applyChanges = nxJson.sync?.applyChanges === true ||
177
+ (await promptForApplyingSyncGeneratorChanges());
178
+ if (applyChanges) {
179
+ const spinner = ora('Syncing the workspace...');
180
+ spinner.start();
181
+ // Flush sync generator changes to disk
182
+ await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
183
+ // Re-create project graph and task graph
184
+ projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
185
+ taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
186
+ if (nxJson.sync?.applyChanges === true) {
187
+ spinner.succeed(`The workspace was synced successfully!
188
+
189
+ Please make sure to commit the changes to your repository or this will error on CI.`);
190
+ }
191
+ else {
192
+ // The user was prompted and we already logged a message about erroring on CI
193
+ // so here we just tell them to commit the changes.
194
+ spinner.succeed(`The workspace was synced successfully!
195
+
196
+ Please make sure to commit the changes to your repository.`);
197
+ }
198
+ }
199
+ else {
200
+ output_1.output.warn({
201
+ title: 'Syncing the workspace was skipped',
202
+ bodyLines: [
203
+ 'This could lead to unexpected results or errors when running tasks.',
204
+ fixMessage,
205
+ ],
206
+ });
207
+ }
208
+ return { projectGraph, taskGraph };
209
+ }
210
+ async function promptForApplyingSyncGeneratorChanges() {
211
+ const promptConfig = {
212
+ name: 'applyChanges',
213
+ type: 'select',
214
+ message: 'Would you like to sync the changes to get your worskpace up to date?',
215
+ choices: [
216
+ {
217
+ name: 'yes',
218
+ message: 'Yes, sync the changes and run the tasks',
219
+ },
220
+ {
221
+ name: 'no',
222
+ message: 'No, run the tasks without syncing the changes',
223
+ },
224
+ ],
225
+ footer: () => chalk.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option in your `nx.json`.'),
226
+ };
227
+ return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
228
+ }
114
229
  function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
115
230
  if (nxArgs.outputStyle == 'stream' ||
116
231
  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)(workspace_root_1.workspaceRoot, 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,7 +11,8 @@ 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 updateFilesInContext(updatedFiles: string[], deletedFiles: string[]): Record<string, string>;
14
+ export declare function updateContextWithChangedFiles(workspaceRoot: string, createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): Promise<void>;
15
+ export declare function updateFilesInContext(workspaceRoot: string, 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[]>;
17
18
  export declare function updateProjectFiles(projectRootMappings: Record<string, string>, rustReferences: NxWorkspaceFilesExternals, updatedFiles: Record<string, string>, deletedFiles: string[]): import("../native").UpdatedWorkspaceFiles;
@@ -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,7 +57,23 @@ async function hashWithWorkspaceContext(workspaceRoot, globs, exclude) {
56
57
  }
57
58
  return client_1.daemonClient.hashGlob(globs, exclude);
58
59
  }
59
- function updateFilesInContext(updatedFiles, deletedFiles) {
60
+ async function updateContextWithChangedFiles(workspaceRoot, createdFiles, updatedFiles, deletedFiles) {
61
+ if (!client_1.daemonClient.enabled()) {
62
+ updateFilesInContext(workspaceRoot, [...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
+ }
75
+ function updateFilesInContext(workspaceRoot, updatedFiles, deletedFiles) {
76
+ ensureContextAvailable(workspaceRoot);
60
77
  return workspaceContext?.incrementalUpdate(updatedFiles, deletedFiles);
61
78
  }
62
79
  async function getAllFileDataInContext(workspaceRoot) {
@@ -1,7 +0,0 @@
1
- export declare const GLOB: "GLOB";
2
- export type HandleUpdateContextMessage = {
3
- type: typeof GLOB;
4
- updatedFiles: string[];
5
- deletedFiles: string[];
6
- };
7
- export declare function isHandleUpdateContextMessage(message: unknown): message is HandleUpdateContextMessage;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GLOB = void 0;
4
- exports.isHandleUpdateContextMessage = isHandleUpdateContextMessage;
5
- exports.GLOB = 'GLOB';
6
- function isHandleUpdateContextMessage(message) {
7
- return (typeof message === 'object' &&
8
- message !== null &&
9
- 'type' in message &&
10
- message['type'] === exports.GLOB);
11
- }