nx 19.7.0-canary.20240831-18e5535 → 19.7.0-canary.20240904-f39b995
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +12 -12
- package/release/changelog-renderer/index.d.ts +1 -1
- package/release/changelog-renderer/index.js +46 -11
- package/src/command-line/login/command-object.js +1 -1
- package/src/command-line/logout/command-object.js +1 -1
- package/src/command-line/release/changelog.js +41 -10
- package/src/command-line/release/config/version-plans.d.ts +14 -1
- package/src/command-line/release/config/version-plans.js +33 -1
- package/src/command-line/release/plan-check.js +1 -1
- package/src/command-line/release/release.js +1 -1
- package/src/command-line/release/utils/git.d.ts +1 -1
- package/src/command-line/release/utils/git.js +45 -18
- package/src/command-line/release/version.js +1 -1
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +42 -6
- package/src/project-graph/plugins/isolation/plugin-pool.js +1 -1
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "nx",
|
3
|
-
"version": "19.7.0-canary.
|
3
|
+
"version": "19.7.0-canary.20240904-f39b995",
|
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.7.0-canary.
|
74
|
+
"@nrwl/tao": "19.7.0-canary.20240904-f39b995"
|
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.7.0-canary.
|
90
|
-
"@nx/nx-darwin-arm64": "19.7.0-canary.
|
91
|
-
"@nx/nx-linux-x64-gnu": "19.7.0-canary.
|
92
|
-
"@nx/nx-linux-x64-musl": "19.7.0-canary.
|
93
|
-
"@nx/nx-win32-x64-msvc": "19.7.0-canary.
|
94
|
-
"@nx/nx-linux-arm64-gnu": "19.7.0-canary.
|
95
|
-
"@nx/nx-linux-arm64-musl": "19.7.0-canary.
|
96
|
-
"@nx/nx-linux-arm-gnueabihf": "19.7.0-canary.
|
97
|
-
"@nx/nx-win32-arm64-msvc": "19.7.0-canary.
|
98
|
-
"@nx/nx-freebsd-x64": "19.7.0-canary.
|
89
|
+
"@nx/nx-darwin-x64": "19.7.0-canary.20240904-f39b995",
|
90
|
+
"@nx/nx-darwin-arm64": "19.7.0-canary.20240904-f39b995",
|
91
|
+
"@nx/nx-linux-x64-gnu": "19.7.0-canary.20240904-f39b995",
|
92
|
+
"@nx/nx-linux-x64-musl": "19.7.0-canary.20240904-f39b995",
|
93
|
+
"@nx/nx-win32-x64-msvc": "19.7.0-canary.20240904-f39b995",
|
94
|
+
"@nx/nx-linux-arm64-gnu": "19.7.0-canary.20240904-f39b995",
|
95
|
+
"@nx/nx-linux-arm64-musl": "19.7.0-canary.20240904-f39b995",
|
96
|
+
"@nx/nx-linux-arm-gnueabihf": "19.7.0-canary.20240904-f39b995",
|
97
|
+
"@nx/nx-win32-arm64-msvc": "19.7.0-canary.20240904-f39b995",
|
98
|
+
"@nx/nx-freebsd-x64": "19.7.0-canary.20240904-f39b995"
|
99
99
|
},
|
100
100
|
"nx-migrations": {
|
101
101
|
"migrations": "./migrations.json",
|
@@ -41,7 +41,7 @@ export type ChangelogRenderer = (config: {
|
|
41
41
|
changelogRenderOptions: DefaultChangelogRenderOptions;
|
42
42
|
dependencyBumps?: DependencyBump[];
|
43
43
|
repoSlug?: RepoSlug;
|
44
|
-
conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'];
|
44
|
+
conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'] | null;
|
45
45
|
}) => Promise<string> | string;
|
46
46
|
/**
|
47
47
|
* The specific options available to the default implementation of the ChangelogRenderer that nx exports
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
const semver_1 = require("semver");
|
4
|
+
const conventional_commits_1 = require("../../src/command-line/release/config/conventional-commits");
|
4
5
|
const github_1 = require("../../src/command-line/release/utils/github");
|
5
6
|
// axios types and values don't seem to match
|
6
7
|
const _axios = require("axios");
|
@@ -10,9 +11,7 @@ const axios = _axios;
|
|
10
11
|
* from the given commits and other metadata.
|
11
12
|
*/
|
12
13
|
const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, dependencyBumps, repoSlug, conventionalCommitsConfig, }) => {
|
13
|
-
const changeTypes = conventionalCommitsConfig.types;
|
14
14
|
const markdownLines = [];
|
15
|
-
const breakingChanges = [];
|
16
15
|
// If the current range of changes contains both a commit and its revert, we strip them both from the final list. Changes from version plans are unaffected, as they have no hashes.
|
17
16
|
for (const change of changes) {
|
18
17
|
if (change.type === 'revert' && change.revertedHashes) {
|
@@ -26,10 +25,38 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
26
25
|
}
|
27
26
|
}
|
28
27
|
let relevantChanges = changes;
|
28
|
+
const breakingChanges = [];
|
29
|
+
// For now to keep the interface of the changelog renderer non-breaking for v19 releases we have a somewhat indirect check for whether or not we are generating a changelog for version plans
|
30
|
+
const isVersionPlans = !conventionalCommitsConfig;
|
31
|
+
// Only applicable for version plans
|
32
|
+
const additionalChangesForAuthorsSection = [];
|
33
|
+
// Provide a default configuration for version plans to allow most of the subsequent logic to work in the same way it would for conventional commits
|
34
|
+
// NOTE: The one exception is breaking/major changes, where we do not follow the same structure and instead only show the changes once
|
35
|
+
if (isVersionPlans) {
|
36
|
+
conventionalCommitsConfig = {
|
37
|
+
types: {
|
38
|
+
feat: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.feat,
|
39
|
+
fix: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.fix,
|
40
|
+
},
|
41
|
+
};
|
42
|
+
// Trim down "relevant changes" to only include non-breaking ones so that we can render them differently under version plans,
|
43
|
+
// but keep track of the changes for the purposes of the authors section
|
44
|
+
// TODO(v20): Clean this abstraction up as part of the larger overall refactor of changelog rendering
|
45
|
+
for (let i = 0; i < relevantChanges.length; i++) {
|
46
|
+
if (relevantChanges[i].isBreaking) {
|
47
|
+
const change = relevantChanges[i];
|
48
|
+
additionalChangesForAuthorsSection.push(change);
|
49
|
+
const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
|
50
|
+
breakingChanges.push(line);
|
51
|
+
relevantChanges.splice(i, 1);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
const changeTypes = conventionalCommitsConfig.types;
|
29
56
|
// workspace root level changelog
|
30
57
|
if (project === null) {
|
31
58
|
// No changes for the workspace
|
32
|
-
if (relevantChanges.length === 0) {
|
59
|
+
if (relevantChanges.length === 0 && breakingChanges.length === 0) {
|
33
60
|
if (dependencyBumps?.length) {
|
34
61
|
applyAdditionalDependencyBumps({
|
35
62
|
markdownLines,
|
@@ -62,7 +89,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
62
89
|
for (const scope of scopesSortedAlphabetically) {
|
63
90
|
const changes = changesGroupedByScope[scope];
|
64
91
|
for (const change of changes) {
|
65
|
-
const line = formatChange(change, changelogRenderOptions, repoSlug);
|
92
|
+
const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
|
66
93
|
markdownLines.push(line);
|
67
94
|
if (change.isBreaking) {
|
68
95
|
const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
|
@@ -79,7 +106,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
79
106
|
relevantChanges = relevantChanges.filter((c) => c.affectedProjects &&
|
80
107
|
(c.affectedProjects === '*' || c.affectedProjects.includes(project)));
|
81
108
|
// Generating for a named project, but that project has no relevant changes in the current set of commits, exit early
|
82
|
-
if (relevantChanges.length === 0) {
|
109
|
+
if (relevantChanges.length === 0 && breakingChanges.length === 0) {
|
83
110
|
if (dependencyBumps?.length) {
|
84
111
|
applyAdditionalDependencyBumps({
|
85
112
|
markdownLines,
|
@@ -105,7 +132,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
105
132
|
markdownLines.push('', `### ${changeTypes[type].changelog.title}`, '');
|
106
133
|
const changesInChronologicalOrder = group.reverse();
|
107
134
|
for (const change of changesInChronologicalOrder) {
|
108
|
-
const line = formatChange(change, changelogRenderOptions, repoSlug);
|
135
|
+
const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
|
109
136
|
markdownLines.push(line + '\n');
|
110
137
|
if (change.isBreaking) {
|
111
138
|
const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
|
@@ -117,7 +144,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
117
144
|
}
|
118
145
|
}
|
119
146
|
if (breakingChanges.length > 0) {
|
120
|
-
markdownLines.push('', '
|
147
|
+
markdownLines.push('', '### ⚠️ Breaking Changes', '', ...breakingChanges);
|
121
148
|
}
|
122
149
|
if (dependencyBumps?.length) {
|
123
150
|
applyAdditionalDependencyBumps({
|
@@ -129,7 +156,10 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
|
|
129
156
|
}
|
130
157
|
if (changelogRenderOptions.authors) {
|
131
158
|
const _authors = new Map();
|
132
|
-
for (const change of
|
159
|
+
for (const change of [
|
160
|
+
...relevantChanges,
|
161
|
+
...additionalChangesForAuthorsSection,
|
162
|
+
]) {
|
133
163
|
if (!change.author) {
|
134
164
|
continue;
|
135
165
|
}
|
@@ -215,7 +245,7 @@ function groupBy(items, key) {
|
|
215
245
|
}
|
216
246
|
return groups;
|
217
247
|
}
|
218
|
-
function formatChange(change, changelogRenderOptions, repoSlug) {
|
248
|
+
function formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug) {
|
219
249
|
let description = change.description;
|
220
250
|
let extraLines = [];
|
221
251
|
let extraLinesStr = '';
|
@@ -228,9 +258,14 @@ function formatChange(change, changelogRenderOptions, repoSlug) {
|
|
228
258
|
.map((l) => `${indentation}${l}`)
|
229
259
|
.join('\n');
|
230
260
|
}
|
261
|
+
/**
|
262
|
+
* In version plans changelogs:
|
263
|
+
* - don't repeat the breaking change icon
|
264
|
+
* - don't render the scope
|
265
|
+
*/
|
231
266
|
let changeLine = '- ' +
|
232
|
-
(change.isBreaking ? '⚠️ ' : '') +
|
233
|
-
(change.scope ? `**${change.scope.trim()}:** ` : '') +
|
267
|
+
(!isVersionPlans && change.isBreaking ? '⚠️ ' : '') +
|
268
|
+
(!isVersionPlans && change.scope ? `**${change.scope.trim()}:** ` : '') +
|
234
269
|
description;
|
235
270
|
if (repoSlug && changelogRenderOptions.commitReferences) {
|
236
271
|
changeLine += (0, github_1.formatReferences)(change.githubReferences, repoSlug);
|
@@ -4,7 +4,7 @@ exports.yargsLoginCommand = void 0;
|
|
4
4
|
const shared_options_1 = require("../../command-line/yargs-utils/shared-options");
|
5
5
|
exports.yargsLoginCommand = {
|
6
6
|
command: 'login [nxCloudUrl]',
|
7
|
-
describe:
|
7
|
+
describe: false,
|
8
8
|
builder: (yargs) => (0, shared_options_1.withVerbose)(yargs.positional('nxCloudUrl', {
|
9
9
|
describe: 'The Nx Cloud URL of the instance you are trying to connect to. If no positional argument is provided, this command will connect to https://cloud.nx.app.',
|
10
10
|
type: 'string',
|
@@ -4,7 +4,7 @@ exports.yargsLogoutCommand = void 0;
|
|
4
4
|
const shared_options_1 = require("../../command-line/yargs-utils/shared-options");
|
5
5
|
exports.yargsLogoutCommand = {
|
6
6
|
command: 'logout',
|
7
|
-
describe:
|
7
|
+
describe: false,
|
8
8
|
builder: (yargs) => (0, shared_options_1.withVerbose)(yargs),
|
9
9
|
handler: async (args) => {
|
10
10
|
process.exit(await (await Promise.resolve().then(() => require('./logout'))).logoutHandler(args));
|
@@ -81,7 +81,7 @@ function createAPI(overrideReleaseConfig) {
|
|
81
81
|
process.exit(1);
|
82
82
|
}
|
83
83
|
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
|
84
|
-
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
|
84
|
+
await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
|
85
85
|
if (args.deleteVersionPlans === undefined) {
|
86
86
|
// default to deleting version plans in this command instead of after versioning
|
87
87
|
args.deleteVersionPlans = true;
|
@@ -146,6 +146,15 @@ function createAPI(overrideReleaseConfig) {
|
|
146
146
|
workspaceChangelogChanges = versionPlans
|
147
147
|
.flatMap((vp) => {
|
148
148
|
const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
|
149
|
+
let githubReferences = [];
|
150
|
+
let author = undefined;
|
151
|
+
const parsedCommit = vp.commit
|
152
|
+
? (0, git_1.parseGitCommit)(vp.commit, true)
|
153
|
+
: null;
|
154
|
+
if (parsedCommit) {
|
155
|
+
githubReferences = parsedCommit.references;
|
156
|
+
author = parsedCommit.author;
|
157
|
+
}
|
149
158
|
const changes = !vp.triggeredByProjects
|
150
159
|
? {
|
151
160
|
type: releaseType.type,
|
@@ -153,7 +162,8 @@ function createAPI(overrideReleaseConfig) {
|
|
153
162
|
description: vp.message,
|
154
163
|
body: '',
|
155
164
|
isBreaking: releaseType.isBreaking,
|
156
|
-
githubReferences
|
165
|
+
githubReferences,
|
166
|
+
author,
|
157
167
|
affectedProjects: '*',
|
158
168
|
}
|
159
169
|
: vp.triggeredByProjects.map((project) => {
|
@@ -162,9 +172,9 @@ function createAPI(overrideReleaseConfig) {
|
|
162
172
|
scope: project,
|
163
173
|
description: vp.message,
|
164
174
|
body: '',
|
165
|
-
// TODO: what about github references?
|
166
175
|
isBreaking: releaseType.isBreaking,
|
167
|
-
githubReferences
|
176
|
+
githubReferences,
|
177
|
+
author,
|
168
178
|
affectedProjects: [project],
|
169
179
|
};
|
170
180
|
});
|
@@ -301,6 +311,15 @@ function createAPI(overrideReleaseConfig) {
|
|
301
311
|
return null;
|
302
312
|
}
|
303
313
|
const releaseType = versionPlanSemverReleaseTypeToChangelogType(bumpForProject);
|
314
|
+
let githubReferences = [];
|
315
|
+
let author = undefined;
|
316
|
+
const parsedCommit = vp.commit
|
317
|
+
? (0, git_1.parseGitCommit)(vp.commit, true)
|
318
|
+
: null;
|
319
|
+
if (parsedCommit) {
|
320
|
+
githubReferences = parsedCommit.references;
|
321
|
+
author = parsedCommit.author;
|
322
|
+
}
|
304
323
|
return {
|
305
324
|
type: releaseType.type,
|
306
325
|
scope: project.name,
|
@@ -308,8 +327,8 @@ function createAPI(overrideReleaseConfig) {
|
|
308
327
|
body: '',
|
309
328
|
isBreaking: releaseType.isBreaking,
|
310
329
|
affectedProjects: Object.keys(vp.projectVersionBumps),
|
311
|
-
|
312
|
-
|
330
|
+
githubReferences,
|
331
|
+
author,
|
313
332
|
};
|
314
333
|
})
|
315
334
|
.filter(Boolean);
|
@@ -397,6 +416,15 @@ function createAPI(overrideReleaseConfig) {
|
|
397
416
|
changes = releaseGroup.resolvedVersionPlans
|
398
417
|
.flatMap((vp) => {
|
399
418
|
const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
|
419
|
+
let githubReferences = [];
|
420
|
+
let author = undefined;
|
421
|
+
const parsedCommit = vp.commit
|
422
|
+
? (0, git_1.parseGitCommit)(vp.commit, true)
|
423
|
+
: null;
|
424
|
+
if (parsedCommit) {
|
425
|
+
githubReferences = parsedCommit.references;
|
426
|
+
author = parsedCommit.author;
|
427
|
+
}
|
400
428
|
const changes = !vp.triggeredByProjects
|
401
429
|
? {
|
402
430
|
type: releaseType.type,
|
@@ -404,7 +432,8 @@ function createAPI(overrideReleaseConfig) {
|
|
404
432
|
description: vp.message,
|
405
433
|
body: '',
|
406
434
|
isBreaking: releaseType.isBreaking,
|
407
|
-
githubReferences
|
435
|
+
githubReferences,
|
436
|
+
author,
|
408
437
|
affectedProjects: '*',
|
409
438
|
}
|
410
439
|
: vp.triggeredByProjects.map((project) => {
|
@@ -413,9 +442,9 @@ function createAPI(overrideReleaseConfig) {
|
|
413
442
|
scope: project,
|
414
443
|
description: vp.message,
|
415
444
|
body: '',
|
416
|
-
// TODO: what about github references?
|
417
445
|
isBreaking: releaseType.isBreaking,
|
418
|
-
githubReferences
|
446
|
+
githubReferences,
|
447
|
+
author,
|
419
448
|
affectedProjects: [project],
|
420
449
|
};
|
421
450
|
});
|
@@ -811,7 +840,9 @@ async function generateChangelogForProjects({ tree, args, projectGraph, changes,
|
|
811
840
|
})
|
812
841
|
: false,
|
813
842
|
changelogRenderOptions: config.renderOptions,
|
814
|
-
conventionalCommitsConfig:
|
843
|
+
conventionalCommitsConfig: releaseGroup.versionPlans
|
844
|
+
? null
|
845
|
+
: nxReleaseConfig.conventionalCommits,
|
815
846
|
dependencyBumps: projectToAdditionalDependencyBumps.get(project.name),
|
816
847
|
});
|
817
848
|
/**
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ReleaseType } from 'semver';
|
2
|
+
import { RawGitCommit } from '../utils/git';
|
2
3
|
import { ReleaseGroupWithName } from './filter-release-groups';
|
3
4
|
export interface VersionPlanFile {
|
4
5
|
absolutePath: string;
|
@@ -12,9 +13,21 @@ export interface RawVersionPlan extends VersionPlanFile {
|
|
12
13
|
}
|
13
14
|
export interface VersionPlan extends VersionPlanFile {
|
14
15
|
message: string;
|
16
|
+
/**
|
17
|
+
* The commit that added the version plan file, will be null if the file was never committed.
|
18
|
+
* For optimal performance, we don't apply it at the time of reading the raw contents, because
|
19
|
+
* it hasn't yet passed further validation at that point.
|
20
|
+
*/
|
21
|
+
commit: RawGitCommit | null;
|
15
22
|
}
|
16
23
|
export interface GroupVersionPlan extends VersionPlan {
|
17
24
|
groupVersionBump: ReleaseType;
|
25
|
+
/**
|
26
|
+
* The commit that added the version plan file, will be null if the file was never committed.
|
27
|
+
* For optimal performance, we don't apply it at the time of reading the raw contents, because.
|
28
|
+
* it hasn't yet passed validation.
|
29
|
+
*/
|
30
|
+
commit: RawGitCommit | null;
|
18
31
|
/**
|
19
32
|
* Will not be set if the group name was the trigger, otherwise will be a list of
|
20
33
|
* all the individual project names explicitly found in the version plan file.
|
@@ -25,5 +38,5 @@ export interface ProjectsVersionPlan extends VersionPlan {
|
|
25
38
|
projectVersionBumps: Record<string, ReleaseType>;
|
26
39
|
}
|
27
40
|
export declare function readRawVersionPlans(): Promise<RawVersionPlan[]>;
|
28
|
-
export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[]
|
41
|
+
export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[], isVerbose: boolean): Promise<ReleaseGroupWithName[]>;
|
29
42
|
export declare function getVersionPlansAbsolutePath(): string;
|
@@ -5,6 +5,7 @@ exports.setResolvedVersionPlansOnGroups = setResolvedVersionPlansOnGroups;
|
|
5
5
|
exports.getVersionPlansAbsolutePath = getVersionPlansAbsolutePath;
|
6
6
|
const fs_1 = require("fs");
|
7
7
|
const fs_extra_1 = require("fs-extra");
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
8
9
|
const path_1 = require("path");
|
9
10
|
const semver_1 = require("semver");
|
10
11
|
const workspace_root_1 = require("../../../utils/workspace-root");
|
@@ -35,7 +36,7 @@ async function readRawVersionPlans() {
|
|
35
36
|
}
|
36
37
|
return versionPlans;
|
37
38
|
}
|
38
|
-
function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
|
39
|
+
async function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace, isVerbose) {
|
39
40
|
const groupsByName = releaseGroups.reduce((acc, group) => acc.set(group.name, group), new Map());
|
40
41
|
const isDefaultGroup = isDefault(releaseGroups);
|
41
42
|
for (const rawVersionPlan of rawVersionPlans) {
|
@@ -88,6 +89,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
|
|
88
89
|
createdOnMs: rawVersionPlan.createdOnMs,
|
89
90
|
message: rawVersionPlan.message,
|
90
91
|
groupVersionBump: value,
|
92
|
+
commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
|
91
93
|
});
|
92
94
|
}
|
93
95
|
}
|
@@ -130,6 +132,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
|
|
130
132
|
projectVersionBumps: {
|
131
133
|
[key]: value,
|
132
134
|
},
|
135
|
+
commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
|
133
136
|
});
|
134
137
|
}
|
135
138
|
}
|
@@ -161,6 +164,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
|
|
161
164
|
// but we track the projects that triggered the version bump so that we can accurately produce changelog entries.
|
162
165
|
groupVersionBump: value,
|
163
166
|
triggeredByProjects: [key],
|
167
|
+
commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
|
164
168
|
});
|
165
169
|
}
|
166
170
|
}
|
@@ -185,3 +189,31 @@ function getVersionPlansAbsolutePath() {
|
|
185
189
|
function isReleaseType(value) {
|
186
190
|
return semver_1.RELEASE_TYPES.includes(value);
|
187
191
|
}
|
192
|
+
async function getCommitForVersionPlanFile(rawVersionPlan, isVerbose) {
|
193
|
+
return new Promise((resolve) => {
|
194
|
+
(0, node_child_process_1.exec)(`git log --diff-filter=A --pretty=format:"%s|%h|%an|%ae|%b" -n 1 -- ${rawVersionPlan.absolutePath}`, (error, stdout, stderr) => {
|
195
|
+
if (error) {
|
196
|
+
if (isVerbose) {
|
197
|
+
console.error(`Error executing git command for ${rawVersionPlan.relativePath}: ${error.message}`);
|
198
|
+
}
|
199
|
+
return resolve(null);
|
200
|
+
}
|
201
|
+
if (stderr) {
|
202
|
+
if (isVerbose) {
|
203
|
+
console.error(`Git command stderr for ${rawVersionPlan.relativePath}: ${stderr}`);
|
204
|
+
}
|
205
|
+
return resolve(null);
|
206
|
+
}
|
207
|
+
const [message, shortHash, authorName, authorEmail, ...body] = stdout
|
208
|
+
.trim()
|
209
|
+
.split('|');
|
210
|
+
const commitDetails = {
|
211
|
+
message: message || '',
|
212
|
+
shortHash: shortHash || '',
|
213
|
+
author: { name: authorName || '', email: authorEmail || '' },
|
214
|
+
body: body.join('|') || '', // Handle case where body might be empty or contain multiple '|'
|
215
|
+
};
|
216
|
+
return resolve(commitDetails);
|
217
|
+
});
|
218
|
+
});
|
219
|
+
}
|
@@ -53,7 +53,7 @@ function createAPI(overrideReleaseConfig) {
|
|
53
53
|
return 1;
|
54
54
|
}
|
55
55
|
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
|
56
|
-
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
|
56
|
+
await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
|
57
57
|
// Resolve the final values for base, head etc to use when resolving the changes to consider
|
58
58
|
const { nxArgs } = (0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', {
|
59
59
|
printWarnings: args.verbose,
|
@@ -94,7 +94,7 @@ function createAPI(overrideReleaseConfig) {
|
|
94
94
|
output_1.output.error(filterError);
|
95
95
|
process.exit(1);
|
96
96
|
}
|
97
|
-
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
|
97
|
+
await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
|
98
98
|
const planFiles = new Set();
|
99
99
|
releaseGroups.forEach((group) => {
|
100
100
|
if (group.resolvedVersionPlans) {
|
@@ -62,6 +62,6 @@ export declare function parseConventionalCommitsMessage(message: string): {
|
|
62
62
|
description: string;
|
63
63
|
breaking: boolean;
|
64
64
|
} | null;
|
65
|
-
export declare function parseGitCommit(commit: RawGitCommit): GitCommit | null;
|
65
|
+
export declare function parseGitCommit(commit: RawGitCommit, isVersionPlanCommit?: boolean): GitCommit | null;
|
66
66
|
export declare function getCommitHash(ref: string): Promise<string>;
|
67
67
|
export declare function getFirstGitCommit(): Promise<string>;
|
@@ -281,6 +281,30 @@ function parseConventionalCommitsMessage(message) {
|
|
281
281
|
breaking: Boolean(match.groups.breaking),
|
282
282
|
};
|
283
283
|
}
|
284
|
+
function extractReferencesFromCommitMessage(message, shortHash) {
|
285
|
+
const references = [];
|
286
|
+
for (const m of message.matchAll(PullRequestRE)) {
|
287
|
+
references.push({ type: 'pull-request', value: m[1] });
|
288
|
+
}
|
289
|
+
for (const m of message.matchAll(IssueRE)) {
|
290
|
+
if (!references.some((i) => i.value === m[1])) {
|
291
|
+
references.push({ type: 'issue', value: m[1] });
|
292
|
+
}
|
293
|
+
}
|
294
|
+
references.push({ value: shortHash, type: 'hash' });
|
295
|
+
return references;
|
296
|
+
}
|
297
|
+
function getAllAuthorsForCommit(commit) {
|
298
|
+
const authors = [commit.author];
|
299
|
+
// Additional authors can be specified in the commit body (depending on the VCS provider)
|
300
|
+
for (const match of commit.body.matchAll(CoAuthoredByRegex)) {
|
301
|
+
authors.push({
|
302
|
+
name: (match.groups.name || '').trim(),
|
303
|
+
email: (match.groups.email || '').trim(),
|
304
|
+
});
|
305
|
+
}
|
306
|
+
return authors;
|
307
|
+
}
|
284
308
|
// https://www.conventionalcommits.org/en/v1.0.0/
|
285
309
|
// https://regex101.com/r/FSfNvA/1
|
286
310
|
const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
|
@@ -289,7 +313,25 @@ const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
|
|
289
313
|
const IssueRE = /(#\d+)/gm;
|
290
314
|
const ChangedFileRegex = /(A|M|D|R\d*|C\d*)\t([^\t\n]*)\t?(.*)?/gm;
|
291
315
|
const RevertHashRE = /This reverts commit (?<hash>[\da-f]{40})./gm;
|
292
|
-
function parseGitCommit(commit) {
|
316
|
+
function parseGitCommit(commit, isVersionPlanCommit = false) {
|
317
|
+
// For version plans, we do not require conventional commits and therefore cannot extract data based on that format
|
318
|
+
if (isVersionPlanCommit) {
|
319
|
+
return {
|
320
|
+
...commit,
|
321
|
+
description: commit.message,
|
322
|
+
type: '',
|
323
|
+
scope: '',
|
324
|
+
references: extractReferencesFromCommitMessage(commit.message, commit.shortHash),
|
325
|
+
// The commit message is not the source of truth for a breaking (major) change in version plans, so the value is not relevant
|
326
|
+
// TODO(v20): Make the current GitCommit interface more clearly tied to conventional commits
|
327
|
+
isBreaking: false,
|
328
|
+
authors: getAllAuthorsForCommit(commit),
|
329
|
+
// Not applicable to version plans
|
330
|
+
affectedFiles: [],
|
331
|
+
// Not applicable, a version plan cannot have been added in a commit that also reverts another commit
|
332
|
+
revertedHashes: [],
|
333
|
+
};
|
334
|
+
}
|
293
335
|
const parsedMessage = parseConventionalCommitsMessage(commit.message);
|
294
336
|
if (!parsedMessage) {
|
295
337
|
return null;
|
@@ -298,16 +340,7 @@ function parseGitCommit(commit) {
|
|
298
340
|
const isBreaking = parsedMessage.breaking || commit.body.includes('BREAKING CHANGE:');
|
299
341
|
let description = parsedMessage.description;
|
300
342
|
// Extract references from message
|
301
|
-
const references =
|
302
|
-
for (const m of description.matchAll(PullRequestRE)) {
|
303
|
-
references.push({ type: 'pull-request', value: m[1] });
|
304
|
-
}
|
305
|
-
for (const m of description.matchAll(IssueRE)) {
|
306
|
-
if (!references.some((i) => i.value === m[1])) {
|
307
|
-
references.push({ type: 'issue', value: m[1] });
|
308
|
-
}
|
309
|
-
}
|
310
|
-
references.push({ value: commit.shortHash, type: 'hash' });
|
343
|
+
const references = extractReferencesFromCommitMessage(description, commit.shortHash);
|
311
344
|
// Remove references and normalize
|
312
345
|
description = description.replace(PullRequestRE, '').trim();
|
313
346
|
let type = parsedMessage.type;
|
@@ -322,13 +355,7 @@ function parseGitCommit(commit) {
|
|
322
355
|
description = commit.message;
|
323
356
|
}
|
324
357
|
// Find all authors
|
325
|
-
const authors =
|
326
|
-
for (const match of commit.body.matchAll(CoAuthoredByRegex)) {
|
327
|
-
authors.push({
|
328
|
-
name: (match.groups.name || '').trim(),
|
329
|
-
email: (match.groups.email || '').trim(),
|
330
|
-
});
|
331
|
-
}
|
358
|
+
const authors = getAllAuthorsForCommit(commit);
|
332
359
|
// Extract file changes from commit body
|
333
360
|
const affectedFiles = Array.from(commit.body.matchAll(ChangedFileRegex)).reduce((prev, [fullLine, changeType, file1, file2]) =>
|
334
361
|
// file2 only exists for some change types, such as renames
|
@@ -82,7 +82,7 @@ function createAPI(overrideReleaseConfig) {
|
|
82
82
|
}
|
83
83
|
if (!args.specifier) {
|
84
84
|
const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
|
85
|
-
(0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
|
85
|
+
await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
|
86
86
|
}
|
87
87
|
else {
|
88
88
|
if (args.verbose && releaseGroups.some((g) => !!g.versionPlans)) {
|
Binary file
|
@@ -42,6 +42,18 @@ function getNxInitDate() {
|
|
42
42
|
return null;
|
43
43
|
}
|
44
44
|
}
|
45
|
+
async function createNxCloudWorkspaceV1(workspaceName, installationSource, nxInitDate) {
|
46
|
+
const apiUrl = (0, get_cloud_options_1.getCloudUrl)();
|
47
|
+
const response = await require('axios').post(`${apiUrl}/nx-cloud/create-org-and-workspace`, {
|
48
|
+
workspaceName,
|
49
|
+
installationSource,
|
50
|
+
nxInitDate,
|
51
|
+
});
|
52
|
+
if (response.data.message) {
|
53
|
+
throw new Error(response.data.message);
|
54
|
+
}
|
55
|
+
return response.data;
|
56
|
+
}
|
45
57
|
async function createNxCloudWorkspaceV2(workspaceName, installationSource, nxInitDate) {
|
46
58
|
const apiUrl = (0, get_cloud_options_1.getCloudUrl)();
|
47
59
|
const response = await require('axios').post(`${apiUrl}/nx-cloud/v2/create-org-and-workspace`, {
|
@@ -69,6 +81,19 @@ async function printSuccessMessage(token, installationSource, usesGithub) {
|
|
69
81
|
});
|
70
82
|
return connectCloudUrl;
|
71
83
|
}
|
84
|
+
function addNxCloudOptionsToNxJson(tree, token, directory = '') {
|
85
|
+
const nxJsonPath = (0, path_1.join)(directory, 'nx.json');
|
86
|
+
if (tree.exists(nxJsonPath)) {
|
87
|
+
(0, json_1.updateJson)(tree, (0, path_1.join)(directory, 'nx.json'), (nxJson) => {
|
88
|
+
const overrideUrl = process.env.NX_CLOUD_API || process.env.NRWL_API;
|
89
|
+
if (overrideUrl) {
|
90
|
+
nxJson.nxCloudUrl = overrideUrl;
|
91
|
+
}
|
92
|
+
nxJson.nxCloudAccessToken = token;
|
93
|
+
return nxJson;
|
94
|
+
});
|
95
|
+
}
|
96
|
+
}
|
72
97
|
function addNxCloudIdToNxJson(tree, nxCloudId, directory = '') {
|
73
98
|
const nxJsonPath = (0, path_1.join)(directory, 'nx.json');
|
74
99
|
if (tree.exists(nxJsonPath)) {
|
@@ -89,6 +114,7 @@ async function connectToNxCloud(tree, schema, nxJson = (0, nx_json_1.readNxJson)
|
|
89
114
|
return null;
|
90
115
|
}
|
91
116
|
const isGitHubDetected = schema.github ?? (await (0, url_shorten_1.repoUsesGithub)(schema.github));
|
117
|
+
let responseFromCreateNxCloudWorkspaceV1;
|
92
118
|
let responseFromCreateNxCloudWorkspaceV2;
|
93
119
|
/**
|
94
120
|
* Do not create an Nx Cloud token if the user is using GitHub and
|
@@ -98,12 +124,22 @@ async function connectToNxCloud(tree, schema, nxJson = (0, nx_json_1.readNxJson)
|
|
98
124
|
isGitHubDetected &&
|
99
125
|
schema.installationSource === 'nx-connect')
|
100
126
|
return null;
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
127
|
+
if (process.env.NX_ENABLE_LOGIN === 'true') {
|
128
|
+
responseFromCreateNxCloudWorkspaceV2 = await createNxCloudWorkspaceV2(getRootPackageName(tree), schema.installationSource, getNxInitDate());
|
129
|
+
addNxCloudIdToNxJson(tree, responseFromCreateNxCloudWorkspaceV2?.nxCloudId, schema.directory);
|
130
|
+
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree, {
|
131
|
+
silent: schema.hideFormatLogs,
|
132
|
+
});
|
133
|
+
return responseFromCreateNxCloudWorkspaceV2.nxCloudId;
|
134
|
+
}
|
135
|
+
else {
|
136
|
+
responseFromCreateNxCloudWorkspaceV1 = await createNxCloudWorkspaceV1(getRootPackageName(tree), schema.installationSource, getNxInitDate());
|
137
|
+
addNxCloudOptionsToNxJson(tree, responseFromCreateNxCloudWorkspaceV1?.token, schema.directory);
|
138
|
+
await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree, {
|
139
|
+
silent: schema.hideFormatLogs,
|
140
|
+
});
|
141
|
+
return responseFromCreateNxCloudWorkspaceV1.token;
|
142
|
+
}
|
107
143
|
}
|
108
144
|
async function connectToNxCloudGenerator(tree, options) {
|
109
145
|
await connectToNxCloud(tree, options);
|
@@ -273,7 +273,7 @@ async function startPluginWorker() {
|
|
273
273
|
socket,
|
274
274
|
});
|
275
275
|
}
|
276
|
-
else if (attempts >
|
276
|
+
else if (attempts > 10000) {
|
277
277
|
// daemon fails to start, the process probably exited
|
278
278
|
// we print the logs and exit the client
|
279
279
|
reject('Failed to start plugin worker.');
|