nx 19.6.4 → 19.6.6

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 (43) hide show
  1. package/package.json +12 -12
  2. package/release/changelog-renderer/index.d.ts +1 -1
  3. package/release/changelog-renderer/index.js +46 -11
  4. package/schemas/nx-schema.json +5 -0
  5. package/src/command-line/import/command-object.js +4 -0
  6. package/src/command-line/import/import.d.ts +4 -0
  7. package/src/command-line/import/import.js +147 -12
  8. package/src/command-line/import/utils/prepare-source-repo.d.ts +1 -1
  9. package/src/command-line/import/utils/prepare-source-repo.js +31 -85
  10. package/src/command-line/release/changelog.js +53 -12
  11. package/src/command-line/release/command-object.d.ts +1 -0
  12. package/src/command-line/release/command-object.js +6 -1
  13. package/src/command-line/release/config/version-plans.d.ts +14 -1
  14. package/src/command-line/release/config/version-plans.js +33 -1
  15. package/src/command-line/release/plan-check.js +8 -61
  16. package/src/command-line/release/plan.js +131 -37
  17. package/src/command-line/release/release.js +1 -1
  18. package/src/command-line/release/utils/get-touched-projects-for-group.d.ts +7 -0
  19. package/src/command-line/release/utils/get-touched-projects-for-group.js +78 -0
  20. package/src/command-line/release/utils/git.d.ts +1 -1
  21. package/src/command-line/release/utils/git.js +46 -19
  22. package/src/command-line/release/version.js +1 -1
  23. package/src/command-line/yargs-utils/shared-options.d.ts +2 -1
  24. package/src/command-line/yargs-utils/shared-options.js +5 -0
  25. package/src/core/graph/main.js +1 -1
  26. package/src/daemon/server/sync-generators.d.ts +4 -0
  27. package/src/daemon/server/sync-generators.js +172 -52
  28. package/src/migrations/update-15-0-0/prefix-outputs.js +3 -18
  29. package/src/native/index.d.ts +4 -0
  30. package/src/native/native-bindings.js +2 -0
  31. package/src/native/nx.wasi-browser.js +42 -36
  32. package/src/native/nx.wasi.cjs +40 -36
  33. package/src/native/nx.wasm32-wasi.wasm +0 -0
  34. package/src/project-graph/plugins/isolation/plugin-pool.js +1 -1
  35. package/src/tasks-runner/run-command.js +4 -1
  36. package/src/tasks-runner/utils.d.ts +1 -8
  37. package/src/tasks-runner/utils.js +9 -12
  38. package/src/utils/command-line-utils.d.ts +1 -0
  39. package/src/utils/git-utils.d.ts +7 -10
  40. package/src/utils/git-utils.js +61 -44
  41. package/src/utils/sync-generators.d.ts +2 -2
  42. package/src/utils/squash.d.ts +0 -1
  43. package/src/utils/squash.js +0 -12
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createGetTouchedProjectsForGroup = createGetTouchedProjectsForGroup;
4
+ const workspace_projects_1 = require("../../../project-graph/affected/locators/workspace-projects");
5
+ const file_utils_1 = require("../../../project-graph/file-utils");
6
+ const ignore_1 = require("../../../utils/ignore");
7
+ const output_1 = require("../../../utils/output");
8
+ const config_1 = require("../config/config");
9
+ /**
10
+ * Create a function that returns the touched projects for a given release group. Only relevant when version plans are enabled.
11
+ */
12
+ function createGetTouchedProjectsForGroup(nxArgs, projectGraph, changedFiles, fileData) {
13
+ /**
14
+ * Create a minimal subset of touched projects based on the configured ignore patterns, we only need
15
+ * to recompute when the ignorePatternsForPlanCheck differs between release groups.
16
+ */
17
+ const serializedIgnorePatternsToTouchedProjects = new Map();
18
+ return async function getTouchedProjectsForGroup(releaseGroup,
19
+ // We don't access releaseGroups.projects directly, because we need to take the --projects filter into account
20
+ releaseGroupFilteredProjectNames, hasProjectsFilter) {
21
+ // The current release group doesn't leverage version plans
22
+ if (!releaseGroup.versionPlans) {
23
+ return [];
24
+ }
25
+ // Exclude patterns from .nxignore, .gitignore and explicit version plan config
26
+ let serializedIgnorePatterns = '[]';
27
+ const ignore = (0, ignore_1.getIgnoreObject)();
28
+ if (typeof releaseGroup.versionPlans !== 'boolean' &&
29
+ Array.isArray(releaseGroup.versionPlans.ignorePatternsForPlanCheck) &&
30
+ releaseGroup.versionPlans.ignorePatternsForPlanCheck.length) {
31
+ output_1.output.note({
32
+ title: `Applying configured ignore patterns to changed files${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
33
+ ? ` for release group "${releaseGroup.name}"`
34
+ : ''}`,
35
+ bodyLines: [
36
+ ...releaseGroup.versionPlans.ignorePatternsForPlanCheck.map((pattern) => ` - ${pattern}`),
37
+ ],
38
+ });
39
+ ignore.add(releaseGroup.versionPlans.ignorePatternsForPlanCheck);
40
+ serializedIgnorePatterns = JSON.stringify(releaseGroup.versionPlans.ignorePatternsForPlanCheck);
41
+ }
42
+ let touchedProjects = {};
43
+ if (serializedIgnorePatternsToTouchedProjects.has(serializedIgnorePatterns)) {
44
+ touchedProjects = serializedIgnorePatternsToTouchedProjects.get(serializedIgnorePatterns);
45
+ }
46
+ else {
47
+ // We only care about directly touched projects, not implicitly affected ones etc
48
+ const touchedProjectsArr = await (0, workspace_projects_1.getTouchedProjects)((0, file_utils_1.calculateFileChanges)(changedFiles, fileData, nxArgs, undefined, ignore), projectGraph.nodes);
49
+ touchedProjects = touchedProjectsArr.reduce((acc, project) => ({ ...acc, [project]: true }), {});
50
+ serializedIgnorePatternsToTouchedProjects.set(serializedIgnorePatterns, touchedProjects);
51
+ }
52
+ const touchedProjectsUnderReleaseGroup = releaseGroupFilteredProjectNames.filter((project) => touchedProjects[project]);
53
+ if (touchedProjectsUnderReleaseGroup.length) {
54
+ output_1.output.log({
55
+ title: `Touched projects${hasProjectsFilter ? ` (after --projects filter applied)` : ''} based on changed files${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
56
+ ? ` under release group "${releaseGroup.name}"`
57
+ : ''}`,
58
+ bodyLines: [
59
+ ...touchedProjectsUnderReleaseGroup.map((project) => ` - ${project}`),
60
+ '',
61
+ 'NOTE: You can adjust your "versionPlans.ignorePatternsForPlanCheck" config to stop certain files from resulting in projects being classed as touched for the purposes of this command.',
62
+ ],
63
+ });
64
+ }
65
+ else {
66
+ output_1.output.log({
67
+ title: `No touched projects${hasProjectsFilter ? ` (after --projects filter applied)` : ''} found based on changed files${typeof releaseGroup.versionPlans !== 'boolean' &&
68
+ Array.isArray(releaseGroup.versionPlans.ignorePatternsForPlanCheck) &&
69
+ releaseGroup.versionPlans.ignorePatternsForPlanCheck.length
70
+ ? ' combined with configured ignore patterns'
71
+ : ''}${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
72
+ ? ` under release group "${releaseGroup.name}"`
73
+ : ''}`,
74
+ });
75
+ }
76
+ return touchedProjectsUnderReleaseGroup;
77
+ };
78
+ }
@@ -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>;
@@ -136,7 +136,7 @@ async function gitAdd({ changedFiles, deletedFiles, dryRun, verbose, logFn, cwd,
136
136
  ignoredFiles.push(f);
137
137
  // git add will fail if trying to add an untracked file that doesn't exist
138
138
  }
139
- else if (changedTrackedFiles.has(f)) {
139
+ else if (changedTrackedFiles.has(f) || dryRun) {
140
140
  filesToAdd.push(f);
141
141
  }
142
142
  }
@@ -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 = [commit.author];
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)) {
@@ -3,7 +3,7 @@ interface ExcludeOptions {
3
3
  exclude: string[];
4
4
  }
5
5
  export declare const defaultYargsParserConfiguration: Partial<ParserConfigurationOptions>;
6
- export declare function withExcludeOption(yargs: Argv): Argv<ExcludeOptions>;
6
+ export declare function withExcludeOption<T>(yargs: Argv<T>): Argv<T & ExcludeOptions>;
7
7
  export interface RunOptions {
8
8
  exclude: string;
9
9
  parallel: string;
@@ -20,6 +20,7 @@ export interface RunOptions {
20
20
  batch: boolean;
21
21
  useAgents: boolean;
22
22
  excludeTaskDependencies: boolean;
23
+ skipSync: boolean;
23
24
  }
24
25
  export declare function withRunOptions<T>(yargs: Argv<T>): Argv<T & RunOptions>;
25
26
  export declare function withTargetAndConfigurationOption(yargs: Argv, demandOption?: boolean): Argv<{
@@ -79,6 +79,11 @@ function withRunOptions(yargs) {
79
79
  describe: 'Skips running dependent tasks first',
80
80
  type: 'boolean',
81
81
  default: false,
82
+ })
83
+ .option('skipSync', {
84
+ type: 'boolean',
85
+ // TODO(leo): add description and make it visible once it is stable
86
+ hidden: true,
82
87
  })
83
88
  .options('cloud', {
84
89
  type: 'boolean',