lage 1.1.4 → 1.2.0

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/CHANGELOG.json CHANGED
@@ -2,7 +2,22 @@
2
2
  "name": "lage",
3
3
  "entries": [
4
4
  {
5
- "date": "Sat, 04 Dec 2021 00:24:05 GMT",
5
+ "date": "Mon, 03 Jan 2022 23:13:39 GMT",
6
+ "tag": "lage_v1.2.0",
7
+ "version": "1.2.0",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "author": "mhuan13@gmail.com",
12
+ "package": "lage",
13
+ "comment": "Allow explicit parralel scheduling of transitive dependencies with ^^ prefix",
14
+ "commit": "c3c1c7378f5fdc1e77fbe1aad38627d5d23a8d30"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Sat, 04 Dec 2021 00:24:11 GMT",
6
21
  "tag": "lage_v1.1.4",
7
22
  "version": "1.1.4",
8
23
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # Change Log - lage
2
2
 
3
- This log was last generated on Sat, 04 Dec 2021 00:24:05 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 03 Jan 2022 23:13:39 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 1.2.0
8
+
9
+ Mon, 03 Jan 2022 23:13:39 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - Allow explicit parralel scheduling of transitive dependencies with ^^ prefix (mhuan13@gmail.com)
14
+
7
15
  ## 1.1.4
8
16
 
9
- Sat, 04 Dec 2021 00:24:05 GMT
17
+ Sat, 04 Dec 2021 00:24:11 GMT
10
18
 
11
19
  ### Patches
12
20
 
@@ -14,6 +14,7 @@ export declare const START_TARGET_ID = "__start";
14
14
  export declare class Pipeline {
15
15
  private workspace;
16
16
  private config;
17
+ private cachedTransitiveTaskDependencies;
17
18
  /** Target represent a unit of work and the configuration of how to run it */
18
19
  targets: Map<string, PipelineTarget>;
19
20
  /** Target dependencies determine the run order of the targets */
@@ -63,6 +64,12 @@ export declare class Pipeline {
63
64
  * Adds all the target dependencies to the graph
64
65
  */
65
66
  addDependencies(): void;
67
+ /**
68
+ * Gets a list of package names that are direct or indirect dependencies of rootPackageName in this.graph,
69
+ * and caches them on the Pipeline.
70
+ * @param packageName the root package to begin walking from
71
+ */
72
+ getTransitiveGraphDependencies(packageName: string): Set<string>;
66
73
  generateTargetGraph(): [string, string][];
67
74
  loadConfig(config: Config): void;
68
75
  private getTargetPriority;
@@ -23,6 +23,7 @@ class Pipeline {
23
23
  constructor(workspace, config) {
24
24
  this.workspace = workspace;
25
25
  this.config = config;
26
+ this.cachedTransitiveTaskDependencies = new Map();
26
27
  /** Target represent a unit of work and the configuration of how to run it */
27
28
  this.targets = new Map([
28
29
  [
@@ -197,6 +198,8 @@ class Pipeline {
197
198
  * - for any deps like package#task, we simply add the singular dependency (source could be a single package or all packages)
198
199
  * - for anything that starts with a "^", we add the package-tasks according to the topological package graph
199
200
  * NOTE: in a non-strict mode (TODO), the dependencies can come from transitive task dependencies
201
+ * - for anything that starts with a "^^", we add the package-tasks from the transitive dependencies in the topological
202
+ * package graph.
200
203
  * - for {"pkgA#task": ["dep"]}, we interpret to add "pkgA#dep"
201
204
  * - for anything that is a string without a "^", we treat that string as the name of a task, adding all targets that way
202
205
  * NOTE: in a non-strict mode (TODO), the dependencies can come from transitive task dependencies
@@ -210,11 +213,13 @@ class Pipeline {
210
213
  }
211
214
  else if (dep.startsWith("^") && packageName) {
212
215
  // topo dep -> build: ['^build']
213
- const depTask = dep.substr(1);
216
+ const [depTask, dependencySet] = dep.startsWith("^^") ?
217
+ [dep.substr(2), [...this.getTransitiveGraphDependencies(packageName)]]
218
+ : [dep.substr(1), this.graph[packageName].dependencies];
214
219
  const dependencyIds = targets
215
220
  .filter((needle) => {
216
221
  const { task, packageName: needlePackageName } = needle;
217
- return (task === depTask && this.graph[packageName].dependencies.some((depPkg) => depPkg === needlePackageName));
222
+ return (task === depTask && dependencySet.some((depPkg) => depPkg === needlePackageName));
218
223
  })
219
224
  .map((needle) => needle.id);
220
225
  for (const dependencyId of dependencyIds) {
@@ -239,6 +244,44 @@ class Pipeline {
239
244
  }
240
245
  }
241
246
  }
247
+ /**
248
+ * Gets a list of package names that are direct or indirect dependencies of rootPackageName in this.graph,
249
+ * and caches them on the Pipeline.
250
+ * @param packageName the root package to begin walking from
251
+ */
252
+ getTransitiveGraphDependencies(packageName) {
253
+ var _a, _b;
254
+ const cachedResult = this.cachedTransitiveTaskDependencies.get(packageName);
255
+ if (cachedResult) {
256
+ return (cachedResult === "walk-in-progress")
257
+ // There is a recursive walk over this set of dependencies in progress.
258
+ // If we hit this case, that means that a dependency of this package depends on it.
259
+ //
260
+ // In this case we return an empty set to omit this package and it's downstream from its
261
+ // dependency
262
+ ? new Set()
263
+ // we already computed this for this package, return the cached result.
264
+ : cachedResult;
265
+ }
266
+ else {
267
+ // No cached result. Compute now with a recursive walk
268
+ // mark that we are traversing this package to prevent infinite recursion
269
+ // in cases of circular dependencies
270
+ this.cachedTransitiveTaskDependencies.set(packageName, 'walk-in-progress');
271
+ let immediateDependencies = (_b = (_a = this.graph[packageName]) === null || _a === void 0 ? void 0 : _a.dependencies) !== null && _b !== void 0 ? _b : [];
272
+ // build the set of transitive dependencies by recursively walking the
273
+ // immediate dependencies' dependencies.
274
+ let transitiveDepSet = new Set(immediateDependencies);
275
+ for (let immediateDependency of immediateDependencies) {
276
+ for (let transitiveSubDependency of this.getTransitiveGraphDependencies(immediateDependency)) {
277
+ transitiveDepSet.add(transitiveSubDependency);
278
+ }
279
+ }
280
+ // Cache the result and return
281
+ this.cachedTransitiveTaskDependencies.set(packageName, transitiveDepSet);
282
+ return transitiveDepSet;
283
+ }
284
+ }
242
285
  generateTargetGraph() {
243
286
  const scope = (0, getPipelinePackages_1.getPipelinePackages)(this.workspace, this.config);
244
287
  const tasks = this.config.command;
@@ -6,7 +6,8 @@ import { QueueOptions } from "bullmq";
6
6
  export declare type NpmClient = "npm" | "yarn" | "pnpm";
7
7
  export interface ConfigOptions {
8
8
  /**
9
- * Defines the task pipeline, prefix with "^" character to denote a topological dependency
9
+ * Defines the task pipeline, prefix with "^" character to denote a direct topological dependency,
10
+ * prefix with ^^ to denote a transitive topological dependency.
10
11
  *
11
12
  * Example:
12
13
  *
@@ -15,6 +16,8 @@ export interface ConfigOptions {
15
16
  * build: ["^build"],
16
17
  * test: ["build"],
17
18
  * lint: []
19
+ * bundle: ["^^transpile"],
20
+ * transpile: [],
18
21
  * }
19
22
  * ```
20
23
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lage",
3
- "version": "1.1.4",
3
+ "version": "1.2.0",
4
4
  "description": "A monorepo task runner",
5
5
  "repository": {
6
6
  "url": "https://github.com/microsoft/lage"