@enspirit/emb 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/cli/commands/down.js +2 -2
- package/dist/src/docker/compose/operations/ComposeDownOperation.d.ts +3 -2
- package/dist/src/docker/compose/operations/ComposeDownOperation.js +4 -2
- package/dist/src/docker/compose/operations/ComposeUpOperation.js +2 -2
- package/dist/src/docker/operations/images/BuildImageOperation.d.ts +2 -2
- package/dist/src/docker/operations/images/BuildImageOperation.js +26 -24
- package/dist/src/docker/operations/images/PushImagesOperation.d.ts +14 -0
- package/dist/src/docker/operations/images/PushImagesOperation.js +22 -0
- package/dist/src/docker/resources/DockerImageResource.js +24 -25
- package/dist/src/monorepo/monorepo.d.ts +3 -1
- package/dist/src/monorepo/monorepo.js +5 -4
- package/dist/src/monorepo/operations/fs/CreateFileOperation.d.ts +3 -1
- package/dist/src/monorepo/operations/fs/CreateFileOperation.js +3 -1
- package/dist/src/monorepo/operations/resources/BuildResourcesOperation.d.ts +3 -6
- package/dist/src/monorepo/operations/resources/BuildResourcesOperation.js +19 -31
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.d.ts +3 -2
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +4 -1
- package/dist/src/monorepo/operations/tasks/RunTasksOperation.d.ts +1 -1
- package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +10 -6
- package/dist/src/monorepo/resources/FileResourceBuilder.d.ts +15 -0
- package/dist/src/monorepo/resources/FileResourceBuilder.js +19 -0
- package/dist/src/monorepo/resources/ResourceFactory.d.ts +7 -29
- package/dist/src/monorepo/resources/ResourceFactory.js +5 -5
- package/dist/src/monorepo/resources/abstract/AbstractResourceBuilder.d.ts +23 -0
- package/dist/src/monorepo/resources/abstract/AbstractResourceBuilder.js +18 -0
- package/dist/src/monorepo/resources/abstract/SentinelFileBasedBuilder.d.ts +27 -0
- package/dist/src/monorepo/resources/abstract/SentinelFileBasedBuilder.js +46 -0
- package/dist/src/monorepo/resources/abstract/index.d.ts +2 -0
- package/dist/src/monorepo/resources/abstract/index.js +2 -0
- package/dist/src/monorepo/resources/index.d.ts +3 -1
- package/dist/src/monorepo/resources/index.js +3 -1
- package/dist/src/monorepo/resources/types.d.ts +36 -0
- package/dist/src/monorepo/types.d.ts +3 -1
- package/dist/src/operations/abstract/AbstractOperation.d.ts +5 -5
- package/dist/src/operations/types.d.ts +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +30 -9
- package/dist/src/monorepo/resources/FileResource.js +0 -17
- /package/dist/src/monorepo/resources/{FileResource.d.ts → types.js} +0 -0
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ export default class DownCommand extends FlavoredCommand {
|
|
|
11
11
|
const runner = new Listr([
|
|
12
12
|
{
|
|
13
13
|
rendererOptions: { persistentOutput: true },
|
|
14
|
-
async task() {
|
|
15
|
-
return monorepo.run(new ComposeDownOperation(), {});
|
|
14
|
+
async task(ctx, task) {
|
|
15
|
+
return monorepo.run(new ComposeDownOperation(task.stdout()), {});
|
|
16
16
|
},
|
|
17
17
|
title: 'Stopping project',
|
|
18
18
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
import * as z from 'zod';
|
|
3
3
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
4
|
/**
|
|
@@ -6,7 +6,8 @@ import { AbstractOperation } from '../../../operations/index.js';
|
|
|
6
6
|
*/
|
|
7
7
|
declare const schema: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
|
|
8
8
|
export declare class ComposeDownOperation extends AbstractOperation<typeof schema, Readable> {
|
|
9
|
-
|
|
9
|
+
protected out: Writable;
|
|
10
|
+
constructor(out: Writable);
|
|
10
11
|
protected _run(_input: z.input<typeof schema>): Promise<Readable>;
|
|
11
12
|
}
|
|
12
13
|
export {};
|
|
@@ -7,13 +7,15 @@ import { AbstractOperation } from '../../../operations/index.js';
|
|
|
7
7
|
*/
|
|
8
8
|
const schema = z.object({}).optional();
|
|
9
9
|
export class ComposeDownOperation extends AbstractOperation {
|
|
10
|
-
|
|
10
|
+
out;
|
|
11
|
+
constructor(out) {
|
|
11
12
|
super(schema);
|
|
13
|
+
this.out = out;
|
|
12
14
|
}
|
|
13
15
|
async _run(_input) {
|
|
14
16
|
const { monorepo } = getContext();
|
|
15
17
|
const command = ['docker', 'compose', 'down'];
|
|
16
|
-
return monorepo.run(new ExecuteLocalCommandOperation(), {
|
|
18
|
+
return monorepo.run(new ExecuteLocalCommandOperation(this.out), {
|
|
17
19
|
script: command.join(' '),
|
|
18
20
|
workingDir: monorepo.rootDir,
|
|
19
21
|
});
|
|
@@ -26,8 +26,8 @@ export class ComposeUpOperation extends AbstractOperation {
|
|
|
26
26
|
}
|
|
27
27
|
manager.add([
|
|
28
28
|
{
|
|
29
|
-
async task() {
|
|
30
|
-
return monorepo.run(new ExecuteLocalCommandOperation(), {
|
|
29
|
+
async task(ctx, task) {
|
|
30
|
+
return monorepo.run(new ExecuteLocalCommandOperation(task.stdout()), {
|
|
31
31
|
script: command.join(' '),
|
|
32
32
|
workingDir: monorepo.rootDir,
|
|
33
33
|
});
|
|
@@ -13,8 +13,8 @@ export declare const BuildImageOperationInputSchema: z.ZodObject<{
|
|
|
13
13
|
labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
14
14
|
target: z.ZodOptional<z.ZodString>;
|
|
15
15
|
}, z.core.$strip>;
|
|
16
|
-
export declare class BuildImageOperation extends AbstractOperation<typeof BuildImageOperationInputSchema,
|
|
16
|
+
export declare class BuildImageOperation extends AbstractOperation<typeof BuildImageOperationInputSchema, void> {
|
|
17
17
|
private out?;
|
|
18
18
|
constructor(out?: Writable | undefined);
|
|
19
|
-
protected _run(input: z.input<typeof BuildImageOperationInputSchema>): Promise<
|
|
19
|
+
protected _run(input: z.input<typeof BuildImageOperationInputSchema>): Promise<void>;
|
|
20
20
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
1
2
|
import * as z from 'zod';
|
|
2
3
|
import { decodeBuildkitStatusResponse } from '../../index.js';
|
|
3
4
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
@@ -36,8 +37,28 @@ export class BuildImageOperation extends AbstractOperation {
|
|
|
36
37
|
this.out = out;
|
|
37
38
|
}
|
|
38
39
|
async _run(input) {
|
|
39
|
-
const
|
|
40
|
-
|
|
40
|
+
const logFile = await this.context.monorepo.store.createWriteStream(`logs/docker/build/${input.tag}.log`);
|
|
41
|
+
const decodeBuildkit = new Transform({
|
|
42
|
+
transform: async (chunk, encoding, callback) => {
|
|
43
|
+
try {
|
|
44
|
+
try {
|
|
45
|
+
const { aux } = JSON.parse(chunk);
|
|
46
|
+
const { vertexes } = await decodeBuildkitStatusResponse(aux);
|
|
47
|
+
vertexes.forEach((v) => {
|
|
48
|
+
logFile.write(`${JSON.stringify(v)}\n`);
|
|
49
|
+
this.out?.write(`${v.name}\n`);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
//
|
|
54
|
+
}
|
|
55
|
+
callback();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('__OOPS', error);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
});
|
|
41
62
|
const stream = await this.context.docker.buildImage({
|
|
42
63
|
context: input.context,
|
|
43
64
|
src: [...input.src],
|
|
@@ -49,29 +70,10 @@ export class BuildImageOperation extends AbstractOperation {
|
|
|
49
70
|
target: input.target,
|
|
50
71
|
version: '2',
|
|
51
72
|
});
|
|
52
|
-
this.out?.write('Starting build\n');
|
|
53
73
|
return new Promise((resolve, reject) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}, async (trace) => {
|
|
58
|
-
if (trace.error) {
|
|
59
|
-
logStream.close();
|
|
60
|
-
reject(new Error(trace.error));
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
try {
|
|
64
|
-
const { vertexes } = await decodeBuildkitStatusResponse(trace.aux);
|
|
65
|
-
vertexes.forEach((v) => {
|
|
66
|
-
// logStream.write(JSON.stringify(v) + '\n');
|
|
67
|
-
this.out?.write(v.name + '\n');
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
console.error(error);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
});
|
|
74
|
+
stream.pipe(decodeBuildkit);
|
|
75
|
+
stream.on('close', () => resolve());
|
|
76
|
+
stream.on('error', (error) => reject(error));
|
|
75
77
|
});
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Image/operation/ImagePush
|
|
5
|
+
*/
|
|
6
|
+
declare const schema: z.ZodObject<{
|
|
7
|
+
images: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
8
|
+
tag: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export declare class PushImagesOperation extends AbstractOperation<typeof schema, void> {
|
|
11
|
+
constructor();
|
|
12
|
+
protected _run(_input: z.input<typeof schema>): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Image/operation/ImagePush
|
|
5
|
+
*/
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
images: z
|
|
8
|
+
.array(z.string())
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('The names of images to push (The name should be provided without tag. Use the `tag` parameter to specify why tag to push)'),
|
|
11
|
+
tag: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.default('latest')
|
|
15
|
+
.describe('Tag of the images to push'),
|
|
16
|
+
});
|
|
17
|
+
export class PushImagesOperation extends AbstractOperation {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(schema);
|
|
20
|
+
}
|
|
21
|
+
async _run(_input) { }
|
|
22
|
+
}
|
|
@@ -2,15 +2,17 @@ import { fdir as Fdir } from 'fdir';
|
|
|
2
2
|
import { stat, statfs } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import pMap from 'p-map';
|
|
5
|
+
import { SentinelFileBasedBuilder } from '../../monorepo/index.js';
|
|
5
6
|
import { GitPrerequisitePlugin } from '../../prerequisites/index.js';
|
|
6
7
|
import { ResourceFactory, } from '../../monorepo/resources/ResourceFactory.js';
|
|
7
8
|
import { BuildImageOperation } from '../operations/index.js';
|
|
8
|
-
class DockerImageResourceBuilder {
|
|
9
|
+
class DockerImageResourceBuilder extends SentinelFileBasedBuilder {
|
|
9
10
|
buildContext;
|
|
10
|
-
|
|
11
|
+
dockerContext;
|
|
11
12
|
constructor(buildContext) {
|
|
13
|
+
super(buildContext);
|
|
12
14
|
this.buildContext = buildContext;
|
|
13
|
-
this.
|
|
15
|
+
this.dockerContext = this.config?.context
|
|
14
16
|
? this.config.context[0] === '/'
|
|
15
17
|
? buildContext.monorepo.join(this.config.context)
|
|
16
18
|
: buildContext.component.join(this.config.context)
|
|
@@ -20,72 +22,69 @@ class DockerImageResourceBuilder {
|
|
|
20
22
|
return this.buildContext.monorepo;
|
|
21
23
|
}
|
|
22
24
|
get config() {
|
|
23
|
-
return
|
|
25
|
+
return this.buildContext.config.params;
|
|
24
26
|
}
|
|
25
27
|
get component() {
|
|
26
28
|
return this.buildContext.component;
|
|
27
29
|
}
|
|
28
|
-
async
|
|
30
|
+
async _build(_resource, out) {
|
|
29
31
|
// Ensure the folder exists
|
|
30
|
-
await statfs(this.
|
|
32
|
+
await statfs(this.dockerContext);
|
|
31
33
|
const imageName = [
|
|
32
34
|
this.monorepo.name,
|
|
33
|
-
this.config
|
|
35
|
+
this.config?.tag || this.component.name,
|
|
34
36
|
].join('/');
|
|
35
|
-
const tagName = this.config
|
|
37
|
+
const tagName = this.config?.tag || this.monorepo.defaults.docker?.tag || 'latest';
|
|
36
38
|
const crawler = new Fdir();
|
|
37
39
|
const sources = await crawler
|
|
38
40
|
.withRelativePaths()
|
|
39
|
-
.crawl(this.
|
|
41
|
+
.crawl(this.dockerContext)
|
|
40
42
|
.withPromise();
|
|
41
43
|
const buildParams = {
|
|
42
|
-
context: this.
|
|
43
|
-
dockerfile: this.config
|
|
44
|
+
context: this.dockerContext,
|
|
45
|
+
dockerfile: this.config?.dockerfile || 'Dockerfile',
|
|
44
46
|
src: sources,
|
|
45
47
|
buildArgs: await this.monorepo.expand({
|
|
46
48
|
...this.monorepo.defaults.docker?.buildArgs,
|
|
47
|
-
...this.config
|
|
49
|
+
...this.config?.buildArgs,
|
|
48
50
|
}),
|
|
49
51
|
tag: await this.monorepo.expand(`${imageName}:${tagName}`),
|
|
50
52
|
labels: await this.monorepo.expand({
|
|
51
|
-
...this.config
|
|
53
|
+
...this.config?.labels,
|
|
52
54
|
'emb/project': this.monorepo.name,
|
|
53
55
|
'emb/component': this.component.name,
|
|
54
56
|
'emb/flavor': this.monorepo.currentFlavor,
|
|
55
57
|
}),
|
|
56
|
-
target: this.config
|
|
58
|
+
target: this.config?.target,
|
|
57
59
|
};
|
|
58
60
|
return {
|
|
59
61
|
input: buildParams,
|
|
60
62
|
operation: new BuildImageOperation(out),
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
|
-
async
|
|
65
|
+
async _mustBuild() {
|
|
64
66
|
const plugin = new GitPrerequisitePlugin();
|
|
65
|
-
const sources = await plugin.collect(this.
|
|
67
|
+
const sources = await plugin.collect(this.dockerContext);
|
|
66
68
|
const lastUpdated = await this.lastUpdatedInfo(sources);
|
|
67
|
-
if (!
|
|
68
|
-
return
|
|
69
|
+
if (!lastUpdated) {
|
|
70
|
+
return;
|
|
69
71
|
}
|
|
70
|
-
return
|
|
71
|
-
? lastUpdated
|
|
72
|
-
: undefined;
|
|
72
|
+
return { mtime: lastUpdated.time.getTime() };
|
|
73
73
|
}
|
|
74
74
|
async lastUpdatedInfo(sources) {
|
|
75
75
|
const stats = await pMap(sources, async (s) => {
|
|
76
|
-
const stats = await stat(join(this.
|
|
76
|
+
const stats = await stat(join(this.dockerContext, s.path));
|
|
77
77
|
return {
|
|
78
78
|
time: stats.mtime,
|
|
79
79
|
path: s.path,
|
|
80
80
|
};
|
|
81
81
|
}, { concurrency: 30 });
|
|
82
82
|
if (stats.length === 0) {
|
|
83
|
-
return
|
|
83
|
+
return;
|
|
84
84
|
}
|
|
85
85
|
return stats.reduce((last, entry) => {
|
|
86
86
|
return last.time > entry.time ? last : entry;
|
|
87
87
|
}, stats[0]);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
ResourceFactory.register('docker/image', async (context) => new DockerImageResourceBuilder(context));
|
|
90
|
+
ResourceFactory.register('docker/image', DockerImageResourceBuilder);
|
|
@@ -30,7 +30,9 @@ export declare class Monorepo {
|
|
|
30
30
|
private installEnv;
|
|
31
31
|
init(): Promise<Monorepo>;
|
|
32
32
|
join(...paths: string[]): string;
|
|
33
|
-
run<I, O>(operation: IOperation<I, O
|
|
33
|
+
run<I extends void, O>(operation: IOperation<I, O>): Promise<O>;
|
|
34
|
+
run<I extends void, O>(operation: IOperation<I, O>): Promise<O>;
|
|
35
|
+
run<I, O>(operation: IOperation<I, O>, input: I): Promise<O>;
|
|
34
36
|
private expandPatches;
|
|
35
37
|
withFlavor(flavorName: string): Promise<Monorepo>;
|
|
36
38
|
}
|
|
@@ -161,11 +161,13 @@ export class Monorepo {
|
|
|
161
161
|
join(...paths) {
|
|
162
162
|
return join(this.rootDir, ...paths);
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
run(operation, input = undefined) {
|
|
165
|
+
if (input === undefined) {
|
|
166
|
+
return operation.run();
|
|
167
|
+
}
|
|
168
|
+
return operation.run(input);
|
|
166
169
|
}
|
|
167
170
|
async expandPatches(patches) {
|
|
168
|
-
console.log('PATCHES', patches);
|
|
169
171
|
const expanded = Promise.all(patches.map(async (patch) => {
|
|
170
172
|
if (!('value' in patch)) {
|
|
171
173
|
return patch;
|
|
@@ -175,7 +177,6 @@ export class Monorepo {
|
|
|
175
177
|
value: await this.expand(patch.value),
|
|
176
178
|
};
|
|
177
179
|
}));
|
|
178
|
-
console.log('EXPANDED', patches);
|
|
179
180
|
return expanded;
|
|
180
181
|
}
|
|
181
182
|
async withFlavor(flavorName) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
1
2
|
import * as z from 'zod';
|
|
2
3
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
3
4
|
declare const schema: z.ZodObject<{
|
|
@@ -5,7 +6,8 @@ declare const schema: z.ZodObject<{
|
|
|
5
6
|
force: z.ZodOptional<z.ZodBoolean>;
|
|
6
7
|
}, z.core.$strip>;
|
|
7
8
|
export declare class CreateFileOperation extends AbstractOperation<typeof schema, unknown> {
|
|
8
|
-
|
|
9
|
+
protected out?: Writable | undefined;
|
|
10
|
+
constructor(out?: Writable | undefined);
|
|
9
11
|
protected _run(input: z.input<typeof schema>): Promise<void>;
|
|
10
12
|
}
|
|
11
13
|
export {};
|
|
@@ -10,8 +10,10 @@ const schema = z.object({
|
|
|
10
10
|
.describe("Update 'atime' and 'mtime' if the file already exists"),
|
|
11
11
|
});
|
|
12
12
|
export class CreateFileOperation extends AbstractOperation {
|
|
13
|
-
|
|
13
|
+
out;
|
|
14
|
+
constructor(out) {
|
|
14
15
|
super(schema);
|
|
16
|
+
this.out = out;
|
|
15
17
|
}
|
|
16
18
|
async _run(input) {
|
|
17
19
|
try {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
-
import { ResourceInfo } from '../../index.js';
|
|
3
|
-
import { ResourceBuilderInfo } from '../../resources/ResourceFactory.js';
|
|
2
|
+
import { IResourceBuilder, ResourceInfo } from '../../index.js';
|
|
4
3
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
5
4
|
export type BuildResourceMeta = {
|
|
6
5
|
dryRun?: boolean;
|
|
7
6
|
force?: boolean;
|
|
8
7
|
resource?: ResourceInfo;
|
|
9
|
-
builder?:
|
|
8
|
+
builder?: IResourceBuilder<unknown, unknown, unknown>;
|
|
10
9
|
builderInput?: unknown;
|
|
11
10
|
sentinelData?: unknown;
|
|
12
11
|
cacheHit?: boolean;
|
|
@@ -18,11 +17,9 @@ declare const schema: z.ZodObject<{
|
|
|
18
17
|
force: z.ZodOptional<z.ZodBoolean>;
|
|
19
18
|
}, z.core.$strip>;
|
|
20
19
|
export declare class BuildResourcesOperation extends AbstractOperation<typeof schema, Record<string, BuildResourceMeta>> {
|
|
20
|
+
private built;
|
|
21
21
|
constructor();
|
|
22
22
|
protected _run(input: z.input<typeof schema>): Promise<Record<string, BuildResourceMeta>>;
|
|
23
23
|
private buildResource;
|
|
24
|
-
private sentinelFilePath;
|
|
25
|
-
private storeSentinelData;
|
|
26
|
-
private readSentinelFile;
|
|
27
24
|
}
|
|
28
25
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PRESET_TIMER, } from 'listr2';
|
|
2
2
|
import * as z from 'zod';
|
|
3
3
|
import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
|
|
4
|
-
import { ResourceFactory
|
|
4
|
+
import { ResourceFactory } from '../../resources/ResourceFactory.js';
|
|
5
5
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
6
6
|
const schema = z.object({
|
|
7
7
|
resources: z
|
|
@@ -22,6 +22,9 @@ const schema = z.object({
|
|
|
22
22
|
.describe('Bypass the cache and force the build'),
|
|
23
23
|
});
|
|
24
24
|
export class BuildResourcesOperation extends AbstractOperation {
|
|
25
|
+
// keep track of what has been built
|
|
26
|
+
// to ensure depedencies cannot ignore their turn
|
|
27
|
+
built = [];
|
|
25
28
|
constructor() {
|
|
26
29
|
super(schema);
|
|
27
30
|
}
|
|
@@ -92,16 +95,18 @@ export class BuildResourcesOperation extends AbstractOperation {
|
|
|
92
95
|
/** Skip the build if the builder knows it can be skipped */
|
|
93
96
|
task: async (ctx) => {
|
|
94
97
|
if (ctx.builder?.mustBuild) {
|
|
95
|
-
|
|
96
|
-
ctx.sentinelData =
|
|
97
|
-
await ctx.builder.mustBuild(previousSentinelData);
|
|
98
|
+
ctx.sentinelData = await ctx.builder.mustBuild(ctx.resource);
|
|
98
99
|
ctx.cacheHit = !ctx.sentinelData;
|
|
100
|
+
// If one of our dependency was built, we force the re-build
|
|
101
|
+
// despite the cache-hit
|
|
102
|
+
const found = ctx.resource.dependencies?.find((d) => Boolean(this.built.find((r) => r.id === d)));
|
|
103
|
+
ctx.force = ctx.force || Boolean(found);
|
|
99
104
|
}
|
|
100
105
|
},
|
|
101
106
|
},
|
|
102
107
|
{
|
|
103
|
-
title: `Build
|
|
104
|
-
async
|
|
108
|
+
title: `Build ${resource.id}`,
|
|
109
|
+
task: async (ctx, task) => {
|
|
105
110
|
const skip = (prefix) => {
|
|
106
111
|
parentTask.title = `${prefix} ${resource.id}`;
|
|
107
112
|
task.skip();
|
|
@@ -110,26 +115,28 @@ export class BuildResourcesOperation extends AbstractOperation {
|
|
|
110
115
|
if (ctx.cacheHit && !ctx.force && !ctx.dryRun) {
|
|
111
116
|
return skip('[cache hit]');
|
|
112
117
|
}
|
|
113
|
-
const { input, operation } = await ctx.builder.build(task.stdout());
|
|
118
|
+
const { input, operation } = await ctx.builder.build(ctx.resource, task.stdout());
|
|
114
119
|
ctx.builderInput = input;
|
|
120
|
+
this.built.push(ctx.resource);
|
|
115
121
|
if (ctx.dryRun) {
|
|
116
122
|
return skip('[dry run]');
|
|
117
123
|
}
|
|
118
|
-
|
|
124
|
+
const output = await operation.run(ctx.builderInput);
|
|
125
|
+
if (ctx.sentinelData) {
|
|
126
|
+
ctx.builder.commit?.(ctx.resource, output, ctx.sentinelData);
|
|
127
|
+
}
|
|
128
|
+
return output;
|
|
119
129
|
},
|
|
120
130
|
},
|
|
121
131
|
{
|
|
122
132
|
// Return build meta data and dump
|
|
123
133
|
// cache data into sentinel file
|
|
124
|
-
|
|
134
|
+
async task(ctx) {
|
|
125
135
|
if (ctx.builder) {
|
|
126
136
|
delete ctx.builder;
|
|
127
137
|
}
|
|
128
138
|
//
|
|
129
139
|
parentContext[resource.id] = ctx;
|
|
130
|
-
if (ctx.sentinelData && !ctx.dryRun) {
|
|
131
|
-
await this.storeSentinelData(resource, ctx.sentinelData);
|
|
132
|
-
}
|
|
133
140
|
},
|
|
134
141
|
},
|
|
135
142
|
], {
|
|
@@ -142,23 +149,4 @@ export class BuildResourcesOperation extends AbstractOperation {
|
|
|
142
149
|
});
|
|
143
150
|
return list;
|
|
144
151
|
}
|
|
145
|
-
sentinelFilePath(resource) {
|
|
146
|
-
const { monorepo } = this.context;
|
|
147
|
-
return `sentinels/flavors/${monorepo.currentFlavor}/${resource.component}/${resource.name}.built`;
|
|
148
|
-
}
|
|
149
|
-
async storeSentinelData(resource, data) {
|
|
150
|
-
await this.context.monorepo.store.writeFile(this.sentinelFilePath(resource), JSON.stringify(data));
|
|
151
|
-
}
|
|
152
|
-
async readSentinelFile(resource) {
|
|
153
|
-
const path = this.sentinelFilePath(resource);
|
|
154
|
-
const stats = await this.context.monorepo.store.stat(path, false);
|
|
155
|
-
if (!stats) {
|
|
156
|
-
return undefined;
|
|
157
|
-
}
|
|
158
|
-
const data = await this.context.monorepo.store.readFile(path, false);
|
|
159
|
-
return {
|
|
160
|
-
data,
|
|
161
|
-
mtime: stats.mtime.getTime(),
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
152
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Readable } from 'node:stream';
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
2
|
import * as z from 'zod';
|
|
3
3
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
4
|
/**
|
|
@@ -10,7 +10,8 @@ declare const schema: z.ZodObject<{
|
|
|
10
10
|
workingDir: z.ZodOptional<z.ZodString>;
|
|
11
11
|
}, z.core.$strip>;
|
|
12
12
|
export declare class ExecuteLocalCommandOperation extends AbstractOperation<typeof schema, Readable> {
|
|
13
|
-
|
|
13
|
+
protected out: Writable;
|
|
14
|
+
constructor(out: Writable);
|
|
14
15
|
protected _run(input: z.input<typeof schema>): Promise<Readable>;
|
|
15
16
|
}
|
|
16
17
|
export {};
|
|
@@ -16,8 +16,10 @@ const schema = z.object({
|
|
|
16
16
|
.describe('The working directory for the exec process inside the container'),
|
|
17
17
|
});
|
|
18
18
|
export class ExecuteLocalCommandOperation extends AbstractOperation {
|
|
19
|
-
|
|
19
|
+
out;
|
|
20
|
+
constructor(out) {
|
|
20
21
|
super(schema);
|
|
22
|
+
this.out = out;
|
|
21
23
|
}
|
|
22
24
|
async _run(input) {
|
|
23
25
|
const process = execa(input.script, {
|
|
@@ -25,6 +27,7 @@ export class ExecuteLocalCommandOperation extends AbstractOperation {
|
|
|
25
27
|
cwd: input.workingDir,
|
|
26
28
|
shell: true,
|
|
27
29
|
});
|
|
30
|
+
process.all.pipe(this.out);
|
|
28
31
|
return process.all;
|
|
29
32
|
}
|
|
30
33
|
}
|
|
@@ -16,5 +16,5 @@ export type TaskWithScript = TaskInfo & {
|
|
|
16
16
|
export declare class RunTasksOperation implements IOperation<RunTasksOperationParams, Array<TaskInfo>> {
|
|
17
17
|
run(params: RunTasksOperationParams): Promise<Array<TaskInfo>>;
|
|
18
18
|
protected runDocker(task: TaskWithScript, out?: Writable): Promise<void>;
|
|
19
|
-
protected runLocal(task: TaskWithScript): Promise<import("stream").Readable>;
|
|
19
|
+
protected runLocal(task: TaskWithScript, out: Writable): Promise<import("stream").Readable>;
|
|
20
20
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getContext } from '../../../index.js';
|
|
2
|
+
import { PassThrough } from 'node:stream';
|
|
2
3
|
import { ComposeExecOperation } from '../../../docker/index.js';
|
|
3
4
|
import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
|
|
4
5
|
import { ExecuteLocalCommandOperation } from '../index.js';
|
|
@@ -28,17 +29,22 @@ export class RunTasksOperation {
|
|
|
28
29
|
if (!task.script) {
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
32
|
+
console.log('YES WE DO', task.component);
|
|
31
33
|
const executor = params.executor ??
|
|
32
34
|
(task.component ? ExecutorType.container : ExecutorType.local);
|
|
33
35
|
if (executor === ExecutorType.container && !task.component) {
|
|
34
36
|
throw new Error('Cannot use the container executor with global tasks');
|
|
35
37
|
}
|
|
38
|
+
const tee = new PassThrough();
|
|
39
|
+
const logFile = await monorepo.store.createWriteStream(`logs/tasks/${task.id}.logs`);
|
|
40
|
+
tee.pipe(listrTask.stdout());
|
|
41
|
+
tee.pipe(logFile);
|
|
36
42
|
switch (executor) {
|
|
37
43
|
case ExecutorType.container: {
|
|
38
|
-
return this.runDocker(task,
|
|
44
|
+
return this.runDocker(task, tee);
|
|
39
45
|
}
|
|
40
46
|
case ExecutorType.local: {
|
|
41
|
-
return this.runLocal(task);
|
|
47
|
+
return this.runLocal(task, tee);
|
|
42
48
|
}
|
|
43
49
|
default: {
|
|
44
50
|
throw new Error(`Unssuported executor type: ${executor}`);
|
|
@@ -54,18 +60,16 @@ export class RunTasksOperation {
|
|
|
54
60
|
async runDocker(task, out) {
|
|
55
61
|
const { monorepo } = getContext();
|
|
56
62
|
return monorepo.run(new ComposeExecOperation(out), {
|
|
57
|
-
attachStderr: true,
|
|
58
|
-
attachStdout: true,
|
|
59
63
|
service: task.component,
|
|
60
64
|
command: task.script,
|
|
61
65
|
});
|
|
62
66
|
}
|
|
63
|
-
async runLocal(task) {
|
|
67
|
+
async runLocal(task, out) {
|
|
64
68
|
const { monorepo } = getContext();
|
|
65
69
|
const cwd = task.component
|
|
66
70
|
? monorepo.join(monorepo.component(task.component).rootDir)
|
|
67
71
|
: monorepo.rootDir;
|
|
68
|
-
return monorepo.run(new ExecuteLocalCommandOperation(), {
|
|
72
|
+
return monorepo.run(new ExecuteLocalCommandOperation(out), {
|
|
69
73
|
script: task.script,
|
|
70
74
|
workingDir: cwd,
|
|
71
75
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { CreateFileOperation, IResourceBuilder, ResourceInfo } from '../index.js';
|
|
3
|
+
import { OpInput, OpOutput } from '../../operations/index.js';
|
|
4
|
+
import { ResourceBuildContext } from './ResourceFactory.js';
|
|
5
|
+
export declare class FileResourceBuilder implements IResourceBuilder<OpInput<CreateFileOperation>, OpOutput<CreateFileOperation>, void> {
|
|
6
|
+
protected context: ResourceBuildContext<OpInput<CreateFileOperation>>;
|
|
7
|
+
constructor(context: ResourceBuildContext<OpInput<CreateFileOperation>>);
|
|
8
|
+
build(resource: ResourceInfo<OpInput<CreateFileOperation>>, out?: Writable): Promise<{
|
|
9
|
+
input: {
|
|
10
|
+
path: string;
|
|
11
|
+
force?: boolean | undefined;
|
|
12
|
+
};
|
|
13
|
+
operation: CreateFileOperation;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CreateFileOperation, } from '../index.js';
|
|
2
|
+
import { ResourceFactory } from './ResourceFactory.js';
|
|
3
|
+
export class FileResourceBuilder {
|
|
4
|
+
context;
|
|
5
|
+
constructor(context) {
|
|
6
|
+
this.context = context;
|
|
7
|
+
}
|
|
8
|
+
async build(resource, out) {
|
|
9
|
+
const input = {
|
|
10
|
+
path: this.context.component.join(resource.params?.path || resource.name),
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
input,
|
|
14
|
+
operation: new CreateFileOperation(out),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Bring better abstraction and register as part of the plugin initialization
|
|
19
|
+
ResourceFactory.register('file', FileResourceBuilder);
|
|
@@ -1,34 +1,12 @@
|
|
|
1
|
-
import { Component, Monorepo, ResourceInfo } from '../../index.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export type ResourceBuildContext = {
|
|
5
|
-
config: ResourceInfo;
|
|
1
|
+
import { Component, IResourceBuilder, Monorepo, ResourceInfo } from '../../index.js';
|
|
2
|
+
export type ResourceBuildContext<I> = {
|
|
3
|
+
config: ResourceInfo<I>;
|
|
6
4
|
component: Component;
|
|
7
5
|
monorepo: Monorepo;
|
|
8
6
|
};
|
|
9
|
-
export type
|
|
10
|
-
mtime: number;
|
|
11
|
-
data: T;
|
|
12
|
-
};
|
|
13
|
-
export type ResourceBuilderInfo<I, O, D = unknown> = {
|
|
14
|
-
/**
|
|
15
|
-
* Returns input and operation required to actually
|
|
16
|
-
* build the resources.
|
|
17
|
-
* This allows the dry-run mechanism to be implemented outside
|
|
18
|
-
* resource builder implementations
|
|
19
|
-
*
|
|
20
|
-
* @param out The Writable to use to write logs
|
|
21
|
-
*/
|
|
22
|
-
build(out?: Writable): Promise<{
|
|
23
|
-
input: I;
|
|
24
|
-
operation: IOperation<I, O>;
|
|
25
|
-
}>;
|
|
26
|
-
mustBuild?: (previousSentinelData: SentinelData<D> | undefined) => Promise<undefined | unknown>;
|
|
27
|
-
};
|
|
28
|
-
export type ResourceFactoryOutput<I, O> = Promise<ResourceBuilderInfo<I, O>>;
|
|
29
|
-
export type ResourceOperationFactory<I, O> = (context: ResourceBuildContext) => ResourceFactoryOutput<I, O>;
|
|
7
|
+
export type ResourceBuilderConstructor<I, O, R> = new (context: ResourceBuildContext<I>) => IResourceBuilder<I, O, R>;
|
|
30
8
|
export declare class ResourceFactory {
|
|
31
|
-
protected static types: Record<string,
|
|
32
|
-
static register<I, O>(type: string,
|
|
33
|
-
static factor<I, O>(type: string, context: ResourceBuildContext):
|
|
9
|
+
protected static types: Record<string, ResourceBuilderConstructor<any, any, any>>;
|
|
10
|
+
static register<I, O, R>(type: string, constructor: ResourceBuilderConstructor<I, O, R>): void;
|
|
11
|
+
static factor<I, O, R>(type: string, context: ResourceBuildContext<I>): IResourceBuilder<I, O, R>;
|
|
34
12
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export class ResourceFactory {
|
|
2
2
|
static types = {};
|
|
3
|
-
static register(type,
|
|
3
|
+
static register(type, constructor) {
|
|
4
4
|
if (this.types[type]) {
|
|
5
5
|
throw new Error(`Resource type \`${type}\` already registered`);
|
|
6
6
|
}
|
|
7
|
-
this.types[type] =
|
|
7
|
+
this.types[type] = constructor;
|
|
8
8
|
}
|
|
9
9
|
static factor(type, context) {
|
|
10
|
-
const
|
|
11
|
-
if (!
|
|
10
|
+
const BuilderClass = this.types[type];
|
|
11
|
+
if (!BuilderClass) {
|
|
12
12
|
throw new Error(`Unknown resource type \`${type}\``);
|
|
13
13
|
}
|
|
14
|
-
return
|
|
14
|
+
return new BuilderClass(context);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ResourceInfo } from '../../../index.js';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { IOperation } from '../../../operations/types.js';
|
|
4
|
+
import { ResourceBuildContext } from '../ResourceFactory.js';
|
|
5
|
+
import { IResourceBuilder } from '../types.js';
|
|
6
|
+
export declare abstract class AbstractResourceBuilder<I, O, R> implements IResourceBuilder<I, O, R> {
|
|
7
|
+
protected context: ResourceBuildContext<I>;
|
|
8
|
+
constructor(context: ResourceBuildContext<I>);
|
|
9
|
+
abstract _build(resource: ResourceInfo<I>, out?: Writable): Promise<{
|
|
10
|
+
input: I;
|
|
11
|
+
operation: IOperation<I, O>;
|
|
12
|
+
}>;
|
|
13
|
+
build(resource: ResourceInfo<I>, out?: Writable): Promise<{
|
|
14
|
+
input: I;
|
|
15
|
+
operation: IOperation<I, O>;
|
|
16
|
+
}>;
|
|
17
|
+
abstract _mustBuild?(resource: ResourceInfo<I>): Promise<R | undefined> | undefined;
|
|
18
|
+
mustBuild(resource: ResourceInfo<I>): Promise<R | undefined>;
|
|
19
|
+
_publish?(resource: ResourceInfo<I>, out?: Writable): Promise<void>;
|
|
20
|
+
publish?(resource: ResourceInfo<I>, out?: Writable): Promise<void>;
|
|
21
|
+
abstract _commit(resource: ResourceInfo<I>, output: O, reason: R): Promise<void>;
|
|
22
|
+
commit(resource: ResourceInfo<I>, output: O, reason: R): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class AbstractResourceBuilder {
|
|
2
|
+
context;
|
|
3
|
+
constructor(context) {
|
|
4
|
+
this.context = context;
|
|
5
|
+
}
|
|
6
|
+
build(resource, out) {
|
|
7
|
+
return this._build(resource, out);
|
|
8
|
+
}
|
|
9
|
+
async mustBuild(resource) {
|
|
10
|
+
return this._mustBuild?.(resource);
|
|
11
|
+
}
|
|
12
|
+
async publish(resource, out) {
|
|
13
|
+
return this._publish?.(resource, out);
|
|
14
|
+
}
|
|
15
|
+
async commit(resource, output, reason) {
|
|
16
|
+
return this._commit?.(resource, output, reason);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ResourceInfo } from '../../../index.js';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { IOperation } from '../../../operations/types.js';
|
|
4
|
+
import { AbstractResourceBuilder } from './AbstractResourceBuilder.js';
|
|
5
|
+
export type SentinelFile<T> = {
|
|
6
|
+
mtime: number;
|
|
7
|
+
data?: T;
|
|
8
|
+
};
|
|
9
|
+
export declare abstract class SentinelFileBasedBuilder<I, O, SentinelData extends {
|
|
10
|
+
mtime: number;
|
|
11
|
+
}> extends AbstractResourceBuilder<I, O, SentinelData> {
|
|
12
|
+
private lastSentinelFile?;
|
|
13
|
+
private newSentinelData?;
|
|
14
|
+
/**
|
|
15
|
+
* Checks wether or not the sentinel file is more recent
|
|
16
|
+
* that the output of the builder's sentinel data
|
|
17
|
+
*/
|
|
18
|
+
mustBuild(resource: ResourceInfo<I>): Promise<SentinelData | undefined>;
|
|
19
|
+
build(resource: ResourceInfo<I>, out?: Writable): Promise<{
|
|
20
|
+
input: I;
|
|
21
|
+
operation: IOperation<I, O>;
|
|
22
|
+
}>;
|
|
23
|
+
private get sentinelFileName();
|
|
24
|
+
private storeSentinelData;
|
|
25
|
+
private readSentinel;
|
|
26
|
+
_commit(_resource: ResourceInfo<I>, _output: O, reason: SentinelData): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AbstractResourceBuilder } from './AbstractResourceBuilder.js';
|
|
2
|
+
export class SentinelFileBasedBuilder extends AbstractResourceBuilder {
|
|
3
|
+
lastSentinelFile;
|
|
4
|
+
newSentinelData;
|
|
5
|
+
/**
|
|
6
|
+
* Checks wether or not the sentinel file is more recent
|
|
7
|
+
* that the output of the builder's sentinel data
|
|
8
|
+
*/
|
|
9
|
+
async mustBuild(resource) {
|
|
10
|
+
if (!this._mustBuild) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
this.lastSentinelFile = await this.readSentinel();
|
|
14
|
+
this.newSentinelData = await this._mustBuild(resource);
|
|
15
|
+
if (!(this.lastSentinelFile && this.newSentinelData)) {
|
|
16
|
+
return this.newSentinelData;
|
|
17
|
+
}
|
|
18
|
+
if (this.lastSentinelFile.mtime < this.newSentinelData.mtime) {
|
|
19
|
+
return this.newSentinelData;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async build(resource, out) {
|
|
23
|
+
return this._build(resource, out);
|
|
24
|
+
}
|
|
25
|
+
get sentinelFileName() {
|
|
26
|
+
const { monorepo, config } = this.context;
|
|
27
|
+
return `sentinels/flavors/${monorepo.currentFlavor}/${config.component}/${config.name}.built`;
|
|
28
|
+
}
|
|
29
|
+
async storeSentinelData(data) {
|
|
30
|
+
await this.context.monorepo.store.writeFile(this.sentinelFileName, JSON.stringify(data));
|
|
31
|
+
}
|
|
32
|
+
async readSentinel() {
|
|
33
|
+
const stats = await this.context.monorepo.store.stat(this.sentinelFileName, false);
|
|
34
|
+
if (!stats) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const data = await this.context.monorepo.store.readFile(this.sentinelFileName, false);
|
|
38
|
+
return {
|
|
39
|
+
data: data ? JSON.parse(data) : data,
|
|
40
|
+
mtime: stats.mtime.getTime(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async _commit(_resource, _output, reason) {
|
|
44
|
+
this.storeSentinelData(reason);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ResourceInfo } from '../../index.js';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { IOperation } from '../../operations/types.js';
|
|
4
|
+
export type IResourceBuilder<Input, Output, Reason> = {
|
|
5
|
+
/**
|
|
6
|
+
* Returns input and operation required to actually
|
|
7
|
+
* build the resources.
|
|
8
|
+
* This allows the dry-run mechanism to be implemented outside
|
|
9
|
+
* resource implementations
|
|
10
|
+
*
|
|
11
|
+
* @param resource The resource config
|
|
12
|
+
* @param out The Writable to use to write logs
|
|
13
|
+
*/
|
|
14
|
+
build(resource: ResourceInfo<Input>, out?: Writable): Promise<{
|
|
15
|
+
input: Input;
|
|
16
|
+
operation: IOperation<Input, Output>;
|
|
17
|
+
}>;
|
|
18
|
+
mustBuild?: (resource: ResourceInfo<Input>) => Promise<Reason | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Resource builders will be informed when a successful build of resource
|
|
21
|
+
* has been produced through them
|
|
22
|
+
*
|
|
23
|
+
* This allows them to store metadata to improve their caching algorithm
|
|
24
|
+
*/
|
|
25
|
+
commit?: (resource: ResourceInfo<Input>, output: Output, reason: Reason) => Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Similar to .build(), must return input and operation required to actually
|
|
28
|
+
* publish the resources.
|
|
29
|
+
* This allows the dry-run mechanism to be implemented outside
|
|
30
|
+
* resource implementations
|
|
31
|
+
*
|
|
32
|
+
* @param resource The resource config
|
|
33
|
+
* @param out The Writable to use to write logs
|
|
34
|
+
*/
|
|
35
|
+
publish?(resource: ResourceInfo<Input>, out?: Writable): Promise<void>;
|
|
36
|
+
};
|
|
@@ -4,7 +4,9 @@ export type ComponentIdentifiable<T> = T & {
|
|
|
4
4
|
name: string;
|
|
5
5
|
component: string;
|
|
6
6
|
};
|
|
7
|
-
export type ResourceInfo = ComponentIdentifiable<IResourceConfig
|
|
7
|
+
export type ResourceInfo<T = unknown> = ComponentIdentifiable<IResourceConfig> & {
|
|
8
|
+
params?: T;
|
|
9
|
+
};
|
|
8
10
|
export type Resources = {
|
|
9
11
|
[k: string]: ResourceInfo;
|
|
10
12
|
};
|
|
@@ -3,10 +3,10 @@ import * as z from 'zod';
|
|
|
3
3
|
import { IOperation } from '../index.js';
|
|
4
4
|
export type OpInput<A extends AbstractOperation<z.Schema, unknown>> = A extends AbstractOperation<infer I, unknown> ? z.infer<I> : never;
|
|
5
5
|
export type OpOutput<A extends AbstractOperation<z.Schema, unknown>> = A extends AbstractOperation<z.Schema, infer O> ? O : never;
|
|
6
|
-
export declare abstract class AbstractOperation<
|
|
7
|
-
protected inputSchema:
|
|
6
|
+
export declare abstract class AbstractOperation<I extends z.Schema, O> implements IOperation<z.infer<I>, O> {
|
|
7
|
+
protected inputSchema: I;
|
|
8
8
|
protected context: EmbContext;
|
|
9
|
-
constructor(inputSchema:
|
|
10
|
-
protected abstract _run(input: z.infer<
|
|
11
|
-
run(input:
|
|
9
|
+
constructor(inputSchema: I);
|
|
10
|
+
protected abstract _run(input: z.infer<I>): Promise<O>;
|
|
11
|
+
run(input: z.infer<I>): Promise<O>;
|
|
12
12
|
}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enspirit/emb",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"keywords": [
|
|
4
|
+
"version": "0.4.1",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"monorepo",
|
|
7
|
+
"docker",
|
|
8
|
+
"taskrunner",
|
|
9
|
+
"ci",
|
|
10
|
+
"docker compose",
|
|
11
|
+
"sentinel",
|
|
12
|
+
"makefile"
|
|
13
|
+
],
|
|
6
14
|
"author": "Louis Lambeau <louis.lambeau@enspirit.be>",
|
|
7
15
|
"license": "ISC",
|
|
8
16
|
"description": "A replacement for our Makefile-for-monorepos",
|
|
@@ -114,12 +122,25 @@
|
|
|
114
122
|
],
|
|
115
123
|
"topicSeparator": " ",
|
|
116
124
|
"topics": {
|
|
117
|
-
"images": {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
"images": {
|
|
126
|
+
"description": "List, delete, prune docker containers"
|
|
127
|
+
},
|
|
128
|
+
"containers": {
|
|
129
|
+
"description": "List, delete, prune docker images"
|
|
130
|
+
},
|
|
131
|
+
"resources": {
|
|
132
|
+
"description": "List, clean, build resources"
|
|
133
|
+
},
|
|
134
|
+
"components": {
|
|
135
|
+
"description": "List & build components resources"
|
|
136
|
+
},
|
|
137
|
+
"config": {
|
|
138
|
+
"description": "It's all about config"
|
|
139
|
+
},
|
|
140
|
+
"tasks": {
|
|
141
|
+
"description": "List and run tasks"
|
|
142
|
+
}
|
|
123
143
|
}
|
|
124
|
-
}
|
|
144
|
+
},
|
|
145
|
+
"packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b"
|
|
125
146
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { CreateFileOperation } from '../index.js';
|
|
2
|
-
import { ResourceFactory } from './ResourceFactory.js';
|
|
3
|
-
// Bring better abstraction and register as part of the plugin initialization
|
|
4
|
-
ResourceFactory.register('file', async ({ config, component }) => {
|
|
5
|
-
return {
|
|
6
|
-
async build() {
|
|
7
|
-
const fromConfig = (config.params || {});
|
|
8
|
-
const input = {
|
|
9
|
-
path: component.join(fromConfig?.path || config.name),
|
|
10
|
-
};
|
|
11
|
-
return {
|
|
12
|
-
input,
|
|
13
|
-
operation: new CreateFileOperation(),
|
|
14
|
-
};
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
});
|
|
File without changes
|