nx 19.5.0-beta.1 → 19.5.0-beta.3

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -59,7 +59,7 @@ npx nx@latest init
59
59
  - [Nx.Dev: Documentation, Guides, Tutorials](https://nx.dev)
60
60
  - [Intro to Nx](https://nx.dev/getting-started/intro)
61
61
  - [Official Nx YouTube Channel](https://www.youtube.com/@NxDevtools)
62
- - [Blog Posts About Nx](https://blog.nrwl.io/nx/home)
62
+ - [Blog Posts About Nx](https://nx.dev/blog)
63
63
 
64
64
  <p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
65
65
  width="100%" alt="Nx - Smart Monorepos · Fast CI"></a></p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.5.0-beta.1",
3
+ "version": "19.5.0-beta.3",
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.5.0-beta.1"
74
+ "@nrwl/tao": "19.5.0-beta.3"
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.5.0-beta.1",
90
- "@nx/nx-darwin-arm64": "19.5.0-beta.1",
91
- "@nx/nx-linux-x64-gnu": "19.5.0-beta.1",
92
- "@nx/nx-linux-x64-musl": "19.5.0-beta.1",
93
- "@nx/nx-win32-x64-msvc": "19.5.0-beta.1",
94
- "@nx/nx-linux-arm64-gnu": "19.5.0-beta.1",
95
- "@nx/nx-linux-arm64-musl": "19.5.0-beta.1",
96
- "@nx/nx-linux-arm-gnueabihf": "19.5.0-beta.1",
97
- "@nx/nx-win32-arm64-msvc": "19.5.0-beta.1",
98
- "@nx/nx-freebsd-x64": "19.5.0-beta.1"
89
+ "@nx/nx-darwin-x64": "19.5.0-beta.3",
90
+ "@nx/nx-darwin-arm64": "19.5.0-beta.3",
91
+ "@nx/nx-linux-x64-gnu": "19.5.0-beta.3",
92
+ "@nx/nx-linux-x64-musl": "19.5.0-beta.3",
93
+ "@nx/nx-win32-x64-msvc": "19.5.0-beta.3",
94
+ "@nx/nx-linux-arm64-gnu": "19.5.0-beta.3",
95
+ "@nx/nx-linux-arm64-musl": "19.5.0-beta.3",
96
+ "@nx/nx-linux-arm-gnueabihf": "19.5.0-beta.3",
97
+ "@nx/nx-win32-arm64-msvc": "19.5.0-beta.3",
98
+ "@nx/nx-freebsd-x64": "19.5.0-beta.3"
99
99
  },
100
100
  "nx-migrations": {
101
101
  "migrations": "./migrations.json",
@@ -4,6 +4,27 @@
4
4
  "title": "JSON schema for Nx projects",
5
5
  "type": "object",
6
6
  "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "description": "Project's name. Optional if specified in workspace.json"
10
+ },
11
+ "root": {
12
+ "type": "string",
13
+ "description": "Project's location relative to the root of the workspace"
14
+ },
15
+ "sourceRoot": {
16
+ "type": "string",
17
+ "description": "The location of project's sources relative to the root of the workspace"
18
+ },
19
+ "projectType": {
20
+ "type": "string",
21
+ "description": "Type of project supported",
22
+ "enum": ["library", "application"]
23
+ },
24
+ "generators": {
25
+ "type": "object",
26
+ "description": "List of default values used by generators"
27
+ },
7
28
  "namedInputs": {
8
29
  "type": "object",
9
30
  "description": "Named inputs used by inputs defined in targets",
@@ -112,6 +133,11 @@
112
133
  "cache": {
113
134
  "type": "boolean",
114
135
  "description": "Specifies if the given target should be cacheable"
136
+ },
137
+ "parallelism": {
138
+ "type": "boolean",
139
+ "default": true,
140
+ "description": "Whether this target can be run in parallel with other tasks"
115
141
  }
116
142
  }
117
143
  }
@@ -80,6 +80,10 @@ export interface Task {
80
80
  * Determines if a given task should be cacheable.
81
81
  */
82
82
  cache?: boolean;
83
+ /**
84
+ * Determines if a given task should be parallelizable.
85
+ */
86
+ parallelism: boolean;
83
87
  }
84
88
  /**
85
89
  * Graph of Tasks to be executed
@@ -212,4 +212,9 @@ export interface TargetConfiguration<T = any> {
212
212
  * Metadata about the target
213
213
  */
214
214
  metadata?: TargetMetadata;
215
+ /**
216
+ * Whether this target can be run in parallel with other tasks
217
+ * Default is true
218
+ */
219
+ parallelism?: boolean;
215
220
  }
@@ -185,6 +185,7 @@ export interface Target {
185
185
  outputs?: Array<string>
186
186
  options?: string
187
187
  configurations?: string
188
+ parallelism?: boolean
188
189
  }
189
190
 
190
191
  export interface Task {
Binary file
@@ -14,6 +14,7 @@ function transformProjectGraphForRust(graph) {
14
14
  outputs: targetConfig.outputs,
15
15
  options: JSON.stringify(targetConfig.options),
16
16
  configurations: JSON.stringify(targetConfig.configurations),
17
+ parallelism: targetConfig.parallelism,
17
18
  };
18
19
  }
19
20
  nodes[projectName] = {
@@ -18,6 +18,7 @@ const minimatch_1 = require("minimatch");
18
18
  const path_1 = require("path");
19
19
  const perf_hooks_1 = require("perf_hooks");
20
20
  const error_types_1 = require("../error-types");
21
+ const globs_1 = require("../../utils/globs");
21
22
  function mergeProjectConfigurationIntoRootMap(projectRootMap, project, configurationSourceMaps, sourceInformation,
22
23
  // This function is used when reading project configuration
23
24
  // in generators, where we don't want to do this.
@@ -709,10 +710,23 @@ function readTargetDefaultsForTarget(targetName, targetDefaults, executor) {
709
710
  const key = [executor, targetName].find((x) => targetDefaults?.[x]);
710
711
  return key ? targetDefaults?.[key] : null;
711
712
  }
712
- else {
713
+ else if (targetDefaults?.[targetName]) {
713
714
  // If the executor is not defined, the only key we have is the target name.
714
715
  return targetDefaults?.[targetName];
715
716
  }
717
+ let matchingTargetDefaultKey = null;
718
+ for (const key in targetDefaults ?? {}) {
719
+ if ((0, globs_1.isGlobPattern)(key) && (0, minimatch_1.minimatch)(targetName, key)) {
720
+ if (!matchingTargetDefaultKey ||
721
+ matchingTargetDefaultKey.length < key.length) {
722
+ matchingTargetDefaultKey = key;
723
+ }
724
+ }
725
+ }
726
+ if (matchingTargetDefaultKey) {
727
+ return targetDefaults[matchingTargetDefaultKey];
728
+ }
729
+ return {};
716
730
  }
717
731
  function createRootMap(projectRootMap) {
718
732
  const map = {};
@@ -748,11 +762,17 @@ function resolveCommandSyntacticSugar(target, key) {
748
762
  * @returns The normalized target configuration
749
763
  */
750
764
  function normalizeTarget(target, project) {
765
+ target = {
766
+ ...target,
767
+ configurations: {
768
+ ...target.configurations,
769
+ },
770
+ };
751
771
  target = resolveCommandSyntacticSugar(target, project.root);
752
772
  target.options = resolveNxTokensInOptions(target.options, project, `${project.root}:${target}`);
753
- target.configurations ??= {};
754
773
  for (const configuration in target.configurations) {
755
774
  target.configurations[configuration] = resolveNxTokensInOptions(target.configurations[configuration], project, `${project.root}:${target}:${configuration}`);
756
775
  }
776
+ target.parallelism ??= true;
757
777
  return target;
758
778
  }
@@ -156,6 +156,7 @@ class ProcessTasks {
156
156
  overrides: interpolatedOverrides,
157
157
  outputs: (0, utils_1.getOutputs)(this.projectGraph.nodes, qualifiedTarget, interpolatedOverrides),
158
158
  cache: project.data.targets[target].cache,
159
+ parallelism: project.data.targets[target].parallelism ?? true,
159
160
  };
160
161
  }
161
162
  resolveConfiguration(project, target, configuration) {
@@ -14,6 +14,7 @@ export declare class TasksSchedule {
14
14
  private reverseProjectGraph;
15
15
  private scheduledBatches;
16
16
  private scheduledTasks;
17
+ private runningTasks;
17
18
  private completedTasks;
18
19
  private scheduleRequestsExecutionChain;
19
20
  constructor(projectGraph: ProjectGraph, taskGraph: TaskGraph, options: DefaultTasksRunnerOptions);
@@ -14,6 +14,7 @@ class TasksSchedule {
14
14
  this.reverseProjectGraph = (0, operators_1.reverse)(this.projectGraph);
15
15
  this.scheduledBatches = [];
16
16
  this.scheduledTasks = [];
17
+ this.runningTasks = new Set();
17
18
  this.completedTasks = new Set();
18
19
  this.scheduleRequestsExecutionChain = Promise.resolve();
19
20
  }
@@ -31,6 +32,7 @@ class TasksSchedule {
31
32
  complete(taskIds) {
32
33
  for (const taskId of taskIds) {
33
34
  this.completedTasks.add(taskId);
35
+ this.runningTasks.delete(taskId);
34
36
  }
35
37
  this.notScheduledTaskGraph = (0, utils_1.removeTasksFromTaskGraph)(this.notScheduledTaskGraph, taskIds);
36
38
  }
@@ -84,6 +86,7 @@ class TasksSchedule {
84
86
  (0, project_graph_utils_1.findAllProjectNodeDependencies)(project1, this.reverseProjectGraph)
85
87
  .length);
86
88
  });
89
+ this.runningTasks.add(taskId);
87
90
  }
88
91
  async scheduleBatches() {
89
92
  const batchMap = {};
@@ -102,7 +105,7 @@ class TasksSchedule {
102
105
  this.scheduledBatches.push({ executorName, taskGraph });
103
106
  }
104
107
  async processTaskForBatches(batches, task, rootExecutorName, isRoot) {
105
- if (!this.canBatchTaskBeScheduled(task.id, batches[rootExecutorName])) {
108
+ if (!this.canBatchTaskBeScheduled(task, batches[rootExecutorName])) {
106
109
  return;
107
110
  }
108
111
  const { batchImplementationFactory } = (0, utils_1.getExecutorForTask)(task, this.projectGraph);
@@ -131,12 +134,33 @@ class TasksSchedule {
131
134
  await this.processTaskForBatches(batches, depTask, rootExecutorName, false);
132
135
  }
133
136
  }
134
- canBatchTaskBeScheduled(taskId, batchTaskGraph) {
137
+ canBatchTaskBeScheduled(task, batchTaskGraph) {
138
+ // task self needs to have parallelism true
135
139
  // all deps have either completed or belong to the same batch
136
- return this.taskGraph.dependencies[taskId].every((id) => this.completedTasks.has(id) || !!batchTaskGraph?.tasks[id]);
140
+ return (task.parallelism === true &&
141
+ this.taskGraph.dependencies[task.id].every((id) => this.completedTasks.has(id) || !!batchTaskGraph?.tasks[id]));
137
142
  }
138
143
  canBeScheduled(taskId) {
139
- return this.taskGraph.dependencies[taskId].every((id) => this.completedTasks.has(id));
144
+ const hasDependenciesCompleted = this.taskGraph.dependencies[taskId].every((id) => this.completedTasks.has(id));
145
+ // if dependencies have not completed, cannot schedule
146
+ if (!hasDependenciesCompleted) {
147
+ return false;
148
+ }
149
+ // if there are no running tasks, can schedule anything
150
+ if (this.runningTasks.size === 0) {
151
+ return true;
152
+ }
153
+ const runningTasksNotSupportParallelism = Array.from(this.runningTasks).some((taskId) => {
154
+ return this.taskGraph.tasks[taskId].parallelism === false;
155
+ });
156
+ if (runningTasksNotSupportParallelism) {
157
+ // if any running tasks do not support parallelism, no other tasks can be scheduled
158
+ return false;
159
+ }
160
+ else {
161
+ // if all running tasks support parallelism, can only schedule task with parallelism
162
+ return this.taskGraph.tasks[taskId].parallelism === true;
163
+ }
140
164
  }
141
165
  }
142
166
  exports.TasksSchedule = TasksSchedule;
@@ -36,6 +36,7 @@ const executor_utils_1 = require("../command-line/run/executor-utils");
36
36
  const project_graph_1 = require("../project-graph/project-graph");
37
37
  const find_matching_projects_1 = require("../utils/find-matching-projects");
38
38
  const minimatch_1 = require("minimatch");
39
+ const globs_1 = require("../utils/globs");
39
40
  function getDependencyConfigs({ project, target }, extraTargetDependencies, projectGraph, allTargetNames) {
40
41
  const dependencyConfigs = (projectGraph.nodes[project].data?.targets[target]?.dependsOn ??
41
42
  // This is passed into `run-command` from programmatic invocations
@@ -77,7 +78,7 @@ function expandDependencyConfigSyntaxSugar(dependencyConfigString, graph) {
77
78
  // Weakmap let's the cache get cleared by garbage collector if allTargetNames is no longer used
78
79
  const patternResultCache = new WeakMap();
79
80
  function expandWildcardTargetConfiguration(dependencyConfig, allTargetNames) {
80
- if (!find_matching_projects_1.GLOB_CHARACTERS.some((char) => dependencyConfig.target.includes(char))) {
81
+ if (!(0, globs_1.isGlobPattern)(dependencyConfig.target)) {
81
82
  return [dependencyConfig];
82
83
  }
83
84
  let cache = patternResultCache.get(allTargetNames);
@@ -1,8 +1,4 @@
1
1
  import type { ProjectGraphProjectNode } from '../config/project-graph';
2
- /**
3
- * The presence of these characters in a string indicates that it might be a glob pattern.
4
- */
5
- export declare const GLOB_CHARACTERS: string[];
6
2
  /**
7
3
  * Find matching project names given a list of potential project names or globs.
8
4
  *
@@ -1,18 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMatchingStringsWithCache = exports.GLOB_CHARACTERS = void 0;
3
+ exports.getMatchingStringsWithCache = void 0;
4
4
  exports.findMatchingProjects = findMatchingProjects;
5
5
  const minimatch_1 = require("minimatch");
6
+ const globs_1 = require("./globs");
6
7
  const validPatternTypes = [
7
8
  'name', // Pattern is based on the project's name
8
9
  'tag', // Pattern is based on the project's tags
9
10
  'directory', // Pattern is based on the project's root directory
10
11
  'unlabeled', // Pattern was passed without specifying a type
11
12
  ];
12
- /**
13
- * The presence of these characters in a string indicates that it might be a glob pattern.
14
- */
15
- exports.GLOB_CHARACTERS = ['*', '|', '{', '}', '(', ')'];
16
13
  /**
17
14
  * Find matching project names given a list of potential project names or globs.
18
15
  *
@@ -113,7 +110,7 @@ function addMatchingProjectsByName(projectNames, projects, pattern, matchedProje
113
110
  }
114
111
  return;
115
112
  }
116
- if (!exports.GLOB_CHARACTERS.some((c) => pattern.value.includes(c))) {
113
+ if (!(0, globs_1.isGlobPattern)(pattern.value)) {
117
114
  return;
118
115
  }
119
116
  const matchedProjectNames = (0, exports.getMatchingStringsWithCache)(pattern.value, projectNames);
@@ -138,7 +135,7 @@ function addMatchingProjectsByTag(projectNames, projects, pattern, matchedProjec
138
135
  }
139
136
  continue;
140
137
  }
141
- if (!exports.GLOB_CHARACTERS.some((c) => pattern.value.includes(c))) {
138
+ if (!(0, globs_1.isGlobPattern)(pattern.value)) {
142
139
  continue;
143
140
  }
144
141
  if ((0, exports.getMatchingStringsWithCache)(pattern.value, tags).length) {
@@ -1 +1,3 @@
1
1
  export declare function combineGlobPatterns(...patterns: (string | string[])[]): string;
2
+ export declare const GLOB_CHARACTERS: Set<string>;
3
+ export declare function isGlobPattern(pattern: string): boolean;
@@ -1,7 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GLOB_CHARACTERS = void 0;
3
4
  exports.combineGlobPatterns = combineGlobPatterns;
5
+ exports.isGlobPattern = isGlobPattern;
4
6
  function combineGlobPatterns(...patterns) {
5
7
  const p = patterns.flat();
6
8
  return p.length > 1 ? '{' + p.join(',') + '}' : p.length === 1 ? p[0] : '';
7
9
  }
10
+ exports.GLOB_CHARACTERS = new Set(['*', '|', '{', '}', '(', ')', '[']);
11
+ function isGlobPattern(pattern) {
12
+ for (const c of pattern) {
13
+ if (exports.GLOB_CHARACTERS.has(c)) {
14
+ return true;
15
+ }
16
+ }
17
+ return false;
18
+ }