nx 17.0.1 → 17.0.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.
Files changed (31) hide show
  1. package/changelog-renderer/index.d.ts +43 -0
  2. package/changelog-renderer/index.js +180 -0
  3. package/package.json +12 -13
  4. package/schemas/nx-schema.json +141 -0
  5. package/src/adapter/ngcli-adapter.js +32 -0
  6. package/src/command-line/release/changelog.js +332 -75
  7. package/src/command-line/release/command-object.d.ts +1 -3
  8. package/src/command-line/release/command-object.js +3 -17
  9. package/src/command-line/release/config/config.d.ts +1 -1
  10. package/src/command-line/release/config/config.js +153 -50
  11. package/src/command-line/release/utils/markdown.d.ts +1 -4
  12. package/src/command-line/release/utils/markdown.js +3 -136
  13. package/src/command-line/release/utils/print-changes.d.ts +5 -1
  14. package/src/command-line/release/utils/print-changes.js +3 -2
  15. package/src/command-line/show/show.js +2 -0
  16. package/src/config/nx-json.d.ts +80 -3
  17. package/src/config/nx-json.js +1 -1
  18. package/src/config/project-graph.d.ts +1 -1
  19. package/src/daemon/client/client.js +0 -6
  20. package/src/daemon/server/outputs-tracking.d.ts +2 -2
  21. package/src/daemon/server/outputs-tracking.js +2 -2
  22. package/src/daemon/server/project-graph-incremental-recomputation.js +1 -28
  23. package/src/daemon/server/server.js +22 -58
  24. package/src/daemon/server/shutdown-utils.d.ts +0 -6
  25. package/src/daemon/server/shutdown-utils.js +1 -36
  26. package/src/daemon/server/watcher.d.ts +2 -6
  27. package/src/daemon/server/watcher.js +1 -92
  28. package/src/migrations/update-15-0-0/prefix-outputs.js +9 -9
  29. package/src/project-graph/project-graph.js +6 -1
  30. package/src/project-graph/utils/retrieve-workspace-files.js +1 -1
  31. package/src/tasks-runner/utils.js +8 -4
