nx 19.7.2 → 19.8.0-canary.20240911-2a3307c
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +12 -12
- package/src/command-line/import/command-object.js +6 -4
- package/src/command-line/import/import.d.ts +1 -1
- package/src/command-line/import/import.js +26 -27
- package/src/command-line/sync/sync.js +67 -9
- package/src/daemon/client/client.d.ts +3 -3
- package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.js +2 -2
- package/src/daemon/server/handle-get-sync-generator-changes.js +8 -6
- package/src/daemon/server/sync-generators.d.ts +4 -4
- package/src/daemon/server/sync-generators.js +11 -2
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/tasks-runner/run-command.js +137 -27
- package/src/utils/sync-generators.d.ts +35 -6
- package/src/utils/sync-generators.js +144 -47
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "nx",
|
3
|
-
"version": "19.
|
3
|
+
"version": "19.8.0-canary.20240911-2a3307c",
|
4
4
|
"private": false,
|
5
5
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
6
6
|
"repository": {
|
@@ -71,7 +71,7 @@
|
|
71
71
|
"yargs-parser": "21.1.1",
|
72
72
|
"node-machine-id": "1.1.12",
|
73
73
|
"ora": "5.3.0",
|
74
|
-
"@nrwl/tao": "19.
|
74
|
+
"@nrwl/tao": "19.8.0-canary.20240911-2a3307c"
|
75
75
|
},
|
76
76
|
"peerDependencies": {
|
77
77
|
"@swc-node/register": "^1.8.0",
|
@@ -86,16 +86,16 @@
|
|
86
86
|
}
|
87
87
|
},
|
88
88
|
"optionalDependencies": {
|
89
|
-
"@nx/nx-darwin-x64": "19.
|
90
|
-
"@nx/nx-darwin-arm64": "19.
|
91
|
-
"@nx/nx-linux-x64-gnu": "19.
|
92
|
-
"@nx/nx-linux-x64-musl": "19.
|
93
|
-
"@nx/nx-win32-x64-msvc": "19.
|
94
|
-
"@nx/nx-linux-arm64-gnu": "19.
|
95
|
-
"@nx/nx-linux-arm64-musl": "19.
|
96
|
-
"@nx/nx-linux-arm-gnueabihf": "19.
|
97
|
-
"@nx/nx-win32-arm64-msvc": "19.
|
98
|
-
"@nx/nx-freebsd-x64": "19.
|
89
|
+
"@nx/nx-darwin-x64": "19.8.0-canary.20240911-2a3307c",
|
90
|
+
"@nx/nx-darwin-arm64": "19.8.0-canary.20240911-2a3307c",
|
91
|
+
"@nx/nx-linux-x64-gnu": "19.8.0-canary.20240911-2a3307c",
|
92
|
+
"@nx/nx-linux-x64-musl": "19.8.0-canary.20240911-2a3307c",
|
93
|
+
"@nx/nx-win32-x64-msvc": "19.8.0-canary.20240911-2a3307c",
|
94
|
+
"@nx/nx-linux-arm64-gnu": "19.8.0-canary.20240911-2a3307c",
|
95
|
+
"@nx/nx-linux-arm64-musl": "19.8.0-canary.20240911-2a3307c",
|
96
|
+
"@nx/nx-linux-arm-gnueabihf": "19.8.0-canary.20240911-2a3307c",
|
97
|
+
"@nx/nx-win32-arm64-msvc": "19.8.0-canary.20240911-2a3307c",
|
98
|
+
"@nx/nx-freebsd-x64": "19.8.0-canary.20240911-2a3307c"
|
99
99
|
},
|
100
100
|
"nx-migrations": {
|
101
101
|
"migrations": "./migrations.json",
|
@@ -5,19 +5,21 @@ const documentation_1 = require("../yargs-utils/documentation");
|
|
5
5
|
const shared_options_1 = require("../yargs-utils/shared-options");
|
6
6
|
const params_1 = require("../../utils/params");
|
7
7
|
exports.yargsImportCommand = {
|
8
|
-
command: 'import [
|
8
|
+
command: 'import [sourceRepository] [destinationDirectory]',
|
9
9
|
describe: false,
|
10
10
|
builder: (yargs) => (0, documentation_1.linkToNxDevAndExamples)((0, shared_options_1.withVerbose)(yargs
|
11
|
-
.positional('
|
11
|
+
.positional('sourceRepository', {
|
12
12
|
type: 'string',
|
13
13
|
description: 'The remote URL of the source to import.',
|
14
14
|
})
|
15
|
-
.positional('
|
15
|
+
.positional('destinationDirectory', {
|
16
16
|
type: 'string',
|
17
|
+
alias: 'destination',
|
17
18
|
description: 'The directory in the current workspace to import into.',
|
18
19
|
})
|
19
|
-
.option('
|
20
|
+
.option('sourceDirectory', {
|
20
21
|
type: 'string',
|
22
|
+
alias: 'source',
|
21
23
|
description: 'The directory in the source repository to import from.',
|
22
24
|
})
|
23
25
|
.option('ref', {
|
@@ -25,41 +25,40 @@ const needs_install_1 = require("./utils/needs-install");
|
|
25
25
|
const file_utils_1 = require("../../project-graph/file-utils");
|
26
26
|
const importRemoteName = '__tmp_nx_import__';
|
27
27
|
async function importHandler(options) {
|
28
|
-
let {
|
28
|
+
let { sourceRepository, ref, source, destination } = options;
|
29
29
|
output_1.output.log({
|
30
|
-
title: 'Nx will walk you through the process of importing code from
|
30
|
+
title: 'Nx will walk you through the process of importing code from the source repository into this repository:',
|
31
31
|
bodyLines: [
|
32
|
-
`1. Nx will clone the
|
33
|
-
`2.
|
34
|
-
`3. The
|
35
|
-
`4. Nx will recommend plugins to integrate tools used in the imported code
|
36
|
-
`5. The code will be successfully imported into this workspace`,
|
32
|
+
`1. Nx will clone the source repository into a temporary directory`,
|
33
|
+
`2. The project code from the sourceDirectory will be moved to the destinationDirectory on a temporary branch in this repository`,
|
34
|
+
`3. The temporary branch will be merged into the current branch in this repository`,
|
35
|
+
`4. Nx will recommend plugins to integrate any new tools used in the imported code`,
|
37
36
|
'',
|
38
|
-
`Git history will be preserved during this process`,
|
37
|
+
`Git history will be preserved during this process as long as you MERGE these changes. Do NOT squash and do NOT rebase the changes when merging branches. If you would like to UNDO these changes, run "git reset HEAD~1 --hard"`,
|
39
38
|
],
|
40
39
|
});
|
41
40
|
const tempImportDirectory = (0, path_1.join)(tmp_1.tmpdir, 'nx-import');
|
42
|
-
if (!
|
43
|
-
|
41
|
+
if (!sourceRepository) {
|
42
|
+
sourceRepository = (await (0, enquirer_1.prompt)([
|
44
43
|
{
|
45
44
|
type: 'input',
|
46
|
-
name: '
|
45
|
+
name: 'sourceRepository',
|
47
46
|
message: 'What is the URL of the repository you want to import? (This can be a local git repository or a git remote URL)',
|
48
47
|
required: true,
|
49
48
|
},
|
50
|
-
])).
|
49
|
+
])).sourceRepository;
|
51
50
|
}
|
52
51
|
try {
|
53
|
-
const maybeLocalDirectory = await (0, promises_1.stat)(
|
52
|
+
const maybeLocalDirectory = await (0, promises_1.stat)(sourceRepository);
|
54
53
|
if (maybeLocalDirectory.isDirectory()) {
|
55
|
-
|
54
|
+
sourceRepository = (0, path_1.resolve)(sourceRepository);
|
56
55
|
}
|
57
56
|
}
|
58
57
|
catch (e) {
|
59
58
|
// It's a remote url
|
60
59
|
}
|
61
|
-
const
|
62
|
-
const spinner = createSpinner(`Cloning ${
|
60
|
+
const sourceTempRepoPath = (0, path_1.join)(tempImportDirectory, 'repo');
|
61
|
+
const spinner = createSpinner(`Cloning ${sourceRepository} into a temporary directory: ${sourceTempRepoPath} (Use --depth to limit commit history and speed up clone times)`).start();
|
63
62
|
try {
|
64
63
|
await (0, promises_1.rm)(tempImportDirectory, { recursive: true });
|
65
64
|
}
|
@@ -67,17 +66,17 @@ async function importHandler(options) {
|
|
67
66
|
await (0, promises_1.mkdir)(tempImportDirectory, { recursive: true });
|
68
67
|
let sourceGitClient;
|
69
68
|
try {
|
70
|
-
sourceGitClient = await (0, git_utils_1.cloneFromUpstream)(
|
69
|
+
sourceGitClient = await (0, git_utils_1.cloneFromUpstream)(sourceRepository, sourceTempRepoPath, {
|
71
70
|
originName: importRemoteName,
|
72
71
|
depth: options.depth,
|
73
72
|
});
|
74
73
|
}
|
75
74
|
catch (e) {
|
76
|
-
spinner.fail(`Failed to clone ${
|
77
|
-
let errorMessage = `Failed to clone ${
|
75
|
+
spinner.fail(`Failed to clone ${sourceRepository} into ${sourceTempRepoPath}`);
|
76
|
+
let errorMessage = `Failed to clone ${sourceRepository} into ${sourceTempRepoPath}. Please double check the remote and try again.\n${e.message}`;
|
78
77
|
throw new Error(errorMessage);
|
79
78
|
}
|
80
|
-
spinner.succeed(`Cloned into ${
|
79
|
+
spinner.succeed(`Cloned into ${sourceTempRepoPath}`);
|
81
80
|
// Detecting the package manager before preparing the source repo for import.
|
82
81
|
const sourcePackageManager = (0, package_manager_1.detectPackageManager)(sourceGitClient.root);
|
83
82
|
if (!ref) {
|
@@ -116,14 +115,14 @@ async function importHandler(options) {
|
|
116
115
|
},
|
117
116
|
])).destination;
|
118
117
|
}
|
119
|
-
const absSource = (0, path_1.join)(
|
118
|
+
const absSource = (0, path_1.join)(sourceTempRepoPath, source);
|
120
119
|
const absDestination = (0, path_1.join)(process.cwd(), destination);
|
121
120
|
const destinationGitClient = new git_utils_1.GitRepository(process.cwd());
|
122
121
|
await assertDestinationEmpty(destinationGitClient, absDestination);
|
123
122
|
const tempImportBranch = getTempImportBranch(ref);
|
124
123
|
await sourceGitClient.addFetchRemote(importRemoteName, ref);
|
125
124
|
await sourceGitClient.fetch(importRemoteName, ref);
|
126
|
-
spinner.succeed(`Fetched ${ref} from ${
|
125
|
+
spinner.succeed(`Fetched ${ref} from ${sourceRepository}`);
|
127
126
|
spinner.start(`Checking out a temporary branch, ${tempImportBranch} based on ${ref}`);
|
128
127
|
await sourceGitClient.checkout(tempImportBranch, {
|
129
128
|
new: true,
|
@@ -134,14 +133,14 @@ async function importHandler(options) {
|
|
134
133
|
await (0, promises_1.stat)(absSource);
|
135
134
|
}
|
136
135
|
catch (e) {
|
137
|
-
throw new Error(`The source directory ${source} does not exist in ${
|
136
|
+
throw new Error(`The source directory ${source} does not exist in ${sourceRepository}. Please double check to make sure it exists.`);
|
138
137
|
}
|
139
138
|
const packageManager = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot);
|
140
139
|
const originalPackageWorkspaces = await (0, needs_install_1.getPackagesInPackageManagerWorkspace)(packageManager);
|
141
140
|
const relativeDestination = (0, path_1.relative)(destinationGitClient.root, absDestination);
|
142
|
-
await (0, prepare_source_repo_1.prepareSourceRepo)(sourceGitClient, ref, source, relativeDestination, tempImportBranch,
|
143
|
-
await createTemporaryRemote(destinationGitClient, (0, path_1.join)(
|
144
|
-
await (0, merge_remote_source_1.mergeRemoteSource)(destinationGitClient,
|
141
|
+
await (0, prepare_source_repo_1.prepareSourceRepo)(sourceGitClient, ref, source, relativeDestination, tempImportBranch, sourceRepository);
|
142
|
+
await createTemporaryRemote(destinationGitClient, (0, path_1.join)(sourceTempRepoPath, '.git'), importRemoteName);
|
143
|
+
await (0, merge_remote_source_1.mergeRemoteSource)(destinationGitClient, sourceRepository, tempImportBranch, destination, importRemoteName, ref);
|
145
144
|
spinner.start('Cleaning up temporary files and remotes');
|
146
145
|
await (0, promises_1.rm)(tempImportDirectory, { recursive: true });
|
147
146
|
await destinationGitClient.deleteGitRemote(importRemoteName);
|
@@ -208,7 +207,7 @@ async function importHandler(options) {
|
|
208
207
|
output_1.output.log({
|
209
208
|
title: `Check root dependencies`,
|
210
209
|
bodyLines: [
|
211
|
-
`"dependencies" and "devDependencies" are not imported from the source repository (${
|
210
|
+
`"dependencies" and "devDependencies" are not imported from the source repository (${sourceRepository}).`,
|
212
211
|
`You may need to add some of those dependencies to this workspace in order to run tasks successfully.`,
|
213
212
|
],
|
214
213
|
});
|
@@ -32,24 +32,82 @@ function syncHandler(options) {
|
|
32
32
|
});
|
33
33
|
return 0;
|
34
34
|
}
|
35
|
+
const { failedGeneratorsCount, areAllResultsFailures, anySyncGeneratorsFailed, } = (0, sync_generators_1.processSyncGeneratorResultErrors)(results);
|
36
|
+
const failedSyncGeneratorsFixMessageLines = (0, sync_generators_1.getFailedSyncGeneratorsFixMessageLines)(results, options.verbose);
|
37
|
+
if (areAllResultsFailures) {
|
38
|
+
output_1.output.error({
|
39
|
+
title: `The workspace is probably out of sync because ${failedGeneratorsCount === 1
|
40
|
+
? 'a sync generator'
|
41
|
+
: 'some sync generators'} failed to run`,
|
42
|
+
bodyLines: failedSyncGeneratorsFixMessageLines,
|
43
|
+
});
|
44
|
+
return 1;
|
45
|
+
}
|
46
|
+
const resultBodyLines = (0, sync_generators_1.getSyncGeneratorSuccessResultsMessageLines)(results);
|
35
47
|
if (options.check) {
|
36
48
|
output_1.output.error({
|
37
|
-
title:
|
38
|
-
bodyLines:
|
49
|
+
title: 'The workspace is out of sync',
|
50
|
+
bodyLines: resultBodyLines,
|
39
51
|
});
|
52
|
+
if (anySyncGeneratorsFailed) {
|
53
|
+
output_1.output.error({
|
54
|
+
title: failedGeneratorsCount === 1
|
55
|
+
? 'A sync generator failed to run'
|
56
|
+
: 'Some sync generators failed to run',
|
57
|
+
bodyLines: failedSyncGeneratorsFixMessageLines,
|
58
|
+
});
|
59
|
+
}
|
40
60
|
return 1;
|
41
61
|
}
|
42
62
|
output_1.output.warn({
|
43
|
-
title:
|
44
|
-
bodyLines:
|
63
|
+
title: 'The workspace is out of sync',
|
64
|
+
bodyLines: resultBodyLines,
|
45
65
|
});
|
46
66
|
const spinner = ora('Syncing the workspace...');
|
47
67
|
spinner.start();
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
68
|
+
try {
|
69
|
+
const flushResult = await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
|
70
|
+
if ('generatorFailures' in flushResult) {
|
71
|
+
spinner.fail();
|
72
|
+
output_1.output.error({
|
73
|
+
title: 'Failed to sync the workspace',
|
74
|
+
bodyLines: (0, sync_generators_1.getFlushFailureMessageLines)(flushResult, options.verbose),
|
75
|
+
});
|
76
|
+
return 1;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
catch (e) {
|
80
|
+
spinner.fail();
|
81
|
+
output_1.output.error({
|
82
|
+
title: 'Failed to sync the workspace',
|
83
|
+
bodyLines: [
|
84
|
+
'Syncing the workspace failed with the following error:',
|
85
|
+
'',
|
86
|
+
e.message,
|
87
|
+
...(options.verbose && !!e.stack ? [`\n${e.stack}`] : []),
|
88
|
+
'',
|
89
|
+
'Please rerun with `--verbose` and report the error at: https://github.com/nrwl/nx/issues/new/choose',
|
90
|
+
],
|
91
|
+
});
|
92
|
+
return 1;
|
93
|
+
}
|
94
|
+
const successTitle = anySyncGeneratorsFailed
|
95
|
+
? // the identified changes were synced successfully, but the workspace
|
96
|
+
// is still not up to date, which we'll mention next
|
97
|
+
'The identified changes were synced successfully!'
|
98
|
+
: // the workspace is fully up to date
|
99
|
+
'The workspace was synced successfully!';
|
100
|
+
const successSubtitle = 'Please make sure to commit the changes to your repository.';
|
101
|
+
spinner.succeed(`${successTitle}\n\n${successSubtitle}`);
|
102
|
+
if (anySyncGeneratorsFailed) {
|
103
|
+
output_1.output.error({
|
104
|
+
title: `The workspace is probably still out of sync because ${failedGeneratorsCount === 1
|
105
|
+
? 'a sync generator'
|
106
|
+
: 'some sync generators'} failed to run`,
|
107
|
+
bodyLines: failedSyncGeneratorsFixMessageLines,
|
108
|
+
});
|
109
|
+
return 1;
|
110
|
+
}
|
53
111
|
return 0;
|
54
112
|
});
|
55
113
|
}
|
@@ -4,7 +4,7 @@ import { Hash } from '../../hasher/task-hasher';
|
|
4
4
|
import { Task, TaskGraph } from '../../config/task-graph';
|
5
5
|
import { ConfigurationSourceMaps } from '../../project-graph/utils/project-configuration-utils';
|
6
6
|
import { NxWorkspaceFiles, TaskRun } from '../../native';
|
7
|
-
import type {
|
7
|
+
import type { FlushSyncGeneratorChangesResult, SyncGeneratorRunResult } from '../../utils/sync-generators';
|
8
8
|
export type UnregisterCallback = () => void;
|
9
9
|
export type ChangedFile = {
|
10
10
|
path: string;
|
@@ -52,8 +52,8 @@ export declare class DaemonClient {
|
|
52
52
|
hashGlob(globs: string[], exclude?: string[]): Promise<string>;
|
53
53
|
getFlakyTasks(hashes: string[]): Promise<string[]>;
|
54
54
|
recordTaskRuns(taskRuns: TaskRun[]): Promise<void>;
|
55
|
-
getSyncGeneratorChanges(generators: string[]): Promise<
|
56
|
-
flushSyncGeneratorChangesToDisk(generators: string[]): Promise<
|
55
|
+
getSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorRunResult[]>;
|
56
|
+
flushSyncGeneratorChangesToDisk(generators: string[]): Promise<FlushSyncGeneratorChangesResult>;
|
57
57
|
getRegisteredSyncGenerators(): Promise<string[]>;
|
58
58
|
updateWorkspaceContext(createdFiles: string[], updatedFiles: string[], deletedFiles: string[]): Promise<void>;
|
59
59
|
isServerAvailable(): Promise<boolean>;
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleFlushSyncGeneratorChangesToDisk = handleFlushSyncGeneratorChangesToDisk;
|
4
4
|
const sync_generators_1 = require("./sync-generators");
|
5
5
|
async function handleFlushSyncGeneratorChangesToDisk(generators) {
|
6
|
-
await (0, sync_generators_1.flushSyncGeneratorChangesToDisk)(generators);
|
6
|
+
const result = await (0, sync_generators_1.flushSyncGeneratorChangesToDisk)(generators);
|
7
7
|
return {
|
8
|
-
response:
|
8
|
+
response: JSON.stringify(result),
|
9
9
|
description: 'handleFlushSyncGeneratorChangesToDisk',
|
10
10
|
};
|
11
11
|
}
|
@@ -4,12 +4,14 @@ exports.handleGetSyncGeneratorChanges = handleGetSyncGeneratorChanges;
|
|
4
4
|
const sync_generators_1 = require("./sync-generators");
|
5
5
|
async function handleGetSyncGeneratorChanges(generators) {
|
6
6
|
const changes = await (0, sync_generators_1.getCachedSyncGeneratorChanges)(generators);
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
const result = changes.map((change) => 'error' in change
|
8
|
+
? change
|
9
|
+
: // strip out the content of the changes and any potential callback
|
10
|
+
{
|
11
|
+
generatorName: change.generatorName,
|
12
|
+
changes: change.changes.map((c) => ({ ...c, content: null })),
|
13
|
+
outOfSyncMessage: change.outOfSyncMessage,
|
14
|
+
});
|
13
15
|
return {
|
14
16
|
response: JSON.stringify(result),
|
15
17
|
description: 'handleGetSyncGeneratorChanges',
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import type { ProjectGraph } from '../../config/project-graph';
|
2
|
-
import { type
|
3
|
-
export declare function getCachedSyncGeneratorChanges(generators: string[]): Promise<
|
4
|
-
export declare function flushSyncGeneratorChangesToDisk(generators: string[]): Promise<
|
2
|
+
import { type FlushSyncGeneratorChangesResult, type SyncGeneratorRunResult } from '../../utils/sync-generators';
|
3
|
+
export declare function getCachedSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorRunResult[]>;
|
4
|
+
export declare function flushSyncGeneratorChangesToDisk(generators: string[]): Promise<FlushSyncGeneratorChangesResult>;
|
5
5
|
export declare function collectAndScheduleSyncGenerators(projectGraph: ProjectGraph): void;
|
6
6
|
export declare function getCachedRegisteredSyncGenerators(): Promise<string[]>;
|
7
7
|
/**
|
8
8
|
* @internal
|
9
9
|
*/
|
10
|
-
export declare function _getConflictingGeneratorGroups(results:
|
10
|
+
export declare function _getConflictingGeneratorGroups(results: SyncGeneratorRunResult[]): string[][];
|
@@ -59,7 +59,7 @@ async function flushSyncGeneratorChangesToDisk(generators) {
|
|
59
59
|
for (const generator of generators) {
|
60
60
|
syncGeneratorsCacheResultPromises.delete(generator);
|
61
61
|
}
|
62
|
-
await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
|
62
|
+
return await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
|
63
63
|
}
|
64
64
|
function collectAndScheduleSyncGenerators(projectGraph) {
|
65
65
|
if (!projectGraph) {
|
@@ -191,6 +191,7 @@ async function processConflictingGenerators(conflicts, initialResults) {
|
|
191
191
|
const conflictRunResults = (await Promise.all(conflicts.map((generators) => {
|
192
192
|
const [firstGenerator, ...generatorsToRun] = generators;
|
193
193
|
// it must exists because the conflicts were identified from the initial results
|
194
|
+
// and it's guaranteed to be a success result
|
194
195
|
const firstGeneratorResult = initialResults.find((r) => r.generatorName === firstGenerator);
|
195
196
|
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, `running sync generators ${generators.join(',')}`);
|
196
197
|
// pre-apply the changes from the first generator to avoid running it
|
@@ -234,6 +235,9 @@ async function processConflictingGenerators(conflicts, initialResults) {
|
|
234
235
|
function _getConflictingGeneratorGroups(results) {
|
235
236
|
const changedFileToGeneratorMap = new Map();
|
236
237
|
for (const result of results) {
|
238
|
+
if ('error' in result) {
|
239
|
+
continue;
|
240
|
+
}
|
237
241
|
for (const change of result.changes) {
|
238
242
|
if (!changedFileToGeneratorMap.has(change.path)) {
|
239
243
|
changedFileToGeneratorMap.set(change.path, new Set());
|
@@ -318,7 +322,12 @@ function runGenerator(generator, projects, tree) {
|
|
318
322
|
scheduledGenerators.delete(generator);
|
319
323
|
tree ??= new tree_1.FsTree(workspace_root_1.workspaceRoot, false, `running sync generator ${generator}`);
|
320
324
|
return (0, sync_generators_1.runSyncGenerator)(tree, generator, projects).then((result) => {
|
321
|
-
|
325
|
+
if ('error' in result) {
|
326
|
+
log(generator, 'error:', result.error.message);
|
327
|
+
}
|
328
|
+
else {
|
329
|
+
log(generator, 'changes:', result.changes.map((c) => c.path).join(', '));
|
330
|
+
}
|
322
331
|
return result;
|
323
332
|
});
|
324
333
|
}
|
Binary file
|
@@ -11,6 +11,7 @@ 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");
|
@@ -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;
|
@@ -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 =
|
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
|
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
|
-
|
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
|
-
'
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
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' ||
|
@@ -9,17 +9,46 @@ export type SyncGeneratorResult = void | {
|
|
9
9
|
outOfSyncMessage?: string;
|
10
10
|
};
|
11
11
|
export type SyncGenerator = (tree: Tree) => SyncGeneratorResult | Promise<SyncGeneratorResult>;
|
12
|
-
export type
|
13
|
-
changes: FileChange[];
|
12
|
+
export type SyncGeneratorRunSuccessResult = {
|
14
13
|
generatorName: string;
|
14
|
+
changes: FileChange[];
|
15
15
|
callback?: GeneratorCallback;
|
16
16
|
outOfSyncMessage?: string;
|
17
17
|
};
|
18
|
-
|
19
|
-
|
18
|
+
type SerializableSimpleError = {
|
19
|
+
message: string;
|
20
|
+
stack: string | undefined;
|
21
|
+
};
|
22
|
+
export type SyncGeneratorRunErrorResult = {
|
23
|
+
generatorName: string;
|
24
|
+
error: SerializableSimpleError;
|
25
|
+
};
|
26
|
+
export type SyncGeneratorRunResult = SyncGeneratorRunSuccessResult | SyncGeneratorRunErrorResult;
|
27
|
+
type FlushSyncGeneratorChangesSuccess = {
|
28
|
+
success: true;
|
29
|
+
};
|
30
|
+
type FlushSyncGeneratorFailure = {
|
31
|
+
generator: string;
|
32
|
+
error: SerializableSimpleError;
|
33
|
+
};
|
34
|
+
type FlushSyncGeneratorChangesFailure = {
|
35
|
+
generatorFailures: FlushSyncGeneratorFailure[];
|
36
|
+
generalFailure?: SerializableSimpleError;
|
37
|
+
};
|
38
|
+
export type FlushSyncGeneratorChangesResult = FlushSyncGeneratorChangesSuccess | FlushSyncGeneratorChangesFailure;
|
39
|
+
export declare function getSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorRunResult[]>;
|
40
|
+
export declare function flushSyncGeneratorChanges(results: SyncGeneratorRunResult[]): Promise<FlushSyncGeneratorChangesResult>;
|
20
41
|
export declare function collectAllRegisteredSyncGenerators(projectGraph: ProjectGraph, nxJson: NxJsonConfiguration): Promise<string[]>;
|
21
|
-
export declare function runSyncGenerator(tree: Tree, generatorSpecifier: string, projects: Record<string, ProjectConfiguration>): Promise<
|
42
|
+
export declare function runSyncGenerator(tree: Tree, generatorSpecifier: string, projects: Record<string, ProjectConfiguration>): Promise<SyncGeneratorRunResult>;
|
22
43
|
export declare function collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph: ProjectGraph, nxJson: NxJsonConfiguration): Set<string>;
|
23
44
|
export declare function collectEnabledTaskSyncGeneratorsFromTaskGraph(taskGraph: TaskGraph, projectGraph: ProjectGraph, nxJson: NxJsonConfiguration): Set<string>;
|
24
45
|
export declare function collectRegisteredGlobalSyncGenerators(nxJson?: NxJsonConfiguration<string[] | "*">): Set<string>;
|
25
|
-
export declare function
|
46
|
+
export declare function getSyncGeneratorSuccessResultsMessageLines(results: SyncGeneratorRunResult[]): string[];
|
47
|
+
export declare function getFailedSyncGeneratorsFixMessageLines(results: SyncGeneratorRunResult[], verbose: boolean): string[];
|
48
|
+
export declare function getFlushFailureMessageLines(result: FlushSyncGeneratorChangesFailure, verbose: boolean): string[];
|
49
|
+
export declare function processSyncGeneratorResultErrors(results: SyncGeneratorRunResult[]): {
|
50
|
+
failedGeneratorsCount: number;
|
51
|
+
areAllResultsFailures: boolean;
|
52
|
+
anySyncGeneratorsFailed: boolean;
|
53
|
+
};
|
54
|
+
export {};
|
@@ -7,7 +7,10 @@ exports.runSyncGenerator = runSyncGenerator;
|
|
7
7
|
exports.collectEnabledTaskSyncGeneratorsFromProjectGraph = collectEnabledTaskSyncGeneratorsFromProjectGraph;
|
8
8
|
exports.collectEnabledTaskSyncGeneratorsFromTaskGraph = collectEnabledTaskSyncGeneratorsFromTaskGraph;
|
9
9
|
exports.collectRegisteredGlobalSyncGenerators = collectRegisteredGlobalSyncGenerators;
|
10
|
-
exports.
|
10
|
+
exports.getSyncGeneratorSuccessResultsMessageLines = getSyncGeneratorSuccessResultsMessageLines;
|
11
|
+
exports.getFailedSyncGeneratorsFixMessageLines = getFailedSyncGeneratorsFixMessageLines;
|
12
|
+
exports.getFlushFailureMessageLines = getFlushFailureMessageLines;
|
13
|
+
exports.processSyncGeneratorResultErrors = processSyncGeneratorResultErrors;
|
11
14
|
const perf_hooks_1 = require("perf_hooks");
|
12
15
|
const generate_1 = require("../command-line/generate/generate");
|
13
16
|
const generator_utils_1 = require("../command-line/generate/generator-utils");
|
@@ -30,15 +33,13 @@ async function getSyncGeneratorChanges(generators) {
|
|
30
33
|
}
|
31
34
|
perf_hooks_1.performance.mark('get-sync-generators-changes:end');
|
32
35
|
perf_hooks_1.performance.measure('get-sync-generators-changes', 'get-sync-generators-changes:start', 'get-sync-generators-changes:end');
|
33
|
-
return results.filter((r) => r.changes.length > 0);
|
36
|
+
return results.filter((r) => ('error' in r ? true : r.changes.length > 0));
|
34
37
|
}
|
35
38
|
async function flushSyncGeneratorChanges(results) {
|
36
39
|
if ((0, is_on_daemon_1.isOnDaemon)() || !client_1.daemonClient.enabled()) {
|
37
|
-
await flushSyncGeneratorChangesToDisk(results);
|
38
|
-
}
|
39
|
-
else {
|
40
|
-
await client_1.daemonClient.flushSyncGeneratorChangesToDisk(results.map((r) => r.generatorName));
|
40
|
+
return await flushSyncGeneratorChangesToDisk(results);
|
41
41
|
}
|
42
|
+
return await client_1.daemonClient.flushSyncGeneratorChangesToDisk(results.map((r) => r.generatorName));
|
42
43
|
}
|
43
44
|
async function collectAllRegisteredSyncGenerators(projectGraph, nxJson) {
|
44
45
|
if (!client_1.daemonClient.enabled()) {
|
@@ -50,25 +51,33 @@ async function collectAllRegisteredSyncGenerators(projectGraph, nxJson) {
|
|
50
51
|
return await client_1.daemonClient.getRegisteredSyncGenerators();
|
51
52
|
}
|
52
53
|
async function runSyncGenerator(tree, generatorSpecifier, projects) {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
54
|
+
try {
|
55
|
+
perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:start`);
|
56
|
+
const { collection, generator } = (0, generate_1.parseGeneratorString)(generatorSpecifier);
|
57
|
+
const { implementationFactory } = (0, generator_utils_1.getGeneratorInformation)(collection, generator, workspace_root_1.workspaceRoot, projects);
|
58
|
+
const implementation = implementationFactory();
|
59
|
+
const result = await implementation(tree);
|
60
|
+
let callback;
|
61
|
+
let outOfSyncMessage;
|
62
|
+
if (result && typeof result === 'object') {
|
63
|
+
callback = result.callback;
|
64
|
+
outOfSyncMessage = result.outOfSyncMessage;
|
65
|
+
}
|
66
|
+
perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:end`);
|
67
|
+
perf_hooks_1.performance.measure(`run-sync-generator:${generatorSpecifier}`, `run-sync-generator:${generatorSpecifier}:start`, `run-sync-generator:${generatorSpecifier}:end`);
|
68
|
+
return {
|
69
|
+
changes: tree.listChanges(),
|
70
|
+
generatorName: generatorSpecifier,
|
71
|
+
callback,
|
72
|
+
outOfSyncMessage,
|
73
|
+
};
|
74
|
+
}
|
75
|
+
catch (e) {
|
76
|
+
return {
|
77
|
+
generatorName: generatorSpecifier,
|
78
|
+
error: { message: e.message, stack: e.stack },
|
79
|
+
};
|
80
|
+
}
|
72
81
|
}
|
73
82
|
function collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph, nxJson) {
|
74
83
|
const taskSyncGenerators = new Set();
|
@@ -118,9 +127,12 @@ function collectRegisteredGlobalSyncGenerators(nxJson = (0, nx_json_1.readNxJson
|
|
118
127
|
}
|
119
128
|
return globalSyncGenerators;
|
120
129
|
}
|
121
|
-
function
|
130
|
+
function getSyncGeneratorSuccessResultsMessageLines(results) {
|
122
131
|
const messageLines = [];
|
123
132
|
for (const result of results) {
|
133
|
+
if ('error' in result) {
|
134
|
+
continue;
|
135
|
+
}
|
124
136
|
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 ? ':' : '.'}`);
|
125
137
|
if (result.outOfSyncMessage) {
|
126
138
|
messageLines.push(result.outOfSyncMessage);
|
@@ -128,6 +140,65 @@ function syncGeneratorResultsToMessageLines(results) {
|
|
128
140
|
}
|
129
141
|
return messageLines;
|
130
142
|
}
|
143
|
+
function getFailedSyncGeneratorsFixMessageLines(results, verbose) {
|
144
|
+
const messageLines = [];
|
145
|
+
const generators = [];
|
146
|
+
for (const result of results) {
|
147
|
+
if ('error' in result) {
|
148
|
+
messageLines.push(`The ${chalk.bold(result.generatorName)} sync generator reported the following error:
|
149
|
+
${chalk.bold(result.error.message)}${verbose && result.error.stack ? '\n' + result.error.stack : ''}`);
|
150
|
+
generators.push(result.generatorName);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
messageLines.push(...getFailedSyncGeneratorsMessageLines(generators, verbose));
|
154
|
+
return messageLines;
|
155
|
+
}
|
156
|
+
function getFlushFailureMessageLines(result, verbose) {
|
157
|
+
const messageLines = [];
|
158
|
+
const generators = [];
|
159
|
+
for (const failure of result.generatorFailures) {
|
160
|
+
messageLines.push(`The ${chalk.bold(failure.generator)} sync generator failed to apply its changes with the following error:
|
161
|
+
${chalk.bold(failure.error.message)}${verbose && failure.error.stack ? '\n' + failure.error.stack : ''}`);
|
162
|
+
generators.push(failure.generator);
|
163
|
+
}
|
164
|
+
messageLines.push(...getFailedSyncGeneratorsMessageLines(generators, verbose));
|
165
|
+
if (result.generalFailure) {
|
166
|
+
if (messageLines.length > 0) {
|
167
|
+
messageLines.push('');
|
168
|
+
messageLines.push('Additionally, an unexpected error occurred:');
|
169
|
+
}
|
170
|
+
else {
|
171
|
+
messageLines.push('An unexpected error occurred:');
|
172
|
+
}
|
173
|
+
messageLines.push(...[
|
174
|
+
'',
|
175
|
+
result.generalFailure.message,
|
176
|
+
...(verbose && !!result.generalFailure.stack
|
177
|
+
? [`\n${result.generalFailure.stack}`]
|
178
|
+
: []),
|
179
|
+
'',
|
180
|
+
verbose
|
181
|
+
? 'Please report the error at: https://github.com/nrwl/nx/issues/new/choose'
|
182
|
+
: 'Please run with `--verbose` and report the error at: https://github.com/nrwl/nx/issues/new/choose',
|
183
|
+
]);
|
184
|
+
}
|
185
|
+
return messageLines;
|
186
|
+
}
|
187
|
+
function processSyncGeneratorResultErrors(results) {
|
188
|
+
let failedGeneratorsCount = 0;
|
189
|
+
for (const result of results) {
|
190
|
+
if ('error' in result) {
|
191
|
+
failedGeneratorsCount++;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
const areAllResultsFailures = failedGeneratorsCount === results.length;
|
195
|
+
const anySyncGeneratorsFailed = failedGeneratorsCount > 0;
|
196
|
+
return {
|
197
|
+
failedGeneratorsCount,
|
198
|
+
areAllResultsFailures,
|
199
|
+
anySyncGeneratorsFailed,
|
200
|
+
};
|
201
|
+
}
|
131
202
|
async function runSyncGenerators(generators) {
|
132
203
|
const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, 'running sync generators');
|
133
204
|
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
|
@@ -141,32 +212,15 @@ async function runSyncGenerators(generators) {
|
|
141
212
|
}
|
142
213
|
async function flushSyncGeneratorChangesToDisk(results) {
|
143
214
|
perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:start');
|
144
|
-
const { changes, createdFiles, updatedFiles, deletedFiles, callbacks } = processSyncGeneratorResults(results);
|
145
|
-
// Write changes to disk
|
146
|
-
(0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, changes);
|
147
|
-
// Run the callbacks
|
148
|
-
if (callbacks.length) {
|
149
|
-
for (const callback of callbacks) {
|
150
|
-
await callback();
|
151
|
-
}
|
152
|
-
}
|
153
|
-
// Update the context files
|
154
|
-
await (0, workspace_context_1.updateContextWithChangedFiles)(workspace_root_1.workspaceRoot, createdFiles, updatedFiles, deletedFiles);
|
155
|
-
perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:end');
|
156
|
-
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');
|
157
|
-
}
|
158
|
-
function processSyncGeneratorResults(results) {
|
159
|
-
const changes = [];
|
160
215
|
const createdFiles = [];
|
161
216
|
const updatedFiles = [];
|
162
217
|
const deletedFiles = [];
|
163
|
-
const
|
218
|
+
const generatorFailures = [];
|
164
219
|
for (const result of results) {
|
165
|
-
if (result
|
166
|
-
|
220
|
+
if ('error' in result) {
|
221
|
+
continue;
|
167
222
|
}
|
168
223
|
for (const change of result.changes) {
|
169
|
-
changes.push(change);
|
170
224
|
if (change.type === 'CREATE') {
|
171
225
|
createdFiles.push(change.path);
|
172
226
|
}
|
@@ -177,6 +231,49 @@ function processSyncGeneratorResults(results) {
|
|
177
231
|
deletedFiles.push(change.path);
|
178
232
|
}
|
179
233
|
}
|
234
|
+
try {
|
235
|
+
// Write changes to disk
|
236
|
+
(0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, result.changes);
|
237
|
+
// Run the callback
|
238
|
+
if (result.callback) {
|
239
|
+
await result.callback();
|
240
|
+
}
|
241
|
+
}
|
242
|
+
catch (e) {
|
243
|
+
generatorFailures.push({
|
244
|
+
generator: result.generatorName,
|
245
|
+
error: { message: e.message, stack: e.stack },
|
246
|
+
});
|
247
|
+
}
|
248
|
+
}
|
249
|
+
try {
|
250
|
+
// Update the context files
|
251
|
+
await (0, workspace_context_1.updateContextWithChangedFiles)(workspace_root_1.workspaceRoot, createdFiles, updatedFiles, deletedFiles);
|
252
|
+
perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:end');
|
253
|
+
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');
|
254
|
+
}
|
255
|
+
catch (e) {
|
256
|
+
return {
|
257
|
+
generatorFailures,
|
258
|
+
generalFailure: { message: e.message, stack: e.stack },
|
259
|
+
};
|
180
260
|
}
|
181
|
-
return
|
261
|
+
return generatorFailures.length > 0
|
262
|
+
? { generatorFailures }
|
263
|
+
: { success: true };
|
264
|
+
}
|
265
|
+
function getFailedSyncGeneratorsMessageLines(generators, verbose) {
|
266
|
+
const messageLines = [];
|
267
|
+
if (generators.length === 1) {
|
268
|
+
messageLines.push('', verbose
|
269
|
+
? 'Please check the error above and address the issue.'
|
270
|
+
: 'Please check the error above and address the issue. You can provide the `--verbose` flag to get more details.', `If needed, you can disable the failing sync generator by setting \`sync.disabledTaskSyncGenerators: ["${generators[0]}"]\` in your \`nx.json\`.`);
|
271
|
+
}
|
272
|
+
else if (generators.length > 1) {
|
273
|
+
const generatorsString = generators.map((g) => `"${g}"`).join(', ');
|
274
|
+
messageLines.push('', verbose
|
275
|
+
? 'Please check the errors above and address the issues.'
|
276
|
+
: 'Please check the errors above and address the issues. You can provide the `--verbose` flag to get more details.', `If needed, you can disable the failing sync generators by setting \`sync.disabledTaskSyncGenerators: [${generatorsString}]\` in your \`nx.json\`.`);
|
277
|
+
}
|
278
|
+
return messageLines;
|
182
279
|
}
|