@enspirit/emb 0.0.4 → 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.
Files changed (53) hide show
  1. package/README.md +2 -19
  2. package/dist/src/cli/commands/config/print.js +1 -1
  3. package/dist/src/cli/commands/tasks/run.d.ts +0 -2
  4. package/dist/src/cli/commands/tasks/run.js +10 -59
  5. package/dist/src/config/convert.d.ts +2 -3
  6. package/dist/src/config/convert.js +2 -7
  7. package/dist/src/config/schema.d.ts +28 -28
  8. package/dist/src/config/schema.json +45 -50
  9. package/dist/src/config/types.d.ts +2 -2
  10. package/dist/src/config/validation.d.ts +2 -0
  11. package/dist/src/config/validation.js +26 -1
  12. package/dist/src/docker/operations/containers/ExecContainerOperation.d.ts +22 -0
  13. package/dist/src/docker/operations/containers/ExecContainerOperation.js +78 -0
  14. package/dist/src/docker/operations/containers/index.d.ts +1 -0
  15. package/dist/src/docker/operations/containers/index.js +1 -0
  16. package/dist/src/monorepo/config.d.ts +2 -1
  17. package/dist/src/monorepo/config.js +8 -2
  18. package/dist/src/monorepo/operations/components/GetComponentContainerOperation.d.ts +6 -0
  19. package/dist/src/monorepo/operations/components/GetComponentContainerOperation.js +21 -0
  20. package/dist/src/monorepo/operations/components/index.d.ts +1 -0
  21. package/dist/src/monorepo/operations/components/index.js +1 -0
  22. package/dist/src/monorepo/operations/index.d.ts +2 -0
  23. package/dist/src/monorepo/operations/index.js +2 -0
  24. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.d.ts +18 -0
  25. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +35 -0
  26. package/dist/src/monorepo/operations/shell/index.d.ts +1 -0
  27. package/dist/src/monorepo/operations/shell/index.js +1 -0
  28. package/dist/src/monorepo/operations/tasks/RunTaskOperation.d.ts +18 -0
  29. package/dist/src/monorepo/operations/tasks/RunTaskOperation.js +50 -0
  30. package/dist/src/monorepo/operations/tasks/index.d.ts +1 -0
  31. package/dist/src/monorepo/operations/tasks/index.js +1 -0
  32. package/dist/src/monorepo/plugins/ComponentDiscoverPlugin.d.ts +15 -0
  33. package/dist/src/monorepo/plugins/{ComponentsDiscover.js → ComponentDiscoverPlugin.js} +13 -1
  34. package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.d.ts +14 -0
  35. package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.js +33 -0
  36. package/dist/src/monorepo/plugins/index.d.ts +3 -2
  37. package/dist/src/monorepo/plugins/index.js +5 -2
  38. package/dist/src/operations/abstract/AbstractOperation.d.ts +1 -1
  39. package/dist/src/utils/deepMergeArray.d.ts +3 -0
  40. package/dist/src/utils/deepMergeArray.js +1 -0
  41. package/oclif.manifest.json +33 -67
  42. package/package.json +2 -2
  43. package/dist/src/cli/commands/run/index.d.ts +0 -10
  44. package/dist/src/cli/commands/run/index.js +0 -49
  45. package/dist/src/executors/docker.d.ts +0 -6
  46. package/dist/src/executors/docker.js +0 -14
  47. package/dist/src/executors/index.d.ts +0 -6
  48. package/dist/src/executors/index.js +0 -7
  49. package/dist/src/executors/shell.d.ts +0 -2
  50. package/dist/src/executors/shell.js +0 -14
  51. package/dist/src/executors/types.d.ts +0 -8
  52. package/dist/src/executors/types.js +0 -1
  53. 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/pulls)
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.4 darwin-x64 node-v22.12.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
- console.log(YAML.stringify(monorepo.config));
12
+ this.log(YAML.stringify(monorepo.config));
13
13
  }
14
14
  return monorepo.config;
15
15
  }
@@ -11,6 +11,4 @@ export default class RunTask extends Command {
11
11
  };
12
12
  static strict: boolean;
13
13
  run(): Promise<void>;
14
- private dockerExec;
15
- private shellExec;
16
14
  }
@@ -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 { PassThrough } from 'node:stream';
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.keys(ExecutorType),
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
- task: async (_ctx, listrTask) => {
44
- const type = flags.executor
45
- ? flags.executor
46
- : ExecutorType.container;
47
- const logStream = await monorepo.store.createWriteStream(`logs/tasks/run/${task.id}.log`);
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 { Component, Flavor } from './schema.js';
2
- import { ComponentConfig, FlavorConfig, IMonorepoConfig, UserConfig } from './types.js';
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?.map(toComponent),
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 = (config.components || []).map((cmp) => toComponent(cmp));
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]: unknown;
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": true
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
- "oneOf": [
128
- {
129
+ "type": "object",
130
+ "required": ["name"],
131
+ "properties": {
132
+ "name": {
129
133
  "type": "string",
130
134
  "minLength": 3,
131
- "description": "Shortcut for specifying the component name."
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
- "required": ["name"],
136
- "properties": {
137
- "name": {
138
- "type": "string",
139
- "minLength": 3,
140
- "description": "The name of the component."
141
- },
142
- "context": {
143
- "type": "string",
144
- "minLength": 1,
145
- "description": "The directory of the component."
146
- },
147
- "description": {
148
- "type": "string",
149
- "minLength": 1,
150
- "description": "A description of the component."
151
- },
152
- "buildArgs": {
153
- "type": "object",
154
- "properties": {},
155
- "additionalProperties": true
156
- },
157
- "dependencies": {
158
- "type": "array",
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<PropertyKey, string>;
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, unknown>;
19
+ buildArgs?: Record<string, string>;
20
20
  labels?: Record<string, string>;
21
21
  tag?: string;
22
22
  target?: string;
@@ -1 +1,3 @@
1
+ import { Component } from './schema.js';
1
2
  export declare const validateUserConfig: (pathOrObject: string | unknown) => Promise<import("./types.js").IMonorepoConfig>;
3
+ export declare const validateEmbfile: (pathOrObject: string | unknown) => Promise<Component>;
@@ -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,2 +1,3 @@
1
+ export * from './ExecContainerOperation.js';
1
2
  export * from './ListContainersOperation.js';
2
3
  export * from './PruneContainersOperation.js';
@@ -1,2 +1,3 @@
1
+ export * from './ExecContainerOperation.js';
1
2
  export * from './ListContainersOperation.js';
2
3
  export * from './PruneContainersOperation.js';
@@ -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.components = config.components;
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
+ }
@@ -1 +1,2 @@
1
1
  export * from './BuildComponentsOperation.js';
2
+ export * from './GetComponentContainerOperation.js';
@@ -1 +1,2 @@
1
1
  export * from './BuildComponentsOperation.js';
2
+ export * from './GetComponentContainerOperation.js';
@@ -1 +1,3 @@
1
1
  export * from './components/index.js';
2
+ export * from './shell/index.js';
3
+ export * from './tasks/index.js';
@@ -1 +1,3 @@
1
1
  export * from './components/index.js';
2
+ export * from './shell/index.js';
3
+ export * from './tasks/index.js';