@enspirit/emb 0.0.5 → 0.0.6
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 +2 -19
- package/dist/src/cli/commands/config/print.js +1 -1
- package/dist/src/cli/commands/tasks/run.d.ts +0 -2
- package/dist/src/cli/commands/tasks/run.js +10 -59
- package/dist/src/config/convert.d.ts +2 -3
- package/dist/src/config/convert.js +2 -7
- package/dist/src/config/schema.d.ts +28 -28
- package/dist/src/config/schema.json +45 -50
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/config/validation.d.ts +2 -0
- package/dist/src/config/validation.js +26 -1
- package/dist/src/docker/operations/containers/ExecContainerOperation.d.ts +22 -0
- package/dist/src/docker/operations/containers/ExecContainerOperation.js +78 -0
- package/dist/src/docker/operations/containers/index.d.ts +1 -0
- package/dist/src/docker/operations/containers/index.js +1 -0
- package/dist/src/monorepo/config.d.ts +2 -1
- package/dist/src/monorepo/config.js +8 -2
- package/dist/src/monorepo/operations/components/GetComponentContainerOperation.d.ts +6 -0
- package/dist/src/monorepo/operations/components/GetComponentContainerOperation.js +21 -0
- package/dist/src/monorepo/operations/components/index.d.ts +1 -0
- package/dist/src/monorepo/operations/components/index.js +1 -0
- package/dist/src/monorepo/operations/index.d.ts +2 -0
- package/dist/src/monorepo/operations/index.js +2 -0
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.d.ts +18 -0
- package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +35 -0
- package/dist/src/monorepo/operations/shell/index.d.ts +1 -0
- package/dist/src/monorepo/operations/shell/index.js +1 -0
- package/dist/src/monorepo/operations/tasks/RunTaskOperation.d.ts +18 -0
- package/dist/src/monorepo/operations/tasks/RunTaskOperation.js +50 -0
- package/dist/src/monorepo/operations/tasks/index.d.ts +1 -0
- package/dist/src/monorepo/operations/tasks/index.js +1 -0
- package/dist/src/monorepo/plugins/ComponentDiscoverPlugin.d.ts +15 -0
- package/dist/src/monorepo/plugins/{ComponentsDiscover.js → ComponentDiscoverPlugin.js} +13 -1
- package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.d.ts +14 -0
- package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.js +33 -0
- package/dist/src/monorepo/plugins/index.d.ts +3 -2
- package/dist/src/monorepo/plugins/index.js +5 -2
- package/dist/src/operations/abstract/AbstractOperation.d.ts +1 -1
- package/dist/src/utils/deepMergeArray.d.ts +3 -0
- package/dist/src/utils/deepMergeArray.js +1 -0
- package/oclif.manifest.json +1 -35
- package/package.json +1 -1
- package/dist/src/cli/commands/run/index.d.ts +0 -10
- package/dist/src/cli/commands/run/index.js +0 -49
- package/dist/src/executors/docker.d.ts +0 -6
- package/dist/src/executors/docker.js +0 -14
- package/dist/src/executors/index.d.ts +0 -6
- package/dist/src/executors/index.js +0 -7
- package/dist/src/executors/shell.d.ts +0 -2
- package/dist/src/executors/shell.js +0 -14
- package/dist/src/executors/types.d.ts +0 -8
- package/dist/src/executors/types.js +0 -1
- package/dist/src/monorepo/plugins/ComponentsDiscover.d.ts +0 -6
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
emb (Enspirit's Monorepo Builder)
|
|
2
2
|
=================
|
|
3
3
|
|
|
4
|
-
A CLI to help on Enspirit monorepos. This aims at replacing our aging [Makefile for monorepos](https://github.com/enspirit/makefile-for-monorepos
|
|
4
|
+
A CLI to help on Enspirit monorepos. This aims at replacing our aging [Makefile for monorepos](https://github.com/enspirit/makefile-for-monorepos)
|
|
5
5
|
|
|
6
6
|
<!-- toc -->
|
|
7
7
|
* [Usage](#usage)
|
|
@@ -14,7 +14,7 @@ $ npm install -g @enspirit/emb
|
|
|
14
14
|
$ emb COMMAND
|
|
15
15
|
running command...
|
|
16
16
|
$ emb (--version)
|
|
17
|
-
@enspirit/emb/0.0.
|
|
17
|
+
@enspirit/emb/0.0.6 darwin-x64 node-v22.12.0
|
|
18
18
|
$ emb --help [COMMAND]
|
|
19
19
|
USAGE
|
|
20
20
|
$ emb COMMAND
|
|
@@ -36,7 +36,6 @@ USAGE
|
|
|
36
36
|
* [`emb images delete`](#emb-images-delete)
|
|
37
37
|
* [`emb images prune`](#emb-images-prune)
|
|
38
38
|
* [`emb ps`](#emb-ps)
|
|
39
|
-
* [`emb run COMPONENT SCRIPT`](#emb-run-component-script)
|
|
40
39
|
* [`emb tasks`](#emb-tasks)
|
|
41
40
|
* [`emb tasks run [TASK]`](#emb-tasks-run-task)
|
|
42
41
|
* [`emb up`](#emb-up)
|
|
@@ -323,22 +322,6 @@ EXAMPLES
|
|
|
323
322
|
$ emb ps
|
|
324
323
|
```
|
|
325
324
|
|
|
326
|
-
## `emb run COMPONENT SCRIPT`
|
|
327
|
-
|
|
328
|
-
Run an npm script from a component's package.json
|
|
329
|
-
|
|
330
|
-
```
|
|
331
|
-
USAGE
|
|
332
|
-
$ emb run COMPONENT SCRIPT
|
|
333
|
-
|
|
334
|
-
ARGUMENTS
|
|
335
|
-
COMPONENT Component name
|
|
336
|
-
SCRIPT NPM script to run
|
|
337
|
-
|
|
338
|
-
DESCRIPTION
|
|
339
|
-
Run an npm script from a component's package.json
|
|
340
|
-
```
|
|
341
|
-
|
|
342
325
|
## `emb tasks`
|
|
343
326
|
|
|
344
327
|
List tasks.
|
|
@@ -9,7 +9,7 @@ export default class ConfigPrint extends FlavoredCommand {
|
|
|
9
9
|
const context = await getContext();
|
|
10
10
|
const { monorepo } = context;
|
|
11
11
|
if (!flags.json) {
|
|
12
|
-
|
|
12
|
+
this.log(YAML.stringify(monorepo.config));
|
|
13
13
|
}
|
|
14
14
|
return monorepo.config;
|
|
15
15
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { getContext } from '../../../index.js';
|
|
2
2
|
import { Args, Command, Flags } from '@oclif/core';
|
|
3
3
|
import { Listr } from 'listr2';
|
|
4
|
-
import {
|
|
5
|
-
import { getContainer, ListContainersOperation } from '../../../docker/index.js';
|
|
6
|
-
import { dockerExecutor } from '../../../executors/docker.js';
|
|
7
|
-
import { ExecutorType } from '../../../executors/index.js';
|
|
8
|
-
import { shellExecutor } from '../../../executors/shell.js';
|
|
4
|
+
import { ExecutorType, RunTaskOperation, } from '../../../monorepo/operations/tasks/RunTaskOperation.js';
|
|
9
5
|
export default class RunTask extends Command {
|
|
10
6
|
static args = {
|
|
11
7
|
task: Args.string({
|
|
@@ -20,7 +16,7 @@ export default class RunTask extends Command {
|
|
|
20
16
|
executor: Flags.string({
|
|
21
17
|
char: 'x',
|
|
22
18
|
name: 'executor',
|
|
23
|
-
options: Object.
|
|
19
|
+
options: Object.values(ExecutorType),
|
|
24
20
|
}),
|
|
25
21
|
};
|
|
26
22
|
static strict = false;
|
|
@@ -38,30 +34,17 @@ export default class RunTask extends Command {
|
|
|
38
34
|
}, [])
|
|
39
35
|
: monorepo.tasks;
|
|
40
36
|
const runTasks = toRun.map((task) => {
|
|
37
|
+
const executor = flags.executor ||
|
|
38
|
+
(task.component ? ExecutorType.container : ExecutorType.local);
|
|
41
39
|
return {
|
|
42
40
|
rendererOptions: { persistentOutput: true },
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// Gonna log on both the logStream and stdout
|
|
49
|
-
const tee = new PassThrough();
|
|
50
|
-
tee.pipe(listrTask.stdout());
|
|
51
|
-
tee.pipe(logStream);
|
|
52
|
-
switch (type) {
|
|
53
|
-
case ExecutorType.container: {
|
|
54
|
-
return this.dockerExec(task, tee);
|
|
55
|
-
}
|
|
56
|
-
case ExecutorType.local: {
|
|
57
|
-
return this.shellExec(task, tee);
|
|
58
|
-
}
|
|
59
|
-
default: {
|
|
60
|
-
throw new Error(`Unsupported executor: ${type}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
41
|
+
async task(_ctx, listrTask) {
|
|
42
|
+
await monorepo.run(new RunTaskOperation(listrTask.stdout()), {
|
|
43
|
+
executor,
|
|
44
|
+
task,
|
|
45
|
+
});
|
|
63
46
|
},
|
|
64
|
-
title: `Running ${task.id}`,
|
|
47
|
+
title: `Running ${task.id} (${executor})`,
|
|
65
48
|
};
|
|
66
49
|
});
|
|
67
50
|
const runner = new Listr([
|
|
@@ -78,36 +61,4 @@ export default class RunTask extends Command {
|
|
|
78
61
|
]);
|
|
79
62
|
await runner.run();
|
|
80
63
|
}
|
|
81
|
-
async dockerExec(task, out) {
|
|
82
|
-
const { monorepo } = getContext();
|
|
83
|
-
const matching = await monorepo.run(new ListContainersOperation(), {
|
|
84
|
-
filters: {
|
|
85
|
-
label: [
|
|
86
|
-
`emb/project=${monorepo.name}`,
|
|
87
|
-
`emb/component=${task.component}`,
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
if (matching.length === 0) {
|
|
92
|
-
throw new Error(`Could not find a running container for '${task.component}'`);
|
|
93
|
-
}
|
|
94
|
-
if (matching.length > 1) {
|
|
95
|
-
throw new Error(`More than one running container found for '${task.component}'`);
|
|
96
|
-
}
|
|
97
|
-
const container = await getContainer(matching[0].Id);
|
|
98
|
-
return dockerExecutor.run(task.script, {
|
|
99
|
-
container,
|
|
100
|
-
out,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
async shellExec(task, out) {
|
|
104
|
-
const { monorepo } = getContext();
|
|
105
|
-
const cwd = task.component
|
|
106
|
-
? monorepo.component(task.component).rootdir
|
|
107
|
-
: monorepo.rootDir;
|
|
108
|
-
return shellExecutor.run(task.script, {
|
|
109
|
-
cwd,
|
|
110
|
-
out,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
64
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Flavor } from './schema.js';
|
|
2
|
+
import { FlavorConfig, IMonorepoConfig, UserConfig } from './types.js';
|
|
3
3
|
export declare const toFlavor: (flavor: Flavor) => FlavorConfig;
|
|
4
|
-
export declare const toComponent: (cmp: Component) => ComponentConfig;
|
|
5
4
|
export declare const toProjectConfig: (config: UserConfig, rootDir?: string) => IMonorepoConfig;
|
|
@@ -3,14 +3,9 @@ import { cwd } from 'node:process';
|
|
|
3
3
|
export const toFlavor = (flavor) => {
|
|
4
4
|
return {
|
|
5
5
|
...flavor,
|
|
6
|
-
components: flavor.components
|
|
6
|
+
components: flavor.components,
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
|
-
export const toComponent = (cmp) => {
|
|
10
|
-
return typeof cmp === 'string'
|
|
11
|
-
? { context: cmp, name: cmp }
|
|
12
|
-
: cmp;
|
|
13
|
-
};
|
|
14
9
|
export const toProjectConfig = (config, rootDir) => {
|
|
15
10
|
const project = typeof config.project === 'string'
|
|
16
11
|
? { name: config.project }
|
|
@@ -23,7 +18,7 @@ export const toProjectConfig = (config, rootDir) => {
|
|
|
23
18
|
else {
|
|
24
19
|
project.rootDir = rootDir || cwd();
|
|
25
20
|
}
|
|
26
|
-
const components =
|
|
21
|
+
const components = config.components || [];
|
|
27
22
|
const { defaults, env, flavors, plugins, vars } = config;
|
|
28
23
|
return {
|
|
29
24
|
components,
|
|
@@ -3,33 +3,6 @@
|
|
|
3
3
|
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
|
4
4
|
* and run json-schema-to-typescript to regenerate this file.
|
|
5
5
|
*/
|
|
6
|
-
export type Component = string | {
|
|
7
|
-
/**
|
|
8
|
-
* The name of the component.
|
|
9
|
-
*/
|
|
10
|
-
name: string;
|
|
11
|
-
/**
|
|
12
|
-
* The directory of the component.
|
|
13
|
-
*/
|
|
14
|
-
context?: string;
|
|
15
|
-
/**
|
|
16
|
-
* A description of the component.
|
|
17
|
-
*/
|
|
18
|
-
description?: string;
|
|
19
|
-
buildArgs?: {
|
|
20
|
-
[k: string]: unknown;
|
|
21
|
-
};
|
|
22
|
-
dependencies?: string[];
|
|
23
|
-
/**
|
|
24
|
-
* The stage to target for the build
|
|
25
|
-
*/
|
|
26
|
-
target?: string;
|
|
27
|
-
/**
|
|
28
|
-
* The Dockerfile to use
|
|
29
|
-
*/
|
|
30
|
-
dockerfile?: string;
|
|
31
|
-
tasks?: Task[];
|
|
32
|
-
};
|
|
33
6
|
export interface EMBConfigSchema {
|
|
34
7
|
project: string | {
|
|
35
8
|
/**
|
|
@@ -72,7 +45,7 @@ export interface Defaults {
|
|
|
72
45
|
tag?: string;
|
|
73
46
|
target?: string;
|
|
74
47
|
buildArgs?: {
|
|
75
|
-
[k: string]:
|
|
48
|
+
[k: string]: string;
|
|
76
49
|
};
|
|
77
50
|
labels?: {
|
|
78
51
|
[k: string]: string;
|
|
@@ -80,6 +53,33 @@ export interface Defaults {
|
|
|
80
53
|
[k: string]: unknown;
|
|
81
54
|
};
|
|
82
55
|
}
|
|
56
|
+
export interface Component {
|
|
57
|
+
/**
|
|
58
|
+
* The name of the component.
|
|
59
|
+
*/
|
|
60
|
+
name: string;
|
|
61
|
+
/**
|
|
62
|
+
* The directory of the component.
|
|
63
|
+
*/
|
|
64
|
+
context?: string;
|
|
65
|
+
/**
|
|
66
|
+
* A description of the component.
|
|
67
|
+
*/
|
|
68
|
+
description?: string;
|
|
69
|
+
buildArgs?: {
|
|
70
|
+
[k: string]: string;
|
|
71
|
+
};
|
|
72
|
+
dependencies?: string[];
|
|
73
|
+
/**
|
|
74
|
+
* The stage to target for the build
|
|
75
|
+
*/
|
|
76
|
+
target?: string;
|
|
77
|
+
/**
|
|
78
|
+
* The Dockerfile to use
|
|
79
|
+
*/
|
|
80
|
+
dockerfile?: string;
|
|
81
|
+
tasks?: Task[];
|
|
82
|
+
}
|
|
83
83
|
export interface Task {
|
|
84
84
|
name: string;
|
|
85
85
|
description?: string;
|
|
@@ -88,7 +88,9 @@
|
|
|
88
88
|
"target": { "type": "string" },
|
|
89
89
|
"buildArgs": {
|
|
90
90
|
"type": "object",
|
|
91
|
-
"additionalProperties":
|
|
91
|
+
"additionalProperties": {
|
|
92
|
+
"type": "string"
|
|
93
|
+
}
|
|
92
94
|
},
|
|
93
95
|
"labels": {
|
|
94
96
|
"type": "object",
|
|
@@ -124,60 +126,53 @@
|
|
|
124
126
|
"additionalProperties": false
|
|
125
127
|
},
|
|
126
128
|
"component": {
|
|
127
|
-
"
|
|
128
|
-
|
|
129
|
+
"type": "object",
|
|
130
|
+
"required": ["name"],
|
|
131
|
+
"properties": {
|
|
132
|
+
"name": {
|
|
129
133
|
"type": "string",
|
|
130
134
|
"minLength": 3,
|
|
131
|
-
"description": "
|
|
135
|
+
"description": "The name of the component."
|
|
132
136
|
},
|
|
133
|
-
{
|
|
137
|
+
"context": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"minLength": 1,
|
|
140
|
+
"description": "The directory of the component."
|
|
141
|
+
},
|
|
142
|
+
"description": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"minLength": 1,
|
|
145
|
+
"description": "A description of the component."
|
|
146
|
+
},
|
|
147
|
+
"buildArgs": {
|
|
134
148
|
"type": "object",
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
"
|
|
158
|
-
|
|
159
|
-
"items": {
|
|
160
|
-
"type": "string"
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
"target": {
|
|
164
|
-
"type": "string",
|
|
165
|
-
"description": "The stage to target for the build"
|
|
166
|
-
},
|
|
167
|
-
"dockerfile": {
|
|
168
|
-
"type": "string",
|
|
169
|
-
"description": "The Dockerfile to use"
|
|
170
|
-
},
|
|
171
|
-
"tasks": {
|
|
172
|
-
"type": "array",
|
|
173
|
-
"items": {
|
|
174
|
-
"$ref": "#/$defs/task"
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
"additionalProperties": false
|
|
149
|
+
"properties": {},
|
|
150
|
+
"additionalProperties": {
|
|
151
|
+
"type": "string"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"dependencies": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"items": {
|
|
157
|
+
"type": "string"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"target": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"description": "The stage to target for the build"
|
|
163
|
+
},
|
|
164
|
+
"dockerfile": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"description": "The Dockerfile to use"
|
|
167
|
+
},
|
|
168
|
+
"tasks": {
|
|
169
|
+
"type": "array",
|
|
170
|
+
"items": {
|
|
171
|
+
"$ref": "#/$defs/task"
|
|
172
|
+
}
|
|
179
173
|
}
|
|
180
|
-
|
|
174
|
+
},
|
|
175
|
+
"additionalProperties": false
|
|
181
176
|
},
|
|
182
177
|
"flavor": {
|
|
183
178
|
"type": "object",
|
|
@@ -5,7 +5,7 @@ export type IProjectConfig = {
|
|
|
5
5
|
rootDir: string;
|
|
6
6
|
};
|
|
7
7
|
export type ComponentConfig = {
|
|
8
|
-
buildArgs?: Record<
|
|
8
|
+
buildArgs?: Record<string, string>;
|
|
9
9
|
context?: string;
|
|
10
10
|
dependencies?: Array<string>;
|
|
11
11
|
dockerfile?: string;
|
|
@@ -16,7 +16,7 @@ export type ComponentConfig = {
|
|
|
16
16
|
};
|
|
17
17
|
export type DefaultSettings = {
|
|
18
18
|
docker?: {
|
|
19
|
-
buildArgs?: Record<string,
|
|
19
|
+
buildArgs?: Record<string, string>;
|
|
20
20
|
labels?: Record<string, string>;
|
|
21
21
|
tag?: string;
|
|
22
22
|
target?: string;
|
|
@@ -3,8 +3,9 @@ import { readFile, stat } from 'node:fs/promises';
|
|
|
3
3
|
import yaml from 'yaml';
|
|
4
4
|
import { toProjectConfig } from './convert.js';
|
|
5
5
|
import configSchema from './schema.json' with { type: 'json' };
|
|
6
|
+
const ajv = new Ajv();
|
|
7
|
+
ajv.addSchema(configSchema);
|
|
6
8
|
export const validateUserConfig = async (pathOrObject) => {
|
|
7
|
-
const ajv = new Ajv();
|
|
8
9
|
let userConfig;
|
|
9
10
|
if (typeof pathOrObject === 'string') {
|
|
10
11
|
if (await stat(pathOrObject)) {
|
|
@@ -24,3 +25,27 @@ export const validateUserConfig = async (pathOrObject) => {
|
|
|
24
25
|
}
|
|
25
26
|
return toProjectConfig(userConfig);
|
|
26
27
|
};
|
|
28
|
+
export const validateEmbfile = async (pathOrObject) => {
|
|
29
|
+
let component;
|
|
30
|
+
if (typeof pathOrObject === 'string') {
|
|
31
|
+
if (await stat(pathOrObject)) {
|
|
32
|
+
const cfgYaml = (await readFile(pathOrObject)).toString();
|
|
33
|
+
component = yaml.parse(cfgYaml.toString());
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new Error(`Could not find file: ${pathOrObject}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
component = pathOrObject;
|
|
41
|
+
}
|
|
42
|
+
const validate = ajv.getSchema('/schemas/config#/$defs/component');
|
|
43
|
+
if (!validate) {
|
|
44
|
+
throw new Error('Could not find the JSON schema validator for Embfile');
|
|
45
|
+
}
|
|
46
|
+
if (!validate(component)) {
|
|
47
|
+
ajv.errors.forEach((err) => console.error(err));
|
|
48
|
+
throw new Error(`Your .emb.yml is incorrect`);
|
|
49
|
+
}
|
|
50
|
+
return component;
|
|
51
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
|
|
6
|
+
*/
|
|
7
|
+
declare const schema: z.ZodObject<{
|
|
8
|
+
attachStderr: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
9
|
+
attachStdin: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
10
|
+
attachStdout: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
11
|
+
container: z.ZodString;
|
|
12
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13
|
+
script: z.ZodString;
|
|
14
|
+
tty: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
15
|
+
workingDir: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export declare class ContainerExecOperation extends AbstractOperation<typeof schema, void> {
|
|
18
|
+
protected out?: Writable | undefined;
|
|
19
|
+
constructor(out?: Writable | undefined);
|
|
20
|
+
protected _run(input: z.input<typeof schema>): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
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/Exec/operation/ContainerExec
|
|
5
|
+
*/
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
attachStderr: z
|
|
8
|
+
.boolean()
|
|
9
|
+
.default(false)
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Attach to `stderr` of the exec command.'),
|
|
12
|
+
attachStdin: z
|
|
13
|
+
.boolean()
|
|
14
|
+
.default(false)
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Attach to `stdin` of the exec command.'),
|
|
17
|
+
attachStdout: z
|
|
18
|
+
.boolean()
|
|
19
|
+
.default(false)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Attach to `stdout` of the exec command.'),
|
|
22
|
+
container: z.string().describe('ID or name of the container'),
|
|
23
|
+
env: z
|
|
24
|
+
.record(z.string(), z.string())
|
|
25
|
+
.optional()
|
|
26
|
+
.describe('A list of environment variables in the form'),
|
|
27
|
+
script: z.string().describe('Command to run, as a string'),
|
|
28
|
+
tty: z.boolean().default(false).optional().describe('Allocate a pseudo-TTY'),
|
|
29
|
+
workingDir: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('The working directory for the exec process inside the container'),
|
|
33
|
+
});
|
|
34
|
+
export class ContainerExecOperation extends AbstractOperation {
|
|
35
|
+
out;
|
|
36
|
+
constructor(out) {
|
|
37
|
+
super(schema);
|
|
38
|
+
this.out = out;
|
|
39
|
+
}
|
|
40
|
+
async _run(input) {
|
|
41
|
+
const container = await this.context.docker.getContainer(input.container);
|
|
42
|
+
const envVars = Object.entries(input.env || {}).reduce((arr, [key, value]) => {
|
|
43
|
+
return [...arr, `${key}=${value}`];
|
|
44
|
+
}, []);
|
|
45
|
+
const options = {
|
|
46
|
+
AttachStderr: input.attachStderr,
|
|
47
|
+
AttachStdin: input.attachStdin,
|
|
48
|
+
AttachStdout: input.attachStdout,
|
|
49
|
+
Cmd: ['bash', '-eu', '-o', 'pipefail', '-c', input.script],
|
|
50
|
+
Env: envVars,
|
|
51
|
+
Tty: input.tty,
|
|
52
|
+
WorkingDir: input.workingDir,
|
|
53
|
+
};
|
|
54
|
+
const exec = await container.exec(options);
|
|
55
|
+
const stream = await exec.start({});
|
|
56
|
+
container.modem.demuxStream(stream, this.out || process.stdout, this.out || process.stderr);
|
|
57
|
+
await new Promise((resolve, reject) => {
|
|
58
|
+
const onError = (err) => reject(err);
|
|
59
|
+
const onEnd = async () => {
|
|
60
|
+
exec.inspect((error, res) => {
|
|
61
|
+
if (error)
|
|
62
|
+
return reject(error);
|
|
63
|
+
const code = res?.ExitCode ?? 0;
|
|
64
|
+
if (code !== 0) {
|
|
65
|
+
const msg = res?.ProcessConfig?.entrypoint
|
|
66
|
+
? `container exec failed (exit ${code})`
|
|
67
|
+
: `command failed (exit ${code})`;
|
|
68
|
+
return reject(new Error(msg));
|
|
69
|
+
}
|
|
70
|
+
resolve();
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
stream.on('error', onError);
|
|
74
|
+
stream.on('end', onEnd);
|
|
75
|
+
stream.on('close', onEnd); // some engines emit 'close' not 'end'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ComponentConfig, DefaultSettings, FlavorConfig, IMonorepoConfig, IProjectConfig, PluginConfig } from '../config/index.js';
|
|
2
2
|
export declare class MonorepoConfig implements IMonorepoConfig {
|
|
3
|
-
components: ComponentConfig[];
|
|
4
3
|
defaults: DefaultSettings;
|
|
5
4
|
env: Record<string, string>;
|
|
6
5
|
flavors: Array<FlavorConfig>;
|
|
7
6
|
plugins: Array<PluginConfig>;
|
|
8
7
|
project: IProjectConfig;
|
|
9
8
|
vars: Record<string, unknown>;
|
|
9
|
+
private _components;
|
|
10
10
|
constructor(config: IMonorepoConfig);
|
|
11
|
+
get components(): ComponentConfig[];
|
|
11
12
|
component(name: string): ComponentConfig;
|
|
12
13
|
flavor(name: string): FlavorConfig;
|
|
13
14
|
toJSON(): Required<IMonorepoConfig>;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import deepMerge from '@fastify/deepmerge';
|
|
2
2
|
import { deepMergeArray } from '../utils/index.js';
|
|
3
3
|
export class MonorepoConfig {
|
|
4
|
-
components;
|
|
5
4
|
defaults;
|
|
6
5
|
env;
|
|
7
6
|
flavors;
|
|
8
7
|
plugins;
|
|
9
8
|
project;
|
|
10
9
|
vars;
|
|
10
|
+
_components;
|
|
11
11
|
constructor(config) {
|
|
12
|
-
this.
|
|
12
|
+
this._components = config.components.reduce((map, cmp) => {
|
|
13
|
+
map.set(cmp.name, cmp);
|
|
14
|
+
return map;
|
|
15
|
+
}, new Map());
|
|
13
16
|
this.defaults = config.defaults || {};
|
|
14
17
|
this.project = config.project;
|
|
15
18
|
this.vars = config.vars || {};
|
|
@@ -17,6 +20,9 @@ export class MonorepoConfig {
|
|
|
17
20
|
this.env = config.env || {};
|
|
18
21
|
this.plugins = config.plugins || [];
|
|
19
22
|
}
|
|
23
|
+
get components() {
|
|
24
|
+
return [...this._components.values()];
|
|
25
|
+
}
|
|
20
26
|
component(name) {
|
|
21
27
|
const config = this.components.find((c) => c.name === name);
|
|
22
28
|
if (!config) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ContainerInfo } from 'dockerode';
|
|
2
|
+
import { Component } from '../../component.js';
|
|
3
|
+
import { IOperation } from '../../../operations/index.js';
|
|
4
|
+
export declare class GetComponentContainerOperation implements IOperation<Component, ContainerInfo> {
|
|
5
|
+
run(component: Component | string): Promise<ContainerInfo>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getContext } from '../../../index.js';
|
|
2
|
+
import { ListContainersOperation } from '../../../docker/index.js';
|
|
3
|
+
import { Component } from '../../component.js';
|
|
4
|
+
export class GetComponentContainerOperation {
|
|
5
|
+
async run(component) {
|
|
6
|
+
const { monorepo } = getContext();
|
|
7
|
+
const cmpName = component instanceof Component ? component.name : component;
|
|
8
|
+
const matching = await monorepo.run(new ListContainersOperation(), {
|
|
9
|
+
filters: {
|
|
10
|
+
label: [`emb/project=${monorepo.name}`, `emb/component=${cmpName}`],
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
if (matching.length === 0) {
|
|
14
|
+
throw new Error(`Could not find a running container for '${cmpName}'`);
|
|
15
|
+
}
|
|
16
|
+
if (matching.length > 1) {
|
|
17
|
+
throw new Error(`More than one running container found for '${cmpName}'`);
|
|
18
|
+
}
|
|
19
|
+
return matching[0];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ResultPromise } from 'execa';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import * as z from 'zod';
|
|
4
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
|
|
7
|
+
*/
|
|
8
|
+
declare const schema: z.ZodObject<{
|
|
9
|
+
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
10
|
+
script: z.ZodString;
|
|
11
|
+
workingDir: z.ZodOptional<z.ZodString>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
export declare class ExecuteLocalCommandOperation extends AbstractOperation<typeof schema, ResultPromise> {
|
|
14
|
+
protected out?: Writable | undefined;
|
|
15
|
+
constructor(out?: Writable | undefined);
|
|
16
|
+
protected _run(input: z.input<typeof schema>): Promise<ResultPromise>;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../../operations/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
|
|
6
|
+
*/
|
|
7
|
+
const schema = z.object({
|
|
8
|
+
env: z
|
|
9
|
+
.record(z.string(), z.string())
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('A list of environment variables in the form'),
|
|
12
|
+
script: z.string().describe('Command to run, as a string'),
|
|
13
|
+
workingDir: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('The working directory for the exec process inside the container'),
|
|
17
|
+
});
|
|
18
|
+
export class ExecuteLocalCommandOperation extends AbstractOperation {
|
|
19
|
+
out;
|
|
20
|
+
constructor(out) {
|
|
21
|
+
super(schema);
|
|
22
|
+
this.out = out;
|
|
23
|
+
}
|
|
24
|
+
async _run(input) {
|
|
25
|
+
const process = execa(input.script, {
|
|
26
|
+
all: true,
|
|
27
|
+
cwd: input.workingDir,
|
|
28
|
+
shell: true,
|
|
29
|
+
});
|
|
30
|
+
if (this.out) {
|
|
31
|
+
process.all?.pipe(this.out);
|
|
32
|
+
}
|
|
33
|
+
return process;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ExecuteLocalCommandOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ExecuteLocalCommandOperation.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { TaskInfo } from '../../types.js';
|
|
3
|
+
import { IOperation } from '../../../operations/types.js';
|
|
4
|
+
export declare enum ExecutorType {
|
|
5
|
+
container = "container",
|
|
6
|
+
local = "local"
|
|
7
|
+
}
|
|
8
|
+
export type RunTaskOperationParams = {
|
|
9
|
+
executor: ExecutorType;
|
|
10
|
+
task: TaskInfo;
|
|
11
|
+
};
|
|
12
|
+
export declare class RunTaskOperation implements IOperation<RunTaskOperationParams, void> {
|
|
13
|
+
protected out?: Writable | undefined;
|
|
14
|
+
constructor(out?: Writable | undefined);
|
|
15
|
+
run(params: RunTaskOperationParams): Promise<void>;
|
|
16
|
+
private runDocker;
|
|
17
|
+
private runLocal;
|
|
18
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getContext } from '../../../index.js';
|
|
2
|
+
import { ContainerExecOperation } from '../../../docker/index.js';
|
|
3
|
+
import { ExecuteLocalCommandOperation, GetComponentContainerOperation, } from '../index.js';
|
|
4
|
+
export var ExecutorType;
|
|
5
|
+
(function (ExecutorType) {
|
|
6
|
+
ExecutorType["container"] = "container";
|
|
7
|
+
ExecutorType["local"] = "local";
|
|
8
|
+
})(ExecutorType || (ExecutorType = {}));
|
|
9
|
+
export class RunTaskOperation {
|
|
10
|
+
out;
|
|
11
|
+
constructor(out) {
|
|
12
|
+
this.out = out;
|
|
13
|
+
}
|
|
14
|
+
async run(params) {
|
|
15
|
+
switch (params.executor) {
|
|
16
|
+
case ExecutorType.container: {
|
|
17
|
+
return this.runDocker(params);
|
|
18
|
+
}
|
|
19
|
+
case ExecutorType.local: {
|
|
20
|
+
return this.runLocal(params);
|
|
21
|
+
}
|
|
22
|
+
default: {
|
|
23
|
+
throw new Error(`Unsupported executor type: ${params.executor}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async runDocker(params) {
|
|
28
|
+
const { monorepo } = getContext();
|
|
29
|
+
if (!params.task.component) {
|
|
30
|
+
throw new Error(`Support for non-component tasks not implemented`);
|
|
31
|
+
}
|
|
32
|
+
const containerInfo = await monorepo.run(new GetComponentContainerOperation(), params.task.component);
|
|
33
|
+
await monorepo.run(new ContainerExecOperation(this.out), {
|
|
34
|
+
attachStderr: true,
|
|
35
|
+
attachStdout: true,
|
|
36
|
+
container: containerInfo.Id,
|
|
37
|
+
script: params.task.script,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async runLocal(params) {
|
|
41
|
+
const { monorepo } = getContext();
|
|
42
|
+
const cwd = params.task.component
|
|
43
|
+
? monorepo.component(params.task.component).rootdir
|
|
44
|
+
: monorepo.rootDir;
|
|
45
|
+
await monorepo.run(new ExecuteLocalCommandOperation(this.out), {
|
|
46
|
+
script: params.task.script,
|
|
47
|
+
workingDir: cwd,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RunTaskOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RunTaskOperation.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Monorepo, MonorepoConfig } from '../index.js';
|
|
2
|
+
import { AbstractPlugin } from './plugin.js';
|
|
3
|
+
export type ComponentDiscoverPluginOptions = {
|
|
4
|
+
glob?: string;
|
|
5
|
+
ignore?: string | string[];
|
|
6
|
+
};
|
|
7
|
+
export declare const ComponentDiscoverPluginDefaultOptions: {
|
|
8
|
+
glob: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class ComponentDiscoverPlugin extends AbstractPlugin<ComponentDiscoverPluginOptions> {
|
|
11
|
+
protected monorepo: Monorepo;
|
|
12
|
+
static name: string;
|
|
13
|
+
constructor(config: Partial<ComponentDiscoverPluginOptions>, monorepo: Monorepo);
|
|
14
|
+
extendConfig(config: MonorepoConfig): Promise<MonorepoConfig>;
|
|
15
|
+
}
|
|
@@ -3,10 +3,22 @@ import { glob } from 'glob';
|
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
4
|
import { MonorepoConfig } from '../index.js';
|
|
5
5
|
import { AbstractPlugin } from './plugin.js';
|
|
6
|
+
export const ComponentDiscoverPluginDefaultOptions = {
|
|
7
|
+
glob: '*/Dockerfile',
|
|
8
|
+
};
|
|
6
9
|
export class ComponentDiscoverPlugin extends AbstractPlugin {
|
|
10
|
+
monorepo;
|
|
7
11
|
static name = 'autodiscover';
|
|
12
|
+
constructor(config, monorepo) {
|
|
13
|
+
super({
|
|
14
|
+
...ComponentDiscoverPluginDefaultOptions,
|
|
15
|
+
...config,
|
|
16
|
+
}, monorepo);
|
|
17
|
+
this.monorepo = monorepo;
|
|
18
|
+
}
|
|
8
19
|
async extendConfig(config) {
|
|
9
|
-
const files = await glob(
|
|
20
|
+
const files = await glob(this.config.glob || ComponentDiscoverPluginDefaultOptions.glob, {
|
|
21
|
+
...this.config,
|
|
10
22
|
cwd: config.project.rootDir,
|
|
11
23
|
});
|
|
12
24
|
const overrides = files.map((path) => {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Monorepo, MonorepoConfig } from '../index.js';
|
|
2
|
+
import { AbstractPlugin } from './plugin.js';
|
|
3
|
+
export type EmbfileLoaderPluginOptions = {
|
|
4
|
+
glob?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const EmbfileLoaderPluginDefaultOptions: {
|
|
7
|
+
glob: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class EmbfileLoaderPlugin extends AbstractPlugin<EmbfileLoaderPluginOptions> {
|
|
10
|
+
protected monorepo: Monorepo;
|
|
11
|
+
static name: string;
|
|
12
|
+
constructor(config: Partial<EmbfileLoaderPluginOptions>, monorepo: Monorepo);
|
|
13
|
+
extendConfig(config: MonorepoConfig): Promise<MonorepoConfig>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { validateEmbfile } from '../../config/index.js';
|
|
4
|
+
import { AbstractPlugin } from './plugin.js';
|
|
5
|
+
export const EmbfileLoaderPluginDefaultOptions = {
|
|
6
|
+
glob: '*/Embfile.{yaml,yml}',
|
|
7
|
+
};
|
|
8
|
+
export class EmbfileLoaderPlugin extends AbstractPlugin {
|
|
9
|
+
monorepo;
|
|
10
|
+
static name = 'embfiles';
|
|
11
|
+
constructor(config, monorepo) {
|
|
12
|
+
super({
|
|
13
|
+
...EmbfileLoaderPluginDefaultOptions,
|
|
14
|
+
...config,
|
|
15
|
+
}, monorepo);
|
|
16
|
+
this.monorepo = monorepo;
|
|
17
|
+
}
|
|
18
|
+
async extendConfig(config) {
|
|
19
|
+
const files = await glob(this.config.glob || EmbfileLoaderPluginDefaultOptions.glob, {
|
|
20
|
+
...this.config,
|
|
21
|
+
cwd: config.project.rootDir,
|
|
22
|
+
});
|
|
23
|
+
const newConfig = await files.reduce(async (pConfig, path) => {
|
|
24
|
+
const config = await pConfig;
|
|
25
|
+
const embfile = await join(config.project.rootDir, path);
|
|
26
|
+
const component = await validateEmbfile(embfile);
|
|
27
|
+
return config.with({
|
|
28
|
+
components: [component],
|
|
29
|
+
});
|
|
30
|
+
}, Promise.resolve(config));
|
|
31
|
+
return newConfig;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AbstractPlugin } from './plugin.js';
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './ComponentDiscoverPlugin.js';
|
|
3
3
|
export * from './DotEnvPlugin.js';
|
|
4
|
-
|
|
4
|
+
export * from './EmbfileLoaderPlugin.js';
|
|
5
|
+
import { Monorepo } from '../index.js';
|
|
5
6
|
export type AbstractPluginConstructor = new <C, P extends AbstractPlugin<C>>(config: C, monorepo: Monorepo) => P;
|
|
6
7
|
export declare const registerPlugin: (plugin: AbstractPluginConstructor) => void;
|
|
7
8
|
export declare const getPlugin: (name: string) => AbstractPluginConstructor;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './ComponentDiscoverPlugin.js';
|
|
2
2
|
export * from './DotEnvPlugin.js';
|
|
3
|
-
|
|
3
|
+
export * from './EmbfileLoaderPlugin.js';
|
|
4
|
+
import { ComponentDiscoverPlugin } from './ComponentDiscoverPlugin.js';
|
|
4
5
|
import { DotEnvPlugin } from './DotEnvPlugin.js';
|
|
6
|
+
import { EmbfileLoaderPlugin } from './EmbfileLoaderPlugin.js';
|
|
5
7
|
const PluginRegistry = new Map();
|
|
6
8
|
export const registerPlugin = (plugin) => {
|
|
7
9
|
if (PluginRegistry.has(plugin.name)) {
|
|
@@ -18,3 +20,4 @@ export const getPlugin = (name) => {
|
|
|
18
20
|
/** Not sure why we need casting */
|
|
19
21
|
registerPlugin(ComponentDiscoverPlugin);
|
|
20
22
|
registerPlugin(DotEnvPlugin);
|
|
23
|
+
registerPlugin(EmbfileLoaderPlugin);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EmbContext } from '../../index.js';
|
|
2
2
|
import * as z from 'zod';
|
|
3
|
-
import { IOperation } from '../
|
|
3
|
+
import { IOperation } from '../index.js';
|
|
4
4
|
export declare abstract class AbstractOperation<S extends z.Schema, O = unknown> implements IOperation<z.infer<S>, O> {
|
|
5
5
|
protected inputSchema: S;
|
|
6
6
|
protected context: EmbContext;
|
package/oclif.manifest.json
CHANGED
|
@@ -450,40 +450,6 @@
|
|
|
450
450
|
"prune.js"
|
|
451
451
|
]
|
|
452
452
|
},
|
|
453
|
-
"run": {
|
|
454
|
-
"aliases": [],
|
|
455
|
-
"args": {
|
|
456
|
-
"component": {
|
|
457
|
-
"description": "Component name",
|
|
458
|
-
"name": "component",
|
|
459
|
-
"required": true
|
|
460
|
-
},
|
|
461
|
-
"script": {
|
|
462
|
-
"description": "NPM script to run",
|
|
463
|
-
"name": "script",
|
|
464
|
-
"required": true
|
|
465
|
-
}
|
|
466
|
-
},
|
|
467
|
-
"description": "Run an npm script from a component's package.json",
|
|
468
|
-
"flags": {},
|
|
469
|
-
"hasDynamicHelp": false,
|
|
470
|
-
"hiddenAliases": [],
|
|
471
|
-
"id": "run",
|
|
472
|
-
"pluginAlias": "@enspirit/emb",
|
|
473
|
-
"pluginName": "@enspirit/emb",
|
|
474
|
-
"pluginType": "core",
|
|
475
|
-
"strict": true,
|
|
476
|
-
"enableJsonFlag": false,
|
|
477
|
-
"isESM": true,
|
|
478
|
-
"relativePath": [
|
|
479
|
-
"dist",
|
|
480
|
-
"src",
|
|
481
|
-
"cli",
|
|
482
|
-
"commands",
|
|
483
|
-
"run",
|
|
484
|
-
"index.js"
|
|
485
|
-
]
|
|
486
|
-
},
|
|
487
453
|
"tasks": {
|
|
488
454
|
"aliases": [],
|
|
489
455
|
"args": {},
|
|
@@ -570,5 +536,5 @@
|
|
|
570
536
|
]
|
|
571
537
|
}
|
|
572
538
|
},
|
|
573
|
-
"version": "0.0.
|
|
539
|
+
"version": "0.0.6"
|
|
574
540
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enspirit/emb",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"keywords": ["monorepo", "docker", "taskrunner", "ci", "docker compose", "sentinel", "makefile"],
|
|
6
6
|
"author": "Louis Lambeau <louis.lambeau@enspirit.be>",
|
|
7
7
|
"license": "ISC",
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
2
|
-
export default class RunComponentScript extends Command {
|
|
3
|
-
static args: {
|
|
4
|
-
component: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
-
script: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
-
};
|
|
7
|
-
static description: string;
|
|
8
|
-
static strict: boolean;
|
|
9
|
-
run(): Promise<void>;
|
|
10
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { getContext } from '../../../index.js';
|
|
2
|
-
import { Args, Command } from '@oclif/core';
|
|
3
|
-
import { Listr } from 'listr2';
|
|
4
|
-
import { spawn } from 'node:child_process';
|
|
5
|
-
import fs from 'node:fs/promises';
|
|
6
|
-
export default class RunComponentScript extends Command {
|
|
7
|
-
static args = {
|
|
8
|
-
component: Args.string({
|
|
9
|
-
description: 'Component name',
|
|
10
|
-
required: true,
|
|
11
|
-
}),
|
|
12
|
-
script: Args.string({ description: 'NPM script to run', required: true }),
|
|
13
|
-
};
|
|
14
|
-
static description = "Run an npm script from a component's package.json";
|
|
15
|
-
static strict = true;
|
|
16
|
-
async run() {
|
|
17
|
-
const { args } = await this.parse(RunComponentScript);
|
|
18
|
-
const { monorepo } = getContext();
|
|
19
|
-
const component = monorepo.component(args.component);
|
|
20
|
-
const pkgPath = component.join('package.json');
|
|
21
|
-
const tasks = new Listr([
|
|
22
|
-
{
|
|
23
|
-
rendererOptions: {
|
|
24
|
-
persistentOutput: true,
|
|
25
|
-
},
|
|
26
|
-
async task(_ctx, _task) {
|
|
27
|
-
try {
|
|
28
|
-
const pkgRaw = await fs.readFile(pkgPath, 'utf8');
|
|
29
|
-
const pkg = JSON.parse(pkgRaw);
|
|
30
|
-
if (!pkg.scripts?.[args.script]) {
|
|
31
|
-
throw new Error(`Script "${args.script}" not found in ${component.name}/package.json`);
|
|
32
|
-
}
|
|
33
|
-
return spawn('npm', ['run', args.script], {
|
|
34
|
-
cwd: component.rootdir,
|
|
35
|
-
}).stdout;
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
const error_ = error instanceof Error
|
|
39
|
-
? new TypeError(`Failed to run ${component.name}:${args.script}\n${error.message}`)
|
|
40
|
-
: new Error(`Failed to run ${component.name}:${args.script}\n${error}`);
|
|
41
|
-
throw error_;
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
title: `Running npm script '${args.script}' on ${args.component}`,
|
|
45
|
-
},
|
|
46
|
-
], { concurrent: false });
|
|
47
|
-
await tasks.run();
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|