hammerkit 1.4.0 → 1.5.0-alpha.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/.devcontainer/Dockerfile +5 -0
- package/.devcontainer/devcontainer.json +40 -0
- package/README.md +13 -86
- package/SUMMARY.md +43 -0
- package/build.schema.json +56 -2
- package/dist/cli.js +97 -0
- package/dist/cli.spec.js +5 -0
- package/dist/console/console-context-mock.js +11 -0
- package/dist/console/get-logger.js +23 -0
- package/dist/docker/pull.js +5 -5
- package/dist/docker/remove-container.js +21 -0
- package/dist/docker/stream.js +14 -10
- package/dist/docker/using-container.js +28 -0
- package/dist/environment/get-process-env.js +4 -4
- package/dist/environment/replace-env-variables.js +2 -3
- package/dist/executer/abort.js +13 -0
- package/dist/executer/check-readiness.js +25 -0
- package/dist/executer/create-scheduler-state.js +32 -0
- package/dist/executer/docker-node.js +123 -0
- package/dist/executer/docker-service.js +113 -0
- package/dist/executer/environment-mock.js +17 -0
- package/dist/executer/event-cache.js +165 -0
- package/dist/executer/execute-command.js +42 -0
- package/dist/executer/execute-docker.js +58 -194
- package/dist/executer/execute.spec.js +37 -37
- package/dist/executer/execution-steps.js +57 -0
- package/dist/executer/get-docker-executor.js +6 -100
- package/dist/executer/hierarchy-scheduler.js +94 -0
- package/dist/executer/kubernetes-service.js +64 -0
- package/dist/executer/label-values.js +65 -0
- package/dist/executer/local-node.js +57 -0
- package/dist/executer/print-container-options.js +17 -0
- package/dist/{logging/log-strategy.js → executer/process-item.js} +1 -1
- package/dist/executer/process-listener.js +3 -0
- package/dist/executer/process-manager.js +111 -0
- package/dist/executer/process-manager.spec.js +91 -0
- package/dist/executer/{executor.js → process.js} +1 -1
- package/dist/executer/{execute-result.js → readonly-state.js} +1 -1
- package/dist/executer/schedule.js +139 -0
- package/dist/executer/scheduler/check-for-loop.js +21 -0
- package/dist/executer/scheduler/enqueue-next.js +27 -0
- package/dist/{testing/test-context.js → executer/scheduler/node-state.js} +1 -1
- package/dist/executer/scheduler/scheduler-result.js +3 -0
- package/dist/executer/scheduler/scheduler-state.js +3 -0
- package/dist/executer/scheduler/service-state.js +3 -0
- package/dist/executer/service-dns.js +6 -0
- package/dist/executer/set-user-permission.js +16 -0
- package/dist/executer/start-node.js +59 -0
- package/dist/executer/state-listener.js +3 -0
- package/dist/executer/state.js +49 -0
- package/dist/executer/states.js +4 -159
- package/dist/executer/watch-node.js +57 -0
- package/dist/executer/watch-service.js +54 -0
- package/dist/executer/work-scope.js +10 -0
- package/dist/file/get-file-context-mock.spec.js +5 -5
- package/dist/file/get-file-context.js +41 -18
- package/dist/file/move-files.js +1 -1
- package/dist/get-work-context.js +29 -0
- package/dist/index.js +8 -4
- package/dist/log.js +192 -50
- package/dist/logging/grouped-logger.js +31 -19
- package/dist/logging/interactive-logger.js +20 -23
- package/dist/logging/live-logger.js +7 -17
- package/dist/optimizer/calculate-checksum.js +1 -1
- package/dist/optimizer/get-cache-directory.js +8 -13
- package/dist/optimizer/get-work-node-cache-stats.js +68 -21
- package/dist/optimizer/read-work-node-cache.js +2 -2
- package/dist/optimizer/work-node-cache-description.js +12 -11
- package/dist/optimizer/write-work-node-cache.js +9 -8
- package/dist/{executer/execution-context.js → parser/build-file-service.js} +1 -1
- package/dist/{optimizer → parser}/cache-method.js +0 -0
- package/dist/parser/get-build-file.js +1 -1
- package/dist/parser/parse-boolean.js +29 -0
- package/dist/parser/parse-boolean.spec.js +48 -0
- package/dist/parser/parse-build-file-references.js +2 -2
- package/dist/parser/parse-build-file-services.js +58 -0
- package/dist/parser/parse-build-file-task-command.js +6 -5
- package/dist/parser/parse-build-file-task-source.js +5 -5
- package/dist/parser/parse-build-file.js +27 -15
- package/dist/parser/parse-context.js +13 -0
- package/dist/parser/parse-envs.js +4 -3
- package/dist/parser/parse-healthcheck.js +28 -0
- package/dist/parser/parse-label-arguments.js +23 -0
- package/dist/parser/parse-service-selector.js +39 -0
- package/dist/parser/parse-string-array.js +6 -5
- package/dist/parser/parse-string-map.js +30 -0
- package/dist/parser/parse-string.js +20 -0
- package/dist/parser/read-build-file.js +16 -5
- package/dist/parser/read-env-file.js +3 -3
- package/dist/planner/utils/get-container-mounts.js +24 -0
- package/dist/planner/utils/normalize-path.js +17 -0
- package/dist/planner/utils/parse-work-node-mount.js +3 -14
- package/dist/planner/utils/parse-work-node-mount.spec.js +10 -10
- package/dist/planner/utils/parse-work-service-volume.js +21 -0
- package/dist/planner/utils/plan-work-command.js +1 -1
- package/dist/planner/utils/plan-work-dependency.js +17 -5
- package/dist/planner/utils/plan-work-node.js +203 -128
- package/dist/planner/utils/plan-work-nodes.js +59 -14
- package/dist/planner/utils/plan-work-tree.js +8 -4
- package/dist/planner/utils/plan-work-volume.js +25 -0
- package/dist/planner/validate.js +56 -8
- package/dist/planner/work-context.js +20 -0
- package/dist/planner/work-mount.js +3 -0
- package/dist/planner/work-node-id.js +4 -4
- package/dist/planner/work-node-id.spec.js +11 -8
- package/dist/planner/work-node-path.js +0 -1
- package/dist/planner/work-node-status.js +121 -18
- package/dist/planner/work-node.js +3 -3
- package/dist/planner/work-service-id.js +13 -0
- package/dist/planner/work-service-volume.js +3 -0
- package/dist/planner/work-service.js +6 -0
- package/dist/planner/work-services.js +3 -0
- package/dist/planner/work-volume.js +3 -0
- package/dist/program.js +155 -90
- package/dist/program.spec.js +20 -0
- package/dist/start-watch-processes.js +28 -0
- package/dist/testing/cli.js +73 -0
- package/dist/testing/create-build-file.js +1 -1
- package/dist/testing/example-test-suite.js +54 -0
- package/dist/testing/expect.js +30 -18
- package/dist/testing/get-logger.js +23 -0
- package/dist/testing/get-node.js +2 -2
- package/dist/testing/get-test-context.js +5 -3
- package/dist/testing/get-test-suite.js +2 -50
- package/dist/testing/integration/cache.spec.js +25 -28
- package/dist/testing/integration/cancellation.spec.js +19 -21
- package/dist/testing/integration/clean.spec.js +25 -28
- package/dist/testing/integration/cmd.spec.js +5 -8
- package/dist/testing/integration/concurrency.spec.js +8 -17
- package/dist/testing/integration/docker.spec.js +6 -9
- package/dist/testing/integration/env.spec.js +27 -34
- package/dist/testing/integration/error.spec.js +5 -9
- package/dist/testing/integration/extend.spec.js +32 -0
- package/dist/testing/integration/glob.spec.js +35 -28
- package/dist/testing/integration/include.spec.js +17 -16
- package/dist/testing/integration/invalid.spec.js +3 -2
- package/dist/testing/integration/invalid_loop.spec.js +13 -0
- package/dist/testing/integration/kubernetes.spec.js +15 -0
- package/dist/testing/integration/labels.spec.js +47 -0
- package/dist/testing/integration/local.spec.js +4 -7
- package/dist/testing/integration/monorepo.spec.js +5 -9
- package/dist/testing/integration/multi-line.spec.js +4 -4
- package/dist/testing/integration/program.spec.js +3 -10
- package/dist/testing/integration/reference.spec.js +10 -13
- package/dist/testing/integration/services.spec.js +14 -0
- package/dist/testing/integration/store.spec.js +42 -38
- package/dist/testing/integration/unknown.spec.js +4 -4
- package/dist/testing/integration/validate.spec.js +4 -4
- package/dist/testing/integration/watch.spec.js +34 -33
- package/dist/testing/lazy.js +17 -0
- package/dist/testing/start-watch-processes.js +29 -0
- package/dist/testing/test-suite-setup.js +3 -0
- package/dist/utils/abort-event.js +14 -1
- package/dist/utils/abortable-function.js +71 -0
- package/dist/utils/debouncer.spec.js +8 -8
- package/dist/utils/environment-config.js +13 -0
- package/dist/utils/fail-never.js +1 -1
- package/dist/utils/sleep.spec.js +3 -3
- package/package.json +24 -21
- package/dist/console/get-console-context-mock.js +0 -33
- package/dist/executer/clean.js +0 -17
- package/dist/executer/execute-local.js +0 -59
- package/dist/executer/execute.js +0 -139
- package/dist/executer/execution-context-event.js +0 -3
- package/dist/executer/execution-context-mock.js +0 -3
- package/dist/executer/executor-mock.js +0 -61
- package/dist/executer/get-environment-mock.js +0 -16
- package/dist/executer/get-execution-context-mock.js +0 -18
- package/dist/executer/get-local-executor.js +0 -56
- package/dist/executer/restore.js +0 -19
- package/dist/executer/store.js +0 -19
- package/dist/logging/get-logger.js +0 -23
- package/dist/logging/message-to-console.js +0 -16
- package/dist/optimizer/optimize.js +0 -32
- package/dist/optimizer/work-node-description.js +0 -12
- package/dist/planner/utils/find-build-task.js +0 -18
- package/dist/testing/create-work-tree.js +0 -11
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startService = exports.startNode = void 0;
|
|
4
|
+
const enqueue_next_1 = require("./scheduler/enqueue-next");
|
|
5
|
+
const states_1 = require("./states");
|
|
6
|
+
const work_service_1 = require("../planner/work-service");
|
|
7
|
+
const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
|
|
8
|
+
async function startNode(node, state, environment) {
|
|
9
|
+
const cacheState = await (0, enqueue_next_1.checkCacheState)(node.node, state.current.cacheMethod, environment);
|
|
10
|
+
const currentState = state.current.node[node.node.id];
|
|
11
|
+
if (!!currentState.stateKey && currentState.stateKey !== cacheState.stateKey) {
|
|
12
|
+
const status = environment.status.task(node.node);
|
|
13
|
+
status.write('debug', `cache check for ${node.node.name} no longer valid, skipping result`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (cacheState.cached) {
|
|
17
|
+
state.patchNode({
|
|
18
|
+
type: 'completed',
|
|
19
|
+
node: node.node,
|
|
20
|
+
cached: true,
|
|
21
|
+
stateKey: cacheState.stateKey,
|
|
22
|
+
duration: currentState.type === 'starting' ? (0, states_1.getDuration)(currentState.started) : 0,
|
|
23
|
+
}, node.stateKey);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
state.patchNode({
|
|
27
|
+
type: 'ready',
|
|
28
|
+
node: node.node,
|
|
29
|
+
stateKey: cacheState.stateKey,
|
|
30
|
+
started: currentState.type === 'starting' ? currentState.started : new Date(),
|
|
31
|
+
}, node.stateKey);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.startNode = startNode;
|
|
35
|
+
async function startService(service, state, environment) {
|
|
36
|
+
if (!(0, work_service_1.isContainerWorkService)(service)) {
|
|
37
|
+
state.patchService({
|
|
38
|
+
type: 'ready',
|
|
39
|
+
service,
|
|
40
|
+
stateKey: '', // TODO statekey from kube config
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const fileStats = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
|
|
45
|
+
const fileStateKey = (0, get_work_node_cache_stats_1.getStateKey)(fileStats, 'checksum');
|
|
46
|
+
const currentState = state.current.service[service.id];
|
|
47
|
+
if (!!currentState.stateKey && currentState.stateKey !== fileStateKey) {
|
|
48
|
+
const status = environment.status.service(service);
|
|
49
|
+
status.write('debug', `cache check for ${service.name} no longer valid, skipping result`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
state.patchService({
|
|
53
|
+
type: 'ready',
|
|
54
|
+
service,
|
|
55
|
+
stateKey: fileStateKey,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
exports.startService = startService;
|
|
59
|
+
//# sourceMappingURL=start-node.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.State = void 0;
|
|
4
|
+
class State {
|
|
5
|
+
constructor(current) {
|
|
6
|
+
this.current = current;
|
|
7
|
+
this.listeners = [];
|
|
8
|
+
}
|
|
9
|
+
assignState(state, newValue) {
|
|
10
|
+
const currentKeys = Object.keys(state);
|
|
11
|
+
const newKeys = Object.keys(newValue);
|
|
12
|
+
const keysToRemove = currentKeys.filter((k) => newKeys.indexOf(k) === -1);
|
|
13
|
+
for (const key of keysToRemove) {
|
|
14
|
+
delete state[key];
|
|
15
|
+
}
|
|
16
|
+
for (const key of newKeys) {
|
|
17
|
+
state[key] = newValue[key];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
resetNode(newState) {
|
|
21
|
+
const state = this.current.node[newState.node.id];
|
|
22
|
+
this.assignState(state, newState);
|
|
23
|
+
this.notifyListeners(this.current);
|
|
24
|
+
return state;
|
|
25
|
+
}
|
|
26
|
+
patchNode(newState, stateKey) {
|
|
27
|
+
const state = this.current.node[newState.node.id];
|
|
28
|
+
if (state.stateKey === stateKey) {
|
|
29
|
+
this.assignState(state, newState);
|
|
30
|
+
this.notifyListeners(this.current);
|
|
31
|
+
}
|
|
32
|
+
return state;
|
|
33
|
+
}
|
|
34
|
+
patchService(newState) {
|
|
35
|
+
this.assignState(this.current.service[newState.service.id], newState);
|
|
36
|
+
this.notifyListeners(this.current);
|
|
37
|
+
}
|
|
38
|
+
on(listener) {
|
|
39
|
+
this.listeners.push(listener);
|
|
40
|
+
listener(this.current);
|
|
41
|
+
}
|
|
42
|
+
notifyListeners(evt) {
|
|
43
|
+
for (const listener of this.listeners) {
|
|
44
|
+
listener(evt);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.State = State;
|
|
49
|
+
//# sourceMappingURL=state.js.map
|
package/dist/executer/states.js
CHANGED
|
@@ -1,163 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function getDuration(state) {
|
|
7
|
-
if (state.type === 'running') {
|
|
8
|
-
return new Date().getTime() - state.started.getTime();
|
|
9
|
-
}
|
|
10
|
-
return 0;
|
|
3
|
+
exports.getDuration = void 0;
|
|
4
|
+
function getDuration(started) {
|
|
5
|
+
return new Date().getTime() - started.getTime();
|
|
11
6
|
}
|
|
12
|
-
|
|
13
|
-
const runningState = {
|
|
14
|
-
type: 'running',
|
|
15
|
-
started: new Date(),
|
|
16
|
-
abortCtrl: new AbortController(),
|
|
17
|
-
};
|
|
18
|
-
abort_event_1.listenOnAbort(context.environment.abortCtrl.signal, () => {
|
|
19
|
-
runningState.abortCtrl.abort();
|
|
20
|
-
});
|
|
21
|
-
const currentState = workTree.nodes[nodeId].status.state;
|
|
22
|
-
workTree.nodes[nodeId].status.state = runningState;
|
|
23
|
-
context.events.emit({ oldState: currentState, newState: runningState, nodeId, workTree });
|
|
24
|
-
return runningState.abortCtrl;
|
|
25
|
-
}
|
|
26
|
-
exports.runNode = runNode;
|
|
27
|
-
function completeNode(workTree, nodeId, context) {
|
|
28
|
-
const node = workTree.nodes[nodeId];
|
|
29
|
-
const currentState = node.status.state;
|
|
30
|
-
const completedState = {
|
|
31
|
-
type: 'completed',
|
|
32
|
-
ended: new Date(),
|
|
33
|
-
duration: getDuration(currentState),
|
|
34
|
-
};
|
|
35
|
-
node.status.state = completedState;
|
|
36
|
-
if (!context.watch && !node.status.defer.signal.aborted) {
|
|
37
|
-
node.status.defer.abort();
|
|
38
|
-
}
|
|
39
|
-
context.events.emit({ oldState: currentState, newState: completedState, nodeId, workTree });
|
|
40
|
-
for (const otherNode of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
|
|
41
|
-
if (otherNode.status.state.type !== 'pending') {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const pendingDependencies = otherNode.status.state.pendingDependencies;
|
|
45
|
-
const dependency = pendingDependencies[node.id];
|
|
46
|
-
if (!dependency) {
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
const newState = {
|
|
50
|
-
type: 'pending',
|
|
51
|
-
pendingDependencies: Object.keys(pendingDependencies).reduce((map, key) => {
|
|
52
|
-
if (pendingDependencies[key].status.state.type !== 'completed') {
|
|
53
|
-
map[key] = pendingDependencies[key];
|
|
54
|
-
}
|
|
55
|
-
return map;
|
|
56
|
-
}, {}),
|
|
57
|
-
};
|
|
58
|
-
const evt = {
|
|
59
|
-
oldState: otherNode.status.state,
|
|
60
|
-
nodeId: otherNode.id,
|
|
61
|
-
workTree,
|
|
62
|
-
newState,
|
|
63
|
-
};
|
|
64
|
-
otherNode.status.state = newState;
|
|
65
|
-
context.events.emit(evt);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
exports.completeNode = completeNode;
|
|
69
|
-
function failNode(workTree, nodeId, context, error) {
|
|
70
|
-
const node = workTree.nodes[nodeId];
|
|
71
|
-
node.status.console.write('internal', 'error', error.message);
|
|
72
|
-
const canceledExecution = context.environment.abortCtrl.signal.aborted;
|
|
73
|
-
const currentState = node.status.state;
|
|
74
|
-
if (currentState.type === 'running') {
|
|
75
|
-
const newState = canceledExecution
|
|
76
|
-
? { type: 'aborted' }
|
|
77
|
-
: { type: 'failed', ended: new Date(), duration: getDuration(node.status.state), error };
|
|
78
|
-
node.status.state = newState;
|
|
79
|
-
context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
|
|
80
|
-
}
|
|
81
|
-
else if (currentState.type === 'cancel') {
|
|
82
|
-
const newState = canceledExecution ? { type: 'aborted' } : getPendingState(node);
|
|
83
|
-
node.status.state = newState;
|
|
84
|
-
context.events.emit({ nodeId: node.id, workTree, newState, oldState: currentState });
|
|
85
|
-
}
|
|
86
|
-
if (!canceledExecution && !context.watch) {
|
|
87
|
-
cancelPendingNodes(workTree, nodeId, context);
|
|
88
|
-
}
|
|
89
|
-
if ((canceledExecution || !context.watch) && !node.status.defer.signal.aborted) {
|
|
90
|
-
node.status.defer.abort();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
exports.failNode = failNode;
|
|
94
|
-
function getPendingState(node) {
|
|
95
|
-
return {
|
|
96
|
-
type: 'pending',
|
|
97
|
-
pendingDependencies: node.deps.reduce((map, dep) => {
|
|
98
|
-
if (dep.status.state.type !== 'completed') {
|
|
99
|
-
map[dep.id] = dep;
|
|
100
|
-
}
|
|
101
|
-
return map;
|
|
102
|
-
}, {}),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
function resetNode(workTree, nodeId, context) {
|
|
106
|
-
const node = workTree.nodes[nodeId];
|
|
107
|
-
const currentState = node.status.state;
|
|
108
|
-
if (currentState.type === 'running') {
|
|
109
|
-
const cancelState = { type: 'cancel' };
|
|
110
|
-
node.status.state = cancelState;
|
|
111
|
-
currentState.abortCtrl.abort();
|
|
112
|
-
context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
|
|
113
|
-
}
|
|
114
|
-
else if (currentState.type === 'completed' || currentState.type === 'failed') {
|
|
115
|
-
const pendingState = getPendingState(node);
|
|
116
|
-
node.status.state = pendingState;
|
|
117
|
-
context.events.emit({ workTree, nodeId, oldState: currentState, newState: pendingState });
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
exports.resetNode = resetNode;
|
|
121
|
-
function cancelPendingNodes(workTree, nodeId, context) {
|
|
122
|
-
for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
|
|
123
|
-
if (node.status.state.type !== 'pending') {
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (!node.status.state.pendingDependencies[nodeId]) {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const currentState = node.status.state;
|
|
130
|
-
if (currentState.type === 'pending') {
|
|
131
|
-
const cancelState = { type: 'cancel' };
|
|
132
|
-
node.status.state = cancelState;
|
|
133
|
-
context.events.emit({ workTree, nodeId, oldState: currentState, newState: cancelState });
|
|
134
|
-
if (!context.watch) {
|
|
135
|
-
node.status.defer.abort();
|
|
136
|
-
}
|
|
137
|
-
cancelPendingNodes(workTree, node.id, context);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function cancelNodes(workTree, context) {
|
|
142
|
-
for (const node of plan_work_nodes_1.iterateWorkNodes(workTree.nodes)) {
|
|
143
|
-
const currentState = node.status.state;
|
|
144
|
-
if (currentState.type === 'pending') {
|
|
145
|
-
const abortState = { type: 'aborted' };
|
|
146
|
-
node.status.state = abortState;
|
|
147
|
-
node.status.defer.abort();
|
|
148
|
-
context.events.emit({ nodeId: node.id, workTree, newState: abortState, oldState: currentState });
|
|
149
|
-
}
|
|
150
|
-
else if (currentState.type === 'running') {
|
|
151
|
-
const cancelState = { type: 'cancel' };
|
|
152
|
-
node.status.state = cancelState;
|
|
153
|
-
currentState.abortCtrl.abort();
|
|
154
|
-
context.events.emit({ workTree, nodeId: node.id, oldState: currentState, newState: cancelState });
|
|
155
|
-
}
|
|
156
|
-
else if ((currentState.type === 'completed' || currentState.type === 'failed') &&
|
|
157
|
-
!node.status.defer.signal.aborted) {
|
|
158
|
-
node.status.defer.abort();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
exports.cancelNodes = cancelNodes;
|
|
7
|
+
exports.getDuration = getDuration;
|
|
163
8
|
//# sourceMappingURL=states.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watchNode = void 0;
|
|
4
|
+
const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
|
|
5
|
+
const debouncer_1 = require("../utils/debouncer");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const abort_event_1 = require("../utils/abort-event");
|
|
8
|
+
function watchNode(node, state, processManager, environment) {
|
|
9
|
+
return async (abort) => {
|
|
10
|
+
const status = environment.status.task(node);
|
|
11
|
+
let currentState = await (0, get_work_node_cache_stats_1.getWorkNodeCacheStats)(node, environment);
|
|
12
|
+
const debouncer = new debouncer_1.Debouncer(async () => {
|
|
13
|
+
if (environment.abortCtrl.signal.aborted) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const newStats = await (0, get_work_node_cache_stats_1.getWorkNodeCacheStats)(node, environment);
|
|
17
|
+
const currentFileState = (0, get_work_node_cache_stats_1.getCacheState)(status, { name: node.name, caching: node.caching ?? state.current.cacheMethod }, currentState, newStats);
|
|
18
|
+
currentState = newStats;
|
|
19
|
+
const currentNodeState = state.current.node[node.id];
|
|
20
|
+
if (currentNodeState.stateKey === currentFileState.stateKey) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
status.write('debug', `source changed for node ${node.name}, restart process`);
|
|
24
|
+
state.resetNode({
|
|
25
|
+
type: 'pending',
|
|
26
|
+
node,
|
|
27
|
+
stateKey: currentFileState.stateKey,
|
|
28
|
+
});
|
|
29
|
+
// TODO set dependants as pending
|
|
30
|
+
}, 100);
|
|
31
|
+
const fileWatchers = [];
|
|
32
|
+
const sources = [];
|
|
33
|
+
for (const src of node.src) {
|
|
34
|
+
status.write('debug', `watch ${src.absolutePath} source`);
|
|
35
|
+
const watcher = environment.file.watch(src.absolutePath, async (fileName) => {
|
|
36
|
+
const absoluteFileName = (0, path_1.join)(src.absolutePath, fileName);
|
|
37
|
+
if (src.matcher(absoluteFileName, node.cwd)) {
|
|
38
|
+
status.write('debug', `source ${absoluteFileName} change for watched task ${node.name}`);
|
|
39
|
+
debouncer.bounce();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
sources.push(src.absolutePath);
|
|
43
|
+
fileWatchers.push(watcher);
|
|
44
|
+
}
|
|
45
|
+
await (0, abort_event_1.waitOnAbort)(abort.signal);
|
|
46
|
+
debouncer.clear();
|
|
47
|
+
for (const watcher of fileWatchers) {
|
|
48
|
+
watcher.close();
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
type: 'node-watch-canceled',
|
|
52
|
+
node,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
exports.watchNode = watchNode;
|
|
57
|
+
//# sourceMappingURL=watch-node.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watchService = void 0;
|
|
4
|
+
const get_work_node_cache_stats_1 = require("../optimizer/get-work-node-cache-stats");
|
|
5
|
+
const debouncer_1 = require("../utils/debouncer");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const abort_event_1 = require("../utils/abort-event");
|
|
8
|
+
function watchService(service, state, processManager, environment) {
|
|
9
|
+
return async (abort) => {
|
|
10
|
+
let currentState = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
|
|
11
|
+
const status = environment.status.service(service);
|
|
12
|
+
const debouncer = new debouncer_1.Debouncer(async () => {
|
|
13
|
+
if (environment.abortCtrl.signal.aborted) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const newStats = await (0, get_work_node_cache_stats_1.getServiceNodeCacheStats)(service, environment);
|
|
17
|
+
const currentFileState = (0, get_work_node_cache_stats_1.getCacheState)(status, { name: service.name, caching: state.current.cacheMethod }, currentState, newStats);
|
|
18
|
+
currentState = newStats;
|
|
19
|
+
const currentServiceState = state.current.service[service.id];
|
|
20
|
+
if (currentServiceState.stateKey === currentFileState.stateKey) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
status.write('debug', `source changed for service ${service.name}, restart process`);
|
|
24
|
+
state.patchService({
|
|
25
|
+
type: 'pending',
|
|
26
|
+
service,
|
|
27
|
+
stateKey: currentFileState.stateKey,
|
|
28
|
+
});
|
|
29
|
+
}, 100);
|
|
30
|
+
const fileWatchers = [];
|
|
31
|
+
const mounts = [];
|
|
32
|
+
for (const mount of service.mounts) {
|
|
33
|
+
status.write('debug', `watch ${mount.localPath} mount`);
|
|
34
|
+
const watcher = environment.file.watch(mount.localPath, async (fileName) => {
|
|
35
|
+
const absoluteFileName = (0, path_1.join)(mount.localPath, fileName);
|
|
36
|
+
status.write('debug', `source ${absoluteFileName} change for watched service ${service.name}`);
|
|
37
|
+
debouncer.bounce();
|
|
38
|
+
});
|
|
39
|
+
mounts.push(mount.localPath);
|
|
40
|
+
fileWatchers.push(watcher);
|
|
41
|
+
}
|
|
42
|
+
await (0, abort_event_1.waitOnAbort)(abort.signal);
|
|
43
|
+
debouncer.clear();
|
|
44
|
+
for (const watcher of fileWatchers) {
|
|
45
|
+
watcher.close();
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
type: 'service-watch-canceled',
|
|
49
|
+
service,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.watchService = watchService;
|
|
54
|
+
//# sourceMappingURL=watch-service.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isContextTaskFilter = exports.emptyWorkLabelScope = void 0;
|
|
4
|
+
function emptyWorkLabelScope() {
|
|
5
|
+
return { excludeLabels: {}, filterLabels: {} };
|
|
6
|
+
}
|
|
7
|
+
exports.emptyWorkLabelScope = emptyWorkLabelScope;
|
|
8
|
+
const isContextTaskFilter = (target) => 'taskName' in target;
|
|
9
|
+
exports.isContextTaskFilter = isContextTaskFilter;
|
|
10
|
+
//# sourceMappingURL=work-scope.js.map
|
|
@@ -3,18 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const get_file_context_mock_1 = require("./get-file-context-mock");
|
|
4
4
|
describe('file/get-file-context-mock', () => {
|
|
5
5
|
it('should create directory', async () => {
|
|
6
|
-
const ctx = get_file_context_mock_1.getFileContextMock();
|
|
6
|
+
const ctx = (0, get_file_context_mock_1.getFileContextMock)();
|
|
7
7
|
await ctx.createDirectory('/home/user/repo');
|
|
8
8
|
expect(await ctx.listFiles('/home/user')).toEqual(['repo']);
|
|
9
9
|
});
|
|
10
10
|
it('should list files', async () => {
|
|
11
|
-
const ctx = get_file_context_mock_1.getFileContextMock();
|
|
11
|
+
const ctx = (0, get_file_context_mock_1.getFileContextMock)();
|
|
12
12
|
await ctx.createDirectory('/home/user/repo');
|
|
13
13
|
await ctx.writeFile('/home/user/test', 'abc');
|
|
14
14
|
expect(await ctx.listFiles('/home/user')).toEqual(['repo', 'test']);
|
|
15
15
|
});
|
|
16
16
|
it('should emit listener if file below gets changed', async () => {
|
|
17
|
-
const ctx = get_file_context_mock_1.getFileContextMock();
|
|
17
|
+
const ctx = (0, get_file_context_mock_1.getFileContextMock)();
|
|
18
18
|
await ctx.createDirectory('/home/user/repo');
|
|
19
19
|
await ctx.writeFile('/home/user/test', 'abc');
|
|
20
20
|
await new Promise((resolve) => {
|
|
@@ -27,7 +27,7 @@ describe('file/get-file-context-mock', () => {
|
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
29
|
it('should emit listener if directory below gets created', async () => {
|
|
30
|
-
const ctx = get_file_context_mock_1.getFileContextMock();
|
|
30
|
+
const ctx = (0, get_file_context_mock_1.getFileContextMock)();
|
|
31
31
|
await ctx.createDirectory('/home/user/repo');
|
|
32
32
|
await new Promise((resolve) => {
|
|
33
33
|
const watch = ctx.watch('/home/user', (fileName) => {
|
|
@@ -39,7 +39,7 @@ describe('file/get-file-context-mock', () => {
|
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
it('should not emit listener if directory above gets created', async () => {
|
|
42
|
-
const ctx = get_file_context_mock_1.getFileContextMock();
|
|
42
|
+
const ctx = (0, get_file_context_mock_1.getFileContextMock)();
|
|
43
43
|
await ctx.createDirectory('/home/user/repo');
|
|
44
44
|
await new Promise((resolve, reject) => {
|
|
45
45
|
const watch = ctx.watch('/home/user', () => {
|
|
@@ -16,11 +16,19 @@ function handleCallback(callback) {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
function
|
|
19
|
+
function getAbsolutePath(cwd, path) {
|
|
20
|
+
if ((0, path_1.isAbsolute)(path)) {
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return (0, path_1.join)(cwd, path);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function getFileContext(cwd) {
|
|
20
28
|
return {
|
|
21
29
|
stats(path) {
|
|
22
30
|
return new Promise((resolve, reject) => {
|
|
23
|
-
fs_1.stat(path, (err, stats) => {
|
|
31
|
+
(0, fs_1.stat)(getAbsolutePath(cwd, path), (err, stats) => {
|
|
24
32
|
if (err) {
|
|
25
33
|
reject(err);
|
|
26
34
|
}
|
|
@@ -39,16 +47,25 @@ function getFileContext() {
|
|
|
39
47
|
});
|
|
40
48
|
},
|
|
41
49
|
appendFile(path, content) {
|
|
42
|
-
return handleCallback((cb) => fs_1.appendFile(path, content, cb));
|
|
50
|
+
return handleCallback((cb) => (0, fs_1.appendFile)(getAbsolutePath(cwd, path), content, cb));
|
|
43
51
|
},
|
|
44
52
|
writeFile(path, content) {
|
|
45
|
-
return handleCallback((cb) => fs_1.writeFile(path, content, cb));
|
|
53
|
+
return handleCallback((cb) => (0, fs_1.writeFile)(getAbsolutePath(cwd, path), content, cb));
|
|
54
|
+
},
|
|
55
|
+
async writeStream(path, stream) {
|
|
56
|
+
const writeStream = (0, fs_1.createWriteStream)(path);
|
|
57
|
+
await new Promise((resolve, reject) => {
|
|
58
|
+
stream
|
|
59
|
+
.pipe(writeStream)
|
|
60
|
+
.on('error', (err) => reject(err))
|
|
61
|
+
.on('close', () => resolve());
|
|
62
|
+
});
|
|
46
63
|
},
|
|
47
64
|
listFiles(path) {
|
|
48
|
-
return handleCallback((cb) => fs_1.readdir(path, cb));
|
|
65
|
+
return handleCallback((cb) => (0, fs_1.readdir)(getAbsolutePath(cwd, path), cb));
|
|
49
66
|
},
|
|
50
67
|
exists(path) {
|
|
51
|
-
return handleCallback((cb) => fs_1.stat(path, (err) => {
|
|
68
|
+
return handleCallback((cb) => (0, fs_1.stat)(getAbsolutePath(cwd, path), (err) => {
|
|
52
69
|
if (err) {
|
|
53
70
|
cb(null, false);
|
|
54
71
|
}
|
|
@@ -57,8 +74,11 @@ function getFileContext() {
|
|
|
57
74
|
}
|
|
58
75
|
}));
|
|
59
76
|
},
|
|
77
|
+
readStream(path) {
|
|
78
|
+
return (0, fs_1.createReadStream)(path);
|
|
79
|
+
},
|
|
60
80
|
read(path) {
|
|
61
|
-
return handleCallback((cb) => fs_1.readFile(path, (err, content) => {
|
|
81
|
+
return handleCallback((cb) => (0, fs_1.readFile)(getAbsolutePath(cwd, path), (err, content) => {
|
|
62
82
|
if (err) {
|
|
63
83
|
cb(err, null);
|
|
64
84
|
}
|
|
@@ -68,36 +88,39 @@ function getFileContext() {
|
|
|
68
88
|
}));
|
|
69
89
|
},
|
|
70
90
|
async copy(source, destination) {
|
|
71
|
-
const
|
|
91
|
+
const absoluteSource = getAbsolutePath(cwd, source);
|
|
92
|
+
const absoluteDestination = getAbsolutePath(cwd, destination);
|
|
93
|
+
const exists = await this.exists(absoluteSource);
|
|
72
94
|
if (!exists) {
|
|
73
95
|
return;
|
|
74
96
|
}
|
|
75
|
-
const stats = await this.stats(
|
|
97
|
+
const stats = await this.stats(absoluteSource);
|
|
76
98
|
if (stats.type === 'directory') {
|
|
77
|
-
await this.createDirectory(
|
|
78
|
-
for (const child of await this.listFiles(
|
|
79
|
-
await this.copy(path_1.join(
|
|
99
|
+
await this.createDirectory(absoluteDestination);
|
|
100
|
+
for (const child of await this.listFiles(absoluteSource)) {
|
|
101
|
+
await this.copy((0, path_1.join)(absoluteSource, child), (0, path_1.join)(absoluteDestination, child));
|
|
80
102
|
}
|
|
81
103
|
}
|
|
82
104
|
else {
|
|
83
|
-
const destinationDirectory = path_1.dirname(
|
|
105
|
+
const destinationDirectory = (0, path_1.dirname)(absoluteDestination);
|
|
84
106
|
const existsDestinationDirectory = await this.exists(destinationDirectory);
|
|
85
107
|
if (!existsDestinationDirectory) {
|
|
86
108
|
await this.createDirectory(destinationDirectory);
|
|
87
109
|
}
|
|
88
|
-
return handleCallback((cb) => fs_1.copyFile(
|
|
110
|
+
return handleCallback((cb) => (0, fs_1.copyFile)(absoluteSource, absoluteDestination, cb));
|
|
89
111
|
}
|
|
90
112
|
},
|
|
91
113
|
createDirectory(path) {
|
|
92
|
-
return handleCallback((cb) => fs_1.mkdir(path, { recursive: true }, cb));
|
|
114
|
+
return handleCallback((cb) => (0, fs_1.mkdir)(getAbsolutePath(cwd, path), { recursive: true }, cb));
|
|
93
115
|
},
|
|
94
116
|
async remove(path) {
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
const absolutePath = getAbsolutePath(cwd, path);
|
|
118
|
+
if (await this.exists(absolutePath)) {
|
|
119
|
+
return handleCallback((cb) => (0, fs_1.rm)(absolutePath, { recursive: true }, cb));
|
|
97
120
|
}
|
|
98
121
|
},
|
|
99
122
|
watch(path, callback) {
|
|
100
|
-
const watcher = chokidar_1.watch(path);
|
|
123
|
+
const watcher = (0, chokidar_1.watch)(getAbsolutePath(cwd, path));
|
|
101
124
|
watcher.on('add', (fileName) => {
|
|
102
125
|
callback(fileName);
|
|
103
126
|
});
|
package/dist/file/move-files.js
CHANGED
|
@@ -19,7 +19,7 @@ async function moveFiles(node, context, folder) {
|
|
|
19
19
|
if (await context.file.exists(folder.to)) {
|
|
20
20
|
await context.file.remove(folder.to);
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
context.status.task(node).write('debug', `copy ${folder.from} to ${folder.to}`);
|
|
23
23
|
await context.file.copy(folder.from, folder.to);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getWorkScope = void 0;
|
|
4
|
+
const plan_work_tree_1 = require("./planner/utils/plan-work-tree");
|
|
5
|
+
const plan_work_nodes_1 = require("./planner/utils/plan-work-nodes");
|
|
6
|
+
const work_scope_1 = require("./executer/work-scope");
|
|
7
|
+
const replace_env_variables_1 = require("./environment/replace-env-variables");
|
|
8
|
+
const work_service_1 = require("./planner/work-service");
|
|
9
|
+
const work_node_1 = require("./planner/work-node");
|
|
10
|
+
const get_process_env_1 = require("./environment/get-process-env");
|
|
11
|
+
function getWorkScope(buildFile, contextFilter, environment) {
|
|
12
|
+
const tree = (0, work_scope_1.isContextTaskFilter)(contextFilter)
|
|
13
|
+
? (0, plan_work_tree_1.planWorkTree)(buildFile, { taskName: contextFilter.taskName })
|
|
14
|
+
: (0, plan_work_nodes_1.planWorkNodes)(buildFile, contextFilter);
|
|
15
|
+
for (const node of (0, plan_work_nodes_1.iterateWorkNodes)(tree.nodes)) {
|
|
16
|
+
node.envs = (0, replace_env_variables_1.replaceEnvVariables)(node.envs, environment.processEnvs);
|
|
17
|
+
if (!(0, work_node_1.isContainerWorkNode)(node)) {
|
|
18
|
+
node.envs = (0, get_process_env_1.extendHostVariables)(node.envs, environment);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const service of (0, plan_work_nodes_1.iterateWorkServices)(tree.services)) {
|
|
22
|
+
if ((0, work_service_1.isContainerWorkService)(service)) {
|
|
23
|
+
service.envs = (0, replace_env_variables_1.replaceEnvVariables)(service.envs, environment.processEnvs);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return tree;
|
|
27
|
+
}
|
|
28
|
+
exports.getWorkScope = getWorkScope;
|
|
29
|
+
//# sourceMappingURL=get-work-context.js.map
|
package/dist/index.js
CHANGED
|
@@ -4,17 +4,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const program_1 = require("./program");
|
|
5
5
|
const log_1 = require("./log");
|
|
6
6
|
const get_file_context_1 = require("./file/get-file-context");
|
|
7
|
+
const work_node_status_1 = require("./planner/work-node-status");
|
|
8
|
+
const execute_docker_1 = require("./executer/execute-docker");
|
|
7
9
|
const abortCtrl = new AbortController();
|
|
8
10
|
process.on('SIGINT', function () {
|
|
9
11
|
abortCtrl.abort();
|
|
10
12
|
});
|
|
11
|
-
program_1.getProgram({
|
|
13
|
+
(0, program_1.getProgram)({
|
|
12
14
|
cwd: process.cwd(),
|
|
13
15
|
abortCtrl,
|
|
14
16
|
processEnvs: process.env,
|
|
15
|
-
file: get_file_context_1.getFileContext(),
|
|
16
|
-
console: log_1.consoleContext(),
|
|
17
|
+
file: (0, get_file_context_1.getFileContext)(process.cwd()),
|
|
18
|
+
console: (0, log_1.consoleContext)(),
|
|
19
|
+
status: (0, work_node_status_1.statusConsole)(),
|
|
20
|
+
docker: (0, execute_docker_1.getContainerCli)(),
|
|
17
21
|
}, process.argv).then(({ program, args }) => {
|
|
18
|
-
program.
|
|
22
|
+
return program.parseAsync(args);
|
|
19
23
|
});
|
|
20
24
|
//# sourceMappingURL=index.js.map
|