@lage-run/scheduler 0.1.1
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 +32 -0
- package/CHANGELOG.md +15 -0
- package/README.md +53 -0
- package/jest.config.js +1 -0
- package/lib/SimpleScheduler.d.ts +52 -0
- package/lib/SimpleScheduler.js +95 -0
- package/lib/SimpleScheduler.js.map +1 -0
- package/lib/WrappedTarget.d.ts +56 -0
- package/lib/WrappedTarget.js +133 -0
- package/lib/WrappedTarget.js.map +1 -0
- package/lib/formatDuration.d.ts +2 -0
- package/lib/formatDuration.js +22 -0
- package/lib/formatDuration.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/runners/NoOpRunner.d.ts +2 -0
- package/lib/runners/NoOpRunner.js +7 -0
- package/lib/runners/NoOpRunner.js.map +1 -0
- package/lib/runners/NpmScriptRunner.d.ts +37 -0
- package/lib/runners/NpmScriptRunner.js +123 -0
- package/lib/runners/NpmScriptRunner.js.map +1 -0
- package/lib/runners/workspace/findNpmClient.d.ts +1 -0
- package/lib/runners/workspace/findNpmClient.js +31 -0
- package/lib/runners/workspace/findNpmClient.js.map +1 -0
- package/lib/types/TargetRunContext.d.ts +10 -0
- package/lib/types/TargetRunContext.js +3 -0
- package/lib/types/TargetRunContext.js.map +1 -0
- package/lib/types/TargetRunner.d.ts +5 -0
- package/lib/types/TargetRunner.js +3 -0
- package/lib/types/TargetRunner.js.map +1 -0
- package/lib/types/TargetScheduler.d.ts +7 -0
- package/lib/types/TargetScheduler.js +3 -0
- package/lib/types/TargetScheduler.js.map +1 -0
- package/lib/types/TargetStatus.d.ts +1 -0
- package/lib/types/TargetStatus.js +3 -0
- package/lib/types/TargetStatus.js.map +1 -0
- package/package.json +35 -0
- package/tsconfig.json +23 -0
package/CHANGELOG.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lage-run/scheduler",
|
|
3
|
+
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"date": "Tue, 09 Aug 2022 21:16:19 GMT",
|
|
6
|
+
"tag": "@lage-run/scheduler_v0.1.1",
|
|
7
|
+
"version": "0.1.1",
|
|
8
|
+
"comments": {
|
|
9
|
+
"patch": [
|
|
10
|
+
{
|
|
11
|
+
"author": "ken@gizzar.com",
|
|
12
|
+
"package": "@lage-run/scheduler",
|
|
13
|
+
"commit": "6dc38b30d19b0cba7e2609d3681e4e55c4fd6238",
|
|
14
|
+
"comment": "brand new package to do scheduling of work"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"author": "beachball",
|
|
18
|
+
"package": "@lage-run/scheduler",
|
|
19
|
+
"comment": "Bump @lage-run/target-graph to v0.2.0",
|
|
20
|
+
"commit": "6dc38b30d19b0cba7e2609d3681e4e55c4fd6238"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"author": "beachball",
|
|
24
|
+
"package": "@lage-run/scheduler",
|
|
25
|
+
"comment": "Bump @lage-run/cache to v0.1.1",
|
|
26
|
+
"commit": "6dc38b30d19b0cba7e2609d3681e4e55c4fd6238"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Change Log - @lage-run/scheduler
|
|
2
|
+
|
|
3
|
+
This log was last generated on Tue, 09 Aug 2022 21:16:19 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
<!-- Start content -->
|
|
6
|
+
|
|
7
|
+
## 0.1.1
|
|
8
|
+
|
|
9
|
+
Tue, 09 Aug 2022 21:16:19 GMT
|
|
10
|
+
|
|
11
|
+
### Patches
|
|
12
|
+
|
|
13
|
+
- brand new package to do scheduling of work (ken@gizzar.com)
|
|
14
|
+
- Bump @lage-run/target-graph to v0.2.0
|
|
15
|
+
- Bump @lage-run/cache to v0.1.1
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @lage-run/scheduler
|
|
2
|
+
|
|
3
|
+
This package provides:
|
|
4
|
+
|
|
5
|
+
1. `Scheduler` interface
|
|
6
|
+
2. `
|
|
7
|
+
3. a default cache provider that uses `backfill`
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Logger } from "@lage-run/logger";
|
|
13
|
+
import { RemoteFallbackCacheProvider, TargetHasher } from "@lage-run/cache";
|
|
14
|
+
import { SimpleScheduler } from "@lage-run/scheduler";
|
|
15
|
+
import { TargetGraph } from "@lage-run/target-graph";
|
|
16
|
+
|
|
17
|
+
const root = "/root-of-repo";
|
|
18
|
+
const logger = new Logger();
|
|
19
|
+
const cacheProvider = new RemoteFallbackCacheProvider({ root, logger, ... });
|
|
20
|
+
const hasher = new TargetHasher({ root, ... });
|
|
21
|
+
|
|
22
|
+
const runner = new NpmScriptRunner({
|
|
23
|
+
logger,
|
|
24
|
+
...
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const scheduler = new SimpleScheduler({
|
|
28
|
+
logger,
|
|
29
|
+
concurrency,
|
|
30
|
+
cacheProvider,
|
|
31
|
+
hasher,
|
|
32
|
+
continueOnError: true,
|
|
33
|
+
shouldCache: true,
|
|
34
|
+
shouldResetCache: false,
|
|
35
|
+
runner
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const targetGraphBuilder = new TargetGraphBuilder();
|
|
39
|
+
const packageInfos = getPackageInfos(rootDir);
|
|
40
|
+
|
|
41
|
+
const builder = new TargetGraphBuilder(rootDir, packageInfos);
|
|
42
|
+
|
|
43
|
+
// these would normally come from the CLI
|
|
44
|
+
const tasks = ["build", "test"];
|
|
45
|
+
const packages = ["package-a", "package-b"];
|
|
46
|
+
|
|
47
|
+
const targetGraph = builder.buildTargetGraph(tasks, packages);
|
|
48
|
+
|
|
49
|
+
await scheduler.run(root, targetGraph);
|
|
50
|
+
|
|
51
|
+
// If an error happened...
|
|
52
|
+
scheduler.abort();
|
|
53
|
+
```
|
package/jest.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("monorepo-scripts/config/jest.config.js");
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TargetGraph } from "@lage-run/target-graph";
|
|
2
|
+
import { Logger } from "@lage-run/logger";
|
|
3
|
+
import type { CacheProvider, TargetHasher } from "@lage-run/cache";
|
|
4
|
+
import type { TargetRunner } from "./types/TargetRunner";
|
|
5
|
+
import type { TargetScheduler } from "./types/TargetScheduler";
|
|
6
|
+
import type { TargetRunContext } from "./types/TargetRunContext";
|
|
7
|
+
import type { AbortSignal } from "abort-controller";
|
|
8
|
+
import { AbortController } from "abort-controller";
|
|
9
|
+
export interface SimpleSchedulerOptions {
|
|
10
|
+
logger: Logger;
|
|
11
|
+
concurrency: number;
|
|
12
|
+
continueOnError: boolean;
|
|
13
|
+
cacheProvider: CacheProvider;
|
|
14
|
+
hasher: TargetHasher;
|
|
15
|
+
shouldCache: boolean;
|
|
16
|
+
shouldResetCache: boolean;
|
|
17
|
+
runner: TargetRunner;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Simple scheduler that runs all targets in a promise graph using p-graph library.
|
|
21
|
+
*
|
|
22
|
+
* Some characteristics:
|
|
23
|
+
* 1. Can cache results of target runs via the cache provider.
|
|
24
|
+
* 2. Takes a TargetRunner, a CacheProvider, a TargetHasher and a Logger as constructor parameters (dependency injection).
|
|
25
|
+
* 3. Directly constructs new WrappedTarget, which provides the call to caching and logging.
|
|
26
|
+
*
|
|
27
|
+
* Roadmap / future enhancements:
|
|
28
|
+
* 1. Allow for multiple kinds of runner (currently only ONE is supported, and it is applied to all targets)
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
export declare class SimpleScheduler implements TargetScheduler {
|
|
32
|
+
private options;
|
|
33
|
+
targetRunContexts: Map<string, TargetRunContext>;
|
|
34
|
+
abortController: AbortController;
|
|
35
|
+
abortSignal: AbortSignal;
|
|
36
|
+
constructor(options: SimpleSchedulerOptions);
|
|
37
|
+
/**
|
|
38
|
+
* The job of the run method is to:
|
|
39
|
+
* 1. Convert the target graph into a promise graph.
|
|
40
|
+
* 2. Create a promise graph of all targets
|
|
41
|
+
* 3. Pass the continueOnError option to the promise graph runner.
|
|
42
|
+
*
|
|
43
|
+
* @param root
|
|
44
|
+
* @param targetGraph
|
|
45
|
+
* @returns
|
|
46
|
+
*/
|
|
47
|
+
run(root: string, targetGraph: TargetGraph): Promise<Map<string, TargetRunContext>>;
|
|
48
|
+
/**
|
|
49
|
+
* Abort the scheduler using the abort controller.
|
|
50
|
+
*/
|
|
51
|
+
abort(): void;
|
|
52
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SimpleScheduler = void 0;
|
|
7
|
+
const target_graph_1 = require("@lage-run/target-graph");
|
|
8
|
+
const WrappedTarget_1 = require("./WrappedTarget");
|
|
9
|
+
const p_graph_1 = __importDefault(require("p-graph"));
|
|
10
|
+
const abort_controller_1 = require("abort-controller");
|
|
11
|
+
const NoOpRunner_1 = require("./runners/NoOpRunner");
|
|
12
|
+
/**
|
|
13
|
+
* Simple scheduler that runs all targets in a promise graph using p-graph library.
|
|
14
|
+
*
|
|
15
|
+
* Some characteristics:
|
|
16
|
+
* 1. Can cache results of target runs via the cache provider.
|
|
17
|
+
* 2. Takes a TargetRunner, a CacheProvider, a TargetHasher and a Logger as constructor parameters (dependency injection).
|
|
18
|
+
* 3. Directly constructs new WrappedTarget, which provides the call to caching and logging.
|
|
19
|
+
*
|
|
20
|
+
* Roadmap / future enhancements:
|
|
21
|
+
* 1. Allow for multiple kinds of runner (currently only ONE is supported, and it is applied to all targets)
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
class SimpleScheduler {
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.options = options;
|
|
27
|
+
this.targetRunContexts = new Map();
|
|
28
|
+
this.abortController = new abort_controller_1.AbortController();
|
|
29
|
+
this.abortSignal = this.abortController.signal;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The job of the run method is to:
|
|
33
|
+
* 1. Convert the target graph into a promise graph.
|
|
34
|
+
* 2. Create a promise graph of all targets
|
|
35
|
+
* 3. Pass the continueOnError option to the promise graph runner.
|
|
36
|
+
*
|
|
37
|
+
* @param root
|
|
38
|
+
* @param targetGraph
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
async run(root, targetGraph) {
|
|
42
|
+
const { concurrency, continueOnError, logger, cacheProvider, shouldCache, shouldResetCache, hasher, runner } = this.options;
|
|
43
|
+
const { dependencies, targets } = targetGraph;
|
|
44
|
+
const pGraphNodes = new Map();
|
|
45
|
+
const pGraphEdges = dependencies;
|
|
46
|
+
for (const target of targets.values()) {
|
|
47
|
+
const wrappedTarget = new WrappedTarget_1.WrappedTarget({
|
|
48
|
+
target,
|
|
49
|
+
root,
|
|
50
|
+
logger,
|
|
51
|
+
cacheProvider,
|
|
52
|
+
hasher,
|
|
53
|
+
shouldCache,
|
|
54
|
+
shouldResetCache,
|
|
55
|
+
continueOnError,
|
|
56
|
+
abortController: this.abortController,
|
|
57
|
+
});
|
|
58
|
+
this.targetRunContexts.set(target.id, wrappedTarget);
|
|
59
|
+
pGraphNodes.set(target.id, {
|
|
60
|
+
/**
|
|
61
|
+
* Picks the runner, and run the wrapped target with the runner
|
|
62
|
+
*/
|
|
63
|
+
run: async () => {
|
|
64
|
+
if (this.abortSignal.aborted) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (target.id === (0, target_graph_1.getStartTargetId)()) {
|
|
68
|
+
return this.targetRunContexts.get(target.id).run(NoOpRunner_1.NoOpRunner);
|
|
69
|
+
}
|
|
70
|
+
return this.targetRunContexts.get(target.id).run(runner);
|
|
71
|
+
},
|
|
72
|
+
priority: target.priority,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
await (0, p_graph_1.default)(pGraphNodes, pGraphEdges).run({
|
|
77
|
+
concurrency,
|
|
78
|
+
continue: continueOnError,
|
|
79
|
+
});
|
|
80
|
+
return this.targetRunContexts;
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
logger.error(typeof e === "string" ? e : e instanceof Error && "message" in e ? e.message : "unknown error");
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Abort the scheduler using the abort controller.
|
|
89
|
+
*/
|
|
90
|
+
abort() {
|
|
91
|
+
this.abortController.abort();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.SimpleScheduler = SimpleScheduler;
|
|
95
|
+
//# sourceMappingURL=SimpleScheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SimpleScheduler.js","sourceRoot":"","sources":["../src/SimpleScheduler.ts"],"names":[],"mappings":";;;;;;AAAA,yDAAuE;AAEvE,mDAAgD;AAChD,sDAA6B;AAO7B,uDAAmD;AACnD,qDAAkD;AAelD;;;;;;;;;;;GAWG;AACH,MAAa,eAAe;IAK1B,YAAoB,OAA+B;QAA/B,YAAO,GAAP,OAAO,CAAwB;QACjD,IAAI,CAAC,iBAAiB,GAAG,IAAI,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,IAAI,kCAAe,EAAE,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;IACjD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,CAAC,IAAY,EAAE,WAAwB;QAC9C,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5H,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;QAE9C,MAAM,WAAW,GAAkB,IAAI,GAAG,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,YAAY,CAAC;QAEjC,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE;YACrC,MAAM,aAAa,GAAG,IAAI,6BAAa,CAAC;gBACtC,MAAM;gBACN,IAAI;gBACJ,MAAM;gBACN,aAAa;gBACb,MAAM;gBACN,WAAW;gBACX,gBAAgB;gBAChB,eAAe;gBACf,eAAe,EAAE,IAAI,CAAC,eAAe;aACtC,CAAC,CAAC;YAEH,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YAErD,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE;gBACzB;;mBAEG;gBACH,GAAG,EAAE,KAAK,IAAI,EAAE;oBACd,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;wBAC5B,OAAO;qBACR;oBAED,IAAI,MAAM,CAAC,EAAE,KAAK,IAAA,+BAAgB,GAAE,EAAE;wBACpC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAE,CAAC,GAAG,CAAC,uBAAU,CAAC,CAAC;qBAC/D;oBAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC5D,CAAC;gBAED,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B,CAAC,CAAC;SACJ;QAED,IAAI;YACF,MAAM,IAAA,iBAAM,EAAC,WAAW,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC;gBACzC,WAAW;gBACX,QAAQ,EAAE,eAAe;aAC1B,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC,iBAAiB,CAAC;SAC/B;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;YAC7G,MAAM,CAAC,CAAC;SACT;IACH,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;CACF;AAlFD,0CAkFC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Logger } from "@lage-run/logger";
|
|
2
|
+
import { TargetHasher } from "@lage-run/cache";
|
|
3
|
+
import type { AbortController } from "abort-controller";
|
|
4
|
+
import type { CacheProvider } from "@lage-run/cache";
|
|
5
|
+
import type { Target } from "@lage-run/target-graph";
|
|
6
|
+
import type { TargetRunContext } from "./types/TargetRunContext";
|
|
7
|
+
import type { TargetRunner } from "./types/TargetRunner";
|
|
8
|
+
import type { TargetStatus } from "./types/TargetStatus";
|
|
9
|
+
export interface WrappedTargetOptions {
|
|
10
|
+
root: string;
|
|
11
|
+
target: Target;
|
|
12
|
+
logger: Logger;
|
|
13
|
+
cacheProvider: CacheProvider;
|
|
14
|
+
hasher: TargetHasher;
|
|
15
|
+
shouldCache: boolean;
|
|
16
|
+
shouldResetCache: boolean;
|
|
17
|
+
continueOnError: boolean;
|
|
18
|
+
abortController: AbortController;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Wraps a target with additional functionality:
|
|
22
|
+
* 1. Caching
|
|
23
|
+
* 2. Logging
|
|
24
|
+
* 3. Abort signal
|
|
25
|
+
* 4. Continue on error
|
|
26
|
+
*/
|
|
27
|
+
export declare class WrappedTarget implements TargetRunContext {
|
|
28
|
+
options: WrappedTargetOptions;
|
|
29
|
+
startTime: [number, number];
|
|
30
|
+
duration: [number, number];
|
|
31
|
+
target: Target;
|
|
32
|
+
status: TargetStatus;
|
|
33
|
+
constructor(options: WrappedTargetOptions);
|
|
34
|
+
onAbort(): void;
|
|
35
|
+
onStart(): void;
|
|
36
|
+
onComplete(): void;
|
|
37
|
+
onFail(): void;
|
|
38
|
+
onSkipped(hash: string | null): void;
|
|
39
|
+
getCache(): Promise<{
|
|
40
|
+
hash: string | null;
|
|
41
|
+
cacheHit: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
saveCache(hash: string | null): Promise<void>;
|
|
44
|
+
run(runner: TargetRunner): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* A JSON representation of this wrapped target, suitable for serialization in tests.
|
|
47
|
+
*
|
|
48
|
+
* Skips the unpredictable properties of the wrapped target like the startTime and duration.
|
|
49
|
+
*
|
|
50
|
+
* @returns
|
|
51
|
+
*/
|
|
52
|
+
toJSON(): {
|
|
53
|
+
target: string;
|
|
54
|
+
status: TargetStatus;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WrappedTarget = void 0;
|
|
4
|
+
const formatDuration_1 = require("./formatDuration");
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a target with additional functionality:
|
|
7
|
+
* 1. Caching
|
|
8
|
+
* 2. Logging
|
|
9
|
+
* 3. Abort signal
|
|
10
|
+
* 4. Continue on error
|
|
11
|
+
*/
|
|
12
|
+
class WrappedTarget {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
this.startTime = [0, 0];
|
|
16
|
+
this.duration = [0, 0];
|
|
17
|
+
this.status = "pending";
|
|
18
|
+
this.target = options.target;
|
|
19
|
+
}
|
|
20
|
+
onAbort() {
|
|
21
|
+
this.status = "aborted";
|
|
22
|
+
this.options.logger.info("aborted", { target: this.target, status: "aborted" });
|
|
23
|
+
}
|
|
24
|
+
onStart() {
|
|
25
|
+
this.status = "running";
|
|
26
|
+
this.startTime = process.hrtime();
|
|
27
|
+
this.options.logger.info("started", { target: this.target, status: "started" });
|
|
28
|
+
}
|
|
29
|
+
onComplete() {
|
|
30
|
+
this.status = "success";
|
|
31
|
+
this.duration = process.hrtime(this.startTime);
|
|
32
|
+
this.options.logger.info("completed", {
|
|
33
|
+
target: this.target,
|
|
34
|
+
status: "completed",
|
|
35
|
+
duration: (0, formatDuration_1.hrToSeconds)(this.duration),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
onFail() {
|
|
39
|
+
this.status = "failed";
|
|
40
|
+
this.duration = process.hrtime(this.startTime);
|
|
41
|
+
this.options.logger.info("failed", {
|
|
42
|
+
target: this.target,
|
|
43
|
+
status: "failed",
|
|
44
|
+
duration: (0, formatDuration_1.hrToSeconds)(this.duration),
|
|
45
|
+
});
|
|
46
|
+
if (!this.options.continueOnError) {
|
|
47
|
+
this.options.abortController.abort();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
onSkipped(hash) {
|
|
51
|
+
this.status = "skipped";
|
|
52
|
+
this.duration = process.hrtime(this.startTime);
|
|
53
|
+
this.options.logger.info(`skipped`, {
|
|
54
|
+
target: this.target,
|
|
55
|
+
status: "skipped",
|
|
56
|
+
duration: (0, formatDuration_1.hrToSeconds)(this.duration),
|
|
57
|
+
hash,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async getCache() {
|
|
61
|
+
const { cacheProvider, hasher } = this.options;
|
|
62
|
+
let hash = null;
|
|
63
|
+
let cacheHit = false;
|
|
64
|
+
const { target, shouldCache, shouldResetCache } = this.options;
|
|
65
|
+
if (shouldCache && target.cache) {
|
|
66
|
+
hash = await hasher.hash(target);
|
|
67
|
+
if (hash && !shouldResetCache) {
|
|
68
|
+
cacheHit = await cacheProvider.fetch(hash, target);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return { hash, cacheHit };
|
|
72
|
+
}
|
|
73
|
+
async saveCache(hash) {
|
|
74
|
+
if (!hash) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const { logger, target, cacheProvider } = this.options;
|
|
78
|
+
logger.verbose(`hash put ${hash}`);
|
|
79
|
+
await cacheProvider.put(hash, target);
|
|
80
|
+
}
|
|
81
|
+
async run(runner) {
|
|
82
|
+
const { target, logger, shouldCache, abortController } = this.options;
|
|
83
|
+
const abortSignal = abortController.signal;
|
|
84
|
+
if (abortSignal.aborted) {
|
|
85
|
+
this.onAbort();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const { hash, cacheHit } = await this.getCache();
|
|
90
|
+
this.onStart();
|
|
91
|
+
const cacheEnabled = target.cache && shouldCache && hash;
|
|
92
|
+
if (cacheEnabled) {
|
|
93
|
+
logger.verbose(`hash: ${hash}, cache hit? ${cacheHit}`);
|
|
94
|
+
}
|
|
95
|
+
// skip if cache hit!
|
|
96
|
+
if (cacheHit) {
|
|
97
|
+
this.onSkipped(hash);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* TargetRunner should run() a target. The promise resolves if successful, or rejects otherwise (aborted or failed).
|
|
102
|
+
*/
|
|
103
|
+
await runner.run(target, abortSignal);
|
|
104
|
+
if (cacheEnabled) {
|
|
105
|
+
await this.saveCache(hash);
|
|
106
|
+
}
|
|
107
|
+
this.onComplete();
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
if (abortSignal.aborted) {
|
|
111
|
+
this.onAbort();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.onFail();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A JSON representation of this wrapped target, suitable for serialization in tests.
|
|
120
|
+
*
|
|
121
|
+
* Skips the unpredictable properties of the wrapped target like the startTime and duration.
|
|
122
|
+
*
|
|
123
|
+
* @returns
|
|
124
|
+
*/
|
|
125
|
+
toJSON() {
|
|
126
|
+
return {
|
|
127
|
+
target: this.target.id,
|
|
128
|
+
status: this.status,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.WrappedTarget = WrappedTarget;
|
|
133
|
+
//# sourceMappingURL=WrappedTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WrappedTarget.js","sourceRoot":"","sources":["../src/WrappedTarget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hrToSeconds = exports.formatDuration = void 0;
|
|
4
|
+
function formatDuration(seconds) {
|
|
5
|
+
let raw = parseFloat(seconds);
|
|
6
|
+
if (raw > 60) {
|
|
7
|
+
const minutes = Math.floor(raw / 60);
|
|
8
|
+
const seconds = (raw - minutes * 60).toFixed(2);
|
|
9
|
+
return `${minutes}m ${seconds}s`;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
const seconds = raw.toFixed(2);
|
|
13
|
+
return `${seconds}s`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.formatDuration = formatDuration;
|
|
17
|
+
function hrToSeconds(hrtime) {
|
|
18
|
+
let raw = hrtime[0] + hrtime[1] / 1e9;
|
|
19
|
+
return raw.toFixed(2);
|
|
20
|
+
}
|
|
21
|
+
exports.hrToSeconds = hrToSeconds;
|
|
22
|
+
//# sourceMappingURL=formatDuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatDuration.js","sourceRoot":"","sources":["../src/formatDuration.ts"],"names":[],"mappings":";;;AAAA,SAAgB,cAAc,CAAC,OAAe;IAC5C,IAAI,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,GAAG,GAAG,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAC;KAClC;SAAM;QACL,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,GAAG,OAAO,GAAG,CAAC;KACtB;AACH,CAAC;AAVD,wCAUC;AAED,SAAgB,WAAW,CAAC,MAAwB;IAClD,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC;AAHD,kCAGC"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NpmScriptRunner = exports.SimpleScheduler = void 0;
|
|
4
|
+
var SimpleScheduler_1 = require("./SimpleScheduler");
|
|
5
|
+
Object.defineProperty(exports, "SimpleScheduler", { enumerable: true, get: function () { return SimpleScheduler_1.SimpleScheduler; } });
|
|
6
|
+
var NpmScriptRunner_1 = require("./runners/NpmScriptRunner");
|
|
7
|
+
Object.defineProperty(exports, "NpmScriptRunner", { enumerable: true, get: function () { return NpmScriptRunner_1.NpmScriptRunner; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AAExB,6DAA4D;AAAnD,kHAAA,eAAe,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoOpRunner.js","sourceRoot":"","sources":["../../src/runners/NoOpRunner.ts"],"names":[],"mappings":";;;AAEa,QAAA,UAAU,GAAiB;IACtC,KAAK,CAAC,GAAG,CAAC,OAAO,IAAG,CAAC;CACtB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AbortSignal } from "abort-controller";
|
|
2
|
+
import { Logger } from "@lage-run/logger";
|
|
3
|
+
import { TargetRunner } from "../types/TargetRunner";
|
|
4
|
+
import type { Target } from "@lage-run/target-graph";
|
|
5
|
+
export interface NpmScriptRunnerOptions {
|
|
6
|
+
logger: Logger;
|
|
7
|
+
taskArgs: string[];
|
|
8
|
+
nodeOptions: string;
|
|
9
|
+
npmCmd: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Runs a npm script on a target.
|
|
13
|
+
*
|
|
14
|
+
* Requires target to have a packageName, and a task.
|
|
15
|
+
*
|
|
16
|
+
* This class deals with these concepts:
|
|
17
|
+
*
|
|
18
|
+
* 1. Spawning the npm client.
|
|
19
|
+
* 2. Generates npm command line arguments
|
|
20
|
+
* 3. Handling exit & error events from child process.
|
|
21
|
+
* 4. Stream stdout & stderr from child process to a logger.
|
|
22
|
+
* 5. Handling the abort controller signal - kills the child process if started.
|
|
23
|
+
* 6. injecting these environment variables into the child process:
|
|
24
|
+
* - LAGE_PACKAGE_NAME - the name of the package
|
|
25
|
+
* - LAGE_TASK - the name of the task
|
|
26
|
+
* - NODE_OPTIONS - the node options to use when spawning the child process
|
|
27
|
+
* - FORCE_COLOR - set to "1" detect that this is a TTY
|
|
28
|
+
*/
|
|
29
|
+
export declare class NpmScriptRunner implements TargetRunner {
|
|
30
|
+
private options;
|
|
31
|
+
static gracefulKillTimeout: number;
|
|
32
|
+
constructor(options: NpmScriptRunnerOptions);
|
|
33
|
+
private getNpmArgs;
|
|
34
|
+
private hasNpmScript;
|
|
35
|
+
private validateOptions;
|
|
36
|
+
run(target: Target, abortSignal?: AbortSignal): Promise<void>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NpmScriptRunner = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const logger_1 = require("@lage-run/logger");
|
|
8
|
+
const promises_1 = require("fs/promises");
|
|
9
|
+
/**
|
|
10
|
+
* Runs a npm script on a target.
|
|
11
|
+
*
|
|
12
|
+
* Requires target to have a packageName, and a task.
|
|
13
|
+
*
|
|
14
|
+
* This class deals with these concepts:
|
|
15
|
+
*
|
|
16
|
+
* 1. Spawning the npm client.
|
|
17
|
+
* 2. Generates npm command line arguments
|
|
18
|
+
* 3. Handling exit & error events from child process.
|
|
19
|
+
* 4. Stream stdout & stderr from child process to a logger.
|
|
20
|
+
* 5. Handling the abort controller signal - kills the child process if started.
|
|
21
|
+
* 6. injecting these environment variables into the child process:
|
|
22
|
+
* - LAGE_PACKAGE_NAME - the name of the package
|
|
23
|
+
* - LAGE_TASK - the name of the task
|
|
24
|
+
* - NODE_OPTIONS - the node options to use when spawning the child process
|
|
25
|
+
* - FORCE_COLOR - set to "1" detect that this is a TTY
|
|
26
|
+
*/
|
|
27
|
+
class NpmScriptRunner {
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.options = options;
|
|
30
|
+
this.validateOptions(options);
|
|
31
|
+
}
|
|
32
|
+
getNpmArgs(task, taskTargs) {
|
|
33
|
+
const extraArgs = taskTargs.length > 0 ? ["--", ...taskTargs] : [];
|
|
34
|
+
return ["run", task, ...extraArgs];
|
|
35
|
+
}
|
|
36
|
+
async hasNpmScript(target) {
|
|
37
|
+
var _a;
|
|
38
|
+
const { task } = target;
|
|
39
|
+
const packageJsonPath = (0, path_1.join)(target.cwd, "package.json");
|
|
40
|
+
const packageJson = JSON.parse(await (0, promises_1.readFile)(packageJsonPath, "utf8"));
|
|
41
|
+
return (_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a[task];
|
|
42
|
+
}
|
|
43
|
+
validateOptions(options) {
|
|
44
|
+
if (!(0, fs_1.existsSync)(options.npmCmd)) {
|
|
45
|
+
throw new Error(`NPM Script Runner: ${this.options.npmCmd} does not exist`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async run(target, abortSignal) {
|
|
49
|
+
var _a;
|
|
50
|
+
const { logger, nodeOptions, npmCmd, taskArgs } = this.options;
|
|
51
|
+
let childProcess;
|
|
52
|
+
// By convention, do not run anything if there is no script for this task defined in package.json (counts as "success")
|
|
53
|
+
if (!(await this.hasNpmScript(target))) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Handling abort signal from the abort controller. Gracefully kills the process,
|
|
58
|
+
* will be handled by exit handler separately to resolve the promise.
|
|
59
|
+
*/
|
|
60
|
+
if (abortSignal) {
|
|
61
|
+
if (abortSignal.aborted) {
|
|
62
|
+
return Promise.resolve();
|
|
63
|
+
}
|
|
64
|
+
const abortSignalHandler = () => {
|
|
65
|
+
abortSignal.removeEventListener("abort", abortSignalHandler);
|
|
66
|
+
if (childProcess && !childProcess.killed) {
|
|
67
|
+
const pid = childProcess.pid;
|
|
68
|
+
logger.verbose(`Abort signal detected, attempting to killing process id ${pid}`, { target, pid });
|
|
69
|
+
childProcess.kill("SIGTERM");
|
|
70
|
+
// wait for "gracefulKillTimeout" to make sure everything is terminated via SIGKILL
|
|
71
|
+
const t = setTimeout(() => {
|
|
72
|
+
if (childProcess && !childProcess.killed) {
|
|
73
|
+
childProcess.kill("SIGKILL");
|
|
74
|
+
}
|
|
75
|
+
}, NpmScriptRunner.gracefulKillTimeout);
|
|
76
|
+
// Remember that even this timeout needs to be unref'ed, otherwise the process will hang due to this timeout
|
|
77
|
+
if (t.unref) {
|
|
78
|
+
t.unref();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
abortSignal.addEventListener("abort", abortSignalHandler);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Actually spawn the npm client to run the task
|
|
86
|
+
*/
|
|
87
|
+
const npmRunArgs = this.getNpmArgs(target.task, taskArgs);
|
|
88
|
+
const npmRunNodeOptions = [nodeOptions, (_a = target.options) === null || _a === void 0 ? void 0 : _a.nodeOptions].filter((str) => str).join(" ");
|
|
89
|
+
await new Promise((resolve, reject) => {
|
|
90
|
+
childProcess = (0, child_process_1.spawn)(npmCmd, npmRunArgs, {
|
|
91
|
+
cwd: target.cwd,
|
|
92
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
93
|
+
env: Object.assign(Object.assign(Object.assign(Object.assign({}, process.env), (process.stdout.isTTY && { FORCE_COLOR: "1" })), (npmRunNodeOptions && { NODE_OPTIONS: npmRunNodeOptions })), { LAGE_PACKAGE_NAME: target.packageName, LAGE_TASK: target.task }),
|
|
94
|
+
});
|
|
95
|
+
let exitHandled = false;
|
|
96
|
+
const handleChildProcessExit = (code, signal) => {
|
|
97
|
+
var _a, _b, _c;
|
|
98
|
+
childProcess === null || childProcess === void 0 ? void 0 : childProcess.off("exit", handleChildProcessExit);
|
|
99
|
+
childProcess === null || childProcess === void 0 ? void 0 : childProcess.off("error", handleChildProcessExit);
|
|
100
|
+
if (exitHandled) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
exitHandled = true;
|
|
104
|
+
(_a = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stdout) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
105
|
+
(_b = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stderr) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
106
|
+
(_c = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stdin) === null || _c === void 0 ? void 0 : _c.destroy();
|
|
107
|
+
if (code === 0) {
|
|
108
|
+
return resolve();
|
|
109
|
+
}
|
|
110
|
+
reject();
|
|
111
|
+
};
|
|
112
|
+
const { pid } = childProcess;
|
|
113
|
+
logger.verbose(`Running ${[npmCmd, ...npmRunArgs].join(" ")}, pid: ${pid}`, { target, pid });
|
|
114
|
+
logger.stream(logger_1.LogLevel.verbose, childProcess.stdout, { target, pid });
|
|
115
|
+
logger.stream(logger_1.LogLevel.verbose, childProcess.stderr, { target, pid });
|
|
116
|
+
childProcess.on("exit", handleChildProcessExit);
|
|
117
|
+
childProcess.on("error", () => handleChildProcessExit(1));
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.NpmScriptRunner = NpmScriptRunner;
|
|
122
|
+
NpmScriptRunner.gracefulKillTimeout = 2500;
|
|
123
|
+
//# sourceMappingURL=NpmScriptRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NpmScriptRunner.js","sourceRoot":"","sources":["../../src/runners/NpmScriptRunner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function findNpmClient(npmClient: string): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findNpmClient = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
function findNpmClient(npmClient) {
|
|
10
|
+
const found = findInPath(npmClient);
|
|
11
|
+
if (!found) {
|
|
12
|
+
throw new Error(`npm client not found: ${npmClient}`);
|
|
13
|
+
}
|
|
14
|
+
return found;
|
|
15
|
+
}
|
|
16
|
+
exports.findNpmClient = findNpmClient;
|
|
17
|
+
function findInPath(target) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
const envPath = (_a = process.env.PATH) !== null && _a !== void 0 ? _a : "";
|
|
20
|
+
const pathExt = (_b = process.env.PATHEXT) !== null && _b !== void 0 ? _b : "";
|
|
21
|
+
for (const search of envPath.split(path_1.default.delimiter)) {
|
|
22
|
+
const found = pathExt
|
|
23
|
+
.split(path_1.default.delimiter)
|
|
24
|
+
.map((ext) => path_1.default.join(search, `${target}${ext}`))
|
|
25
|
+
.find((p) => fs_1.default.existsSync(p));
|
|
26
|
+
if (found) {
|
|
27
|
+
return found;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=findNpmClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findNpmClient.js","sourceRoot":"","sources":["../../../src/runners/workspace/findNpmClient.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AACxB,4CAAoB;AAEpB,SAAgB,aAAa,CAAC,SAAiB;IAC7C,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAEpC,IAAI,CAAC,KAAK,EAAE;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,EAAE,CAAC,CAAC;KACvD;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AARD,sCAQC;AAED,SAAS,UAAU,CAAC,MAAc;;IAChC,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,OAAO,mCAAI,EAAE,CAAC;IAE1C,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,cAAI,CAAC,SAAS,CAAC,EAAE;QAClD,MAAM,KAAK,GAAG,OAAO;aAClB,KAAK,CAAC,cAAI,CAAC,SAAS,CAAC;aACrB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC;aAClD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjC,IAAI,KAAK,EAAE;YACT,OAAO,KAAK,CAAC;SACd;KACF;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Target } from "@lage-run/target-graph";
|
|
2
|
+
import { TargetRunner } from "./TargetRunner";
|
|
3
|
+
import { TargetStatus } from "./TargetStatus";
|
|
4
|
+
export interface TargetRunContext {
|
|
5
|
+
startTime: [number, number];
|
|
6
|
+
duration: [number, number];
|
|
7
|
+
target: Target;
|
|
8
|
+
status: TargetStatus;
|
|
9
|
+
run(runner: TargetRunner): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TargetRunContext.js","sourceRoot":"","sources":["../../src/types/TargetRunContext.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TargetRunner.js","sourceRoot":"","sources":["../../src/types/TargetRunner.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TargetGraph } from "@lage-run/target-graph";
|
|
2
|
+
import { TargetRunContext } from "./TargetRunContext";
|
|
3
|
+
export interface TargetScheduler {
|
|
4
|
+
targetRunContexts: Map<string, TargetRunContext>;
|
|
5
|
+
abort(): void;
|
|
6
|
+
run(root: string, targetGraph: TargetGraph): Promise<TargetScheduler["targetRunContexts"]>;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TargetScheduler.js","sourceRoot":"","sources":["../../src/types/TargetScheduler.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare type TargetStatus = "pending" | "running" | "success" | "failed" | "skipped" | "aborted";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TargetStatus.js","sourceRoot":"","sources":["../../src/types/TargetStatus.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lage-run/scheduler",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Scheduler for Lage",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/microsoft/lage"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"types": "lib/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "monorepo-scripts tsc",
|
|
13
|
+
"start": "monorepo-scripts tsc -w --preserveWatchOutput",
|
|
14
|
+
"test": "monorepo-scripts jest",
|
|
15
|
+
"lint": "monorepo-scripts lint"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@lage-run/target-graph": "^0.2.0",
|
|
19
|
+
"@lage-run/logger": "^1.1.0",
|
|
20
|
+
"@lage-run/cache": "^0.1.1",
|
|
21
|
+
"p-graph": "^1.1.1",
|
|
22
|
+
"p-profiler": "^0.2.1",
|
|
23
|
+
"abort-controller": "^3.0.0",
|
|
24
|
+
"workspace-tools": "^0.23.3"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@lage-run/monorepo-fixture": "^0.1.0",
|
|
28
|
+
"@types/jest": "^27.0.1",
|
|
29
|
+
"@types/node": "^14.0.0",
|
|
30
|
+
"monorepo-scripts": "*"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ts-node": {
|
|
3
|
+
"transpileOnly": true
|
|
4
|
+
},
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"target": "ES2017",
|
|
7
|
+
"module": "CommonJS",
|
|
8
|
+
"moduleResolution": "Node",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"lib": ["ES2017"],
|
|
11
|
+
"allowJs": true,
|
|
12
|
+
"outDir": "./lib",
|
|
13
|
+
"strict": true,
|
|
14
|
+
"noImplicitAny": false,
|
|
15
|
+
"allowSyntheticDefaultImports": true,
|
|
16
|
+
"esModuleInterop": true,
|
|
17
|
+
"forceConsistentCasingInFileNames": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"noUnusedLocals": false,
|
|
20
|
+
"sourceMap": true
|
|
21
|
+
},
|
|
22
|
+
"include": ["src"]
|
|
23
|
+
}
|