@enspirit/emb 0.0.5 → 0.0.7
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/README.md +61 -31
- package/dist/src/cli/commands/clean.d.ts +3 -1
- package/dist/src/cli/commands/clean.js +13 -2
- package/dist/src/cli/commands/components/build.d.ts +6 -2
- package/dist/src/cli/commands/components/build.js +16 -7
- package/dist/src/cli/commands/config/print.js +2 -3
- package/dist/src/cli/commands/down.d.ts +2 -2
- package/dist/src/cli/commands/down.js +5 -25
- package/dist/src/cli/commands/tasks/index.js +11 -5
- package/dist/src/cli/commands/tasks/run.d.ts +1 -3
- package/dist/src/cli/commands/tasks/run.js +11 -93
- package/dist/src/cli/commands/up.d.ts +1 -1
- package/dist/src/cli/commands/up.js +12 -34
- package/dist/src/config/convert.d.ts +2 -3
- package/dist/src/config/convert.js +4 -11
- package/dist/src/config/index.d.ts +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/schema.d.ts +36 -29
- package/dist/src/config/schema.json +42 -25
- package/dist/src/config/types.d.ts +11 -7
- package/dist/src/config/validation.d.ts +2 -0
- package/dist/src/config/validation.js +26 -1
- package/dist/src/docker/compose/index.d.ts +1 -7
- package/dist/src/docker/compose/index.js +1 -13
- package/dist/src/docker/compose/operations/ComposeDownOperation.d.ts +12 -0
- package/dist/src/docker/compose/operations/ComposeDownOperation.js +21 -0
- package/dist/src/docker/compose/operations/ComposeUpOperation.d.ts +13 -0
- package/dist/src/docker/compose/operations/ComposeUpOperation.js +39 -0
- package/dist/src/docker/compose/operations/index.d.ts +2 -0
- package/dist/src/docker/compose/operations/index.js +2 -0
- package/dist/src/docker/operations/containers/ExecContainerOperation.d.ts +22 -0
- package/dist/src/docker/operations/containers/ExecContainerOperation.js +78 -0
- package/dist/src/docker/operations/containers/index.d.ts +1 -0
- package/dist/src/docker/operations/containers/index.js +1 -0
- package/dist/src/monorepo/component.d.ts +2 -2
- package/dist/src/monorepo/component.js +6 -6
- package/dist/src/monorepo/config.d.ts +6 -3
- package/dist/src/monorepo/config.js +22 -4
- package/dist/src/monorepo/index.d.ts +2 -0
- package/dist/src/monorepo/index.js +2 -0
- package/dist/src/monorepo/monorepo.d.ts +4 -2
- package/dist/src/monorepo/monorepo.js +30 -6
- package/dist/src/monorepo/operations/components/BuildComponentsOperation.d.ts +11 -2
- package/dist/src/monorepo/operations/components/BuildComponentsOperation.js +45 -59
- package/dist/src/monorepo/operations/components/GetComponentContainerOperation.d.ts +6 -0
- package/dist/src/monorepo/operations/components/GetComponentContainerOperation.js +21 -0
- package/dist/src/monorepo/operations/components/index.d.ts +1 -0
- package/dist/src/monorepo/operations/components/index.js +1 -0
- package/dist/src/monorepo/operations/index.d.ts +2 -0
- package/dist/src/monorepo/operations/index.js +2 -0
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.d.ts +16 -0
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +30 -0
- package/dist/src/monorepo/operations/shell/index.d.ts +1 -0
- package/dist/src/monorepo/operations/shell/index.js +1 -0
- package/dist/src/monorepo/operations/tasks/RunTasksOperation.d.ts +21 -0
- package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +84 -0
- package/dist/src/monorepo/operations/tasks/index.d.ts +1 -0
- package/dist/src/monorepo/operations/tasks/index.js +1 -0
- package/dist/src/monorepo/plugins/ComponentDiscoverPlugin.d.ts +15 -0
- package/dist/src/monorepo/plugins/{ComponentsDiscover.js → ComponentDiscoverPlugin.js} +16 -2
- package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.d.ts +14 -0
- package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.js +37 -0
- package/dist/src/monorepo/plugins/index.d.ts +3 -2
- package/dist/src/monorepo/plugins/index.js +5 -2
- package/dist/src/monorepo/store/index.js +5 -3
- package/dist/src/monorepo/taskManagerFactory.d.ts +3 -0
- package/dist/src/monorepo/taskManagerFactory.js +20 -0
- package/dist/src/monorepo/types.d.ts +2 -1
- package/dist/src/monorepo/utils/findRunOrder.d.ts +34 -0
- package/dist/src/monorepo/utils/findRunOrder.js +165 -0
- package/dist/src/monorepo/utils/index.d.ts +1 -1
- package/dist/src/monorepo/utils/index.js +1 -1
- package/dist/src/operations/abstract/AbstractOperation.d.ts +1 -1
- package/dist/src/utils/deepMergeArray.d.ts +3 -0
- package/dist/src/utils/deepMergeArray.js +1 -0
- package/oclif.manifest.json +63 -74
- package/package.json +4 -2
- package/dist/src/cli/commands/run/index.d.ts +0 -10
- package/dist/src/cli/commands/run/index.js +0 -49
- package/dist/src/executors/docker.d.ts +0 -6
- package/dist/src/executors/docker.js +0 -14
- package/dist/src/executors/index.d.ts +0 -6
- package/dist/src/executors/index.js +0 -7
- package/dist/src/executors/shell.d.ts +0 -2
- package/dist/src/executors/shell.js +0 -14
- package/dist/src/executors/types.d.ts +0 -8
- package/dist/src/executors/types.js +0 -1
- package/dist/src/monorepo/plugins/ComponentsDiscover.d.ts +0 -6
- package/dist/src/monorepo/utils/findBuildOrder.d.ts +0 -2
- package/dist/src/monorepo/utils/findBuildOrder.js +0 -41
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
import deepMerge from '@fastify/deepmerge';
|
|
2
2
|
import { deepMergeArray } from '../utils/index.js';
|
|
3
3
|
export class MonorepoConfig {
|
|
4
|
-
|
|
4
|
+
// the flavor we come from
|
|
5
|
+
currentFlavor;
|
|
6
|
+
//
|
|
5
7
|
defaults;
|
|
6
8
|
env;
|
|
7
9
|
flavors;
|
|
8
10
|
plugins;
|
|
9
11
|
project;
|
|
10
12
|
vars;
|
|
13
|
+
tasks;
|
|
14
|
+
_components;
|
|
11
15
|
constructor(config) {
|
|
12
|
-
this.
|
|
16
|
+
this._components = config.components.reduce((map, cmp) => {
|
|
17
|
+
map.set(cmp.name, cmp);
|
|
18
|
+
return map;
|
|
19
|
+
}, new Map());
|
|
13
20
|
this.defaults = config.defaults || {};
|
|
14
21
|
this.project = config.project;
|
|
15
22
|
this.vars = config.vars || {};
|
|
16
23
|
this.flavors = config.flavors || [];
|
|
17
24
|
this.env = config.env || {};
|
|
18
25
|
this.plugins = config.plugins || [];
|
|
26
|
+
this.tasks = config.tasks || [];
|
|
27
|
+
this.currentFlavor = config.currentFlavor || 'default';
|
|
28
|
+
}
|
|
29
|
+
get components() {
|
|
30
|
+
return [...this._components.values()];
|
|
19
31
|
}
|
|
20
32
|
component(name) {
|
|
21
33
|
const config = this.components.find((c) => c.name === name);
|
|
@@ -33,6 +45,7 @@ export class MonorepoConfig {
|
|
|
33
45
|
}
|
|
34
46
|
toJSON() {
|
|
35
47
|
return {
|
|
48
|
+
currentFlavor: this.currentFlavor,
|
|
36
49
|
components: this.components,
|
|
37
50
|
defaults: this.defaults,
|
|
38
51
|
env: this.env,
|
|
@@ -40,11 +53,13 @@ export class MonorepoConfig {
|
|
|
40
53
|
plugins: this.plugins,
|
|
41
54
|
project: this.project,
|
|
42
55
|
vars: this.vars,
|
|
56
|
+
tasks: this.tasks,
|
|
43
57
|
};
|
|
44
58
|
}
|
|
45
59
|
with(overrides) {
|
|
46
60
|
const newConfig = {
|
|
47
61
|
...this.toJSON(),
|
|
62
|
+
...overrides,
|
|
48
63
|
components: deepMerge({
|
|
49
64
|
mergeArray() {
|
|
50
65
|
// Merge components by identifying them by name
|
|
@@ -53,7 +68,7 @@ export class MonorepoConfig {
|
|
|
53
68
|
});
|
|
54
69
|
},
|
|
55
70
|
})(this.components, overrides?.components || []),
|
|
56
|
-
defaults: deepMerge()(this.defaults, overrides.defaults),
|
|
71
|
+
defaults: deepMerge()(this.defaults || {}, overrides.defaults || {}),
|
|
57
72
|
env: deepMerge()(this.env, overrides?.env || {}),
|
|
58
73
|
project: deepMerge()(this.project, overrides?.project || {}),
|
|
59
74
|
vars: deepMerge()(this.vars, overrides?.vars || {}),
|
|
@@ -61,6 +76,9 @@ export class MonorepoConfig {
|
|
|
61
76
|
return new MonorepoConfig(newConfig);
|
|
62
77
|
}
|
|
63
78
|
withFlavor(name) {
|
|
64
|
-
return this.with(
|
|
79
|
+
return this.with({
|
|
80
|
+
...this.flavor(name),
|
|
81
|
+
currentFlavor: name,
|
|
82
|
+
});
|
|
65
83
|
}
|
|
66
84
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './component.js';
|
|
2
2
|
export * from './config.js';
|
|
3
3
|
export * from './monorepo.js';
|
|
4
|
+
export * from './operations/index.js';
|
|
4
5
|
export * from './plugins/index.js';
|
|
5
6
|
export * from './store/index.js';
|
|
7
|
+
export * from './taskManagerFactory.js';
|
|
6
8
|
export * from './types.js';
|
|
7
9
|
export * from './utils/index.js';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './component.js';
|
|
2
2
|
export * from './config.js';
|
|
3
3
|
export * from './monorepo.js';
|
|
4
|
+
export * from './operations/index.js';
|
|
4
5
|
export * from './plugins/index.js';
|
|
5
6
|
export * from './store/index.js';
|
|
7
|
+
export * from './taskManagerFactory.js';
|
|
6
8
|
export * from './types.js';
|
|
7
9
|
export * from './utils/index.js';
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { IMonorepoConfig } from '../config/index.js';
|
|
2
|
-
import { IOperation } from '../operations/
|
|
2
|
+
import { IOperation } from '../operations/index.js';
|
|
3
3
|
import { TemplateExpander } from '../utils/index.js';
|
|
4
4
|
import { Component } from './component.js';
|
|
5
5
|
import { EMBStore } from './store/index.js';
|
|
6
6
|
import { TaskInfo } from './types.js';
|
|
7
7
|
export declare class Monorepo {
|
|
8
8
|
private _config;
|
|
9
|
-
private _env;
|
|
10
9
|
private _store;
|
|
11
10
|
private initialized;
|
|
12
11
|
constructor(config: IMonorepoConfig);
|
|
@@ -16,12 +15,15 @@ export declare class Monorepo {
|
|
|
16
15
|
get flavors(): string[];
|
|
17
16
|
get name(): string;
|
|
18
17
|
get rootDir(): string;
|
|
18
|
+
get currentFlavor(): string;
|
|
19
19
|
get store(): EMBStore;
|
|
20
20
|
get tasks(): TaskInfo[];
|
|
21
21
|
get vars(): Record<string, unknown>;
|
|
22
22
|
component(name: string): Component;
|
|
23
|
+
task(nameOrId: string): TaskInfo;
|
|
23
24
|
expand(str: string, expander?: TemplateExpander): Promise<string>;
|
|
24
25
|
expand<R extends Record<string, unknown>>(record: R, expander?: TemplateExpander): Promise<R>;
|
|
26
|
+
private installStore;
|
|
25
27
|
init(): Promise<Monorepo>;
|
|
26
28
|
join(...paths: string[]): string;
|
|
27
29
|
run<I, O>(operation: IOperation<I, O>, args: I): Promise<O>;
|
|
@@ -6,12 +6,10 @@ import { getPlugin } from './plugins/index.js';
|
|
|
6
6
|
import { EMBStore } from './store/index.js';
|
|
7
7
|
export class Monorepo {
|
|
8
8
|
_config;
|
|
9
|
-
_env;
|
|
10
9
|
_store;
|
|
11
10
|
initialized = false;
|
|
12
11
|
constructor(config) {
|
|
13
12
|
this._config = new MonorepoConfig(config);
|
|
14
|
-
this._env = config.env || {};
|
|
15
13
|
}
|
|
16
14
|
// TODO: cache/improve
|
|
17
15
|
get components() {
|
|
@@ -32,13 +30,22 @@ export class Monorepo {
|
|
|
32
30
|
get rootDir() {
|
|
33
31
|
return this._config.project.rootDir;
|
|
34
32
|
}
|
|
33
|
+
get currentFlavor() {
|
|
34
|
+
return this._config.currentFlavor;
|
|
35
|
+
}
|
|
35
36
|
get store() {
|
|
36
37
|
return this._store;
|
|
37
38
|
}
|
|
38
39
|
get tasks() {
|
|
40
|
+
const globalTasks = (this._config.tasks || [])?.map((t) => {
|
|
41
|
+
return {
|
|
42
|
+
...t,
|
|
43
|
+
id: `global:${t.name}`,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
39
46
|
return this.components.reduce((tasks, cmp) => {
|
|
40
47
|
return [...tasks, ...cmp.tasks];
|
|
41
|
-
},
|
|
48
|
+
}, globalTasks);
|
|
42
49
|
}
|
|
43
50
|
get vars() {
|
|
44
51
|
return this._config.vars;
|
|
@@ -46,6 +53,20 @@ export class Monorepo {
|
|
|
46
53
|
component(name) {
|
|
47
54
|
return new Component(this._config.component(name), this);
|
|
48
55
|
}
|
|
56
|
+
task(nameOrId) {
|
|
57
|
+
const byId = this.tasks.find((t) => t.id === nameOrId);
|
|
58
|
+
if (byId) {
|
|
59
|
+
return byId;
|
|
60
|
+
}
|
|
61
|
+
const found = this.tasks.filter((t) => t.name === nameOrId);
|
|
62
|
+
if (found.length > 1) {
|
|
63
|
+
throw new Error(`Task name ambigous, found multiple matches: ${nameOrId}`);
|
|
64
|
+
}
|
|
65
|
+
if (found.length === 0) {
|
|
66
|
+
throw new Error(`Task not found: ${nameOrId}`);
|
|
67
|
+
}
|
|
68
|
+
return found[0];
|
|
69
|
+
}
|
|
49
70
|
async expand(strOrRecord, expander = new TemplateExpander()) {
|
|
50
71
|
const options = {
|
|
51
72
|
default: 'vars',
|
|
@@ -59,13 +80,16 @@ export class Monorepo {
|
|
|
59
80
|
}
|
|
60
81
|
return expander.expandRecord(strOrRecord, options);
|
|
61
82
|
}
|
|
83
|
+
async installStore(store) {
|
|
84
|
+
this._store = store || new EMBStore(this);
|
|
85
|
+
await this._store.init();
|
|
86
|
+
}
|
|
62
87
|
// Initialize
|
|
63
88
|
async init() {
|
|
64
89
|
if (this.initialized) {
|
|
65
90
|
throw new Error('Monorepo already initialized');
|
|
66
91
|
}
|
|
67
|
-
this.
|
|
68
|
-
await this._store.init();
|
|
92
|
+
await this.installStore();
|
|
69
93
|
const plugins = this._config.plugins.map((p) => {
|
|
70
94
|
const PluginClass = getPlugin(p.name);
|
|
71
95
|
return new PluginClass(p.config, this);
|
|
@@ -100,7 +124,7 @@ export class Monorepo {
|
|
|
100
124
|
}
|
|
101
125
|
async withFlavor(name) {
|
|
102
126
|
const repo = new Monorepo(this._config.withFlavor(name));
|
|
103
|
-
await repo.
|
|
127
|
+
await repo.installStore();
|
|
104
128
|
return repo;
|
|
105
129
|
}
|
|
106
130
|
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
+
import { DockerComponentBuild } from '../../../docker/index.js';
|
|
2
3
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
export type BuildComponentMeta = {
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
cacheHit?: boolean;
|
|
7
|
+
build: DockerComponentBuild;
|
|
8
|
+
preBuildMeta?: string;
|
|
9
|
+
sentinelFile: string;
|
|
10
|
+
};
|
|
3
11
|
declare const schema: z.ZodObject<{
|
|
4
12
|
components: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
5
14
|
}, z.core.$strip>;
|
|
6
|
-
export declare class BuildComponentsOperation extends AbstractOperation<typeof schema,
|
|
15
|
+
export declare class BuildComponentsOperation extends AbstractOperation<typeof schema, Record<string, BuildComponentMeta>> {
|
|
7
16
|
constructor();
|
|
8
|
-
protected _run(input: z.input<typeof schema>): Promise<
|
|
17
|
+
protected _run(input: z.input<typeof schema>): Promise<Record<string, BuildComponentMeta>>;
|
|
9
18
|
private buildComponent;
|
|
10
19
|
}
|
|
11
20
|
export {};
|
|
@@ -1,79 +1,58 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createColors } from 'colorette';
|
|
3
|
-
import { delay, ListrDefaultRendererLogLevels, PRESET_TIMER, } from 'listr2';
|
|
1
|
+
import { getContext } from '../../../index.js';
|
|
4
2
|
import * as z from 'zod';
|
|
5
3
|
import { BuildImageOperation, getSentinelFile, } from '../../../docker/index.js';
|
|
6
|
-
import {
|
|
4
|
+
import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
|
|
7
5
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
8
|
-
import { FilePrerequisitePlugin } from '../../../prerequisites/
|
|
9
|
-
import { PrerequisiteType } from '../../../prerequisites/types.js';
|
|
6
|
+
import { FilePrerequisitePlugin, PrerequisiteType } from '../../../prerequisites/index.js';
|
|
10
7
|
const schema = z.object({
|
|
11
8
|
components: z
|
|
12
9
|
.array(z.string())
|
|
13
10
|
.describe('The list of components to build')
|
|
14
11
|
.optional(),
|
|
12
|
+
dryRun: z
|
|
13
|
+
.boolean()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Do not build but return the config that would be used to build the images'),
|
|
15
16
|
});
|
|
16
17
|
export class BuildComponentsOperation extends AbstractOperation {
|
|
17
18
|
constructor() {
|
|
18
19
|
super(schema);
|
|
19
20
|
}
|
|
20
21
|
async _run(input) {
|
|
21
|
-
const
|
|
22
|
+
const { monorepo } = getContext();
|
|
23
|
+
const manager = taskManagerFactory();
|
|
24
|
+
const selection = (input.components || []).map((t) => monorepo.component(t));
|
|
25
|
+
const collection = new EMBCollection(this.context.monorepo.components, {
|
|
26
|
+
idField: 'name',
|
|
27
|
+
depField: 'dependencies',
|
|
28
|
+
forbidIdNameCollision: true,
|
|
29
|
+
});
|
|
30
|
+
const ordered = findRunOrder(selection.map((s) => s.name), collection);
|
|
22
31
|
const tasks = await Promise.all(ordered.map((cmp) => {
|
|
23
32
|
return {
|
|
24
33
|
task: async (context, task) => {
|
|
25
|
-
return this.buildComponent(cmp, task);
|
|
34
|
+
return this.buildComponent(cmp, task, context, input.dryRun);
|
|
26
35
|
},
|
|
27
36
|
title: `Building ${cmp.name}`,
|
|
28
37
|
};
|
|
29
38
|
}));
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
exitOnError: true,
|
|
34
|
-
rendererOptions: {
|
|
35
|
-
collapseErrors: false,
|
|
36
|
-
collapseSubtasks: false,
|
|
37
|
-
color: {
|
|
38
|
-
// @ts-expect-error not sure why
|
|
39
|
-
[ListrDefaultRendererLogLevels.SKIPPED_WITH_COLLAPSE]: createColors().green,
|
|
40
|
-
},
|
|
41
|
-
icon: {
|
|
42
|
-
[ListrDefaultRendererLogLevels.SKIPPED_WITH_COLLAPSE]: '♺',
|
|
43
|
-
},
|
|
44
|
-
timer: {
|
|
45
|
-
...PRESET_TIMER,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
39
|
+
const list = manager.newListr([...tasks], {
|
|
40
|
+
rendererOptions: { persistentOutput: true },
|
|
41
|
+
ctx: {},
|
|
48
42
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
async task(_context, task) {
|
|
52
|
-
return task.newListr([...tasks], {
|
|
53
|
-
rendererOptions: {
|
|
54
|
-
collapseSubtasks: false,
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
title: 'Building components',
|
|
59
|
-
},
|
|
60
|
-
]);
|
|
61
|
-
await manager.runAll();
|
|
62
|
-
return ordered;
|
|
43
|
+
const results = await list.run();
|
|
44
|
+
return results;
|
|
63
45
|
}
|
|
64
|
-
async buildComponent(cmp, parentTask) {
|
|
65
|
-
|
|
46
|
+
async buildComponent(cmp, parentTask, parentContext, dryRun = false) {
|
|
47
|
+
const prereqPlugin = new FilePrerequisitePlugin();
|
|
48
|
+
const list = parentTask.newListr([
|
|
66
49
|
// Collect all the prerequisites and other build infos
|
|
67
50
|
// (This is when variables are expanded etc)
|
|
68
51
|
{
|
|
69
52
|
async task(ctx) {
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
ctx.skip = false;
|
|
73
|
-
//
|
|
74
|
-
ctx.parentTask = parentTask;
|
|
53
|
+
// Install the context for this specific component build chain
|
|
54
|
+
ctx.cacheHit = false;
|
|
75
55
|
ctx.sentinelFile = getSentinelFile(cmp);
|
|
76
|
-
ctx.plugin = new FilePrerequisitePlugin();
|
|
77
56
|
ctx.build = await cmp.toDockerBuild();
|
|
78
57
|
},
|
|
79
58
|
title: 'Prepare build context',
|
|
@@ -81,7 +60,7 @@ export class BuildComponentsOperation extends AbstractOperation {
|
|
|
81
60
|
// Check for sentinal information to see if the build can be skipped
|
|
82
61
|
{
|
|
83
62
|
task: async (ctx) => {
|
|
84
|
-
ctx.preBuildMeta = await
|
|
63
|
+
ctx.preBuildMeta = await prereqPlugin.meta(cmp, ctx.build.prerequisites, 'pre');
|
|
85
64
|
let lastValue;
|
|
86
65
|
try {
|
|
87
66
|
lastValue = (await this.context.monorepo.store.readFile(ctx.sentinelFile)).toString();
|
|
@@ -90,10 +69,10 @@ export class BuildComponentsOperation extends AbstractOperation {
|
|
|
90
69
|
lastValue = undefined;
|
|
91
70
|
}
|
|
92
71
|
if (lastValue) {
|
|
93
|
-
const diff = await
|
|
72
|
+
const diff = await prereqPlugin.diff(cmp, ctx.build.prerequisites, lastValue, ctx.preBuildMeta);
|
|
94
73
|
if (!diff) {
|
|
95
|
-
ctx.
|
|
96
|
-
|
|
74
|
+
ctx.cacheHit = true;
|
|
75
|
+
// parentTask.skip(`${parentTask.title} (cache hit)`);
|
|
97
76
|
}
|
|
98
77
|
}
|
|
99
78
|
},
|
|
@@ -101,10 +80,9 @@ export class BuildComponentsOperation extends AbstractOperation {
|
|
|
101
80
|
},
|
|
102
81
|
{
|
|
103
82
|
task: async (ctx, task) => {
|
|
104
|
-
if (ctx.
|
|
83
|
+
if (ctx.cacheHit || ctx.dryRun) {
|
|
105
84
|
return task.skip();
|
|
106
85
|
}
|
|
107
|
-
await delay(500);
|
|
108
86
|
const title = `Building image ${ctx.build.name}:${ctx.build.tag}`;
|
|
109
87
|
task.title = title;
|
|
110
88
|
const op = new BuildImageOperation((progress) => {
|
|
@@ -127,18 +105,26 @@ export class BuildComponentsOperation extends AbstractOperation {
|
|
|
127
105
|
// Update sentinel file
|
|
128
106
|
{
|
|
129
107
|
task: async (ctx, task) => {
|
|
130
|
-
if (ctx.
|
|
108
|
+
if (ctx.cacheHit || ctx.dryRun) {
|
|
131
109
|
return task.skip();
|
|
132
110
|
}
|
|
133
|
-
const sentinelValue = await
|
|
111
|
+
const sentinelValue = await prereqPlugin.meta(cmp, ctx.build.prerequisites, 'post');
|
|
134
112
|
await this.context.monorepo.store.writeFile(ctx.sentinelFile, sentinelValue);
|
|
135
113
|
},
|
|
136
114
|
title: 'Dumping cache info',
|
|
137
115
|
},
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
116
|
+
{
|
|
117
|
+
// Return build meta data
|
|
118
|
+
async task(ctx) {
|
|
119
|
+
parentContext[cmp.name] = ctx;
|
|
120
|
+
if (ctx.dryRun) {
|
|
121
|
+
// parentTask.skip(`${parentTask.title} (dry run)`);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
141
124
|
},
|
|
125
|
+
], {
|
|
126
|
+
ctx: { dryRun },
|
|
142
127
|
});
|
|
128
|
+
return list;
|
|
143
129
|
}
|
|
144
130
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ContainerInfo } from 'dockerode';
|
|
2
|
+
import { Component } from '../../index.js';
|
|
3
|
+
import { IOperation } from '../../../operations/index.js';
|
|
4
|
+
export declare class GetComponentContainerOperation implements IOperation<Component, ContainerInfo> {
|
|
5
|
+
run(component: Component | string): Promise<ContainerInfo>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getContext } from '../../../index.js';
|
|
2
|
+
import { ListContainersOperation } from '../../../docker/index.js';
|
|
3
|
+
import { Component } from '../../index.js';
|
|
4
|
+
export class GetComponentContainerOperation {
|
|
5
|
+
async run(component) {
|
|
6
|
+
const { monorepo } = getContext();
|
|
7
|
+
const cmpName = component instanceof Component ? component.name : component;
|
|
8
|
+
const matching = await monorepo.run(new ListContainersOperation(), {
|
|
9
|
+
filters: {
|
|
10
|
+
label: [`emb/project=${monorepo.name}`, `emb/component=${cmpName}`],
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
if (matching.length === 0) {
|
|
14
|
+
throw new Error(`Could not find a running container for '${cmpName}'`);
|
|
15
|
+
}
|
|
16
|
+
if (matching.length > 1) {
|
|
17
|
+
throw new Error(`More than one running container found for '${cmpName}'`);
|
|
18
|
+
}
|
|
19
|
+
return matching[0];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
|
|
6
|
+
*/
|
|
7
|
+
declare const schema: z.ZodObject<{
|
|
8
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
9
|
+
script: z.ZodString;
|
|
10
|
+
workingDir: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export declare class ExecuteLocalCommandOperation extends AbstractOperation<typeof schema, Readable> {
|
|
13
|
+
constructor();
|
|
14
|
+
protected _run(input: z.input<typeof schema>): Promise<Readable>;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
|
|
6
|
+
*/
|
|
7
|
+
const schema = z.object({
|
|
8
|
+
env: z
|
|
9
|
+
.record(z.string(), z.string())
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('A list of environment variables in the form'),
|
|
12
|
+
script: z.string().describe('Command to run, as a string'),
|
|
13
|
+
workingDir: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('The working directory for the exec process inside the container'),
|
|
17
|
+
});
|
|
18
|
+
export class ExecuteLocalCommandOperation extends AbstractOperation {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(schema);
|
|
21
|
+
}
|
|
22
|
+
async _run(input) {
|
|
23
|
+
const process = execa(input.script, {
|
|
24
|
+
all: true,
|
|
25
|
+
cwd: input.workingDir,
|
|
26
|
+
shell: true,
|
|
27
|
+
});
|
|
28
|
+
return process.all;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ExecuteLocalCommandOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ExecuteLocalCommandOperation.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { TaskInfo } from '../../index.js';
|
|
3
|
+
import { IOperation } from '../../../operations/index.js';
|
|
4
|
+
export declare enum ExecutorType {
|
|
5
|
+
container = "container",
|
|
6
|
+
local = "local"
|
|
7
|
+
}
|
|
8
|
+
export type RunTasksOperationParams = {
|
|
9
|
+
tasks: Array<string>;
|
|
10
|
+
executor?: ExecutorType | undefined;
|
|
11
|
+
};
|
|
12
|
+
export type TaskWithScript = TaskInfo & {
|
|
13
|
+
script: string;
|
|
14
|
+
};
|
|
15
|
+
export declare class RunTasksOperation implements IOperation<RunTasksOperationParams, Array<TaskInfo>> {
|
|
16
|
+
protected out?: Writable | undefined;
|
|
17
|
+
constructor(out?: Writable | undefined);
|
|
18
|
+
run(params: RunTasksOperationParams): Promise<Array<TaskInfo>>;
|
|
19
|
+
protected runDocker(task: TaskWithScript, out?: Writable): Promise<void>;
|
|
20
|
+
protected runLocal(task: TaskWithScript): Promise<import("stream").Readable>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getContext } from '../../../index.js';
|
|
2
|
+
import { Manager } from '@listr2/manager';
|
|
3
|
+
import { ContainerExecOperation } from '../../../docker/index.js';
|
|
4
|
+
import { EMBCollection, findRunOrder } from '../../index.js';
|
|
5
|
+
import { ExecuteLocalCommandOperation, GetComponentContainerOperation, } from '../index.js';
|
|
6
|
+
export var ExecutorType;
|
|
7
|
+
(function (ExecutorType) {
|
|
8
|
+
ExecutorType["container"] = "container";
|
|
9
|
+
ExecutorType["local"] = "local";
|
|
10
|
+
})(ExecutorType || (ExecutorType = {}));
|
|
11
|
+
export class RunTasksOperation {
|
|
12
|
+
out;
|
|
13
|
+
constructor(out) {
|
|
14
|
+
this.out = out;
|
|
15
|
+
}
|
|
16
|
+
async run(params) {
|
|
17
|
+
const { monorepo } = getContext();
|
|
18
|
+
// First ensure the selection is valid (user can use task IDs or names)
|
|
19
|
+
const collection = new EMBCollection(monorepo.tasks, {
|
|
20
|
+
idField: 'id',
|
|
21
|
+
depField: 'pre',
|
|
22
|
+
});
|
|
23
|
+
const ordered = findRunOrder(params.tasks, collection);
|
|
24
|
+
const runner = new Manager({
|
|
25
|
+
concurrent: false,
|
|
26
|
+
exitOnError: false,
|
|
27
|
+
rendererOptions: {
|
|
28
|
+
collapseSubtasks: false,
|
|
29
|
+
collapseSkips: false,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const list = runner.newListr(ordered.map((task) => {
|
|
33
|
+
return {
|
|
34
|
+
rendererOptions: {
|
|
35
|
+
persistentOutput: true,
|
|
36
|
+
},
|
|
37
|
+
task: async (context, listrTask) => {
|
|
38
|
+
if (!task.script) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const executor = params.executor ??
|
|
42
|
+
(task.component ? ExecutorType.container : ExecutorType.local);
|
|
43
|
+
if (executor === ExecutorType.container && !task.component) {
|
|
44
|
+
throw new Error('Cannot use the container executor with global tasks');
|
|
45
|
+
}
|
|
46
|
+
switch (executor) {
|
|
47
|
+
case ExecutorType.container: {
|
|
48
|
+
return this.runDocker(task, listrTask.stdout());
|
|
49
|
+
}
|
|
50
|
+
case ExecutorType.local: {
|
|
51
|
+
return this.runLocal(task);
|
|
52
|
+
}
|
|
53
|
+
default: {
|
|
54
|
+
throw new Error(`Unssuported executor type: ${executor}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
title: `Running ${task.id}`,
|
|
59
|
+
};
|
|
60
|
+
}));
|
|
61
|
+
await list.run();
|
|
62
|
+
return ordered;
|
|
63
|
+
}
|
|
64
|
+
async runDocker(task, out) {
|
|
65
|
+
const { monorepo } = getContext();
|
|
66
|
+
const containerInfo = await monorepo.run(new GetComponentContainerOperation(), task.component);
|
|
67
|
+
return monorepo.run(new ContainerExecOperation(out), {
|
|
68
|
+
attachStderr: true,
|
|
69
|
+
attachStdout: true,
|
|
70
|
+
container: containerInfo.Id,
|
|
71
|
+
script: task.script,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async runLocal(task) {
|
|
75
|
+
const { monorepo } = getContext();
|
|
76
|
+
const cwd = task.component
|
|
77
|
+
? monorepo.component(task.component).rootdir
|
|
78
|
+
: monorepo.rootDir;
|
|
79
|
+
return monorepo.run(new ExecuteLocalCommandOperation(), {
|
|
80
|
+
script: task.script,
|
|
81
|
+
workingDir: cwd,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RunTasksOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RunTasksOperation.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Monorepo, MonorepoConfig } from '../index.js';
|
|
2
|
+
import { AbstractPlugin } from './plugin.js';
|
|
3
|
+
export type ComponentDiscoverPluginOptions = {
|
|
4
|
+
glob?: string;
|
|
5
|
+
ignore?: string | string[];
|
|
6
|
+
};
|
|
7
|
+
export declare const ComponentDiscoverPluginDefaultOptions: {
|
|
8
|
+
glob: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class ComponentDiscoverPlugin extends AbstractPlugin<ComponentDiscoverPluginOptions> {
|
|
11
|
+
protected monorepo: Monorepo;
|
|
12
|
+
static name: string;
|
|
13
|
+
constructor(config: Partial<ComponentDiscoverPluginOptions>, monorepo: Monorepo);
|
|
14
|
+
extendConfig(config: MonorepoConfig): Promise<MonorepoConfig>;
|
|
15
|
+
}
|