@enspirit/emb 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +83 -3
  2. package/dist/src/cli/commands/components/logs.js +4 -3
  3. package/dist/src/cli/commands/restart.d.ts +14 -0
  4. package/dist/src/cli/commands/restart.js +38 -0
  5. package/dist/src/cli/commands/stop.d.ts +8 -0
  6. package/dist/src/cli/commands/stop.js +22 -0
  7. package/dist/src/cli/commands/tasks/index.js +1 -1
  8. package/dist/src/cli/commands/tasks/run.d.ts +1 -0
  9. package/dist/src/cli/commands/tasks/run.js +1 -0
  10. package/dist/src/config/schema.d.ts +6 -0
  11. package/dist/src/config/schema.json +7 -0
  12. package/dist/src/docker/compose/operations/ComposeExecOperation.d.ts +1 -0
  13. package/dist/src/docker/compose/operations/ComposeExecOperation.js +12 -1
  14. package/dist/src/docker/compose/operations/ComposeRestartOperation.d.ts +14 -0
  15. package/dist/src/docker/compose/operations/ComposeRestartOperation.js +46 -0
  16. package/dist/src/docker/compose/operations/ComposeStopOperation.d.ts +13 -0
  17. package/dist/src/docker/compose/operations/ComposeStopOperation.js +23 -0
  18. package/dist/src/docker/compose/operations/index.d.ts +2 -0
  19. package/dist/src/docker/compose/operations/index.js +2 -0
  20. package/dist/src/docker/operations/containers/ContainerExecOperation.d.ts +0 -3
  21. package/dist/src/docker/operations/containers/ContainerExecOperation.js +3 -19
  22. package/dist/src/monorepo/config.js +1 -1
  23. package/dist/src/monorepo/operations/resources/BuildResourcesOperation.js +0 -1
  24. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +1 -0
  25. package/dist/src/monorepo/operations/tasks/RunTasksOperation.d.ts +5 -1
  26. package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +20 -4
  27. package/dist/src/monorepo/types.d.ts +6 -1
  28. package/dist/src/monorepo/utils/EMBCollection.d.ts +0 -3
  29. package/dist/src/monorepo/utils/EMBCollection.js +0 -14
  30. package/dist/src/monorepo/utils/index.d.ts +7 -4
  31. package/dist/src/monorepo/utils/index.js +14 -8
  32. package/oclif.manifest.json +123 -36
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -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.5.1 darwin-x64 node-v22.18.0
17
+ @enspirit/emb/0.5.3 darwin-x64 node-v22.18.0
18
18
  $ emb --help [COMMAND]
19
19
  USAGE
20
20
  $ emb COMMAND