@@ -0,0 +1,43 @@
1
+ import type { GitCommit } from '../src/command-line/release/utils/git';
2
+ import { RepoSlug } from '../src/command-line/release/utils/github';
3
+ /**
4
+ * The ChangelogRenderOptions are specific to each ChangelogRenderer implementation, and are taken
5
+ * from the user's nx.json configuration and passed as is into the ChangelogRenderer function.
6
+ */
7
+ export type ChangelogRenderOptions = Record<string, unknown>;
8
+ /**
9
+ * A ChangelogRenderer function takes in the extracted commits and other relevant metadata
10
+ * and returns a string, or a Promise of a string of changelog contents (usually markdown).
11
+ *
12
+ * @param {Object} config The configuration object for the ChangelogRenderer
13
+ * @param {GitCommit[]} config.commits The collection of extracted commits to generate a changelog for
14
+ * @param {string} config.releaseVersion The version that is being released
15
+ * @param {string | null} config.project The name of specific project to generate a changelog for, or `null` if the overall workspace changelog
16
+ * @param {string | false} config.entryWhenNoChanges The (already interpolated) string to use as the changelog entry when there are no changes, or `false` if no entry should be generated
17
+ * @param {ChangelogRenderOptions} config.changelogRenderOptions The options specific to the ChangelogRenderer implementation
18
+ */
19
+ export type ChangelogRenderer = (config: {
20
+ commits: GitCommit[];
21
+ releaseVersion: string;
22
+ project: string | null;
23
+ entryWhenNoChanges: string | false;
24
+ changelogRenderOptions: DefaultChangelogRenderOptions;
25
+ repoSlug?: RepoSlug;
26
+ }) => Promise<string> | string;
27
+ /**
28
+ * The specific options available to the default implementation of the ChangelogRenderer that nx exports
29
+ * for the common case.
30
+ */
31
+ export interface DefaultChangelogRenderOptions extends ChangelogRenderOptions {
32
+ /**
33
+ * Whether or not the commit authors should be added to the bottom of the changelog in a "Thank You"
34
+ * section. Defaults to true.
35
+ */
36
+ includeAuthors?: boolean;
37
+ }
38
+ /**
39
+ * The default ChangelogRenderer implementation that nx exports for the common case of generating markdown
40
+ * from the given commits and other metadata.
41
+ */
42
+ declare const defaultChangelogRenderer: ChangelogRenderer;
43
+ export default defaultChangelogRenderer;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const github_1 = require("../src/command-line/release/utils/github");
4
+ // axios types and values don't seem to match
5
+ const _axios = require("axios");
6
+ const axios = _axios;
7
+ /**
8
+ * The default ChangelogRenderer implementation that nx exports for the common case of generating markdown
9
+ * from the given commits and other metadata.
10
+ */
11
+ const defaultChangelogRenderer = async ({ commits, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, repoSlug, }) => {
12
+ const markdownLines = [];
13
+ const breakingChanges = [];
14
+ const commitTypes = {
15
+ feat: { title: '🚀 Features' },
16
+ perf: { title: '🔥 Performance' },
17
+ fix: { title: '🩹 Fixes' },
18
+ refactor: { title: '💅 Refactors' },
19
+ docs: { title: '📖 Documentation' },
20
+ build: { title: '📦 Build' },
21
+ types: { title: '🌊 Types' },
22
+ chore: { title: '🏡 Chore' },
23
+ examples: { title: '🏀 Examples' },
24
+ test: { title: '✅ Tests' },
25
+ style: { title: '🎨 Styles' },
26
+ ci: { title: '🤖 CI' },
27
+ };
28
+ // workspace root level changelog
29
+ if (project === null) {
30
+ // No changes for the workspace
31
+ if (commits.length === 0) {
32
+ if (entryWhenNoChanges) {
33
+ markdownLines.push('', `## ${releaseVersion}\n\n${entryWhenNoChanges}`, '');
34
+ }
35
+ return markdownLines.join('\n').trim();
36
+ }
37
+ const typeGroups = groupBy(commits, 'type');
38
+ markdownLines.push('', `## ${releaseVersion}`, '');
39
+ for (const type of Object.keys(commitTypes)) {
40
+ const group = typeGroups[type];
41
+ if (!group || group.length === 0) {
42
+ continue;
43
+ }
44
+ markdownLines.push('', '### ' + commitTypes[type].title, '');
45
+ /**
46
+ * In order to make the final changelog most readable, we organize commits as follows:
47
+ * - By scope, where scopes are in alphabetical order (commits with no scope are listed first)
48
+ * - Within a particular scope grouping, we list commits in chronological order
49
+ */
50
+ const commitsInChronologicalOrder = group.reverse();
51
+ const commitsGroupedByScope = groupBy(commitsInChronologicalOrder, 'scope');
52
+ const scopesSortedAlphabetically = Object.keys(commitsGroupedByScope).sort();
53
+ for (const scope of scopesSortedAlphabetically) {
54
+ const commits = commitsGroupedByScope[scope];
55
+ for (const commit of commits) {
56
+ const line = formatCommit(commit, repoSlug);
57
+ markdownLines.push(line);
58
+ if (commit.isBreaking) {
59
+ breakingChanges.push(line);
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ else {
66
+ // project level changelog
67
+ const scopeGroups = groupBy(commits, 'scope');
68
+ // Generating for a named project, but that project has no changes in the current set of commits, exit early
69
+ if (!scopeGroups[project]) {
70
+ if (entryWhenNoChanges) {
71
+ markdownLines.push('', `## ${releaseVersion}\n\n${entryWhenNoChanges}`, '');
72
+ }
73
+ return markdownLines.join('\n').trim();
74
+ }
75
+ markdownLines.push('', `## ${releaseVersion}`, '');
76
+ const typeGroups = groupBy(scopeGroups[project], 'type');
77
+ for (const type of Object.keys(commitTypes)) {
78
+ const group = typeGroups[type];
79
+ if (!group || group.length === 0) {
80
+ continue;
81
+ }
82
+ markdownLines.push('', `### ${commitTypes[type].title}`, '');
83
+ const commitsInChronologicalOrder = group.reverse();
84
+ for (const commit of commitsInChronologicalOrder) {
85
+ const line = formatCommit(commit, repoSlug);
86
+ markdownLines.push(line + '\n');
87
+ if (commit.isBreaking) {
88
+ breakingChanges.push(line);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ if (breakingChanges.length > 0) {
94
+ markdownLines.push('', '#### ⚠️ Breaking Changes', '', ...breakingChanges);
95
+ }
96
+ if (changelogRenderOptions.includeAuthors) {
97
+ const _authors = new Map();
98
+ for (const commit of commits) {
99
+ if (!commit.author) {
100
+ continue;
101
+ }
102
+ const name = formatName(commit.author.name);
103
+ if (!name || name.includes('[bot]')) {
104
+ continue;
105
+ }
106
+ if (_authors.has(name)) {
107
+ const entry = _authors.get(name);
108
+ entry.email.add(commit.author.email);
109
+ }
110
+ else {
111
+ _authors.set(name, { email: new Set([commit.author.email]) });
112
+ }
113
+ }
114
+ // Try to map authors to github usernames
115
+ if (repoSlug) {
116
+ await Promise.all([..._authors.keys()].map(async (authorName) => {
117
+ const meta = _authors.get(authorName);
118
+ for (const email of meta.email) {
119
+ // For these pseudo-anonymized emails we can just extract the Github username from before the @
120
+ // It could either be in the format: username@ or github_id+username@
121
+ if (email.endsWith('@users.noreply.github.com')) {
122
+ const match = email.match(/^(\d+\+)?([^@]+)@users\.noreply\.github\.com$/);
123
+ if (match && match[2]) {
124
+ meta.github = match[2];
125
+ break;
126
+ }
127
+ }
128
+ // Look up any other emails against the ungh.cc API
129
+ const { data } = await axios
130
+ .get(`https://ungh.cc/users/find/${email}`)
131
+ .catch(() => ({ data: { user: null } }));
132
+ if (data?.user) {
133
+ meta.github = data.user.username;
134
+ break;
135
+ }
136
+ }
137
+ }));
138
+ }
139
+ const authors = [..._authors.entries()].map((e) => ({
140
+ name: e[0],
141
+ ...e[1],
142
+ }));
143
+ if (authors.length > 0) {
144
+ markdownLines.push('', '### ' + '❤️ Thank You', '', ...authors
145
+ // Sort the contributors by name
146
+ .sort((a, b) => a.name.localeCompare(b.name))
147
+ .map((i) => {
148
+ // Tag the author's Github username if we were able to resolve it so that Github adds them as a contributor
149
+ const github = i.github ? ` @${i.github}` : '';
150
+ return `- ${i.name}${github}`;
151
+ }));
152
+ }
153
+ }
154
+ return markdownLines.join('\n').trim();
155
+ };
156
+ exports.default = defaultChangelogRenderer;
157
+ function formatName(name = '') {
158
+ return name
159
+ .split(' ')
160
+ .map((p) => p.trim())
161
+ .join(' ');
162
+ }
163
+ function groupBy(items, key) {
164
+ const groups = {};
165
+ for (const item of items) {
166
+ groups[item[key]] = groups[item[key]] || [];
167
+ groups[item[key]].push(item);
168
+ }
169
+ return groups;
170
+ }
171
+ function formatCommit(commit, repoSlug) {
172
+ let commitLine = '- ' +
173
+ (commit.scope ? `**${commit.scope.trim()}:** ` : '') +
174
+ (commit.isBreaking ? '⚠️ ' : '') +
175
+ commit.description;
176
+ if (repoSlug) {
177
+ commitLine += (0, github_1.formatReferences)(commit.references, repoSlug);
178
+ }
179
+ return commitLine;
180
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "17.0.1",
3
+ "version": "17.0.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": {
@@ -33,7 +33,6 @@
33
33
  },
34
34
  "homepage": "https://nx.dev",
35
35
  "dependencies": {
36
- "@parcel/watcher": "2.0.4",
37
36
  "@yarnpkg/lockfile": "^1.1.0",
38
37
  "@yarnpkg/parsers": "3.0.0-rc.46",
39
38
  "@zkochan/js-yaml": "0.0.6",
@@ -68,7 +67,7 @@
68
67
  "yargs": "^17.6.2",
69
68
  "yargs-parser": "21.1.1",
70
69
  "node-machine-id": "1.1.12",
71
- "@nrwl/tao": "17.0.1"
70
+ "@nrwl/tao": "17.0.2"
72
71
  },
73
72
  "peerDependencies": {
74
73
  "@swc-node/register": "^1.6.7",
@@ -83,16 +82,16 @@
83
82
  }
84
83
  },
85
84
  "optionalDependencies": {
86
- "@nx/nx-darwin-x64": "17.0.1",
87
- "@nx/nx-darwin-arm64": "17.0.1",
88
- "@nx/nx-linux-x64-gnu": "17.0.1",
89
- "@nx/nx-linux-x64-musl": "17.0.1",
90
- "@nx/nx-win32-x64-msvc": "17.0.1",
91
- "@nx/nx-linux-arm64-gnu": "17.0.1",
92
- "@nx/nx-linux-arm64-musl": "17.0.1",
93
- "@nx/nx-linux-arm-gnueabihf": "17.0.1",
94
- "@nx/nx-win32-arm64-msvc": "17.0.1",
95
- "@nx/nx-freebsd-x64": "17.0.1"
85
+ "@nx/nx-darwin-x64": "17.0.2",
86
+ "@nx/nx-darwin-arm64": "17.0.2",
87
+ "@nx/nx-linux-x64-gnu": "17.0.2",
88
+ "@nx/nx-linux-x64-musl": "17.0.2",
89
+ "@nx/nx-win32-x64-msvc": "17.0.2",
90
+ "@nx/nx-linux-arm64-gnu": "17.0.2",
91
+ "@nx/nx-linux-arm64-musl": "17.0.2",
92
+ "@nx/nx-linux-arm-gnueabihf": "17.0.2",
93
+ "@nx/nx-win32-arm64-msvc": "17.0.2",
94
+ "@nx/nx-freebsd-x64": "17.0.2"
96
95
  },
97
96
  "nx-migrations": {
98
97
  "migrations": "./migrations.json",
@@ -95,6 +95,86 @@
95
95
  "useDaemonProcess": {
96
96
  "type": "boolean",
97
97
  "description": "Specifies whether the daemon should be used for the default tasks runner."
98
+ },
99
+ "release": {
100
+ "type": "object",
101
+ "description": "Configuration for the nx release commands.",
102
+ "additionalProperties": false,
103
+ "properties": {
104
+ "groups": {
105
+ "type": "object",
106
+ "additionalProperties": {
107
+ "type": "object",
108
+ "properties": {
109
+ "projects": {
110
+ "oneOf": [
111
+ {
112
+ "type": "array",
113
+ "items": {
114
+ "type": "string"
115
+ },
116
+ "minItems": 1
117
+ },
118
+ {
119
+ "type": "string"
120
+ }
121
+ ]
122
+ },
123
+ "version": {
124
+ "$ref": "#/definitions/NxReleaseVersionConfiguration"
125
+ },
126
+ "changelog": {
127
+ "oneOf": [
128
+ {
129
+ "$ref": "#/definitions/NxReleaseChangelogConfiguration"
130
+ },
131
+ {
132
+ "type": "boolean",
133
+ "enum": [false]
134
+ }
135
+ ]
136
+ },
137
+ "releaseTagPattern": {
138
+ "type": "string"
139
+ }
140
+ },
141
+ "required": ["projects"]
142
+ }
143
+ },
144
+ "changelog": {
145
+ "type": "object",
146
+ "properties": {
147
+ "workspaceChangelog": {
148
+ "oneOf": [
149
+ {
150
+ "$ref": "#/definitions/NxReleaseChangelogConfiguration"
151
+ },
152
+ {
153
+ "type": "boolean",
154
+ "enum": [false]
155
+ }
156
+ ]
157
+ },
158
+ "projectChangelogs": {
159
+ "oneOf": [
160
+ {
161
+ "$ref": "#/definitions/NxReleaseChangelogConfiguration"
162
+ },
163
+ {
164
+ "type": "boolean",
165
+ "enum": [false]
166
+ }
167
+ ]
168
+ }
169
+ }
170
+ },
171
+ "version": {
172
+ "$ref": "#/definitions/NxReleaseVersionConfiguration"
173
+ },
174
+ "releaseTagPattern": {
175
+ "type": "string"
176
+ }
177
+ }
98
178
  }
99
179
  },
100
180
  "definitions": {
@@ -389,6 +469,67 @@
389
469
  }
390
470
  }
391
471
  ]
472
+ },
473
+ "NxReleaseVersionConfiguration": {
474
+ "type": "object",
475
+ "properties": {
476
+ "generator": {
477
+ "type": "string"
478
+ },
479
+ "generatorOptions": {
480
+ "type": "object",
481
+ "additionalProperties": true
482
+ }
483
+ }
484
+ },
485
+ "NxReleaseChangelogConfiguration": {
486
+ "type": "object",
487
+ "properties": {
488
+ "createRelease": {
489
+ "oneOf": [
490
+ {
491
+ "type": "string",
492
+ "enum": ["github"]
493
+ },
494
+ {
495
+ "type": "boolean",
496
+ "enum": [false]
497
+ }
498
+ ]
499
+ },
500
+ "entryWhenNoChanges": {
501
+ "oneOf": [
502
+ {
503
+ "type": "string"
504
+ },
505
+ {
506
+ "type": "boolean",
507
+ "enum": [false]
508
+ }
509
+ ]
510
+ },
511
+ "file": {
512
+ "oneOf": [
513
+ {
514
+ "type": "string"
515
+ },
516
+ {
517
+ "type": "boolean",
518
+ "enum": [false]
519
+ }
520
+ ]
521
+ },
522
+ "renderer": {
523
+ "type": "string"
524
+ },
525
+ "renderOptions": {
526
+ "$ref": "#/definitions/ChangelogRenderOptions"
527
+ }
528
+ }
529
+ },
530
+ "ChangelogRenderOptions": {
531
+ "type": "object",
532
+ "additionalProperties": true
392
533
  }
393
534
  }
394
535
  }
@@ -105,6 +105,37 @@ async function scheduleTarget(root, opts, verbose) {
105
105
  }));
106
106
  }
107
107
  exports.scheduleTarget = scheduleTarget;
108
+ function createNodeModulesEngineHost(resolvePaths) {
109
+ const NodeModulesEngineHost = require('@angular-devkit/schematics/tools')
110
+ .NodeModulesEngineHost;
111
+ class NxNodeModulesEngineHost extends NodeModulesEngineHost {
112
+ constructor() {
113
+ super(resolvePaths);
114
+ }
115
+ _resolveCollectionPath(name, requester) {
116
+ let collectionFilePath;
117
+ const paths = requester
118
+ ? [(0, path_1.dirname)(requester), ...(resolvePaths || [])]
119
+ : resolvePaths || [];
120
+ if (name.endsWith('.json')) {
121
+ collectionFilePath = require.resolve(name, { paths });
122
+ }
123
+ else {
124
+ const { json: { generators, schematics }, path: packageJsonPath, } = (0, nx_plugin_1.readPluginPackageJson)(name, paths);
125
+ if (!schematics && !generators) {
126
+ throw new Error(`The "${name}" package does not support Nx generators or Angular Devkit schematics.`);
127
+ }
128
+ collectionFilePath = require.resolve((0, path_1.join)((0, path_1.dirname)(packageJsonPath), schematics ?? generators));
129
+ }
130
+ return collectionFilePath;
131
+ }
132
+ _transformCollectionDescription(name, desc) {
133
+ desc.schematics ??= desc.generators;
134
+ return super._transformCollectionDescription(name, desc);
135
+ }
136
+ }
137
+ return new NxNodeModulesEngineHost();
138
+ }
108
139
  function createWorkflow(fsHost, root, opts) {
109
140
  const NodeWorkflow = require('@angular-devkit/schematics/tools').NodeWorkflow;
110
141
  const workflow = new NodeWorkflow(fsHost, {
@@ -114,6 +145,7 @@ function createWorkflow(fsHost, root, opts) {
114
145
  root: (0, core_1.normalize)(root),
115
146
  registry: new core_1.schema.CoreSchemaRegistry(require('@angular-devkit/schematics').formats.standardFormats),
116
147
  resolvePaths: [process.cwd(), root],
148
+ engineHostCreator: (options) => createNodeModulesEngineHost(options.resolvePaths),
117
149
  });
118
150
  workflow.registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults);
119
151
  workflow.engineHost.registerOptionsTransform(require('@angular-devkit/schematics/tools').validateOptionsWithSchema(workflow.registry));