@enspirit/emb 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/cli/commands/components/shell.js +3 -3
- package/dist/src/docker/compose/operations/ComposeExecOperation.d.ts +13 -0
- package/dist/src/docker/compose/operations/ComposeExecOperation.js +59 -0
- package/dist/src/docker/{operations/containers/ExecShellOperation.d.ts → compose/operations/ComposeExecShellOperation.d.ts} +2 -2
- package/dist/src/docker/{operations/containers/ExecShellOperation.js → compose/operations/ComposeExecShellOperation.js} +9 -23
- 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/index.d.ts +1 -2
- package/dist/src/docker/operations/containers/index.js +1 -2
- package/dist/src/docker/resources/DockerImageResource.js +68 -49
- package/dist/src/errors.d.ts +7 -2
- package/dist/src/errors.js +12 -3
- package/dist/src/monorepo/operations/resources/BuildResourcesOperation.d.ts +1 -0
- package/dist/src/monorepo/operations/resources/BuildResourcesOperation.js +27 -13
- package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +6 -7
- package/dist/src/monorepo/resources/FileResource.js +10 -6
- package/dist/src/monorepo/resources/ResourceFactory.d.ts +4 -2
- package/dist/src/monorepo/store/index.d.ts +1 -0
- package/dist/src/monorepo/store/index.js +12 -1
- package/oclif.manifest.json +84 -84
- package/package.json +1 -1
- /package/dist/src/docker/operations/containers/{ExecContainerOperation.d.ts → ContainerExecOperation.d.ts} +0 -0
- /package/dist/src/docker/operations/containers/{ExecContainerOperation.js → ContainerExecOperation.js} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { FlavoredCommand, getContext } from '../../index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { ComposeExecShellOperation } from '../../../docker/index.js';
|
|
4
4
|
import { ShellExitError } from '../../../errors.js';
|
|
5
5
|
export default class ComponentsLogs extends FlavoredCommand {
|
|
6
6
|
static aliases = ['shell'];
|
|
@@ -26,8 +26,8 @@ export default class ComponentsLogs extends FlavoredCommand {
|
|
|
26
26
|
const { flags, args } = await this.parse(ComponentsLogs);
|
|
27
27
|
const { monorepo } = await getContext();
|
|
28
28
|
try {
|
|
29
|
-
await monorepo.run(new
|
|
30
|
-
|
|
29
|
+
await monorepo.run(new ComposeExecShellOperation(), {
|
|
30
|
+
service: args.component,
|
|
31
31
|
shell: flags.shell,
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
declare const schema: z.ZodObject<{
|
|
5
|
+
command: z.ZodString;
|
|
6
|
+
service: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export declare class ComposeExecOperation extends AbstractOperation<typeof schema, void> {
|
|
9
|
+
protected out?: Writable | undefined;
|
|
10
|
+
constructor(out?: Writable | undefined);
|
|
11
|
+
protected _run(input: z.input<typeof schema>): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { ComposeExecError } from '../../../errors.js';
|
|
4
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
5
|
+
const schema = z.object({
|
|
6
|
+
command: z.string().describe('The command to execute on the service'),
|
|
7
|
+
service: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe('The name of the compose service to exec a shell'),
|
|
10
|
+
});
|
|
11
|
+
export class ComposeExecOperation extends AbstractOperation {
|
|
12
|
+
out;
|
|
13
|
+
constructor(out) {
|
|
14
|
+
super(schema);
|
|
15
|
+
this.out = out;
|
|
16
|
+
}
|
|
17
|
+
async _run(input) {
|
|
18
|
+
const { monorepo } = this.context;
|
|
19
|
+
const cmd = 'docker';
|
|
20
|
+
const args = ['compose', 'exec', input.service, input.command];
|
|
21
|
+
const child = spawn(cmd, args, {
|
|
22
|
+
stdio: 'pipe',
|
|
23
|
+
shell: true,
|
|
24
|
+
cwd: monorepo.rootDir,
|
|
25
|
+
});
|
|
26
|
+
if (this.out) {
|
|
27
|
+
child.stderr.pipe(this.out);
|
|
28
|
+
child.stdout.pipe(this.out);
|
|
29
|
+
}
|
|
30
|
+
const forward = (sig) => {
|
|
31
|
+
try {
|
|
32
|
+
child.kill(sig);
|
|
33
|
+
}
|
|
34
|
+
catch { }
|
|
35
|
+
};
|
|
36
|
+
const signals = [
|
|
37
|
+
'SIGINT',
|
|
38
|
+
'SIGTERM',
|
|
39
|
+
'SIGHUP',
|
|
40
|
+
'SIGQUIT',
|
|
41
|
+
];
|
|
42
|
+
signals.forEach((sig) => {
|
|
43
|
+
process.on(sig, () => forward(sig));
|
|
44
|
+
});
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
child.on('error', (err) => {
|
|
47
|
+
reject(new Error(`Failed to execute docker compose: ${err.message}`));
|
|
48
|
+
});
|
|
49
|
+
child.on('exit', (code, signal) => {
|
|
50
|
+
if (code !== null && code !== 0) {
|
|
51
|
+
reject(new ComposeExecError(`The shell exited unexpectedly. ${code}`, code, signal));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
resolve();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -2,9 +2,9 @@ import * as z from 'zod';
|
|
|
2
2
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
3
3
|
declare const schema: z.ZodObject<{
|
|
4
4
|
shell: z.ZodOptional<z.ZodDefault<z.ZodString>>;
|
|
5
|
-
|
|
5
|
+
service: z.ZodString;
|
|
6
6
|
}, z.core.$strip>;
|
|
7
|
-
export declare class
|
|
7
|
+
export declare class ComposeExecShellOperation extends AbstractOperation<typeof schema, void> {
|
|
8
8
|
constructor();
|
|
9
9
|
protected _run(input: z.input<typeof schema>): Promise<void>;
|
|
10
10
|
}
|
|
@@ -1,38 +1,24 @@
|
|
|
1
|
-
import { getContext, ListContainersOperation, MultipleContainersFoundError, NoContainerFoundError, ShellExitError, } from '../../../index.js';
|
|
2
1
|
import { spawn } from 'node:child_process';
|
|
3
2
|
import * as z from 'zod';
|
|
3
|
+
import { ShellExitError } from '../../../errors.js';
|
|
4
4
|
import { AbstractOperation } from '../../../operations/index.js';
|
|
5
5
|
const schema = z.object({
|
|
6
6
|
shell: z.string().default('bash').optional(),
|
|
7
|
-
|
|
7
|
+
service: z
|
|
8
8
|
.string()
|
|
9
|
-
.describe('The name of the
|
|
9
|
+
.describe('The name of the compose service to exec a shell'),
|
|
10
10
|
});
|
|
11
|
-
export class
|
|
11
|
+
export class ComposeExecShellOperation extends AbstractOperation {
|
|
12
12
|
constructor() {
|
|
13
13
|
super(schema);
|
|
14
14
|
}
|
|
15
15
|
async _run(input) {
|
|
16
|
-
const { monorepo } =
|
|
17
|
-
const containers = await monorepo.run(new ListContainersOperation(), {
|
|
18
|
-
filters: {
|
|
19
|
-
label: [
|
|
20
|
-
`emb/project=${monorepo.name}`,
|
|
21
|
-
`emb/component=${input.component}`,
|
|
22
|
-
`emb/flavor=${monorepo.currentFlavor}`,
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
if (containers.length === 0) {
|
|
27
|
-
throw new NoContainerFoundError(`No container found for component \`${input.component}\``, input.component);
|
|
28
|
-
}
|
|
29
|
-
if (containers.length > 1) {
|
|
30
|
-
throw new MultipleContainersFoundError(`More than one container found for component \`${input.component}\``, input.component);
|
|
31
|
-
}
|
|
16
|
+
const { monorepo } = this.context;
|
|
32
17
|
const cmd = 'docker';
|
|
33
|
-
const args = ['
|
|
18
|
+
const args = ['compose', 'exec', input.service, input.shell || 'bash'];
|
|
34
19
|
const child = spawn(cmd, args, {
|
|
35
20
|
stdio: 'inherit',
|
|
21
|
+
cwd: monorepo.rootDir,
|
|
36
22
|
env: {
|
|
37
23
|
...process.env,
|
|
38
24
|
DOCKER_CLI_HINTS: 'false',
|
|
@@ -55,11 +41,11 @@ export class ExecShellOperation extends AbstractOperation {
|
|
|
55
41
|
});
|
|
56
42
|
return new Promise((resolve, reject) => {
|
|
57
43
|
child.on('error', (err) => {
|
|
58
|
-
reject(new Error(`Failed to
|
|
44
|
+
reject(new Error(`Failed to execute docker: ${err.message}`));
|
|
59
45
|
});
|
|
60
46
|
child.on('exit', (code, signal) => {
|
|
61
47
|
if (code !== null && code !== 0) {
|
|
62
|
-
reject(new ShellExitError(`The shell exited unexpectedly. ${code}`, input.
|
|
48
|
+
reject(new ShellExitError(`The shell exited unexpectedly. ${code}`, input.service, code, signal));
|
|
63
49
|
}
|
|
64
50
|
else {
|
|
65
51
|
resolve();
|
|
@@ -1,42 +1,74 @@
|
|
|
1
|
-
import { stat, statfs } from 'node:fs/promises';
|
|
1
|
+
import { readdir, stat, statfs } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import pMap from 'p-map';
|
|
4
4
|
import { GitPrerequisitePlugin } from '../../prerequisites/index.js';
|
|
5
5
|
import { ResourceFactory, } from '../../monorepo/resources/ResourceFactory.js';
|
|
6
6
|
import { BuildImageOperation } from '../operations/index.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
7
|
+
class DockerImageResourceBuilder {
|
|
8
|
+
buildContext;
|
|
9
|
+
context;
|
|
10
|
+
constructor(buildContext) {
|
|
11
|
+
this.buildContext = buildContext;
|
|
12
|
+
this.context = this.config.context
|
|
13
|
+
? this.config.context[0] === '/'
|
|
14
|
+
? buildContext.monorepo.join(this.config.context)
|
|
15
|
+
: buildContext.component.join(this.config.context)
|
|
16
|
+
: buildContext.monorepo.join(buildContext.component.rootDir);
|
|
17
|
+
}
|
|
18
|
+
get monorepo() {
|
|
19
|
+
return this.buildContext.monorepo;
|
|
20
|
+
}
|
|
21
|
+
get config() {
|
|
22
|
+
return (this.buildContext.config.params || {});
|
|
23
|
+
}
|
|
24
|
+
get component() {
|
|
25
|
+
return this.buildContext.component;
|
|
26
|
+
}
|
|
27
|
+
async build() {
|
|
28
|
+
// Ensure the folder exists
|
|
29
|
+
await statfs(this.context);
|
|
30
|
+
const imageName = [
|
|
31
|
+
this.monorepo.name,
|
|
32
|
+
this.config.tag || this.component.name,
|
|
33
|
+
].join('/');
|
|
34
|
+
const tagName = this.config.tag || this.monorepo.defaults.docker?.tag || 'latest';
|
|
35
|
+
const sources = await readdir(this.context, { recursive: true });
|
|
36
|
+
const buildParams = {
|
|
37
|
+
context: this.context,
|
|
38
|
+
dockerfile: this.config.dockerfile || 'Dockerfile',
|
|
39
|
+
src: sources,
|
|
40
|
+
buildArgs: await this.monorepo.expand({
|
|
41
|
+
...this.monorepo.defaults.docker?.buildArgs,
|
|
42
|
+
...this.config.buildArgs,
|
|
43
|
+
}),
|
|
44
|
+
tag: await this.monorepo.expand(`${imageName}:${tagName}`),
|
|
45
|
+
labels: await this.monorepo.expand({
|
|
46
|
+
...this.config.labels,
|
|
47
|
+
'emb/project': this.monorepo.name,
|
|
48
|
+
'emb/component': this.component.name,
|
|
49
|
+
'emb/flavor': this.monorepo.currentFlavor,
|
|
50
|
+
}),
|
|
51
|
+
target: this.config.target,
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
input: buildParams,
|
|
55
|
+
operation: new BuildImageOperation(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async mustBuild(sentinel) {
|
|
59
|
+
const plugin = new GitPrerequisitePlugin();
|
|
60
|
+
const sources = await plugin.collect(this.context);
|
|
61
|
+
const lastUpdated = await this.lastUpdatedInfo(sources);
|
|
62
|
+
if (!sentinel) {
|
|
63
|
+
return lastUpdated;
|
|
64
|
+
}
|
|
65
|
+
return lastUpdated && lastUpdated.time.getTime() > sentinel.mtime
|
|
66
|
+
? lastUpdated
|
|
67
|
+
: undefined;
|
|
68
|
+
}
|
|
69
|
+
async lastUpdatedInfo(sources) {
|
|
38
70
|
const stats = await pMap(sources, async (s) => {
|
|
39
|
-
const stats = await stat(join(context, s.path));
|
|
71
|
+
const stats = await stat(join(this.context, s.path));
|
|
40
72
|
return {
|
|
41
73
|
time: stats.mtime,
|
|
42
74
|
path: s.path,
|
|
@@ -48,20 +80,7 @@ const DockerImageOpFactory = async ({ config, component, monorepo }) => {
|
|
|
48
80
|
return stats.reduce((last, entry) => {
|
|
49
81
|
return last.time > entry.time ? last : entry;
|
|
50
82
|
}, stats[0]);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async mustBuild(sentinel) {
|
|
54
|
-
const lastUpdated = await lastUpdatedInfo(sources);
|
|
55
|
-
if (!sentinel) {
|
|
56
|
-
return lastUpdated;
|
|
57
|
-
}
|
|
58
|
-
return lastUpdated && lastUpdated.time.getTime() > sentinel.mtime
|
|
59
|
-
? lastUpdated
|
|
60
|
-
: undefined;
|
|
61
|
-
},
|
|
62
|
-
input: buildParams,
|
|
63
|
-
operation: new BuildImageOperation(),
|
|
64
|
-
};
|
|
65
|
-
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
66
85
|
// Bring better abstraction and register as part of the plugin initialization
|
|
67
|
-
ResourceFactory.register('docker/image',
|
|
86
|
+
ResourceFactory.register('docker/image', async (context) => new DockerImageResourceBuilder(context));
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -59,10 +59,10 @@ export declare class CircularDependencyError extends EMBError {
|
|
|
59
59
|
constructor(msg: string, deps: Array<Array<string>>);
|
|
60
60
|
}
|
|
61
61
|
export declare class ShellExitError extends EMBError {
|
|
62
|
-
|
|
62
|
+
service: string;
|
|
63
63
|
exitCode: number;
|
|
64
64
|
signal?: (NodeJS.Signals | null) | undefined;
|
|
65
|
-
constructor(msg: string,
|
|
65
|
+
constructor(msg: string, service: string, exitCode: number, signal?: (NodeJS.Signals | null) | undefined);
|
|
66
66
|
}
|
|
67
67
|
export declare class NoContainerFoundError extends EMBError {
|
|
68
68
|
component: string;
|
|
@@ -72,3 +72,8 @@ export declare class MultipleContainersFoundError extends EMBError {
|
|
|
72
72
|
component: string;
|
|
73
73
|
constructor(msg: string, component: string);
|
|
74
74
|
}
|
|
75
|
+
export declare class ComposeExecError extends EMBError {
|
|
76
|
+
exitCode: number;
|
|
77
|
+
signal?: (NodeJS.Signals | null) | undefined;
|
|
78
|
+
constructor(msg: string, exitCode: number, signal?: (NodeJS.Signals | null) | undefined);
|
|
79
|
+
}
|
package/dist/src/errors.js
CHANGED
|
@@ -71,12 +71,12 @@ export class CircularDependencyError extends EMBError {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
export class ShellExitError extends EMBError {
|
|
74
|
-
|
|
74
|
+
service;
|
|
75
75
|
exitCode;
|
|
76
76
|
signal;
|
|
77
|
-
constructor(msg,
|
|
77
|
+
constructor(msg, service, exitCode, signal) {
|
|
78
78
|
super('SHELL_EXIT_ERR', msg);
|
|
79
|
-
this.
|
|
79
|
+
this.service = service;
|
|
80
80
|
this.exitCode = exitCode;
|
|
81
81
|
this.signal = signal;
|
|
82
82
|
}
|
|
@@ -95,3 +95,12 @@ export class MultipleContainersFoundError extends EMBError {
|
|
|
95
95
|
this.component = component;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
export class ComposeExecError extends EMBError {
|
|
99
|
+
exitCode;
|
|
100
|
+
signal;
|
|
101
|
+
constructor(msg, exitCode, signal) {
|
|
102
|
+
super('COMPOSE_EXEC_ERR', msg);
|
|
103
|
+
this.exitCode = exitCode;
|
|
104
|
+
this.signal = signal;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -84,35 +84,42 @@ export class BuildResourcesOperation extends AbstractOperation {
|
|
|
84
84
|
},
|
|
85
85
|
// Actual build
|
|
86
86
|
{
|
|
87
|
-
title: `
|
|
87
|
+
title: `Checking cache for ${resource.id}`,
|
|
88
88
|
/** Skip the build if the builder knows it can be skipped */
|
|
89
|
-
task: async (ctx
|
|
89
|
+
task: async (ctx) => {
|
|
90
90
|
if (ctx.builder?.mustBuild) {
|
|
91
91
|
const previousSentinelData = await this.readSentinelFile(resource);
|
|
92
92
|
ctx.sentinelData =
|
|
93
93
|
await ctx.builder.mustBuild(previousSentinelData);
|
|
94
94
|
ctx.cacheHit = !ctx.sentinelData;
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
title: `Build image for ${resource.id}`,
|
|
100
|
+
async task(ctx, task) {
|
|
101
|
+
const skip = (prefix) => {
|
|
98
102
|
parentTask.title = `${prefix} ${resource.id}`;
|
|
99
103
|
task.skip();
|
|
100
104
|
return parentTask.skip();
|
|
105
|
+
};
|
|
106
|
+
if (ctx.cacheHit && !ctx.force && !ctx.dryRun) {
|
|
107
|
+
return skip('[cache hit]');
|
|
108
|
+
}
|
|
109
|
+
const { input, operation } = await ctx.builder.build();
|
|
110
|
+
ctx.builderInput = input;
|
|
111
|
+
if (ctx.dryRun) {
|
|
112
|
+
return skip('[dry run]');
|
|
101
113
|
}
|
|
102
|
-
return
|
|
114
|
+
return operation.run(ctx.builderInput);
|
|
103
115
|
},
|
|
104
116
|
},
|
|
105
117
|
{
|
|
106
118
|
// Return build meta data and dump
|
|
107
119
|
// cache data into sentinel file
|
|
108
120
|
task: async (ctx) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
delete ctx.builder.mustBuild;
|
|
112
|
-
}
|
|
113
|
-
if (ctx.builder?.operation) {
|
|
114
|
-
// @ts-expect-error duynno
|
|
115
|
-
delete ctx.builder.operation;
|
|
121
|
+
if (ctx.builder) {
|
|
122
|
+
delete ctx.builder;
|
|
116
123
|
}
|
|
117
124
|
//
|
|
118
125
|
parentContext[resource.id] = ctx;
|
|
@@ -140,7 +147,14 @@ export class BuildResourcesOperation extends AbstractOperation {
|
|
|
140
147
|
}
|
|
141
148
|
async readSentinelFile(resource) {
|
|
142
149
|
const path = this.sentinelFilePath(resource);
|
|
150
|
+
const stats = await this.context.monorepo.store.stat(path, false);
|
|
151
|
+
if (!stats) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
143
154
|
const data = await this.context.monorepo.store.readFile(path, false);
|
|
144
|
-
return
|
|
155
|
+
return {
|
|
156
|
+
data,
|
|
157
|
+
mtime: stats.mtime.getTime(),
|
|
158
|
+
};
|
|
145
159
|
}
|
|
146
160
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getContext } from '../../../index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ComposeExecOperation } from '../../../docker/index.js';
|
|
3
3
|
import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
|
|
4
|
-
import { ExecuteLocalCommandOperation
|
|
4
|
+
import { ExecuteLocalCommandOperation } from '../index.js';
|
|
5
5
|
export var ExecutorType;
|
|
6
6
|
(function (ExecutorType) {
|
|
7
7
|
ExecutorType["container"] = "container";
|
|
@@ -53,18 +53,17 @@ export class RunTasksOperation {
|
|
|
53
53
|
}
|
|
54
54
|
async runDocker(task, out) {
|
|
55
55
|
const { monorepo } = getContext();
|
|
56
|
-
|
|
57
|
-
return monorepo.run(new ContainerExecOperation(out), {
|
|
56
|
+
return monorepo.run(new ComposeExecOperation(out), {
|
|
58
57
|
attachStderr: true,
|
|
59
58
|
attachStdout: true,
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
service: task.component,
|
|
60
|
+
command: task.script,
|
|
62
61
|
});
|
|
63
62
|
}
|
|
64
63
|
async runLocal(task) {
|
|
65
64
|
const { monorepo } = getContext();
|
|
66
65
|
const cwd = task.component
|
|
67
|
-
? monorepo.component(task.component).rootDir
|
|
66
|
+
? monorepo.join(monorepo.component(task.component).rootDir)
|
|
68
67
|
: monorepo.rootDir;
|
|
69
68
|
return monorepo.run(new ExecuteLocalCommandOperation(), {
|
|
70
69
|
script: task.script,
|
|
@@ -2,12 +2,16 @@ import { CreateFileOperation } from '../index.js';
|
|
|
2
2
|
import { ResourceFactory } from './ResourceFactory.js';
|
|
3
3
|
// Bring better abstraction and register as part of the plugin initialization
|
|
4
4
|
ResourceFactory.register('file', async ({ config, component }) => {
|
|
5
|
-
const fromConfig = (config.params || {});
|
|
6
|
-
const input = {
|
|
7
|
-
path: component.join(fromConfig?.path || config.name),
|
|
8
|
-
};
|
|
9
5
|
return {
|
|
10
|
-
|
|
11
|
-
|
|
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
|
+
},
|
|
12
16
|
};
|
|
13
17
|
});
|
|
@@ -10,8 +10,10 @@ export type SentinelData<T = void> = {
|
|
|
10
10
|
data: T;
|
|
11
11
|
};
|
|
12
12
|
export type ResourceBuilderInfo<I, O, D = unknown> = {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
build(): Promise<{
|
|
14
|
+
input: I;
|
|
15
|
+
operation: IOperation<I, O>;
|
|
16
|
+
}>;
|
|
15
17
|
mustBuild?: (previousSentinelData: SentinelData<D> | undefined) => Promise<undefined | unknown>;
|
|
16
18
|
};
|
|
17
19
|
export type ResourceFactoryOutput<I, O> = Promise<ResourceBuilderInfo<I, O>>;
|
|
@@ -14,6 +14,7 @@ export declare class EMBStore {
|
|
|
14
14
|
init(): Promise<void>;
|
|
15
15
|
join(path: string): string;
|
|
16
16
|
mkdirp(path: string): Promise<void>;
|
|
17
|
+
stat(path: string, mustExist?: boolean): Promise<import("fs").Stats | undefined>;
|
|
17
18
|
readFile(path: string, mustExist?: boolean): Promise<string | undefined>;
|
|
18
19
|
trash(): Promise<void>;
|
|
19
20
|
writeFile(path: string, data: string): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { constants, createReadStream, createWriteStream } from 'node:fs';
|
|
2
|
-
import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { access, mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, join, normalize } from 'node:path';
|
|
4
4
|
/**
|
|
5
5
|
* A first implementation of a "store" where
|
|
@@ -54,6 +54,17 @@ export class EMBStore {
|
|
|
54
54
|
const normalized = normalize(join('/', path));
|
|
55
55
|
await mkdir(this.join(normalized), { recursive: true });
|
|
56
56
|
}
|
|
57
|
+
async stat(path, mustExist = true) {
|
|
58
|
+
try {
|
|
59
|
+
return await stat(this.join(path));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error.code === 'ENOENT' && !mustExist) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
57
68
|
async readFile(path, mustExist = true) {
|
|
58
69
|
try {
|
|
59
70
|
return (await readFile(this.join(path))).toString();
|
package/oclif.manifest.json
CHANGED
|
@@ -520,12 +520,18 @@
|
|
|
520
520
|
"prune.js"
|
|
521
521
|
]
|
|
522
522
|
},
|
|
523
|
-
"
|
|
523
|
+
"resources:build": {
|
|
524
524
|
"aliases": [],
|
|
525
|
-
"args": {
|
|
526
|
-
|
|
525
|
+
"args": {
|
|
526
|
+
"component": {
|
|
527
|
+
"description": "List of resources to build (defaults to all)",
|
|
528
|
+
"name": "component",
|
|
529
|
+
"required": false
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
"description": "Build the resources of the monorepo",
|
|
527
533
|
"examples": [
|
|
528
|
-
"<%= config.bin %> <%= command.id %>"
|
|
534
|
+
"<%= config.bin %> <%= command.id %> build --flavor development"
|
|
529
535
|
],
|
|
530
536
|
"flags": {
|
|
531
537
|
"json": {
|
|
@@ -534,15 +540,38 @@
|
|
|
534
540
|
"name": "json",
|
|
535
541
|
"allowNo": false,
|
|
536
542
|
"type": "boolean"
|
|
543
|
+
},
|
|
544
|
+
"flavor": {
|
|
545
|
+
"description": "Specify the flavor to use.",
|
|
546
|
+
"name": "flavor",
|
|
547
|
+
"required": false,
|
|
548
|
+
"hasDynamicHelp": false,
|
|
549
|
+
"multiple": false,
|
|
550
|
+
"type": "option"
|
|
551
|
+
},
|
|
552
|
+
"dry-run": {
|
|
553
|
+
"description": "Do not build the resources but only produce build meta information",
|
|
554
|
+
"name": "dry-run",
|
|
555
|
+
"required": false,
|
|
556
|
+
"allowNo": false,
|
|
557
|
+
"type": "boolean"
|
|
558
|
+
},
|
|
559
|
+
"force": {
|
|
560
|
+
"char": "f",
|
|
561
|
+
"description": "Bypass the cache and force the build",
|
|
562
|
+
"name": "force",
|
|
563
|
+
"required": false,
|
|
564
|
+
"allowNo": false,
|
|
565
|
+
"type": "boolean"
|
|
537
566
|
}
|
|
538
567
|
},
|
|
539
568
|
"hasDynamicHelp": false,
|
|
540
569
|
"hiddenAliases": [],
|
|
541
|
-
"id": "
|
|
570
|
+
"id": "resources:build",
|
|
542
571
|
"pluginAlias": "@enspirit/emb",
|
|
543
572
|
"pluginName": "@enspirit/emb",
|
|
544
573
|
"pluginType": "core",
|
|
545
|
-
"strict":
|
|
574
|
+
"strict": false,
|
|
546
575
|
"enableJsonFlag": true,
|
|
547
576
|
"isESM": true,
|
|
548
577
|
"relativePath": [
|
|
@@ -550,20 +579,14 @@
|
|
|
550
579
|
"src",
|
|
551
580
|
"cli",
|
|
552
581
|
"commands",
|
|
553
|
-
"
|
|
554
|
-
"
|
|
582
|
+
"resources",
|
|
583
|
+
"build.js"
|
|
555
584
|
]
|
|
556
585
|
},
|
|
557
|
-
"
|
|
586
|
+
"resources": {
|
|
558
587
|
"aliases": [],
|
|
559
|
-
"args": {
|
|
560
|
-
|
|
561
|
-
"description": "List of tasks to run. You can provide either ids or names (eg: component:task or task)",
|
|
562
|
-
"name": "task",
|
|
563
|
-
"required": true
|
|
564
|
-
}
|
|
565
|
-
},
|
|
566
|
-
"description": "Run tasks.",
|
|
588
|
+
"args": {},
|
|
589
|
+
"description": "List resources.",
|
|
567
590
|
"examples": [
|
|
568
591
|
"<%= config.bin %> <%= command.id %>"
|
|
569
592
|
],
|
|
@@ -575,33 +598,21 @@
|
|
|
575
598
|
"allowNo": false,
|
|
576
599
|
"type": "boolean"
|
|
577
600
|
},
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"
|
|
581
|
-
"
|
|
601
|
+
"flavor": {
|
|
602
|
+
"description": "Specify the flavor to use.",
|
|
603
|
+
"name": "flavor",
|
|
604
|
+
"required": false,
|
|
582
605
|
"hasDynamicHelp": false,
|
|
583
606
|
"multiple": false,
|
|
584
|
-
"options": [
|
|
585
|
-
"container",
|
|
586
|
-
"local"
|
|
587
|
-
],
|
|
588
607
|
"type": "option"
|
|
589
|
-
},
|
|
590
|
-
"all-matching": {
|
|
591
|
-
"char": "a",
|
|
592
|
-
"description": "Run all tasks matching (when multiple matches)",
|
|
593
|
-
"name": "all-matching",
|
|
594
|
-
"allowNo": false,
|
|
595
|
-
"type": "boolean"
|
|
596
608
|
}
|
|
597
609
|
},
|
|
598
610
|
"hasDynamicHelp": false,
|
|
599
611
|
"hiddenAliases": [],
|
|
600
|
-
"id": "
|
|
612
|
+
"id": "resources",
|
|
601
613
|
"pluginAlias": "@enspirit/emb",
|
|
602
614
|
"pluginName": "@enspirit/emb",
|
|
603
615
|
"pluginType": "core",
|
|
604
|
-
"strict": false,
|
|
605
616
|
"enableJsonFlag": true,
|
|
606
617
|
"isESM": true,
|
|
607
618
|
"relativePath": [
|
|
@@ -609,22 +620,16 @@
|
|
|
609
620
|
"src",
|
|
610
621
|
"cli",
|
|
611
622
|
"commands",
|
|
612
|
-
"
|
|
613
|
-
"
|
|
623
|
+
"resources",
|
|
624
|
+
"index.js"
|
|
614
625
|
]
|
|
615
626
|
},
|
|
616
|
-
"
|
|
627
|
+
"tasks": {
|
|
617
628
|
"aliases": [],
|
|
618
|
-
"args": {
|
|
619
|
-
|
|
620
|
-
"description": "List of resources to build (defaults to all)",
|
|
621
|
-
"name": "component",
|
|
622
|
-
"required": false
|
|
623
|
-
}
|
|
624
|
-
},
|
|
625
|
-
"description": "Build the resources of the monorepo",
|
|
629
|
+
"args": {},
|
|
630
|
+
"description": "List tasks.",
|
|
626
631
|
"examples": [
|
|
627
|
-
"<%= config.bin %> <%= command.id %>
|
|
632
|
+
"<%= config.bin %> <%= command.id %>"
|
|
628
633
|
],
|
|
629
634
|
"flags": {
|
|
630
635
|
"json": {
|
|
@@ -633,38 +638,15 @@
|
|
|
633
638
|
"name": "json",
|
|
634
639
|
"allowNo": false,
|
|
635
640
|
"type": "boolean"
|
|
636
|
-
},
|
|
637
|
-
"flavor": {
|
|
638
|
-
"description": "Specify the flavor to use.",
|
|
639
|
-
"name": "flavor",
|
|
640
|
-
"required": false,
|
|
641
|
-
"hasDynamicHelp": false,
|
|
642
|
-
"multiple": false,
|
|
643
|
-
"type": "option"
|
|
644
|
-
},
|
|
645
|
-
"dry-run": {
|
|
646
|
-
"description": "Do not build the resources but only produce build meta information",
|
|
647
|
-
"name": "dry-run",
|
|
648
|
-
"required": false,
|
|
649
|
-
"allowNo": false,
|
|
650
|
-
"type": "boolean"
|
|
651
|
-
},
|
|
652
|
-
"force": {
|
|
653
|
-
"char": "f",
|
|
654
|
-
"description": "Bypass the cache and force the build",
|
|
655
|
-
"name": "force",
|
|
656
|
-
"required": false,
|
|
657
|
-
"allowNo": false,
|
|
658
|
-
"type": "boolean"
|
|
659
641
|
}
|
|
660
642
|
},
|
|
661
643
|
"hasDynamicHelp": false,
|
|
662
644
|
"hiddenAliases": [],
|
|
663
|
-
"id": "
|
|
645
|
+
"id": "tasks",
|
|
664
646
|
"pluginAlias": "@enspirit/emb",
|
|
665
647
|
"pluginName": "@enspirit/emb",
|
|
666
648
|
"pluginType": "core",
|
|
667
|
-
"strict":
|
|
649
|
+
"strict": true,
|
|
668
650
|
"enableJsonFlag": true,
|
|
669
651
|
"isESM": true,
|
|
670
652
|
"relativePath": [
|
|
@@ -672,14 +654,20 @@
|
|
|
672
654
|
"src",
|
|
673
655
|
"cli",
|
|
674
656
|
"commands",
|
|
675
|
-
"
|
|
676
|
-
"
|
|
657
|
+
"tasks",
|
|
658
|
+
"index.js"
|
|
677
659
|
]
|
|
678
660
|
},
|
|
679
|
-
"
|
|
661
|
+
"tasks:run": {
|
|
680
662
|
"aliases": [],
|
|
681
|
-
"args": {
|
|
682
|
-
|
|
663
|
+
"args": {
|
|
664
|
+
"task": {
|
|
665
|
+
"description": "List of tasks to run. You can provide either ids or names (eg: component:task or task)",
|
|
666
|
+
"name": "task",
|
|
667
|
+
"required": true
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
"description": "Run tasks.",
|
|
683
671
|
"examples": [
|
|
684
672
|
"<%= config.bin %> <%= command.id %>"
|
|
685
673
|
],
|
|
@@ -691,21 +679,33 @@
|
|
|
691
679
|
"allowNo": false,
|
|
692
680
|
"type": "boolean"
|
|
693
681
|
},
|
|
694
|
-
"
|
|
695
|
-
"
|
|
696
|
-
"
|
|
697
|
-
"
|
|
682
|
+
"executor": {
|
|
683
|
+
"char": "x",
|
|
684
|
+
"description": "Where to run the task. (experimental!)",
|
|
685
|
+
"name": "executor",
|
|
698
686
|
"hasDynamicHelp": false,
|
|
699
687
|
"multiple": false,
|
|
688
|
+
"options": [
|
|
689
|
+
"container",
|
|
690
|
+
"local"
|
|
691
|
+
],
|
|
700
692
|
"type": "option"
|
|
693
|
+
},
|
|
694
|
+
"all-matching": {
|
|
695
|
+
"char": "a",
|
|
696
|
+
"description": "Run all tasks matching (when multiple matches)",
|
|
697
|
+
"name": "all-matching",
|
|
698
|
+
"allowNo": false,
|
|
699
|
+
"type": "boolean"
|
|
701
700
|
}
|
|
702
701
|
},
|
|
703
702
|
"hasDynamicHelp": false,
|
|
704
703
|
"hiddenAliases": [],
|
|
705
|
-
"id": "
|
|
704
|
+
"id": "tasks:run",
|
|
706
705
|
"pluginAlias": "@enspirit/emb",
|
|
707
706
|
"pluginName": "@enspirit/emb",
|
|
708
707
|
"pluginType": "core",
|
|
708
|
+
"strict": false,
|
|
709
709
|
"enableJsonFlag": true,
|
|
710
710
|
"isESM": true,
|
|
711
711
|
"relativePath": [
|
|
@@ -713,10 +713,10 @@
|
|
|
713
713
|
"src",
|
|
714
714
|
"cli",
|
|
715
715
|
"commands",
|
|
716
|
-
"
|
|
717
|
-
"
|
|
716
|
+
"tasks",
|
|
717
|
+
"run.js"
|
|
718
718
|
]
|
|
719
719
|
}
|
|
720
720
|
},
|
|
721
|
-
"version": "0.
|
|
721
|
+
"version": "0.3.0"
|
|
722
722
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enspirit/emb",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"keywords": ["monorepo", "docker", "taskrunner", "ci", "docker compose", "sentinel", "makefile"],
|
|
6
6
|
"author": "Louis Lambeau <louis.lambeau@enspirit.be>",
|
|
7
7
|
"license": "ISC",
|
|
File without changes
|
|
File without changes
|