@@ -40,7 +40,10 @@ USAGE
40
40
  * [`emb ps`](#emb-ps)
41
41
  * [`emb resources`](#emb-resources)
42
42
  * [`emb resources build [COMPONENT]`](#emb-resources-build-component)
43
+ * [`emb restart [COMPONENT]`](#emb-restart-component)
44
+ * [`emb run TASK`](#emb-run-task)
43
45
  * [`emb shell COMPONENT`](#emb-shell-component)
46
+ * [`emb stop`](#emb-stop)
44
47
  * [`emb tasks`](#emb-tasks)
45
48
  * [`emb tasks run TASK`](#emb-tasks-run-task)
46
49
  * [`emb up [COMPONENT]`](#emb-up-component)
@@ -131,7 +134,7 @@ ARGUMENTS
131
134
  COMPONENT The component you want to see the logs of
132
135
 
133
136
  FLAGS
134
- -f, --follow Follow log output
137
+ -f, --[no-]follow Follow log output
135
138
 
136
139
  DESCRIPTION
137
140
  Get components logs.
@@ -347,7 +350,7 @@ ARGUMENTS
347
350
  COMPONENT The component you want to see the logs of
348
351
 
349
352
  FLAGS
350
- -f, --follow Follow log output
353
+ -f, --[no-]follow Follow log output
351
354
 
352
355
  DESCRIPTION
353
356
  Get components logs.
@@ -430,6 +433,59 @@ EXAMPLES
430
433
  $ emb resources build build --flavor development
431
434
  ```
432
435
 
436
+ ## `emb restart [COMPONENT]`
437
+
438
+ Restart the whole project.
439
+
440
+ ```
441
+ USAGE
442
+ $ emb restart [COMPONENT...] [--json] [-f]
443
+
444
+ ARGUMENTS
445
+ COMPONENT... The component(s) to restart
446
+
447
+ FLAGS
448
+ -f, --no-deps Don't restart depdendent components
449
+
450
+ GLOBAL FLAGS
451
+ --json Format output as json.
452
+
453
+ DESCRIPTION
454
+ Restart the whole project.
455
+
456
+ EXAMPLES
457
+ $ emb restart
458
+ ```
459
+
460
+ ## `emb run TASK`
461
+
462
+ Run tasks.
463
+
464
+ ```
465
+ USAGE
466
+ $ emb run TASK... [--json] [-x container|local] [-a]
467
+
468
+ ARGUMENTS
469
+ TASK... List of tasks to run. You can provide either ids or names (eg: component:task or task)
470
+
471
+ FLAGS
472
+ -a, --all-matching Run all tasks matching (when multiple matches)
473
+ -x, --executor=<option> Where to run the task. (experimental!)
474
+ <options: container|local>
475
+
476
+ GLOBAL FLAGS
477
+ --json Format output as json.
478
+
479
+ DESCRIPTION
480
+ Run tasks.
481
+
482
+ ALIASES
483
+ $ emb run
484
+
485
+ EXAMPLES
486
+ $ emb run
487
+ ```
488
+
433
489
  ## `emb shell COMPONENT`
434
490
 
435
491
  Get a shell on a running component.
@@ -454,6 +510,27 @@ EXAMPLES
454
510
  $ emb shell
455
511
  ```
456
512
 
513
+ ## `emb stop`
514
+
515
+ Stop the whole project.
516
+
517
+ ```
518
+ USAGE
519
+ $ emb stop [--json] [--flavor <value>]
520
+
521
+ FLAGS
522
+ --flavor=<value> Specify the flavor to use.
523
+
524
+ GLOBAL FLAGS
525
+ --json Format output as json.
526
+
527
+ DESCRIPTION
528
+ Stop the whole project.
529
+
530
+ EXAMPLES
531
+ $ emb stop
532
+ ```
533
+
457
534
  ## `emb tasks`
458
535
 
459
536
  List tasks.
@@ -494,6 +571,9 @@ GLOBAL FLAGS
494
571
  DESCRIPTION
495
572
  Run tasks.
496
573
 
574
+ ALIASES
575
+ $ emb run
576
+
497
577
  EXAMPLES
498
578
  $ emb tasks run
499
579
  ```
@@ -10,8 +10,9 @@ export default class ComponentsLogs extends BaseCommand {
10
10
  follow: Flags.boolean({
11
11
  name: 'follow',
12
12
  char: 'f',
13
+ allowNo: true,
13
14
  description: 'Follow log output',
14
- default: false,
15
+ default: true,
15
16
  }),
16
17
  };
17
18
  static args = {
@@ -26,11 +27,11 @@ export default class ComponentsLogs extends BaseCommand {
26
27
  const { monorepo, docker } = await getContext();
27
28
  const component = monorepo.component(args.component);
28
29
  const containers = await monorepo.run(new ListContainersOperation(), {
30
+ all: true,
29
31
  filters: {
30
32
  label: [
31
33
  `emb/project=${monorepo.name}`,
32
34
  `emb/component=${component.name}`,
33
- `emb/flavor=${monorepo.currentFlavor}`,
34
35
  ],
35
36
  },
36
37
  });
@@ -47,7 +48,7 @@ export default class ComponentsLogs extends BaseCommand {
47
48
  stderr: true,
48
49
  stdout: true,
49
50
  });
50
- stream.pipe(process.stdout);
51
+ docker.modem.demuxStream(stream, process.stdout, process.stderr);
51
52
  }
52
53
  else {
53
54
  const res = await container.logs({
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../index.js';
2
+ export default class RestartComand extends BaseCommand {
3
+ static description: string;
4
+ static enableJsonFlag: boolean;
5
+ static examples: string[];
6
+ static flags: {
7
+ 'no-deps': import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ static args: {
10
+ component: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
11
+ };
12
+ static strict: boolean;
13
+ run(): Promise<void>;
14
+ }
@@ -0,0 +1,38 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { BaseCommand, getContext } from '../index.js';
3
+ import { ComposeRestartOperation } from '../../docker/index.js';
4
+ export default class RestartComand extends BaseCommand {
5
+ static description = 'Restart the whole project.';
6
+ static enableJsonFlag = true;
7
+ static examples = ['<%= config.bin %> <%= command.id %>'];
8
+ static flags = {
9
+ 'no-deps': Flags.boolean({
10
+ char: 'f',
11
+ default: false,
12
+ description: "Don't restart depdendent components",
13
+ name: 'no-deps',
14
+ }),
15
+ };
16
+ static args = {
17
+ component: Args.string({
18
+ name: 'component',
19
+ description: 'The component(s) to restart',
20
+ }),
21
+ };
22
+ static strict = false;
23
+ async run() {
24
+ const { flags, argv } = await this.parse(RestartComand);
25
+ const { monorepo } = getContext();
26
+ let components;
27
+ if (argv.length > 0) {
28
+ components =
29
+ argv.length > 0
30
+ ? argv.map((name) => monorepo.component(name))
31
+ : monorepo.components;
32
+ }
33
+ await monorepo.run(new ComposeRestartOperation(), {
34
+ noDeps: flags['no-deps'],
35
+ services: components?.map((c) => c.name),
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,8 @@
1
+ import { FlavoredCommand } from '../index.js';
2
+ export default class StopCommand extends FlavoredCommand<typeof StopCommand> {
3
+ static description: string;
4
+ static enableJsonFlag: boolean;
5
+ static examples: string[];
6
+ static flags: {};
7
+ run(): Promise<void>;
8
+ }
@@ -0,0 +1,22 @@
1
+ import { Listr } from 'listr2';
2
+ import { FlavoredCommand, getContext } from '../index.js';
3
+ import { ComposeStopOperation } from '../../docker/index.js';
4
+ export default class StopCommand extends FlavoredCommand {
5
+ static description = 'Stop the whole project.';
6
+ static enableJsonFlag = true;
7
+ static examples = ['<%= config.bin %> <%= command.id %>'];
8
+ static flags = {};
9
+ async run() {
10
+ const { monorepo } = getContext();
11
+ const runner = new Listr([
12
+ {
13
+ rendererOptions: { persistentOutput: true },
14
+ async task(ctx, task) {
15
+ return monorepo.run(new ComposeStopOperation(task.stdout()), {});
16
+ },
17
+ title: 'Stopping project',
18
+ },
19
+ ]);
20
+ await runner.run();
21
+ }
22
+ }
@@ -20,7 +20,7 @@ export default class TasksIndex extends BaseCommand {
20
20
  return 1;
21
21
  }
22
22
  // Compare components (if both not null)
23
- if (Boolean(ac) && Boolean(bc)) {
23
+ if (ac && bc && Boolean(ac) && Boolean(bc)) {
24
24
  const cmp = ac.localeCompare(bc);
25
25
  if (cmp !== 0) {
26
26
  return cmp;
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../../index.js';
2
2
  export default class RunTask extends BaseCommand {
3
+ static aliases: string[];
3
4
  static args: {
4
5
  task: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
6
  };
@@ -3,6 +3,7 @@ import { Args, Flags } from '@oclif/core';
3
3
  import { BaseCommand } from '../../index.js';
4
4
  import { ExecutorType, RunTasksOperation } from '../../../monorepo/index.js';
5
5
  export default class RunTask extends BaseCommand {
6
+ static aliases = ['run'];
6
7
  static args = {
7
8
  task: Args.string({
8
9
  description: 'List of tasks to run. You can provide either ids or names (eg: component:task or task)',
@@ -12,6 +12,12 @@ export type TaskConfig = TaskConfig1 & {
12
12
  [k: string]: unknown;
13
13
  };
14
14
  pre?: Identifier[];
15
+ /**
16
+ * Variables to pass onto the task
17
+ */
18
+ vars?: {
19
+ [k: string]: string;
20
+ };
15
21
  };
16
22
  export type TaskConfig1 = {
17
23
  [k: string]: unknown;
@@ -136,6 +136,13 @@
136
136
  "items": {
137
137
  "$ref": "#/definitions/Identifier"
138
138
  }
139
+ },
140
+ "vars": {
141
+ "type": "object",
142
+ "description": "Variables to pass onto the task",
143
+ "additionalProperties": {
144
+ "type": "string"
145
+ }
139
146
  }
140
147
  },
141
148
  "additionalProperties": false
@@ -3,6 +3,7 @@ import * as z from 'zod';
3
3
  import { AbstractOperation } from '../../../operations/index.js';
4
4
  declare const schema: z.ZodObject<{
5
5
  command: z.ZodString;
6
+ env: z.ZodOptional<z.ZodObject<{}, z.core.$catchall<z.ZodString>>>;
6
7
  service: z.ZodString;
7
8
  }, z.core.$strip>;
8
9
  export declare class ComposeExecOperation extends AbstractOperation<typeof schema, void> {
@@ -4,6 +4,11 @@ import { ComposeExecError } from '../../../errors.js';
4
4
  import { AbstractOperation } from '../../../operations/index.js';
5
5
  const schema = z.object({
6
6
  command: z.string().describe('The command to execute on the service'),
7
+ env: z
8
+ .object()
9
+ .catchall(z.string())
10
+ .describe('Environment variables to pass to the execution')
11
+ .optional(),
7
12
  service: z
8
13
  .string()
9
14
  .describe('The name of the compose service to exec a shell'),
@@ -17,7 +22,13 @@ export class ComposeExecOperation extends AbstractOperation {
17
22
  async _run(input) {
18
23
  const { monorepo } = this.context;
19
24
  const cmd = 'docker';
20
- const args = ['compose', 'exec', input.service, input.command];
25
+ const args = ['compose', 'exec'];
26
+ // Add any env vars
27
+ Object.entries(input.env || {}).forEach(([key, value]) => {
28
+ args.push('-e', `${key.trim()}=${value.trim()}`);
29
+ });
30
+ // add component and script
31
+ args.push(input.service, input.command);
21
32
  const child = spawn(cmd, args, {
22
33
  stdio: 'pipe',
23
34
  shell: true,
@@ -0,0 +1,14 @@
1
+ import * as z from 'zod';
2
+ import { AbstractOperation } from '../../../operations/index.js';
3
+ /**
4
+ * https://docs.docker.com/reference/cli/docker/compose/restart/
5
+ */
6
+ declare const schema: z.ZodOptional<z.ZodObject<{
7
+ services: z.ZodOptional<z.ZodArray<z.ZodString>>;
8
+ noDeps: z.ZodOptional<z.ZodBoolean>;
9
+ }, z.core.$strip>>;
10
+ export declare class ComposeRestartOperation extends AbstractOperation<typeof schema, void> {
11
+ constructor();
12
+ protected _run(input: z.input<typeof schema>): Promise<void>;
13
+ }
14
+ export {};
@@ -0,0 +1,46 @@
1
+ import { getContext } from '../../../index.js';
2
+ import * as z from 'zod';
3
+ import { ExecuteLocalCommandOperation, taskManagerFactory } from '../../../monorepo/index.js';
4
+ import { AbstractOperation } from '../../../operations/index.js';
5
+ /**
6
+ * https://docs.docker.com/reference/cli/docker/compose/restart/
7
+ */
8
+ const schema = z
9
+ .object({
10
+ services: z
11
+ .array(z.string())
12
+ .optional()
13
+ .describe('The list of service to restart'),
14
+ noDeps: z.boolean().optional().describe("Don't restart dependent services"),
15
+ })
16
+ .optional();
17
+ export class ComposeRestartOperation extends AbstractOperation {
18
+ constructor() {
19
+ super(schema);
20
+ }
21
+ async _run(input) {
22
+ const { monorepo } = getContext();
23
+ const manager = taskManagerFactory();
24
+ const command = ['docker', 'compose', 'restart'];
25
+ if (input?.services) {
26
+ command.push(...input.services);
27
+ }
28
+ if (input?.noDeps) {
29
+ command.push('--no-deps');
30
+ }
31
+ manager.add([
32
+ {
33
+ async task(ctx, task) {
34
+ return monorepo.run(new ExecuteLocalCommandOperation(task.stdout()), {
35
+ script: command.join(' '),
36
+ workingDir: monorepo.rootDir,
37
+ });
38
+ },
39
+ title: input?.services
40
+ ? `Restarting ${input.services.join(', ')}`
41
+ : 'Restarting project',
42
+ },
43
+ ]);
44
+ await manager.runAll();
45
+ }
46
+ }
@@ -0,0 +1,13 @@
1
+ import { Readable, Writable } from 'node:stream';
2
+ import * as z from 'zod';
3
+ import { AbstractOperation } from '../../../operations/index.js';
4
+ /**
5
+ * https://docs.docker.com/reference/cli/docker/compose/stop/
6
+ */
7
+ declare const schema: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
8
+ export declare class ComposeStopOperation extends AbstractOperation<typeof schema, Readable> {
9
+ protected out: Writable;
10
+ constructor(out: Writable);
11
+ protected _run(_input: z.input<typeof schema>): Promise<Readable>;
12
+ }
13
+ export {};
@@ -0,0 +1,23 @@
1
+ import { getContext } from '../../../index.js';
2
+ import * as z from 'zod';
3
+ import { ExecuteLocalCommandOperation } from '../../../monorepo/index.js';
4
+ import { AbstractOperation } from '../../../operations/index.js';
5
+ /**
6
+ * https://docs.docker.com/reference/cli/docker/compose/stop/
7
+ */
8
+ const schema = z.object({}).optional();
9
+ export class ComposeStopOperation extends AbstractOperation {
10
+ out;
11
+ constructor(out) {
12
+ super(schema);
13
+ this.out = out;
14
+ }
15
+ async _run(_input) {
16
+ const { monorepo } = getContext();
17
+ const command = ['docker', 'compose', 'stop'];
18
+ return monorepo.run(new ExecuteLocalCommandOperation(this.out), {
19
+ script: command.join(' '),
20
+ workingDir: monorepo.rootDir,
21
+ });
22
+ }
23
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './ComposeDownOperation.js';
2
2
  export * from './ComposeExecOperation.js';
3
3
  export * from './ComposeExecShellOperation.js';
4
+ export * from './ComposeRestartOperation.js';
5
+ export * from './ComposeStopOperation.js';
4
6
  export * from './ComposeUpOperation.js';
@@ -1,4 +1,6 @@
1
1
  export * from './ComposeDownOperation.js';
2
2
  export * from './ComposeExecOperation.js';
3
3
  export * from './ComposeExecShellOperation.js';
4
+ export * from './ComposeRestartOperation.js';
5
+ export * from './ComposeStopOperation.js';
4
6
  export * from './ComposeUpOperation.js';
@@ -5,9 +5,6 @@ import { AbstractOperation } from '../../../operations/index.js';
5
5
  * https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
6
6
  */
7
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
8
  container: z.ZodString;
12
9
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
13
10
  script: z.ZodString;
@@ -4,21 +4,6 @@ import { AbstractOperation } from '../../../operations/index.js';
4
4
  * https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
5
5
  */
6
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
7
  container: z.string().describe('ID or name of the container'),
23
8
  env: z
24
9
  .record(z.string(), z.string())
@@ -43,9 +28,8 @@ export class ContainerExecOperation extends AbstractOperation {
43
28
  return [...arr, `${key}=${value}`];
44
29
  }, []);
45
30
  const options = {
46
- AttachStderr: input.attachStderr,
47
- AttachStdin: input.attachStdin,
48
- AttachStdout: input.attachStdout,
31
+ AttachStderr: true,
32
+ AttachStdout: true,
49
33
  Cmd: ['bash', '-eu', '-o', 'pipefail', '-c', input.script],
50
34
  Env: envVars,
51
35
  Tty: input.tty,
@@ -53,7 +37,7 @@ export class ContainerExecOperation extends AbstractOperation {
53
37
  };
54
38
  const exec = await container.exec(options);
55
39
  const stream = await exec.start({});
56
- container.modem.demuxStream(stream, this.out || process.stdout, this.out || process.stderr);
40
+ exec.modem.demuxStream(stream, this.out || process.stdout, this.out || process.stderr);
57
41
  await new Promise((resolve, reject) => {
58
42
  const onError = (err) => reject(err);
59
43
  const onEnd = async () => {
@@ -16,7 +16,7 @@ export class MonorepoConfig {
16
16
  this.flavors = config.flavors || {};
17
17
  this.env = config.env || {};
18
18
  this.plugins = config.plugins || [];
19
- this.tasks = toIdentifedHash(config.tasks || {}, 'global');
19
+ this.tasks = toIdentifedHash(config.tasks || {});
20
20
  this.components = config.components || {};
21
21
  }
22
22
  component(id) {
@@ -34,7 +34,6 @@ export class BuildResourcesOperation extends AbstractOperation {
34
34
  const collection = new EMBCollection(monorepo.resources, {
35
35
  idField: 'id',
36
36
  depField: 'dependencies',
37
- forbidIdNameCollision: true,
38
37
  });
39
38
  const ordered = findRunOrder(input.resources || [], collection);
40
39
  const tasks = ordered.map((resource) => {
@@ -26,6 +26,7 @@ export class ExecuteLocalCommandOperation extends AbstractOperation {
26
26
  all: true,
27
27
  cwd: input.workingDir,
28
28
  shell: true,
29
+ env: input.env,
29
30
  });
30
31
  if (this.out) {
31
32
  process.all.pipe(this.out);
@@ -13,8 +13,12 @@ export type RunTasksOperationParams = {
13
13
  export type TaskWithScript = TaskInfo & {
14
14
  script: string;
15
15
  };
16
+ export type TaskWithScriptAndComponent = TaskInfo & {
17
+ script: string;
18
+ component: string;
19
+ };
16
20
  export declare class RunTasksOperation implements IOperation<RunTasksOperationParams, Array<TaskInfo>> {
17
21
  run(params: RunTasksOperationParams): Promise<Array<TaskInfo>>;
18
- protected runDocker(task: TaskWithScript, out?: Writable): Promise<void>;
22
+ protected runDocker(task: TaskWithScriptAndComponent, out?: Writable): Promise<void>;
19
23
  protected runLocal(task: TaskWithScript, out: Writable): Promise<import("stream").Readable>;
20
24
  }
@@ -1,6 +1,6 @@
1
1
  import { getContext } from '../../../index.js';
2
2
  import { PassThrough } from 'node:stream';
3
- import { ComposeExecOperation } from '../../../docker/index.js';
3
+ import { ContainerExecOperation, ListContainersOperation } from '../../../docker/index.js';
4
4
  import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
5
5
  import { ExecuteLocalCommandOperation } from '../index.js';
6
6
  export var ExecutorType;
@@ -58,9 +58,24 @@ export class RunTasksOperation {
58
58
  }
59
59
  async runDocker(task, out) {
60
60
  const { monorepo } = getContext();
61
- return monorepo.run(new ComposeExecOperation(out), {
62
- service: task.component,
63
- command: task.script,
61
+ const containers = await monorepo.run(new ListContainersOperation(), {
62
+ filters: {
63
+ label: [
64
+ `emb/project=${monorepo.name}`,
65
+ `emb/component=${task.component}`,
66
+ ],
67
+ },
68
+ });
69
+ if (containers.length === 0) {
70
+ throw new Error(`No container found for component \`${task.component}\``);
71
+ }
72
+ if (containers.length > 1) {
73
+ throw new Error(`More than one container found for component \`${task.component}\``);
74
+ }
75
+ return monorepo.run(new ContainerExecOperation(out), {
76
+ container: containers[0].Id,
77
+ script: task.script,
78
+ env: await monorepo.expand(task.vars || {}),
64
79
  });
65
80
  }
66
81
  async runLocal(task, out) {
@@ -71,6 +86,7 @@ export class RunTasksOperation {
71
86
  return monorepo.run(new ExecuteLocalCommandOperation(out), {
72
87
  script: task.script,
73
88
  workingDir: cwd,
89
+ env: await monorepo.expand(task.vars || {}),
74
90
  });
75
91
  }
76
92
  }
@@ -1,4 +1,9 @@
1
1
  import { ComponentFlavorConfig, IResourceConfig, ProjectFlavorConfig, TaskConfig } from '../config/types.js';
2
+ export type MaybeComponentIdentifiable<T> = T & {
3
+ id: string;
4
+ name: string;
5
+ component?: string;
6
+ };
2
7
  export type ComponentIdentifiable<T> = T & {
3
8
  id: string;
4
9
  name: string;
@@ -17,7 +22,7 @@ export type ComponentFlavorInfo = ComponentIdentifiable<ComponentFlavorConfig>;
17
22
  export type ComponentFlavors = {
18
23
  [k: string]: ComponentFlavorInfo;
19
24
  };
20
- export type TaskInfo = ComponentIdentifiable<TaskConfig>;
25
+ export type TaskInfo = MaybeComponentIdentifiable<TaskConfig>;
21
26
  export type Tasks = {
22
27
  [k: string]: TaskInfo;
23
28
  };
@@ -2,8 +2,6 @@ import { DepList } from './types.js';
2
2
  export type CollectionConfig<IDK extends PropertyKey, DPK extends PropertyKey> = {
3
3
  idField: IDK;
4
4
  depField: DPK;
5
- /** If true, throw when an item's id equals some other item's name (or vice versa). */
6
- forbidIdNameCollision?: boolean;
7
5
  };
8
6
  export declare class EMBCollection<T extends Partial<Record<DPK, DepList>> & Record<IDK, string> & {
9
7
  name: string;
@@ -11,7 +9,6 @@ export declare class EMBCollection<T extends Partial<Record<DPK, DepList>> & Rec
11
9
  private items;
12
10
  readonly idField: IDK;
13
11
  readonly depField: DPK;
14
- readonly forbidIdNameCollision: boolean;
15
12
  private byId;
16
13
  private byName;
17
14
  constructor(items: Iterable<T>, cfg: CollectionConfig<IDK, DPK>);
@@ -3,7 +3,6 @@ export class EMBCollection {
3
3
  items;
4
4
  idField;
5
5
  depField;
6
- forbidIdNameCollision;
7
6
  //
8
7
  byId;
9
8
  byName;
@@ -11,7 +10,6 @@ export class EMBCollection {
11
10
  this.items = [];
12
11
  this.idField = cfg.idField;
13
12
  this.depField = cfg.depField;
14
- this.forbidIdNameCollision = cfg.forbidIdNameCollision ?? true;
15
13
  this.byId = new Map();
16
14
  this.byName = new Map();
17
15
  // single-pass validation state
@@ -32,18 +30,6 @@ export class EMBCollection {
32
30
  this.byId.set(id, t);
33
31
  seenIds.add(id);
34
32
  }
35
- // --- Optional validation: forbid id <-> name collisions ---
36
- if (this.forbidIdNameCollision) {
37
- if (seenNames.has(id)) {
38
- const nameOwners = this.byName.get(id) ?? [];
39
- const ownerIds = nameOwners.map((o) => o[this.idField]).join(', ');
40
- collisions.push(`value \`${id}\` is an id of \`${name}\` and also a name of item(s) with id(s): [${ownerIds}]`);
41
- }
42
- if (seenIds.has(name)) {
43
- const idOwner = this.byId.get(name);
44
- collisions.push(`value \`${name}\` is a name of \`${t.name}\` and also an id of \`${idOwner.name}\``);
45
- }
46
- }
47
33
  // byName index
48
34
  const list = this.byName.get(name);
49
35
  if (list) {
@@ -1,7 +1,10 @@
1
- import { ComponentIdentifiable } from '../../index.js';
1
+ import { ComponentIdentifiable, MaybeComponentIdentifiable } from '../../index.js';
2
2
  export * from './EMBCollection.js';
3
3
  export * from './graph.js';
4
4
  export * from './types.js';
5
- export declare const toIdentifedHash: <V, T extends {
6
- [k: string]: V;
7
- }>(hash: T, parentName: string) => Record<string, ComponentIdentifiable<V>>;
5
+ export declare function toIdentifedHash<V, T extends Record<string, V>>(hash: T, parentName: string): {
6
+ [K in keyof T]: ComponentIdentifiable<T[K]>;
7
+ };
8
+ export declare function toIdentifedHash<V, T extends Record<string, V>>(hash: T, parentName?: undefined): {
9
+ [K in keyof T]: MaybeComponentIdentifiable<T[K]>;
10
+ };
@@ -1,14 +1,20 @@
1
1
  export * from './EMBCollection.js';
2
2
  export * from './graph.js';
3
3
  export * from './types.js';
4
- export const toIdentifedHash = (hash, parentName) => {
5
- return Object.entries(hash).reduce((hash, [key, value]) => {
6
- hash[key] = {
4
+ // implementation
5
+ export function toIdentifedHash(hash, parentName) {
6
+ const out = {};
7
+ for (const key in hash) {
8
+ if (!Object.hasOwn(hash, key)) {
9
+ continue;
10
+ }
11
+ const value = hash[key];
12
+ out[key] = {
7
13
  ...value,
8
- id: `${parentName}:${key}`,
14
+ id: parentName ? `${parentName}:${key}` : key,
9
15
  name: key,
10
- component: parentName,
16
+ ...(parentName ? { component: parentName } : {}),
11
17
  };
12
- return hash;
13
- }, {});
14
- };
18
+ }
19
+ return out;
20
+ }
@@ -80,6 +80,91 @@
80
80
  "down.js"
81
81
  ]
82
82
  },
83
+ "restart": {
84
+ "aliases": [],
85
+ "args": {
86
+ "component": {
87
+ "description": "The component(s) to restart",
88
+ "name": "component"
89
+ }
90
+ },
91
+ "description": "Restart the whole project.",
92
+ "examples": [
93
+ "<%= config.bin %> <%= command.id %>"
94
+ ],
95
+ "flags": {
96
+ "json": {
97
+ "description": "Format output as json.",
98
+ "helpGroup": "GLOBAL",
99
+ "name": "json",
100
+ "allowNo": false,
101
+ "type": "boolean"
102
+ },
103
+ "no-deps": {
104
+ "char": "f",
105
+ "description": "Don't restart depdendent components",
106
+ "name": "no-deps",
107
+ "allowNo": false,
108
+ "type": "boolean"
109
+ }
110
+ },
111
+ "hasDynamicHelp": false,
112
+ "hiddenAliases": [],
113
+ "id": "restart",
114
+ "pluginAlias": "@enspirit/emb",
115
+ "pluginName": "@enspirit/emb",
116
+ "pluginType": "core",
117
+ "strict": false,
118
+ "enableJsonFlag": true,
119
+ "isESM": true,
120
+ "relativePath": [
121
+ "dist",
122
+ "src",
123
+ "cli",
124
+ "commands",
125
+ "restart.js"
126
+ ]
127
+ },
128
+ "stop": {
129
+ "aliases": [],
130
+ "args": {},
131
+ "description": "Stop the whole project.",
132
+ "examples": [
133
+ "<%= config.bin %> <%= command.id %>"
134
+ ],
135
+ "flags": {
136
+ "json": {
137
+ "description": "Format output as json.",
138
+ "helpGroup": "GLOBAL",
139
+ "name": "json",
140
+ "allowNo": false,
141
+ "type": "boolean"
142
+ },
143
+ "flavor": {
144
+ "description": "Specify the flavor to use.",
145
+ "name": "flavor",
146
+ "required": false,
147
+ "hasDynamicHelp": false,
148
+ "multiple": false,
149
+ "type": "option"
150
+ }
151
+ },
152
+ "hasDynamicHelp": false,
153
+ "hiddenAliases": [],
154
+ "id": "stop",
155
+ "pluginAlias": "@enspirit/emb",
156
+ "pluginName": "@enspirit/emb",
157
+ "pluginType": "core",
158
+ "enableJsonFlag": true,
159
+ "isESM": true,
160
+ "relativePath": [
161
+ "dist",
162
+ "src",
163
+ "cli",
164
+ "commands",
165
+ "stop.js"
166
+ ]
167
+ },
83
168
  "up": {
84
169
  "aliases": [],
85
170
  "args": {
@@ -194,7 +279,7 @@
194
279
  "char": "f",
195
280
  "description": "Follow log output",
196
281
  "name": "follow",
197
- "allowNo": false,
282
+ "allowNo": true,
198
283
  "type": "boolean"
199
284
  }
200
285
  },
@@ -260,12 +345,10 @@
260
345
  "shell.js"
261
346
  ]
262
347
  },
263
- "containers": {
264
- "aliases": [
265
- "ps"
266
- ],
348
+ "config:print": {
349
+ "aliases": [],
267
350
  "args": {},
268
- "description": "List docker containers.",
351
+ "description": "Print the current config.",
269
352
  "examples": [
270
353
  "<%= config.bin %> <%= command.id %>"
271
354
  ],
@@ -277,22 +360,21 @@
277
360
  "allowNo": false,
278
361
  "type": "boolean"
279
362
  },
280
- "all": {
281
- "char": "a",
282
- "description": "Retun all containers. By default, only running containers are shown",
283
- "name": "all",
363
+ "flavor": {
364
+ "description": "Specify the flavor to use.",
365
+ "name": "flavor",
284
366
  "required": false,
285
- "allowNo": false,
286
- "type": "boolean"
367
+ "hasDynamicHelp": false,
368
+ "multiple": false,
369
+ "type": "option"
287
370
  }
288
371
  },
289
372
  "hasDynamicHelp": false,
290
373
  "hiddenAliases": [],
291
- "id": "containers",
374
+ "id": "config:print",
292
375
  "pluginAlias": "@enspirit/emb",
293
376
  "pluginName": "@enspirit/emb",
294
377
  "pluginType": "core",
295
- "strict": true,
296
378
  "enableJsonFlag": true,
297
379
  "isESM": true,
298
380
  "relativePath": [
@@ -300,14 +382,16 @@
300
382
  "src",
301
383
  "cli",
302
384
  "commands",
303
- "containers",
304
- "index.js"
385
+ "config",
386
+ "print.js"
305
387
  ]
306
388
  },
307
- "containers:prune": {
308
- "aliases": [],
389
+ "containers": {
390
+ "aliases": [
391
+ "ps"
392
+ ],
309
393
  "args": {},
310
- "description": "Prune containers.",
394
+ "description": "List docker containers.",
311
395
  "examples": [
312
396
  "<%= config.bin %> <%= command.id %>"
313
397
  ],
@@ -318,11 +402,19 @@
318
402
  "name": "json",
319
403
  "allowNo": false,
320
404
  "type": "boolean"
405
+ },
406
+ "all": {
407
+ "char": "a",
408
+ "description": "Retun all containers. By default, only running containers are shown",
409
+ "name": "all",
410
+ "required": false,
411
+ "allowNo": false,
412
+ "type": "boolean"
321
413
  }
322
414
  },
323
415
  "hasDynamicHelp": false,
324
416
  "hiddenAliases": [],
325
- "id": "containers:prune",
417
+ "id": "containers",
326
418
  "pluginAlias": "@enspirit/emb",
327
419
  "pluginName": "@enspirit/emb",
328
420
  "pluginType": "core",
@@ -335,13 +427,13 @@
335
427
  "cli",
336
428
  "commands",
337
429
  "containers",
338
- "prune.js"
430
+ "index.js"
339
431
  ]
340
432
  },
341
- "config:print": {
433
+ "containers:prune": {
342
434
  "aliases": [],
343
435
  "args": {},
344
- "description": "Print the current config.",
436
+ "description": "Prune containers.",
345
437
  "examples": [
346
438
  "<%= config.bin %> <%= command.id %>"
347
439
  ],
@@ -352,22 +444,15 @@
352
444
  "name": "json",
353
445
  "allowNo": false,
354
446
  "type": "boolean"
355
- },
356
- "flavor": {
357
- "description": "Specify the flavor to use.",
358
- "name": "flavor",
359
- "required": false,
360
- "hasDynamicHelp": false,
361
- "multiple": false,
362
- "type": "option"
363
447
  }
364
448
  },
365
449
  "hasDynamicHelp": false,
366
450
  "hiddenAliases": [],
367
- "id": "config:print",
451
+ "id": "containers:prune",
368
452
  "pluginAlias": "@enspirit/emb",
369
453
  "pluginName": "@enspirit/emb",
370
454
  "pluginType": "core",
455
+ "strict": true,
371
456
  "enableJsonFlag": true,
372
457
  "isESM": true,
373
458
  "relativePath": [
@@ -375,8 +460,8 @@
375
460
  "src",
376
461
  "cli",
377
462
  "commands",
378
- "config",
379
- "print.js"
463
+ "containers",
464
+ "prune.js"
380
465
  ]
381
466
  },
382
467
  "images:delete": {
@@ -651,7 +736,9 @@
651
736
  ]
652
737
  },
653
738
  "tasks:run": {
654
- "aliases": [],
739
+ "aliases": [
740
+ "run"
741
+ ],
655
742
  "args": {
656
743
  "task": {
657
744
  "description": "List of tasks to run. You can provide either ids or names (eg: component:task or task)",
@@ -710,5 +797,5 @@
710
797
  ]
711
798
  }
712
799
  },
713
- "version": "0.5.1"
800
+ "version": "0.5.3"
714
801
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@enspirit/emb",
3
3
  "type": "module",
4
- "version": "0.5.1",
4
+ "version": "0.5.3",
5
5
  "keywords": [
6
6
  "monorepo",
7
7
  "docker",