@enspirit/emb 0.0.1 → 0.0.3
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 +190 -164
- package/bin/run.js +8 -2
- package/dist/src/cli/abstract/FlavouredCommand.d.ts +12 -0
- package/dist/src/cli/abstract/FlavouredCommand.js +40 -0
- package/dist/src/cli/abstract/index.d.ts +1 -0
- package/dist/src/cli/abstract/index.js +1 -0
- package/dist/src/cli/commands/clean.d.ts +15 -0
- package/dist/src/cli/commands/clean.js +29 -0
- package/dist/src/cli/commands/components/build.d.ts +11 -0
- package/dist/src/cli/commands/components/build.js +24 -0
- package/dist/src/cli/commands/components/index.d.ts +14 -0
- package/dist/src/cli/commands/components/index.js +44 -0
- package/dist/src/cli/commands/config/print.d.ts +13 -0
- package/dist/src/cli/commands/config/print.js +16 -0
- package/dist/src/cli/commands/containers/index.d.ts +12 -0
- package/dist/src/cli/commands/containers/index.js +66 -0
- package/dist/src/cli/commands/containers/prune.d.ts +8 -0
- package/dist/src/cli/commands/containers/prune.js +23 -0
- package/dist/src/cli/commands/down.d.ts +8 -0
- package/dist/src/cli/commands/down.js +42 -0
- package/dist/src/cli/commands/images/delete.d.ts +10 -0
- package/dist/src/cli/commands/images/delete.js +44 -0
- package/dist/src/cli/commands/images/index.d.ts +17 -0
- package/dist/src/cli/commands/images/index.js +59 -0
- package/dist/src/cli/commands/images/prune.d.ts +11 -0
- package/dist/src/cli/commands/images/prune.js +35 -0
- package/dist/src/cli/commands/run/index.d.ts +10 -0
- package/dist/src/cli/commands/run/index.js +49 -0
- package/dist/src/cli/commands/tasks/index.d.ts +9 -0
- package/dist/src/cli/commands/tasks/index.js +23 -0
- package/dist/src/cli/commands/tasks/run.d.ts +16 -0
- package/dist/src/cli/commands/tasks/run.js +113 -0
- package/dist/src/cli/commands/up.d.ts +10 -0
- package/dist/src/cli/commands/up.js +49 -0
- package/dist/src/cli/constants.d.ts +2 -0
- package/dist/src/cli/constants.js +6 -0
- package/dist/src/cli/hooks/init.d.ts +3 -0
- package/dist/src/cli/hooks/init.js +27 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.js +3 -0
- package/dist/src/config/convert.d.ts +5 -0
- package/dist/src/config/convert.js +48 -0
- package/dist/src/config/index.d.ts +6 -0
- package/dist/src/config/index.js +25 -0
- package/dist/src/config/schema.d.ts +102 -0
- package/dist/src/config/schema.js +7 -0
- package/dist/src/config/schema.json +209 -0
- package/dist/src/config/types.d.ts +43 -0
- package/dist/src/config/types.js +1 -0
- package/dist/src/config/validation.d.ts +1 -0
- package/dist/src/config/validation.js +27 -0
- package/dist/src/context.d.ts +3 -0
- package/dist/src/context.js +7 -0
- package/dist/src/docker/compose/index.d.ts +7 -0
- package/dist/src/docker/compose/index.js +13 -0
- package/dist/src/docker/containers/getContainer.d.ts +2 -0
- package/dist/src/docker/containers/getContainer.js +5 -0
- package/dist/src/docker/containers/index.d.ts +1 -0
- package/dist/src/docker/containers/index.js +1 -0
- package/dist/src/docker/images/buildImage.d.ts +19 -0
- package/dist/src/docker/images/buildImage.js +64 -0
- package/dist/src/docker/images/deleteImage.d.ts +5 -0
- package/dist/src/docker/images/deleteImage.js +6 -0
- package/dist/src/docker/images/index.d.ts +4 -0
- package/dist/src/docker/images/index.js +4 -0
- package/dist/src/docker/images/listImages.d.ts +2 -0
- package/dist/src/docker/images/listImages.js +8 -0
- package/dist/src/docker/images/pruneImages.d.ts +6 -0
- package/dist/src/docker/images/pruneImages.js +8 -0
- package/dist/src/docker/index.d.ts +7 -0
- package/dist/src/docker/index.js +7 -0
- package/dist/src/docker/operations/containers/ListContainersOperation.d.ts +18 -0
- package/dist/src/docker/operations/containers/ListContainersOperation.js +44 -0
- package/dist/src/docker/operations/containers/PruneContainersOperation.d.ts +16 -0
- package/dist/src/docker/operations/containers/PruneContainersOperation.js +33 -0
- package/dist/src/docker/operations/containers/index.d.ts +2 -0
- package/dist/src/docker/operations/containers/index.js +2 -0
- package/dist/src/docker/operations/images/BuildImageOperation.d.ts +20 -0
- package/dist/src/docker/operations/images/BuildImageOperation.js +69 -0
- package/dist/src/docker/operations/images/ListImagesOperation.d.ts +17 -0
- package/dist/src/docker/operations/images/ListImagesOperation.js +38 -0
- package/dist/src/docker/operations/images/PruneImagesOperation.d.ts +16 -0
- package/dist/src/docker/operations/images/PruneImagesOperation.js +33 -0
- package/dist/src/docker/operations/images/index.d.ts +3 -0
- package/dist/src/docker/operations/images/index.js +3 -0
- package/dist/src/docker/operations/index.d.ts +2 -0
- package/dist/src/docker/operations/index.js +2 -0
- package/dist/src/docker/protobuf/control.proto +48 -0
- package/dist/src/docker/protobuf/index.d.ts +5 -0
- package/dist/src/docker/protobuf/index.js +29 -0
- package/dist/src/docker/types.d.ts +14 -0
- package/dist/src/docker/types.js +1 -0
- package/dist/src/docker/utils.d.ts +7 -0
- package/dist/src/docker/utils.js +10 -0
- package/dist/src/executors/docker.d.ts +6 -0
- package/dist/src/executors/docker.js +14 -0
- package/dist/src/executors/index.d.ts +6 -0
- package/dist/src/executors/index.js +7 -0
- package/dist/src/executors/shell.d.ts +2 -0
- package/dist/src/executors/shell.js +14 -0
- package/dist/src/executors/types.d.ts +8 -0
- package/dist/src/executors/types.js +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/monorepo/component.d.ts +24 -0
- package/dist/src/monorepo/component.js +77 -0
- package/dist/src/monorepo/config.d.ts +16 -0
- package/dist/src/monorepo/config.js +66 -0
- package/dist/src/monorepo/index.d.ts +7 -0
- package/dist/src/monorepo/index.js +7 -0
- package/dist/src/monorepo/monorepo.d.ts +29 -0
- package/dist/src/monorepo/monorepo.js +106 -0
- package/dist/src/monorepo/operations/components/BuildComponentsOperation.d.ts +11 -0
- package/dist/src/monorepo/operations/components/BuildComponentsOperation.js +144 -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 +1 -0
- package/dist/src/monorepo/operations/index.js +1 -0
- package/dist/src/monorepo/plugins/ComponentsDiscover.d.ts +6 -0
- package/dist/src/monorepo/plugins/ComponentsDiscover.js +30 -0
- package/dist/src/monorepo/plugins/DotEnvPlugin.d.ts +5 -0
- package/dist/src/monorepo/plugins/DotEnvPlugin.js +11 -0
- package/dist/src/monorepo/plugins/index.d.ts +7 -0
- package/dist/src/monorepo/plugins/index.js +20 -0
- package/dist/src/monorepo/plugins/plugin.d.ts +15 -0
- package/dist/src/monorepo/plugins/plugin.js +12 -0
- package/dist/src/monorepo/project.d.ts +6 -0
- package/dist/src/monorepo/project.js +8 -0
- package/dist/src/monorepo/store/index.d.ts +20 -0
- package/dist/src/monorepo/store/index.js +65 -0
- package/dist/src/monorepo/types.d.ts +7 -0
- package/dist/src/monorepo/types.js +1 -0
- package/dist/src/monorepo/utils/findBuildOrder.d.ts +2 -0
- package/dist/src/monorepo/utils/findBuildOrder.js +41 -0
- package/dist/src/monorepo/utils/index.d.ts +1 -0
- package/dist/src/monorepo/utils/index.js +1 -0
- package/dist/src/operations/abstract/AbstractOperation.d.ts +10 -0
- package/dist/src/operations/abstract/AbstractOperation.js +13 -0
- package/dist/src/operations/abstract/index.d.ts +1 -0
- package/dist/src/operations/abstract/index.js +1 -0
- package/dist/src/operations/index.d.ts +2 -0
- package/dist/src/operations/index.js +2 -0
- package/dist/src/operations/types.d.ts +3 -0
- package/dist/src/operations/types.js +1 -0
- package/dist/src/prerequisites/FilePrerequisitePlugin.d.ts +7 -0
- package/dist/src/prerequisites/FilePrerequisitePlugin.js +41 -0
- package/dist/src/prerequisites/GitPrerequisitePlugin.d.ts +5 -0
- package/dist/src/prerequisites/GitPrerequisitePlugin.js +17 -0
- package/dist/src/prerequisites/index.d.ts +3 -0
- package/dist/src/prerequisites/index.js +3 -0
- package/dist/src/prerequisites/types.d.ts +46 -0
- package/dist/src/prerequisites/types.js +24 -0
- package/dist/src/types.d.ts +13 -0
- package/dist/src/types.js +1 -0
- package/dist/src/utils/TemplateExpander.d.ts +21 -0
- package/dist/src/utils/TemplateExpander.js +53 -0
- package/dist/src/utils/deepMergeArray.d.ts +1 -0
- package/dist/src/utils/deepMergeArray.js +19 -0
- package/dist/src/utils/index.d.ts +3 -0
- package/dist/src/utils/index.js +3 -0
- package/dist/src/utils/time.d.ts +2 -0
- package/dist/src/utils/time.js +19 -0
- package/oclif.manifest.json +572 -2
- package/package.json +10 -9
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import protobuf from 'protobufjs';
|
|
4
|
+
let control;
|
|
5
|
+
export const loadControl = async () => {
|
|
6
|
+
if (control) {
|
|
7
|
+
return control;
|
|
8
|
+
}
|
|
9
|
+
const path = join(dirname(fileURLToPath(import.meta.url)), './control.proto');
|
|
10
|
+
control = await protobuf.load(path);
|
|
11
|
+
return control;
|
|
12
|
+
};
|
|
13
|
+
export const decodeBuildkitStatusResponse = async (str) => {
|
|
14
|
+
const control = await loadControl();
|
|
15
|
+
const buffer = typeof str === 'string' ? Buffer.from(str, 'base64') : str;
|
|
16
|
+
const uint8 = new Uint8Array(buffer);
|
|
17
|
+
const Trace = control.lookupType('moby.buildkit.v1.StatusResponse');
|
|
18
|
+
const message = Trace.decode(uint8);
|
|
19
|
+
const object = Trace.toObject(message, {
|
|
20
|
+
arrays: true,
|
|
21
|
+
bytes: String,
|
|
22
|
+
defaults: true,
|
|
23
|
+
enums: String,
|
|
24
|
+
longs: String,
|
|
25
|
+
objects: true,
|
|
26
|
+
oneofs: true,
|
|
27
|
+
});
|
|
28
|
+
return object;
|
|
29
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FilePrerequisite } from '../prerequisites/index.js';
|
|
2
|
+
export type EnvVariable = {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export interface DockerComponentBuild {
|
|
6
|
+
buildArgs?: Record<string, string>;
|
|
7
|
+
context: string;
|
|
8
|
+
dockerfile: string;
|
|
9
|
+
labels?: Record<string, string>;
|
|
10
|
+
name: string;
|
|
11
|
+
prerequisites: Array<FilePrerequisite>;
|
|
12
|
+
tag: string;
|
|
13
|
+
target?: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Component } from '../monorepo/index.js';
|
|
2
|
+
export declare const shortId: (id: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* This is too naive and will need better logic to ensure
|
|
5
|
+
* we take care of flavors etc
|
|
6
|
+
*/
|
|
7
|
+
export declare const getSentinelFile: (component: Component) => string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const shortId = (id) => {
|
|
2
|
+
return id.slice(0, 12);
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* This is too naive and will need better logic to ensure
|
|
6
|
+
* we take care of flavors etc
|
|
7
|
+
*/
|
|
8
|
+
export const getSentinelFile = (component) => {
|
|
9
|
+
return `sentinels/docker/build/${component.name}.built`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const dockerExecutor = {
|
|
2
|
+
async run(script, options) {
|
|
3
|
+
const exec = await options.container.exec({
|
|
4
|
+
AttachStderr: true,
|
|
5
|
+
AttachStdout: true,
|
|
6
|
+
Cmd: ['bash', '-c', script],
|
|
7
|
+
});
|
|
8
|
+
const stream = await exec.start({});
|
|
9
|
+
if (options.out) {
|
|
10
|
+
options.container.modem.demuxStream(stream, options.out, options.out);
|
|
11
|
+
}
|
|
12
|
+
return stream;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
export const shellExecutor = {
|
|
3
|
+
async run(script, options) {
|
|
4
|
+
const process = execa(script, {
|
|
5
|
+
all: true,
|
|
6
|
+
cwd: options.cwd,
|
|
7
|
+
shell: true,
|
|
8
|
+
});
|
|
9
|
+
if (options.out) {
|
|
10
|
+
process.all?.pipe(options.out);
|
|
11
|
+
}
|
|
12
|
+
return process;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentConfig } from '../config/index.js';
|
|
2
|
+
import { DockerComponentBuild } from '../docker/index.js';
|
|
3
|
+
import { Monorepo, TaskInfo } from './index.js';
|
|
4
|
+
import { FilePrerequisite } from '../prerequisites/index.js';
|
|
5
|
+
export declare class Component {
|
|
6
|
+
protected _config: ComponentConfig;
|
|
7
|
+
protected monorepo: Monorepo;
|
|
8
|
+
constructor(_config: ComponentConfig, monorepo: Monorepo);
|
|
9
|
+
get config(): ComponentConfig;
|
|
10
|
+
get context(): string | undefined;
|
|
11
|
+
get dependencies(): Component[];
|
|
12
|
+
get imageName(): string;
|
|
13
|
+
get imageTag(): string;
|
|
14
|
+
get labels(): {
|
|
15
|
+
'emb/component': string;
|
|
16
|
+
};
|
|
17
|
+
get name(): string;
|
|
18
|
+
get rootdir(): string;
|
|
19
|
+
get tasks(): Array<TaskInfo>;
|
|
20
|
+
cloneWith(config: Partial<ComponentConfig>): Component;
|
|
21
|
+
getPrerequisites(): Promise<Array<FilePrerequisite>>;
|
|
22
|
+
join(path: string): string;
|
|
23
|
+
toDockerBuild(): Promise<DockerComponentBuild>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import deepmerge from '@fastify/deepmerge';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { GitPrerequisitePlugin } from '../prerequisites/index.js';
|
|
4
|
+
export class Component {
|
|
5
|
+
_config;
|
|
6
|
+
monorepo;
|
|
7
|
+
constructor(_config, monorepo) {
|
|
8
|
+
this._config = _config;
|
|
9
|
+
this.monorepo = monorepo;
|
|
10
|
+
}
|
|
11
|
+
get config() {
|
|
12
|
+
return structuredClone(this._config);
|
|
13
|
+
}
|
|
14
|
+
get context() {
|
|
15
|
+
return this.config.context;
|
|
16
|
+
}
|
|
17
|
+
get dependencies() {
|
|
18
|
+
return this.monorepo.components.filter((c) => this.config.dependencies?.includes(c.name));
|
|
19
|
+
}
|
|
20
|
+
get imageName() {
|
|
21
|
+
return join(this.monorepo.name, this.name);
|
|
22
|
+
}
|
|
23
|
+
get imageTag() {
|
|
24
|
+
return this.monorepo.defaults.docker?.tag || 'latest';
|
|
25
|
+
}
|
|
26
|
+
get labels() {
|
|
27
|
+
return {
|
|
28
|
+
'emb/component': this.name,
|
|
29
|
+
...this._config.labels,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
get name() {
|
|
33
|
+
return this.config.name;
|
|
34
|
+
}
|
|
35
|
+
get rootdir() {
|
|
36
|
+
return this.monorepo.join(this.context || this.name);
|
|
37
|
+
}
|
|
38
|
+
get tasks() {
|
|
39
|
+
return (this.config.tasks || [])?.map((t) => {
|
|
40
|
+
return {
|
|
41
|
+
...t,
|
|
42
|
+
component: this.name,
|
|
43
|
+
id: `${this.name}:${t.name}`,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
cloneWith(config) {
|
|
48
|
+
return new Component({
|
|
49
|
+
...this.config,
|
|
50
|
+
...config,
|
|
51
|
+
}, this.monorepo);
|
|
52
|
+
}
|
|
53
|
+
async getPrerequisites() {
|
|
54
|
+
// TODO: move this to config with potential overridzs
|
|
55
|
+
const plugin = new GitPrerequisitePlugin();
|
|
56
|
+
return plugin.collect(this);
|
|
57
|
+
}
|
|
58
|
+
join(path) {
|
|
59
|
+
return this.monorepo.join(this.context || this.name, path);
|
|
60
|
+
}
|
|
61
|
+
async toDockerBuild() {
|
|
62
|
+
return {
|
|
63
|
+
buildArgs: await this.monorepo.expand(deepmerge()(this.monorepo.defaults.docker?.buildArgs || {}, this.config.buildArgs || {})),
|
|
64
|
+
context: this.rootdir,
|
|
65
|
+
dockerfile: this.config.dockerfile || 'Dockerfile',
|
|
66
|
+
labels: deepmerge()({
|
|
67
|
+
...this.monorepo.defaults.docker?.labels,
|
|
68
|
+
}, this.labels),
|
|
69
|
+
name: this.imageName,
|
|
70
|
+
prerequisites: await this.getPrerequisites(),
|
|
71
|
+
tag: this.imageTag
|
|
72
|
+
? await this.monorepo.expand(this.imageTag)
|
|
73
|
+
: 'latest',
|
|
74
|
+
target: this.config.target || this.monorepo.defaults?.docker?.target,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentConfig, DefaultSettings, FlavorConfig, IMonorepoConfig, IProjectConfig, PluginConfig } from '../config/index.js';
|
|
2
|
+
export declare class MonorepoConfig implements IMonorepoConfig {
|
|
3
|
+
components: ComponentConfig[];
|
|
4
|
+
defaults: DefaultSettings;
|
|
5
|
+
env: Record<string, string>;
|
|
6
|
+
flavors: Array<FlavorConfig>;
|
|
7
|
+
plugins: Array<PluginConfig>;
|
|
8
|
+
project: IProjectConfig;
|
|
9
|
+
vars: Record<string, unknown>;
|
|
10
|
+
constructor(config: IMonorepoConfig);
|
|
11
|
+
component(name: string): ComponentConfig;
|
|
12
|
+
flavor(name: string): FlavorConfig;
|
|
13
|
+
toJSON(): Required<IMonorepoConfig>;
|
|
14
|
+
with(overrides: Partial<IMonorepoConfig>): MonorepoConfig;
|
|
15
|
+
withFlavor(name: string): MonorepoConfig;
|
|
16
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import deepMerge from '@fastify/deepmerge';
|
|
2
|
+
import { deepMergeArray } from '../utils/index.js';
|
|
3
|
+
export class MonorepoConfig {
|
|
4
|
+
components;
|
|
5
|
+
defaults;
|
|
6
|
+
env;
|
|
7
|
+
flavors;
|
|
8
|
+
plugins;
|
|
9
|
+
project;
|
|
10
|
+
vars;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.components = config.components;
|
|
13
|
+
this.defaults = config.defaults || {};
|
|
14
|
+
this.project = config.project;
|
|
15
|
+
this.vars = config.vars || {};
|
|
16
|
+
this.flavors = config.flavors || [];
|
|
17
|
+
this.env = config.env || {};
|
|
18
|
+
this.plugins = config.plugins || [];
|
|
19
|
+
}
|
|
20
|
+
component(name) {
|
|
21
|
+
const config = this.components.find((c) => c.name === name);
|
|
22
|
+
if (!config) {
|
|
23
|
+
throw new Error(`Unknown component ${name}`);
|
|
24
|
+
}
|
|
25
|
+
return config;
|
|
26
|
+
}
|
|
27
|
+
flavor(name) {
|
|
28
|
+
const flavor = this.flavors.find((f) => f.name === name);
|
|
29
|
+
if (!flavor) {
|
|
30
|
+
throw new Error(`Unknown flavor: ${name}`);
|
|
31
|
+
}
|
|
32
|
+
return flavor;
|
|
33
|
+
}
|
|
34
|
+
toJSON() {
|
|
35
|
+
return {
|
|
36
|
+
components: this.components,
|
|
37
|
+
defaults: this.defaults,
|
|
38
|
+
env: this.env,
|
|
39
|
+
flavors: this.flavors,
|
|
40
|
+
plugins: this.plugins,
|
|
41
|
+
project: this.project,
|
|
42
|
+
vars: this.vars,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
with(overrides) {
|
|
46
|
+
const newConfig = {
|
|
47
|
+
...this.toJSON(),
|
|
48
|
+
components: deepMerge({
|
|
49
|
+
mergeArray() {
|
|
50
|
+
// Merge components by identifying them by name
|
|
51
|
+
return (target, source) => deepMergeArray(target, source, (item) => {
|
|
52
|
+
return item.name;
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
})(this.components, overrides?.components || []),
|
|
56
|
+
defaults: deepMerge()(this.defaults, overrides.defaults),
|
|
57
|
+
env: deepMerge()(this.env, overrides?.env || {}),
|
|
58
|
+
project: deepMerge()(this.project, overrides?.project || {}),
|
|
59
|
+
vars: deepMerge()(this.vars, overrides?.vars || {}),
|
|
60
|
+
};
|
|
61
|
+
return new MonorepoConfig(newConfig);
|
|
62
|
+
}
|
|
63
|
+
withFlavor(name) {
|
|
64
|
+
return this.with(this.flavor(name));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IMonorepoConfig } from '../config/index.js';
|
|
2
|
+
import { IOperation } from '../operations/types.js';
|
|
3
|
+
import { TemplateExpander } from '../utils/index.js';
|
|
4
|
+
import { Component } from './component.js';
|
|
5
|
+
import { EMBStore } from './store/index.js';
|
|
6
|
+
import { TaskInfo } from './types.js';
|
|
7
|
+
export declare class Monorepo {
|
|
8
|
+
private _config;
|
|
9
|
+
private _env;
|
|
10
|
+
private _store;
|
|
11
|
+
private initialized;
|
|
12
|
+
constructor(config: IMonorepoConfig);
|
|
13
|
+
get components(): Component[];
|
|
14
|
+
get config(): IMonorepoConfig;
|
|
15
|
+
get defaults(): import("../config/index.js").DefaultSettings;
|
|
16
|
+
get flavors(): string[];
|
|
17
|
+
get name(): string;
|
|
18
|
+
get rootDir(): string;
|
|
19
|
+
get store(): EMBStore;
|
|
20
|
+
get tasks(): TaskInfo[];
|
|
21
|
+
get vars(): Record<string, unknown>;
|
|
22
|
+
component(name: string): Component;
|
|
23
|
+
expand(str: string, expander?: TemplateExpander): Promise<string>;
|
|
24
|
+
expand<R extends Record<string, unknown>>(record: R, expander?: TemplateExpander): Promise<R>;
|
|
25
|
+
init(): Promise<Monorepo>;
|
|
26
|
+
join(...paths: string[]): string;
|
|
27
|
+
run<I, O>(operation: IOperation<I, O>, args: I): Promise<O>;
|
|
28
|
+
withFlavor(name: string): Promise<Monorepo>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { TemplateExpander } from '../utils/index.js';
|
|
3
|
+
import { Component } from './component.js';
|
|
4
|
+
import { MonorepoConfig } from './config.js';
|
|
5
|
+
import { getPlugin } from './plugins/index.js';
|
|
6
|
+
import { EMBStore } from './store/index.js';
|
|
7
|
+
export class Monorepo {
|
|
8
|
+
_config;
|
|
9
|
+
_env;
|
|
10
|
+
_store;
|
|
11
|
+
initialized = false;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this._config = new MonorepoConfig(config);
|
|
14
|
+
this._env = config.env || {};
|
|
15
|
+
}
|
|
16
|
+
// TODO: cache/improve
|
|
17
|
+
get components() {
|
|
18
|
+
return this._config.components.map((c) => new Component(c, this));
|
|
19
|
+
}
|
|
20
|
+
get config() {
|
|
21
|
+
return this._config.toJSON();
|
|
22
|
+
}
|
|
23
|
+
get defaults() {
|
|
24
|
+
return this._config.defaults;
|
|
25
|
+
}
|
|
26
|
+
get flavors() {
|
|
27
|
+
return this._config.flavors.map((f) => f.name);
|
|
28
|
+
}
|
|
29
|
+
get name() {
|
|
30
|
+
return this._config.project.name;
|
|
31
|
+
}
|
|
32
|
+
get rootDir() {
|
|
33
|
+
return this._config.project.rootDir;
|
|
34
|
+
}
|
|
35
|
+
get store() {
|
|
36
|
+
return this._store;
|
|
37
|
+
}
|
|
38
|
+
get tasks() {
|
|
39
|
+
return this.components.reduce((tasks, cmp) => {
|
|
40
|
+
return [...tasks, ...cmp.tasks];
|
|
41
|
+
}, []);
|
|
42
|
+
}
|
|
43
|
+
get vars() {
|
|
44
|
+
return this._config.vars;
|
|
45
|
+
}
|
|
46
|
+
component(name) {
|
|
47
|
+
return new Component(this._config.component(name), this);
|
|
48
|
+
}
|
|
49
|
+
async expand(strOrRecord, expander = new TemplateExpander()) {
|
|
50
|
+
const options = {
|
|
51
|
+
default: 'vars',
|
|
52
|
+
sources: {
|
|
53
|
+
env: process.env,
|
|
54
|
+
vars: this.vars,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
if (typeof strOrRecord === 'string') {
|
|
58
|
+
return expander.expand(strOrRecord, options);
|
|
59
|
+
}
|
|
60
|
+
return expander.expandRecord(strOrRecord, options);
|
|
61
|
+
}
|
|
62
|
+
// Initialize
|
|
63
|
+
async init() {
|
|
64
|
+
if (this.initialized) {
|
|
65
|
+
throw new Error('Monorepo already initialized');
|
|
66
|
+
}
|
|
67
|
+
this._store = new EMBStore(this);
|
|
68
|
+
await this._store.init();
|
|
69
|
+
const plugins = this._config.plugins.map((p) => {
|
|
70
|
+
const PluginClass = getPlugin(p.name);
|
|
71
|
+
return new PluginClass(p.config, this);
|
|
72
|
+
});
|
|
73
|
+
this._config = await plugins.reduce(async (pConfig, plugin) => {
|
|
74
|
+
const newConfig = await plugin.extendConfig?.(await pConfig);
|
|
75
|
+
return newConfig ?? pConfig;
|
|
76
|
+
}, Promise.resolve(this._config));
|
|
77
|
+
// Expand env vars at the init and then we don't expand anymore
|
|
78
|
+
// The only available source for them is the existing env
|
|
79
|
+
const expander = new TemplateExpander();
|
|
80
|
+
const options = {
|
|
81
|
+
default: 'env',
|
|
82
|
+
sources: {
|
|
83
|
+
env: process.env,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const expanded = await expander.expandRecord(this._config.env, options);
|
|
87
|
+
Object.assign(process.env, expanded);
|
|
88
|
+
this.initialized = true;
|
|
89
|
+
await Promise.all(plugins.map(async (p) => {
|
|
90
|
+
await p.init?.();
|
|
91
|
+
}));
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
// Helper to build relative path to the root dir
|
|
95
|
+
join(...paths) {
|
|
96
|
+
return join(this._config.project.rootDir, ...paths);
|
|
97
|
+
}
|
|
98
|
+
async run(operation, args) {
|
|
99
|
+
return operation.run(args);
|
|
100
|
+
}
|
|
101
|
+
async withFlavor(name) {
|
|
102
|
+
const repo = new Monorepo(this._config.withFlavor(name));
|
|
103
|
+
await repo.init();
|
|
104
|
+
return repo;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
components: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare class BuildComponentsOperation extends AbstractOperation<typeof schema, Array<unknown>> {
|
|
7
|
+
constructor();
|
|
8
|
+
protected _run(input: z.input<typeof schema>): Promise<Array<unknown>>;
|
|
9
|
+
private buildComponent;
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Manager } from '@listr2/manager';
|
|
2
|
+
import { createColors } from 'colorette';
|
|
3
|
+
import { delay, ListrDefaultRendererLogLevels, PRESET_TIMER, } from 'listr2';
|
|
4
|
+
import * as z from 'zod';
|
|
5
|
+
import { BuildImageOperation, getSentinelFile, } from '../../../docker/index.js';
|
|
6
|
+
import { findBuildOrder } from '../../utils/findBuildOrder.js';
|
|
7
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
8
|
+
import { FilePrerequisitePlugin } from '../../../prerequisites/FilePrerequisitePlugin.js';
|
|
9
|
+
import { PrerequisiteType } from '../../../prerequisites/types.js';
|
|
10
|
+
const schema = z.object({
|
|
11
|
+
components: z
|
|
12
|
+
.array(z.string())
|
|
13
|
+
.describe('The list of components to build')
|
|
14
|
+
.optional(),
|
|
15
|
+
});
|
|
16
|
+
export class BuildComponentsOperation extends AbstractOperation {
|
|
17
|
+
constructor() {
|
|
18
|
+
super(schema);
|
|
19
|
+
}
|
|
20
|
+
async _run(input) {
|
|
21
|
+
const ordered = findBuildOrder(this.context.monorepo.components, input.components);
|
|
22
|
+
const tasks = await Promise.all(ordered.map((cmp) => {
|
|
23
|
+
return {
|
|
24
|
+
task: async (context, task) => {
|
|
25
|
+
return this.buildComponent(cmp, task);
|
|
26
|
+
},
|
|
27
|
+
title: `Building ${cmp.name}`,
|
|
28
|
+
};
|
|
29
|
+
}));
|
|
30
|
+
const manager = new Manager({
|
|
31
|
+
collectErrors: 'minimal',
|
|
32
|
+
concurrent: false,
|
|
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
|
+
},
|
|
48
|
+
});
|
|
49
|
+
manager.add([
|
|
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;
|
|
63
|
+
}
|
|
64
|
+
async buildComponent(cmp, parentTask) {
|
|
65
|
+
return parentTask.newListr([
|
|
66
|
+
// Collect all the prerequisites and other build infos
|
|
67
|
+
// (This is when variables are expanded etc)
|
|
68
|
+
{
|
|
69
|
+
async task(ctx) {
|
|
70
|
+
// Reset the context to defaults (as apparently the context is shared amongst branches??)
|
|
71
|
+
// TODO understand and fix
|
|
72
|
+
ctx.skip = false;
|
|
73
|
+
//
|
|
74
|
+
ctx.parentTask = parentTask;
|
|
75
|
+
ctx.sentinelFile = getSentinelFile(cmp);
|
|
76
|
+
ctx.plugin = new FilePrerequisitePlugin();
|
|
77
|
+
ctx.build = await cmp.toDockerBuild();
|
|
78
|
+
},
|
|
79
|
+
title: 'Prepare build context',
|
|
80
|
+
},
|
|
81
|
+
// Check for sentinal information to see if the build can be skipped
|
|
82
|
+
{
|
|
83
|
+
task: async (ctx) => {
|
|
84
|
+
ctx.preBuildMeta = await ctx.plugin.meta(cmp, ctx.build.prerequisites, 'pre');
|
|
85
|
+
let lastValue;
|
|
86
|
+
try {
|
|
87
|
+
lastValue = (await this.context.monorepo.store.readFile(ctx.sentinelFile)).toString();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
lastValue = undefined;
|
|
91
|
+
}
|
|
92
|
+
if (lastValue) {
|
|
93
|
+
const diff = await ctx.plugin.diff(cmp, ctx.build.prerequisites, lastValue, ctx.preBuildMeta);
|
|
94
|
+
if (!diff) {
|
|
95
|
+
ctx.skip = true;
|
|
96
|
+
ctx.parentTask.skip(`${ctx.parentTask.title} (cache hit)`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
title: 'Checking prerequisites',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
task: async (ctx, task) => {
|
|
104
|
+
if (ctx.skip) {
|
|
105
|
+
return task.skip();
|
|
106
|
+
}
|
|
107
|
+
await delay(500);
|
|
108
|
+
const title = `Building image ${ctx.build.name}:${ctx.build.tag}`;
|
|
109
|
+
task.title = title;
|
|
110
|
+
const op = new BuildImageOperation((progress) => {
|
|
111
|
+
task.title = progress;
|
|
112
|
+
});
|
|
113
|
+
await this.context.monorepo.run(op, {
|
|
114
|
+
...ctx.build,
|
|
115
|
+
src: ctx.build.prerequisites
|
|
116
|
+
.filter((p) => {
|
|
117
|
+
return p.type === PrerequisiteType.file;
|
|
118
|
+
})
|
|
119
|
+
.map((p) => p.path),
|
|
120
|
+
tag: ctx.build.name + ':' + ctx.build.tag,
|
|
121
|
+
});
|
|
122
|
+
// Restore title
|
|
123
|
+
task.title = title;
|
|
124
|
+
},
|
|
125
|
+
title: 'Building image',
|
|
126
|
+
},
|
|
127
|
+
// Update sentinel file
|
|
128
|
+
{
|
|
129
|
+
task: async (ctx, task) => {
|
|
130
|
+
if (ctx.skip) {
|
|
131
|
+
return task.skip();
|
|
132
|
+
}
|
|
133
|
+
const sentinelValue = await ctx.plugin.meta(cmp, ctx.build.prerequisites, 'post');
|
|
134
|
+
await this.context.monorepo.store.writeFile(ctx.sentinelFile, sentinelValue);
|
|
135
|
+
},
|
|
136
|
+
title: 'Dumping cache info',
|
|
137
|
+
},
|
|
138
|
+
], {
|
|
139
|
+
rendererOptions: {
|
|
140
|
+
collapseSubtasks: true,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './BuildComponentsOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './BuildComponentsOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/index.js';
|