nx 17.0.3 → 17.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/src/command-line/release/changelog.js +2 -1
- package/src/command-line/release/config/config.d.ts +1 -1
- package/src/command-line/release/config/config.js +35 -0
- package/src/command-line/release/config/filter-release-groups.d.ts +1 -2
- package/src/command-line/release/utils/exec-command.d.ts +1 -0
- package/src/command-line/release/utils/exec-command.js +29 -0
- package/src/command-line/release/utils/git.d.ts +5 -1
- package/src/command-line/release/utils/git.js +46 -33
- package/src/command-line/release/utils/resolve-nx-json-error-message.js +4 -1
- package/src/command-line/release/utils/resolve-semver-specifier.d.ts +3 -0
- package/src/command-line/release/utils/resolve-semver-specifier.js +71 -0
- package/src/command-line/release/utils/semver.d.ts +14 -0
- package/src/command-line/release/utils/semver.js +27 -1
- package/src/command-line/release/version.d.ts +5 -2
- package/src/command-line/release/version.js +9 -76
- package/src/devkit-internals.d.ts +1 -0
- package/src/devkit-internals.js +3 -1
- package/src/generators/testing-utils/create-tree-with-empty-workspace.js +0 -3
- package/src/project-graph/utils/normalize-project-nodes.js +1 -1
- package/src/project-graph/utils/project-configuration-utils.d.ts +11 -1
- package/src/project-graph/utils/project-configuration-utils.js +50 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.1.0-beta.2",
|
|
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": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"yargs": "^17.6.2",
|
|
68
68
|
"yargs-parser": "21.1.1",
|
|
69
69
|
"node-machine-id": "1.1.12",
|
|
70
|
-
"@nrwl/tao": "17.0.
|
|
70
|
+
"@nrwl/tao": "17.1.0-beta.2"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"@swc-node/register": "^1.6.7",
|
|
@@ -82,16 +82,16 @@
|
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
"optionalDependencies": {
|
|
85
|
-
"@nx/nx-darwin-x64": "17.0.
|
|
86
|
-
"@nx/nx-darwin-arm64": "17.0.
|
|
87
|
-
"@nx/nx-linux-x64-gnu": "17.0.
|
|
88
|
-
"@nx/nx-linux-x64-musl": "17.0.
|
|
89
|
-
"@nx/nx-win32-x64-msvc": "17.0.
|
|
90
|
-
"@nx/nx-linux-arm64-gnu": "17.0.
|
|
91
|
-
"@nx/nx-linux-arm64-musl": "17.0.
|
|
92
|
-
"@nx/nx-linux-arm-gnueabihf": "17.0.
|
|
93
|
-
"@nx/nx-win32-arm64-msvc": "17.0.
|
|
94
|
-
"@nx/nx-freebsd-x64": "17.0.
|
|
85
|
+
"@nx/nx-darwin-x64": "17.1.0-beta.2",
|
|
86
|
+
"@nx/nx-darwin-arm64": "17.1.0-beta.2",
|
|
87
|
+
"@nx/nx-linux-x64-gnu": "17.1.0-beta.2",
|
|
88
|
+
"@nx/nx-linux-x64-musl": "17.1.0-beta.2",
|
|
89
|
+
"@nx/nx-win32-x64-msvc": "17.1.0-beta.2",
|
|
90
|
+
"@nx/nx-linux-arm64-gnu": "17.1.0-beta.2",
|
|
91
|
+
"@nx/nx-linux-arm64-musl": "17.1.0-beta.2",
|
|
92
|
+
"@nx/nx-linux-arm-gnueabihf": "17.1.0-beta.2",
|
|
93
|
+
"@nx/nx-win32-arm64-msvc": "17.1.0-beta.2",
|
|
94
|
+
"@nx/nx-freebsd-x64": "17.1.0-beta.2"
|
|
95
95
|
},
|
|
96
96
|
"nx-migrations": {
|
|
97
97
|
"migrations": "./migrations.json",
|
|
@@ -62,7 +62,8 @@ async function changelogHandler(args) {
|
|
|
62
62
|
version: args.version,
|
|
63
63
|
releaseTagPattern: nxReleaseConfig.releaseTagPattern,
|
|
64
64
|
});
|
|
65
|
-
const from = args.from ||
|
|
65
|
+
const from = args.from ||
|
|
66
|
+
(await (0, git_1.getLatestGitTagForPattern)(nxReleaseConfig.releaseTagPattern))?.tag;
|
|
66
67
|
if (!from) {
|
|
67
68
|
output_1.output.error({
|
|
68
69
|
title: `Unable to determine the previous git tag, please provide an explicit git reference using --from`,
|
|
@@ -37,7 +37,7 @@ export type NxReleaseConfig = DeepRequired<NxJsonConfiguration['release'] & {
|
|
|
37
37
|
groups: DeepRequired<EnsureProjectsArray<NxJsonConfiguration['release']['groups']>>;
|
|
38
38
|
}>;
|
|
39
39
|
export interface CreateNxReleaseConfigError {
|
|
40
|
-
code: 'RELEASE_GROUP_MATCHES_NO_PROJECTS' | 'PROJECT_MATCHES_MULTIPLE_GROUPS' | 'PROJECTS_MISSING_TARGET';
|
|
40
|
+
code: 'RELEASE_GROUP_MATCHES_NO_PROJECTS' | 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE' | 'PROJECT_MATCHES_MULTIPLE_GROUPS' | 'PROJECTS_MISSING_TARGET';
|
|
41
41
|
data: Record<string, string | string[]>;
|
|
42
42
|
}
|
|
43
43
|
export declare function createNxReleaseConfig(projectGraph: ProjectGraph, userConfig?: NxJsonConfiguration['release'], requiredTargetName?: 'nx-release-publish'): Promise<{
|
|
@@ -113,6 +113,16 @@ requiredTargetName) {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
+
// If provided, ensure release tag pattern is valid
|
|
117
|
+
if (releaseGroup.releaseTagPattern) {
|
|
118
|
+
const error = ensureReleaseTagPatternIsValid(releaseGroup.releaseTagPattern, releaseGroupName);
|
|
119
|
+
if (error) {
|
|
120
|
+
return {
|
|
121
|
+
error,
|
|
122
|
+
nxReleaseConfig: null,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
116
126
|
for (const project of matchingProjects) {
|
|
117
127
|
if (alreadyMatchedProjects.has(project)) {
|
|
118
128
|
return {
|
|
@@ -194,12 +204,37 @@ async function handleNxReleaseConfigError(error) {
|
|
|
194
204
|
});
|
|
195
205
|
}
|
|
196
206
|
break;
|
|
207
|
+
case 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE':
|
|
208
|
+
{
|
|
209
|
+
const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
|
|
210
|
+
'release',
|
|
211
|
+
'groups',
|
|
212
|
+
error.data.releaseGroupName,
|
|
213
|
+
'releaseTagPattern',
|
|
214
|
+
]);
|
|
215
|
+
devkit_exports_1.output.error({
|
|
216
|
+
title: `Release group "${error.data.releaseGroupName}" has an invalid releaseTagPattern. Please ensure the pattern contains exactly one instance of the "{version}" placeholder`,
|
|
217
|
+
bodyLines: [nxJsonMessage],
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
197
221
|
default:
|
|
198
222
|
throw new Error(`Unhandled error code: ${error.code}`);
|
|
199
223
|
}
|
|
200
224
|
process.exit(1);
|
|
201
225
|
}
|
|
202
226
|
exports.handleNxReleaseConfigError = handleNxReleaseConfigError;
|
|
227
|
+
function ensureReleaseTagPatternIsValid(releaseTagPattern, releaseGroupName) {
|
|
228
|
+
// ensure that any provided releaseTagPattern contains exactly one instance of {version}
|
|
229
|
+
return releaseTagPattern.split('{version}').length === 2
|
|
230
|
+
? null
|
|
231
|
+
: {
|
|
232
|
+
code: 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE',
|
|
233
|
+
data: {
|
|
234
|
+
releaseGroupName,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
203
238
|
function ensureProjectsConfigIsArray(groups) {
|
|
204
239
|
const result = {};
|
|
205
240
|
for (const [groupName, groupConfig] of Object.entries(groups)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProjectGraph } from '../../../config/project-graph';
|
|
2
2
|
import { NxReleaseConfig } from './config';
|
|
3
|
-
type ReleaseGroupWithName = NxReleaseConfig['groups'][string] & {
|
|
3
|
+
export type ReleaseGroupWithName = NxReleaseConfig['groups'][string] & {
|
|
4
4
|
name: string;
|
|
5
5
|
};
|
|
6
6
|
export declare function filterReleaseGroups(projectGraph: ProjectGraph, nxReleaseConfig: NxReleaseConfig, projectsFilter?: string[], groupsFilter?: string[]): {
|
|
@@ -11,4 +11,3 @@ export declare function filterReleaseGroups(projectGraph: ProjectGraph, nxReleas
|
|
|
11
11
|
releaseGroups: ReleaseGroupWithName[];
|
|
12
12
|
releaseGroupToFilteredProjects: Map<ReleaseGroupWithName, Set<string>>;
|
|
13
13
|
};
|
|
14
|
-
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function execCommand(cmd: string, args: string[], options?: any): Promise<string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.execCommand = void 0;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
async function execCommand(cmd, args, options) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const child = (0, node_child_process_1.spawn)(cmd, args, {
|
|
8
|
+
...options,
|
|
9
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
10
|
+
encoding: 'utf-8',
|
|
11
|
+
});
|
|
12
|
+
let stdout = '';
|
|
13
|
+
child.stdout.on('data', (chunk) => {
|
|
14
|
+
stdout += chunk;
|
|
15
|
+
});
|
|
16
|
+
child.on('error', (error) => {
|
|
17
|
+
reject(error);
|
|
18
|
+
});
|
|
19
|
+
child.on('close', (code) => {
|
|
20
|
+
if (code !== 0) {
|
|
21
|
+
reject(new Error(`Command failed with exit code ${code}`));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve(stdout);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
exports.execCommand = execCommand;
|
|
@@ -19,8 +19,12 @@ export interface GitCommit extends RawGitCommit {
|
|
|
19
19
|
references: Reference[];
|
|
20
20
|
authors: GitCommitAuthor[];
|
|
21
21
|
isBreaking: boolean;
|
|
22
|
+
affectedFiles: string[];
|
|
22
23
|
}
|
|
23
|
-
export declare function
|
|
24
|
+
export declare function getLatestGitTagForPattern(releaseTagPattern: string, additionalInterpolationData?: {}): Promise<{
|
|
25
|
+
tag: string;
|
|
26
|
+
extractedVersion: string;
|
|
27
|
+
} | null>;
|
|
24
28
|
export declare function getGitDiff(from: string | undefined, to?: string): Promise<RawGitCommit[]>;
|
|
25
29
|
export declare function parseCommits(commits: RawGitCommit[]): GitCommit[];
|
|
26
30
|
export declare function parseGitCommit(commit: RawGitCommit): GitCommit | null;
|
|
@@ -1,21 +1,52 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseGitCommit = exports.parseCommits = exports.getGitDiff = exports.
|
|
3
|
+
exports.parseGitCommit = exports.parseCommits = exports.getGitDiff = exports.getLatestGitTagForPattern = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Special thanks to changelogen for the original inspiration for many of these utilities:
|
|
6
6
|
* https://github.com/unjs/changelogen
|
|
7
7
|
*/
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
.catch(() => []);
|
|
13
|
-
return r.at(-1);
|
|
8
|
+
const utils_1 = require("../../../tasks-runner/utils");
|
|
9
|
+
const exec_command_1 = require("./exec-command");
|
|
10
|
+
function escapeRegExp(string) {
|
|
11
|
+
return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
14
12
|
}
|
|
15
|
-
|
|
13
|
+
// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
|
14
|
+
const SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/g;
|
|
15
|
+
async function getLatestGitTagForPattern(releaseTagPattern, additionalInterpolationData = {}) {
|
|
16
|
+
try {
|
|
17
|
+
const tags = await (0, exec_command_1.execCommand)('git', ['tag', '--sort', '-v:refname']).then((r) => r
|
|
18
|
+
.trim()
|
|
19
|
+
.split('\n')
|
|
20
|
+
.map((t) => t.trim())
|
|
21
|
+
.filter(Boolean));
|
|
22
|
+
if (!tags.length) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const interpolatedTagPattern = (0, utils_1.interpolate)(releaseTagPattern, {
|
|
26
|
+
version: ' ',
|
|
27
|
+
...additionalInterpolationData,
|
|
28
|
+
});
|
|
29
|
+
const tagRegexp = `^${escapeRegExp(interpolatedTagPattern).replace(' ', '(.+)')}`;
|
|
30
|
+
const matchingSemverTags = tags.filter((tag) =>
|
|
31
|
+
// Do the match against SEMVER_REGEX to ensure that we skip tags that aren't valid semver versions
|
|
32
|
+
!!tag.match(tagRegexp) && tag.match(tagRegexp)[1]?.match(SEMVER_REGEX));
|
|
33
|
+
if (!matchingSemverTags.length) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const [latestMatchingTag, version] = matchingSemverTags[0].match(tagRegexp);
|
|
37
|
+
return {
|
|
38
|
+
tag: latestMatchingTag,
|
|
39
|
+
extractedVersion: version,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.getLatestGitTagForPattern = getLatestGitTagForPattern;
|
|
16
47
|
async function getGitDiff(from, to = 'HEAD') {
|
|
17
48
|
// https://git-scm.com/docs/pretty-formats
|
|
18
|
-
const r = await execCommand('git', [
|
|
49
|
+
const r = await (0, exec_command_1.execCommand)('git', [
|
|
19
50
|
'--no-pager',
|
|
20
51
|
'log',
|
|
21
52
|
`${from ? `${from}...` : ''}${to}`,
|
|
@@ -48,6 +79,7 @@ const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!
|
|
|
48
79
|
const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
|
|
49
80
|
const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
|
|
50
81
|
const IssueRE = /(#\d+)/gm;
|
|
82
|
+
const ChangedFileRegex = /(A|M|D|R\d*|C\d*)\t([^\t\n]*)\t?(.*)?/gm;
|
|
51
83
|
function parseGitCommit(commit) {
|
|
52
84
|
const match = commit.message.match(ConventionalCommitRegex);
|
|
53
85
|
if (!match) {
|
|
@@ -78,6 +110,10 @@ function parseGitCommit(commit) {
|
|
|
78
110
|
email: (match.groups.email || '').trim(),
|
|
79
111
|
});
|
|
80
112
|
}
|
|
113
|
+
// Extract file changes from commit body
|
|
114
|
+
const affectedFiles = Array.from(commit.body.matchAll(ChangedFileRegex)).reduce((prev, [fullLine, changeType, file1, file2]) =>
|
|
115
|
+
// file2 only exists for some change types, such as renames
|
|
116
|
+
file2 ? [...prev, file1, file2] : [...prev, file1], []);
|
|
81
117
|
return {
|
|
82
118
|
...commit,
|
|
83
119
|
authors,
|
|
@@ -86,30 +122,7 @@ function parseGitCommit(commit) {
|
|
|
86
122
|
scope,
|
|
87
123
|
references,
|
|
88
124
|
isBreaking,
|
|
125
|
+
affectedFiles,
|
|
89
126
|
};
|
|
90
127
|
}
|
|
91
128
|
exports.parseGitCommit = parseGitCommit;
|
|
92
|
-
async function execCommand(cmd, args, options) {
|
|
93
|
-
return new Promise((resolve, reject) => {
|
|
94
|
-
const child = (0, node_child_process_1.spawn)(cmd, args, {
|
|
95
|
-
...options,
|
|
96
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
97
|
-
encoding: 'utf-8',
|
|
98
|
-
});
|
|
99
|
-
let stdout = '';
|
|
100
|
-
child.stdout.on('data', (chunk) => {
|
|
101
|
-
stdout += chunk;
|
|
102
|
-
});
|
|
103
|
-
child.on('error', (error) => {
|
|
104
|
-
reject(error);
|
|
105
|
-
});
|
|
106
|
-
child.on('close', (code) => {
|
|
107
|
-
if (code !== 0) {
|
|
108
|
-
reject(new Error(`Command failed with exit code ${code}`));
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
resolve(stdout);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
}
|
|
@@ -8,7 +8,10 @@ async function resolveNxJsonConfigErrorMessage(propPath) {
|
|
|
8
8
|
const errorLines = await getJsonConfigLinesForErrorMessage((0, node_fs_1.readFileSync)((0, devkit_exports_1.joinPathFragments)(devkit_exports_1.workspaceRoot, 'nx.json'), 'utf-8'), propPath);
|
|
9
9
|
let nxJsonMessage = `The relevant config is defined here: ${(0, node_path_1.relative)(process.cwd(), (0, devkit_exports_1.joinPathFragments)(devkit_exports_1.workspaceRoot, 'nx.json'))}`;
|
|
10
10
|
if (errorLines) {
|
|
11
|
-
nxJsonMessage +=
|
|
11
|
+
nxJsonMessage +=
|
|
12
|
+
errorLines.startLine === errorLines.endLine
|
|
13
|
+
? `, line ${errorLines.startLine}`
|
|
14
|
+
: `, lines ${errorLines.startLine}-${errorLines.endLine}`;
|
|
12
15
|
}
|
|
13
16
|
return nxJsonMessage;
|
|
14
17
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ProjectGraph } from '../../../config/project-graph';
|
|
2
|
+
export declare function resolveSemverSpecifierFromConventionalCommits(from: string, projectGraph: ProjectGraph, projectNames: string[]): Promise<string | null>;
|
|
3
|
+
export declare function resolveSemverSpecifierFromPrompt(selectionMessage: string, customVersionMessage: string): Promise<string>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveSemverSpecifierFromPrompt = exports.resolveSemverSpecifierFromConventionalCommits = void 0;
|
|
4
|
+
const enquirer_1 = require("enquirer");
|
|
5
|
+
const semver_1 = require("semver");
|
|
6
|
+
const file_map_utils_1 = require("../../../project-graph/file-map-utils");
|
|
7
|
+
const git_1 = require("./git");
|
|
8
|
+
const semver_2 = require("./semver");
|
|
9
|
+
// TODO: Extract config to nx.json configuration when adding changelog customization
|
|
10
|
+
const CONVENTIONAL_COMMITS_CONFIG = {
|
|
11
|
+
types: {
|
|
12
|
+
feat: {
|
|
13
|
+
semver: 'minor',
|
|
14
|
+
},
|
|
15
|
+
fix: {
|
|
16
|
+
semver: 'patch',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
async function resolveSemverSpecifierFromConventionalCommits(from, projectGraph, projectNames) {
|
|
21
|
+
const commits = await (0, git_1.getGitDiff)(from);
|
|
22
|
+
const parsedCommits = (0, git_1.parseCommits)(commits);
|
|
23
|
+
const projectFileMap = await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph);
|
|
24
|
+
const filesInReleaseGroup = new Set(projectNames.reduce((files, p) => [...files, ...projectFileMap[p].map((f) => f.file)], []));
|
|
25
|
+
const relevantCommits = parsedCommits.filter((c) => c.affectedFiles.some((f) => filesInReleaseGroup.has(f)));
|
|
26
|
+
return (0, semver_2.determineSemverChange)(relevantCommits, CONVENTIONAL_COMMITS_CONFIG);
|
|
27
|
+
}
|
|
28
|
+
exports.resolveSemverSpecifierFromConventionalCommits = resolveSemverSpecifierFromConventionalCommits;
|
|
29
|
+
async function resolveSemverSpecifierFromPrompt(selectionMessage, customVersionMessage) {
|
|
30
|
+
try {
|
|
31
|
+
const reply = await (0, enquirer_1.prompt)([
|
|
32
|
+
{
|
|
33
|
+
name: 'specifier',
|
|
34
|
+
message: selectionMessage,
|
|
35
|
+
type: 'select',
|
|
36
|
+
choices: [
|
|
37
|
+
...semver_1.RELEASE_TYPES.map((t) => ({ name: t, message: t })),
|
|
38
|
+
{
|
|
39
|
+
name: 'custom',
|
|
40
|
+
message: 'Custom exact version',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
if (reply.specifier !== 'custom') {
|
|
46
|
+
return reply.specifier;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const reply = await (0, enquirer_1.prompt)([
|
|
50
|
+
{
|
|
51
|
+
name: 'specifier',
|
|
52
|
+
message: customVersionMessage,
|
|
53
|
+
type: 'input',
|
|
54
|
+
validate: (input) => {
|
|
55
|
+
if ((0, semver_1.valid)(input)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return 'Please enter a valid semver version';
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
return reply.specifier;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// TODO: log the error to the user?
|
|
67
|
+
// We need to catch the error from enquirer prompt, otherwise yargs will print its help
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.resolveSemverSpecifierFromPrompt = resolveSemverSpecifierFromPrompt;
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Special thanks to changelogen for the original inspiration for many of these utilities:
|
|
3
|
+
* https://github.com/unjs/changelogen
|
|
4
|
+
*/
|
|
1
5
|
import { ReleaseType } from 'semver';
|
|
6
|
+
import { GitCommit } from './git';
|
|
2
7
|
export declare function isRelativeVersionKeyword(val: string): val is ReleaseType;
|
|
8
|
+
export declare function isValidSemverSpecifier(specifier: string): boolean;
|
|
9
|
+
export interface ConventionalCommitsConfig {
|
|
10
|
+
types: {
|
|
11
|
+
[type: string]: {
|
|
12
|
+
semver: 'patch' | 'minor' | 'major';
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare function determineSemverChange(commits: GitCommit[], config: ConventionalCommitsConfig): 'patch' | 'minor' | 'major' | null;
|
|
3
17
|
export declare function deriveNewSemverVersion(currentSemverVersion: string, semverSpecifier: string, preid?: string): string;
|
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Special thanks to changelogen for the original inspiration for many of these utilities:
|
|
4
|
+
* https://github.com/unjs/changelogen
|
|
5
|
+
*/
|
|
2
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deriveNewSemverVersion = exports.isRelativeVersionKeyword = void 0;
|
|
7
|
+
exports.deriveNewSemverVersion = exports.determineSemverChange = exports.isValidSemverSpecifier = exports.isRelativeVersionKeyword = void 0;
|
|
4
8
|
const semver_1 = require("semver");
|
|
5
9
|
function isRelativeVersionKeyword(val) {
|
|
6
10
|
return semver_1.RELEASE_TYPES.includes(val);
|
|
7
11
|
}
|
|
8
12
|
exports.isRelativeVersionKeyword = isRelativeVersionKeyword;
|
|
13
|
+
function isValidSemverSpecifier(specifier) {
|
|
14
|
+
return (specifier && !!((0, semver_1.valid)(specifier) || isRelativeVersionKeyword(specifier)));
|
|
15
|
+
}
|
|
16
|
+
exports.isValidSemverSpecifier = isValidSemverSpecifier;
|
|
17
|
+
// https://github.com/unjs/changelogen/blob/main/src/semver.ts
|
|
18
|
+
function determineSemverChange(commits, config) {
|
|
19
|
+
let [hasMajor, hasMinor, hasPatch] = [false, false, false];
|
|
20
|
+
for (const commit of commits) {
|
|
21
|
+
const semverType = config.types[commit.type]?.semver;
|
|
22
|
+
if (semverType === 'major' || commit.isBreaking) {
|
|
23
|
+
hasMajor = true;
|
|
24
|
+
}
|
|
25
|
+
else if (semverType === 'minor') {
|
|
26
|
+
hasMinor = true;
|
|
27
|
+
}
|
|
28
|
+
else if (semverType === 'patch') {
|
|
29
|
+
hasPatch = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return hasMajor ? 'major' : hasMinor ? 'minor' : hasPatch ? 'patch' : null;
|
|
33
|
+
}
|
|
34
|
+
exports.determineSemverChange = determineSemverChange;
|
|
9
35
|
function deriveNewSemverVersion(currentSemverVersion, semverSpecifier, preid) {
|
|
10
36
|
if (!(0, semver_1.valid)(currentSemverVersion)) {
|
|
11
37
|
throw new Error(`Invalid semver version "${currentSemverVersion}" provided.`);
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { ProjectGraph, ProjectGraphProjectNode } from '../../config/project-graph';
|
|
2
2
|
import { VersionOptions } from './command-object';
|
|
3
|
+
import { ReleaseGroupWithName } from './config/filter-release-groups';
|
|
3
4
|
export { deriveNewSemverVersion } from './utils/semver';
|
|
4
5
|
export interface ReleaseVersionGeneratorSchema {
|
|
5
6
|
projects: ProjectGraphProjectNode[];
|
|
7
|
+
releaseGroup: ReleaseGroupWithName;
|
|
6
8
|
projectGraph: ProjectGraph;
|
|
7
|
-
specifier
|
|
9
|
+
specifier?: string;
|
|
10
|
+
specifierSource?: 'prompt' | 'conventional-commits';
|
|
8
11
|
preid?: string;
|
|
9
12
|
packageRoot?: string;
|
|
10
|
-
currentVersionResolver?: 'registry' | 'disk';
|
|
13
|
+
currentVersionResolver?: 'registry' | 'disk' | 'git-tag';
|
|
11
14
|
currentVersionResolverMetadata?: Record<string, unknown>;
|
|
12
15
|
}
|
|
13
16
|
export declare function versionHandler(args: VersionOptions): Promise<void>;
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.versionHandler = exports.deriveNewSemverVersion = void 0;
|
|
4
4
|
const chalk = require("chalk");
|
|
5
|
-
const enquirer = require("enquirer");
|
|
6
5
|
const node_fs_1 = require("node:fs");
|
|
7
6
|
const node_path_1 = require("node:path");
|
|
8
|
-
const semver_1 = require("semver");
|
|
9
7
|
const nx_json_1 = require("../../config/nx-json");
|
|
10
8
|
const devkit_exports_1 = require("../../devkit-exports");
|
|
11
9
|
const tree_1 = require("../../generators/tree");
|
|
@@ -16,10 +14,9 @@ const generator_utils_1 = require("../generate/generator-utils");
|
|
|
16
14
|
const config_1 = require("./config/config");
|
|
17
15
|
const filter_release_groups_1 = require("./config/filter-release-groups");
|
|
18
16
|
const print_changes_1 = require("./utils/print-changes");
|
|
19
|
-
const semver_2 = require("./utils/semver");
|
|
20
17
|
// Reexport for use in plugin release-version generator implementations
|
|
21
|
-
var
|
|
22
|
-
Object.defineProperty(exports, "deriveNewSemverVersion", { enumerable: true, get: function () { return
|
|
18
|
+
var semver_1 = require("./utils/semver");
|
|
19
|
+
Object.defineProperty(exports, "deriveNewSemverVersion", { enumerable: true, get: function () { return semver_1.deriveNewSemverVersion; } });
|
|
23
20
|
async function versionHandler(args) {
|
|
24
21
|
const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
|
|
25
22
|
const nxJson = (0, nx_json_1.readNxJson)();
|
|
@@ -48,8 +45,8 @@ async function versionHandler(args) {
|
|
|
48
45
|
...extractGeneratorCollectionAndName(`release-group "${releaseGroupName}"`, releaseGroup.version.generator),
|
|
49
46
|
configGeneratorOptions: releaseGroup.version.generatorOptions,
|
|
50
47
|
});
|
|
51
|
-
const
|
|
52
|
-
await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData,
|
|
48
|
+
const releaseGroupProjectNames = Array.from(releaseGroupToFilteredProjects.get(releaseGroup));
|
|
49
|
+
await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, releaseGroupProjectNames, releaseGroup);
|
|
53
50
|
}
|
|
54
51
|
printChanges(tree, !!args.dryRun);
|
|
55
52
|
return process.exit(0);
|
|
@@ -64,37 +61,19 @@ async function versionHandler(args) {
|
|
|
64
61
|
...extractGeneratorCollectionAndName(`release-group "${releaseGroupName}"`, releaseGroup.version.generator),
|
|
65
62
|
configGeneratorOptions: releaseGroup.version.generatorOptions,
|
|
66
63
|
});
|
|
67
|
-
|
|
68
|
-
? `What kind of change is this for all packages?`
|
|
69
|
-
: `What kind of change is this for release group "${releaseGroupName}"?`, releaseGroupName === config_1.CATCH_ALL_RELEASE_GROUP
|
|
70
|
-
? `What is the exact version for all packages?`
|
|
71
|
-
: `What is the exact version for release group "${releaseGroupName}"?`);
|
|
72
|
-
await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, releaseGroup.projects, semverSpecifier);
|
|
64
|
+
await runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, releaseGroup.projects, releaseGroup);
|
|
73
65
|
}
|
|
74
66
|
printChanges(tree, !!args.dryRun);
|
|
75
67
|
process.exit(0);
|
|
76
68
|
}
|
|
77
69
|
exports.versionHandler = versionHandler;
|
|
78
|
-
async function runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, projectNames,
|
|
79
|
-
// Should be impossible state
|
|
80
|
-
if (!newVersionSpecifier) {
|
|
81
|
-
devkit_exports_1.output.error({
|
|
82
|
-
title: `No version or semver keyword could be determined`,
|
|
83
|
-
});
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
// Specifier could be user provided so we need to validate it
|
|
87
|
-
if (!(0, semver_1.valid)(newVersionSpecifier) &&
|
|
88
|
-
!(0, semver_2.isRelativeVersionKeyword)(newVersionSpecifier)) {
|
|
89
|
-
devkit_exports_1.output.error({
|
|
90
|
-
title: `The given version specifier "${newVersionSpecifier}" is not valid. You provide an exact version or a valid semver keyword such as "major", "minor", "patch", etc.`,
|
|
91
|
-
});
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
70
|
+
async function runVersionOnProjects(projectGraph, nxJson, args, tree, generatorData, projectNames, releaseGroup) {
|
|
94
71
|
const generatorOptions = {
|
|
95
72
|
projects: projectNames.map((p) => projectGraph.nodes[p]),
|
|
96
73
|
projectGraph,
|
|
97
|
-
|
|
74
|
+
releaseGroup,
|
|
75
|
+
// Always ensure a string to avoid generator schema validation errors
|
|
76
|
+
specifier: args.specifier ?? '',
|
|
98
77
|
preid: args.preid,
|
|
99
78
|
...generatorData.configGeneratorOptions,
|
|
100
79
|
};
|
|
@@ -128,52 +107,6 @@ function printChanges(tree, isDryRun) {
|
|
|
128
107
|
devkit_exports_1.logger.warn(`\nNOTE: The "dryRun" flag means no changes were made.`);
|
|
129
108
|
}
|
|
130
109
|
}
|
|
131
|
-
async function resolveSemverSpecifier(cliArgSpecifier, selectionMessage, customVersionMessage) {
|
|
132
|
-
try {
|
|
133
|
-
let newVersionSpecifier = cliArgSpecifier;
|
|
134
|
-
// If the user didn't provide a new version specifier directly on the CLI, prompt for one
|
|
135
|
-
if (!newVersionSpecifier) {
|
|
136
|
-
const reply = await enquirer.prompt([
|
|
137
|
-
{
|
|
138
|
-
name: 'specifier',
|
|
139
|
-
message: selectionMessage,
|
|
140
|
-
type: 'select',
|
|
141
|
-
choices: [
|
|
142
|
-
...semver_1.RELEASE_TYPES.map((t) => ({ name: t, message: t })),
|
|
143
|
-
{
|
|
144
|
-
name: 'custom',
|
|
145
|
-
message: 'Custom exact version',
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
},
|
|
149
|
-
]);
|
|
150
|
-
if (reply.specifier !== 'custom') {
|
|
151
|
-
newVersionSpecifier = reply.specifier;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
const reply = await enquirer.prompt([
|
|
155
|
-
{
|
|
156
|
-
name: 'specifier',
|
|
157
|
-
message: customVersionMessage,
|
|
158
|
-
type: 'input',
|
|
159
|
-
validate: (input) => {
|
|
160
|
-
if ((0, semver_1.valid)(input)) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
return 'Please enter a valid semver version';
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
]);
|
|
167
|
-
newVersionSpecifier = reply.specifier;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return newVersionSpecifier;
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// We need to catch the error from enquirer prompt, otherwise yargs will print its help
|
|
174
|
-
process.exit(1);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
110
|
function extractGeneratorCollectionAndName(description, generatorString) {
|
|
178
111
|
let collectionName;
|
|
179
112
|
let generatorName;
|
|
@@ -14,4 +14,5 @@ export { sortObjectByKeys } from './utils/object-sort';
|
|
|
14
14
|
export { stripIndent } from './utils/logger';
|
|
15
15
|
export { readModulePackageJson } from './utils/package-json';
|
|
16
16
|
export { splitByColons } from './utils/split-target';
|
|
17
|
+
export { hashObject } from './hasher/file-hasher';
|
|
17
18
|
export { createProjectRootMappingsFromProjectConfigurations, findProjectForPath, } from './project-graph/utils/find-project-for-path';
|
package/src/devkit-internals.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
|
|
3
|
+
exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Note to developers: STOP! These exports are available via requireNx in @nx/devkit.
|
|
6
6
|
*
|
|
@@ -28,6 +28,8 @@ var package_json_1 = require("./utils/package-json");
|
|
|
28
28
|
Object.defineProperty(exports, "readModulePackageJson", { enumerable: true, get: function () { return package_json_1.readModulePackageJson; } });
|
|
29
29
|
var split_target_2 = require("./utils/split-target");
|
|
30
30
|
Object.defineProperty(exports, "splitByColons", { enumerable: true, get: function () { return split_target_2.splitByColons; } });
|
|
31
|
+
var file_hasher_1 = require("./hasher/file-hasher");
|
|
32
|
+
Object.defineProperty(exports, "hashObject", { enumerable: true, get: function () { return file_hasher_1.hashObject; } });
|
|
31
33
|
var find_project_for_path_1 = require("./project-graph/utils/find-project-for-path");
|
|
32
34
|
Object.defineProperty(exports, "createProjectRootMappingsFromProjectConfigurations", { enumerable: true, get: function () { return find_project_for_path_1.createProjectRootMappingsFromProjectConfigurations; } });
|
|
33
35
|
Object.defineProperty(exports, "findProjectForPath", { enumerable: true, get: function () { return find_project_for_path_1.findProjectForPath; } });
|
|
@@ -74,7 +74,7 @@ function normalizeProjectTargets(project, targetDefaults, projectName) {
|
|
|
74
74
|
const defaults = resolveCommandSyntacticSugar((0, project_configuration_utils_1.readTargetDefaultsForTarget)(target, targetDefaults, executor), `targetDefaults:${target}`);
|
|
75
75
|
targets[target] = resolveCommandSyntacticSugar(targets[target], `${projectName}:${target}`);
|
|
76
76
|
if (defaults) {
|
|
77
|
-
targets[target] = (0, project_configuration_utils_1.mergeTargetConfigurations)(
|
|
77
|
+
targets[target] = (0, project_configuration_utils_1.mergeTargetConfigurations)(targets[target], defaults);
|
|
78
78
|
}
|
|
79
79
|
targets[target].options = (0, project_configuration_utils_1.resolveNxTokensInOptions)(targets[target].options, project, `${projectName}:${target}`);
|
|
80
80
|
targets[target].configurations ??= {};
|
|
@@ -9,6 +9,16 @@ plugins: LoadedNxPlugin[], root?: string): {
|
|
|
9
9
|
externalNodes: Record<string, ProjectGraphExternalNode>;
|
|
10
10
|
};
|
|
11
11
|
export declare function readProjectConfigurationsFromRootMap(projectRootMap: Map<string, ProjectConfiguration>): Record<string, ProjectConfiguration>;
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Merges two configurations for a target.
|
|
14
|
+
*
|
|
15
|
+
* Most properties from `target` will overwrite any properties from `baseTarget`.
|
|
16
|
+
* Options and configurations are treated differently - they are merged together if the executor definition is compatible.
|
|
17
|
+
*
|
|
18
|
+
* @param target The configuration for the target with higher priority
|
|
19
|
+
* @param baseTarget The configuration for the target that should be overwritten.
|
|
20
|
+
* @returns A merged target configuration
|
|
21
|
+
*/
|
|
22
|
+
export declare function mergeTargetConfigurations(target: TargetConfiguration, baseTarget: TargetConfiguration): TargetConfiguration;
|
|
13
23
|
export declare function resolveNxTokensInOptions<T extends Object | Array<unknown>>(object: T, project: ProjectConfiguration, key: string): T;
|
|
14
24
|
export declare function readTargetDefaultsForTarget(targetName: string, targetDefaults: TargetDefaults, executor?: string): TargetDefaults[string];
|
|
@@ -21,16 +21,28 @@ function mergeProjectConfigurationIntoRootMap(projectRootMap, project) {
|
|
|
21
21
|
};
|
|
22
22
|
// The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies)
|
|
23
23
|
if (project.tags && matchingProject.tags) {
|
|
24
|
-
updatedProjectConfiguration.tags = matchingProject.tags.concat(project.tags);
|
|
24
|
+
updatedProjectConfiguration.tags = Array.from(new Set(matchingProject.tags.concat(project.tags)));
|
|
25
25
|
}
|
|
26
26
|
if (project.implicitDependencies && matchingProject.implicitDependencies) {
|
|
27
27
|
updatedProjectConfiguration.implicitDependencies =
|
|
28
28
|
matchingProject.implicitDependencies.concat(project.implicitDependencies);
|
|
29
29
|
}
|
|
30
30
|
if (project.generators && matchingProject.generators) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Start with generators config in new project.
|
|
32
|
+
updatedProjectConfiguration.generators = { ...project.generators };
|
|
33
|
+
// For each generator that was already defined, shallow merge the options.
|
|
34
|
+
// Project contains the new info, so it has higher priority.
|
|
35
|
+
for (const generator in matchingProject.generators) {
|
|
36
|
+
updatedProjectConfiguration.generators[generator] = {
|
|
37
|
+
...matchingProject.generators[generator],
|
|
38
|
+
...project.generators[generator],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (project.namedInputs && matchingProject.namedInputs) {
|
|
43
|
+
updatedProjectConfiguration.namedInputs = {
|
|
44
|
+
...matchingProject.namedInputs,
|
|
45
|
+
...project.namedInputs,
|
|
34
46
|
};
|
|
35
47
|
}
|
|
36
48
|
if (project.targets && matchingProject.targets) {
|
|
@@ -38,6 +50,14 @@ function mergeProjectConfigurationIntoRootMap(projectRootMap, project) {
|
|
|
38
50
|
...matchingProject.targets,
|
|
39
51
|
...project.targets,
|
|
40
52
|
};
|
|
53
|
+
for (const target in matchingProject.targets) {
|
|
54
|
+
if (target in matchingProject.targets && target in project.targets) {
|
|
55
|
+
// If the target is defined in both places, merge the options
|
|
56
|
+
// Project contains the new info, so it has higher priority.
|
|
57
|
+
// Options from matchingProject are used as defaults.
|
|
58
|
+
updatedProjectConfiguration.targets[target] = mergeTargetConfigurations(project.targets[target], matchingProject.targets[target]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
41
61
|
}
|
|
42
62
|
projectRootMap.set(updatedProjectConfiguration.root, updatedProjectConfiguration);
|
|
43
63
|
}
|
|
@@ -104,27 +124,41 @@ function readProjectConfigurationsFromRootMap(projectRootMap) {
|
|
|
104
124
|
return projects;
|
|
105
125
|
}
|
|
106
126
|
exports.readProjectConfigurationsFromRootMap = readProjectConfigurationsFromRootMap;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Merges two configurations for a target.
|
|
129
|
+
*
|
|
130
|
+
* Most properties from `target` will overwrite any properties from `baseTarget`.
|
|
131
|
+
* Options and configurations are treated differently - they are merged together if the executor definition is compatible.
|
|
132
|
+
*
|
|
133
|
+
* @param target The configuration for the target with higher priority
|
|
134
|
+
* @param baseTarget The configuration for the target that should be overwritten.
|
|
135
|
+
* @returns A merged target configuration
|
|
136
|
+
*/
|
|
137
|
+
function mergeTargetConfigurations(target, baseTarget) {
|
|
138
|
+
const { configurations: defaultConfigurations, options: defaultOptions, ...defaults } = baseTarget;
|
|
113
139
|
const result = {
|
|
114
140
|
...defaults,
|
|
115
|
-
...
|
|
141
|
+
...target,
|
|
116
142
|
};
|
|
117
143
|
// Target is "compatible", e.g. executor is defined only once or is the same
|
|
118
144
|
// in both places. This means that it is likely safe to merge options
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
result.options = { ...defaultOptions, ...targetConfiguration?.options };
|
|
123
|
-
result.configurations = mergeConfigurations(defaultConfigurations, targetConfiguration.configurations);
|
|
145
|
+
if (isCompatibleTarget(defaults, target)) {
|
|
146
|
+
result.options = { ...defaultOptions, ...target?.options };
|
|
147
|
+
result.configurations = mergeConfigurations(defaultConfigurations, target.configurations);
|
|
124
148
|
}
|
|
125
149
|
return result;
|
|
126
150
|
}
|
|
127
151
|
exports.mergeTargetConfigurations = mergeTargetConfigurations;
|
|
152
|
+
/**
|
|
153
|
+
* Checks if targets options are compatible - used when merging configurations
|
|
154
|
+
* to avoid merging options for @nx/js:tsc into something like @nx/webpack:webpack.
|
|
155
|
+
*
|
|
156
|
+
* If the executors are both specified and don't match, the options aren't considered
|
|
157
|
+
* "compatible" and shouldn't be merged.
|
|
158
|
+
*/
|
|
159
|
+
function isCompatibleTarget(a, b) {
|
|
160
|
+
return !a.executor || !b.executor || a.executor === b.executor;
|
|
161
|
+
}
|
|
128
162
|
function mergeConfigurations(defaultConfigurations, projectDefinedConfigurations) {
|
|
129
163
|
const result = {};
|
|
130
164
|
const configurations = new Set([
|