@enspirit/emb 0.0.6 → 0.0.8

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 (66) hide show
  1. package/README.md +61 -13
  2. package/dist/src/cli/commands/clean.d.ts +3 -1
  3. package/dist/src/cli/commands/clean.js +13 -2
  4. package/dist/src/cli/commands/components/build.d.ts +6 -2
  5. package/dist/src/cli/commands/components/build.js +17 -7
  6. package/dist/src/cli/commands/config/print.js +2 -3
  7. package/dist/src/cli/commands/down.d.ts +2 -2
  8. package/dist/src/cli/commands/down.js +5 -25
  9. package/dist/src/cli/commands/tasks/index.js +11 -5
  10. package/dist/src/cli/commands/tasks/run.d.ts +2 -1
  11. package/dist/src/cli/commands/tasks/run.js +30 -45
  12. package/dist/src/cli/commands/up.d.ts +1 -1
  13. package/dist/src/cli/commands/up.js +12 -34
  14. package/dist/src/config/convert.js +2 -4
  15. package/dist/src/config/index.d.ts +1 -0
  16. package/dist/src/config/index.js +1 -0
  17. package/dist/src/config/schema.d.ts +32 -25
  18. package/dist/src/config/schema.json +48 -26
  19. package/dist/src/config/types.d.ts +10 -6
  20. package/dist/src/docker/compose/index.d.ts +1 -7
  21. package/dist/src/docker/compose/index.js +1 -13
  22. package/dist/src/docker/compose/operations/ComposeDownOperation.d.ts +12 -0
  23. package/dist/src/docker/compose/operations/ComposeDownOperation.js +21 -0
  24. package/dist/src/docker/compose/operations/ComposeUpOperation.d.ts +13 -0
  25. package/dist/src/docker/compose/operations/ComposeUpOperation.js +39 -0
  26. package/dist/src/docker/compose/operations/index.d.ts +2 -0
  27. package/dist/src/docker/compose/operations/index.js +2 -0
  28. package/dist/src/errors.d.ts +57 -0
  29. package/dist/src/errors.js +66 -0
  30. package/dist/src/index.d.ts +1 -0
  31. package/dist/src/index.js +1 -0
  32. package/dist/src/monorepo/component.d.ts +2 -2
  33. package/dist/src/monorepo/component.js +6 -6
  34. package/dist/src/monorepo/config.d.ts +4 -2
  35. package/dist/src/monorepo/config.js +14 -2
  36. package/dist/src/monorepo/index.d.ts +2 -0
  37. package/dist/src/monorepo/index.js +2 -0
  38. package/dist/src/monorepo/monorepo.d.ts +5 -2
  39. package/dist/src/monorepo/monorepo.js +45 -17
  40. package/dist/src/monorepo/operations/components/BuildComponentsOperation.d.ts +12 -2
  41. package/dist/src/monorepo/operations/components/BuildComponentsOperation.js +50 -59
  42. package/dist/src/monorepo/operations/components/GetComponentContainerOperation.d.ts +1 -1
  43. package/dist/src/monorepo/operations/components/GetComponentContainerOperation.js +1 -1
  44. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.d.ts +4 -6
  45. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +2 -7
  46. package/dist/src/monorepo/operations/tasks/RunTasksOperation.d.ts +20 -0
  47. package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +82 -0
  48. package/dist/src/monorepo/operations/tasks/index.d.ts +1 -1
  49. package/dist/src/monorepo/operations/tasks/index.js +1 -1
  50. package/dist/src/monorepo/plugins/ComponentDiscoverPlugin.js +3 -1
  51. package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.d.ts +3 -3
  52. package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.js +9 -5
  53. package/dist/src/monorepo/store/index.js +5 -3
  54. package/dist/src/monorepo/taskManagerFactory.d.ts +3 -0
  55. package/dist/src/monorepo/taskManagerFactory.js +20 -0
  56. package/dist/src/monorepo/types.d.ts +2 -1
  57. package/dist/src/monorepo/utils/findRunOrder.d.ts +34 -0
  58. package/dist/src/monorepo/utils/findRunOrder.js +165 -0
  59. package/dist/src/monorepo/utils/index.d.ts +1 -1
  60. package/dist/src/monorepo/utils/index.js +1 -1
  61. package/oclif.manifest.json +94 -64
  62. package/package.json +9 -2
  63. package/dist/src/monorepo/operations/tasks/RunTaskOperation.d.ts +0 -18
  64. package/dist/src/monorepo/operations/tasks/RunTaskOperation.js +0 -50
  65. package/dist/src/monorepo/utils/findBuildOrder.d.ts +0 -2
  66. package/dist/src/monorepo/utils/findBuildOrder.js +0 -41
@@ -6,12 +6,10 @@ import { getPlugin } from './plugins/index.js';
6
6
  import { EMBStore } from './store/index.js';
7
7
  export class Monorepo {
8
8
  _config;
9
- _env;
10
9
  _store;
11
10
  initialized = false;
12
11
  constructor(config) {
13
12
  this._config = new MonorepoConfig(config);
14
- this._env = config.env || {};
15
13
  }
16
14
  // TODO: cache/improve
17
15
  get components() {
@@ -32,13 +30,22 @@ export class Monorepo {
32
30
  get rootDir() {
33
31
  return this._config.project.rootDir;
34
32
  }
33
+ get currentFlavor() {
34
+ return this._config.currentFlavor;
35
+ }
35
36
  get store() {
36
37
  return this._store;
37
38
  }
38
39
  get tasks() {
40
+ const globalTasks = (this._config.tasks || [])?.map((t) => {
41
+ return {
42
+ ...t,
43
+ id: `global:${t.name}`,
44
+ };
45
+ });
39
46
  return this.components.reduce((tasks, cmp) => {
40
47
  return [...tasks, ...cmp.tasks];
41
- }, []);
48
+ }, globalTasks);
42
49
  }
43
50
  get vars() {
44
51
  return this._config.vars;
@@ -46,6 +53,20 @@ export class Monorepo {
46
53
  component(name) {
47
54
  return new Component(this._config.component(name), this);
48
55
  }
56
+ task(nameOrId) {
57
+ const byId = this.tasks.find((t) => t.id === nameOrId);
58
+ if (byId) {
59
+ return byId;
60
+ }
61
+ const found = this.tasks.filter((t) => t.name === nameOrId);
62
+ if (found.length > 1) {
63
+ throw new Error(`Task name ambigous, found multiple matches: ${nameOrId}`);
64
+ }
65
+ if (found.length === 0) {
66
+ throw new Error(`Task not found: ${nameOrId}`);
67
+ }
68
+ return found[0];
69
+ }
49
70
  async expand(strOrRecord, expander = new TemplateExpander()) {
50
71
  const options = {
51
72
  default: 'vars',
@@ -59,13 +80,29 @@ export class Monorepo {
59
80
  }
60
81
  return expander.expandRecord(strOrRecord, options);
61
82
  }
83
+ async installStore(store) {
84
+ this._store = store || new EMBStore(this);
85
+ await this._store.init();
86
+ }
87
+ async installEnv() {
88
+ // Expand env vars at the init and then we don't expand anymore
89
+ // The only available source for them is the existing env
90
+ const expander = new TemplateExpander();
91
+ const options = {
92
+ default: 'env',
93
+ sources: {
94
+ env: process.env,
95
+ },
96
+ };
97
+ const expanded = await expander.expandRecord(this._config.env, options);
98
+ Object.assign(process.env, expanded);
99
+ }
62
100
  // Initialize
63
101
  async init() {
64
102
  if (this.initialized) {
65
103
  throw new Error('Monorepo already initialized');
66
104
  }
67
- this._store = new EMBStore(this);
68
- await this._store.init();
105
+ await this.installStore();
69
106
  const plugins = this._config.plugins.map((p) => {
70
107
  const PluginClass = getPlugin(p.name);
71
108
  return new PluginClass(p.config, this);
@@ -74,17 +111,7 @@ export class Monorepo {
74
111
  const newConfig = await plugin.extendConfig?.(await pConfig);
75
112
  return newConfig ?? pConfig;
76
113
  }, Promise.resolve(this._config));
77
- // Expand env vars at the init and then we don't expand anymore
78
- // The only available source for them is the existing env
79
- const expander = new TemplateExpander();
80
- const options = {
81
- default: 'env',
82
- sources: {
83
- env: process.env,
84
- },
85
- };
86
- const expanded = await expander.expandRecord(this._config.env, options);
87
- Object.assign(process.env, expanded);
114
+ await this.installEnv();
88
115
  this.initialized = true;
89
116
  await Promise.all(plugins.map(async (p) => {
90
117
  await p.init?.();
@@ -100,7 +127,8 @@ export class Monorepo {
100
127
  }
101
128
  async withFlavor(name) {
102
129
  const repo = new Monorepo(this._config.withFlavor(name));
103
- await repo.init();
130
+ await repo.installStore();
131
+ await repo.installEnv();
104
132
  return repo;
105
133
  }
106
134
  }
@@ -1,11 +1,21 @@
1
1
  import * as z from 'zod';
2
+ import { DockerComponentBuild } from '../../../docker/index.js';
2
3
  import { AbstractOperation } from '../../../operations/index.js';
4
+ export type BuildComponentMeta = {
5
+ dryRun?: boolean;
6
+ cacheHit?: boolean;
7
+ build: DockerComponentBuild;
8
+ preBuildMeta?: string;
9
+ sentinelFile: string;
10
+ };
3
11
  declare const schema: z.ZodObject<{
4
12
  components: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ dryRun: z.ZodOptional<z.ZodBoolean>;
14
+ silent: z.ZodOptional<z.ZodBoolean>;
5
15
  }, z.core.$strip>;
6
- export declare class BuildComponentsOperation extends AbstractOperation<typeof schema, Array<unknown>> {
16
+ export declare class BuildComponentsOperation extends AbstractOperation<typeof schema, Record<string, BuildComponentMeta>> {
7
17
  constructor();
8
- protected _run(input: z.input<typeof schema>): Promise<Array<unknown>>;
18
+ protected _run(input: z.input<typeof schema>): Promise<Record<string, BuildComponentMeta>>;
9
19
  private buildComponent;
10
20
  }
11
21
  export {};
@@ -1,79 +1,63 @@
1
- import { Manager } from '@listr2/manager';
2
- import { createColors } from 'colorette';
3
- import { delay, ListrDefaultRendererLogLevels, PRESET_TIMER, } from 'listr2';
1
+ import { getContext } from '../../../index.js';
4
2
  import * as z from 'zod';
5
3
  import { BuildImageOperation, getSentinelFile, } from '../../../docker/index.js';
6
- import { findBuildOrder } from '../../utils/findBuildOrder.js';
4
+ import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
7
5
  import { AbstractOperation } from '../../../operations/index.js';
8
- import { FilePrerequisitePlugin } from '../../../prerequisites/FilePrerequisitePlugin.js';
9
- import { PrerequisiteType } from '../../../prerequisites/types.js';
6
+ import { FilePrerequisitePlugin, PrerequisiteType } from '../../../prerequisites/index.js';
10
7
  const schema = z.object({
11
8
  components: z
12
9
  .array(z.string())
13
10
  .describe('The list of components to build')
14
11
  .optional(),
12
+ dryRun: z
13
+ .boolean()
14
+ .optional()
15
+ .describe('Do not build but return the config that would be used to build the images'),
16
+ silent: z
17
+ .boolean()
18
+ .optional()
19
+ .describe('Do not produce any output on the terminal'),
15
20
  });
16
21
  export class BuildComponentsOperation extends AbstractOperation {
17
22
  constructor() {
18
23
  super(schema);
19
24
  }
20
25
  async _run(input) {
21
- const ordered = findBuildOrder(this.context.monorepo.components, input.components);
26
+ const { monorepo } = getContext();
27
+ const manager = taskManagerFactory();
28
+ const selection = (input.components || []).map((t) => monorepo.component(t));
29
+ const collection = new EMBCollection(this.context.monorepo.components, {
30
+ idField: 'name',
31
+ depField: 'dependencies',
32
+ forbidIdNameCollision: true,
33
+ });
34
+ const ordered = findRunOrder(selection.map((s) => s.name), collection);
22
35
  const tasks = await Promise.all(ordered.map((cmp) => {
23
36
  return {
24
37
  task: async (context, task) => {
25
- return this.buildComponent(cmp, task);
38
+ return this.buildComponent(cmp, task, context, input.dryRun);
26
39
  },
27
40
  title: `Building ${cmp.name}`,
28
41
  };
29
42
  }));
30
- const manager = new Manager({
31
- collectErrors: 'minimal',
32
- concurrent: false,
33
- exitOnError: true,
34
- rendererOptions: {
35
- collapseErrors: false,
36
- collapseSubtasks: false,
37
- color: {
38
- // @ts-expect-error not sure why
39
- [ListrDefaultRendererLogLevels.SKIPPED_WITH_COLLAPSE]: createColors().green,
40
- },
41
- icon: {
42
- [ListrDefaultRendererLogLevels.SKIPPED_WITH_COLLAPSE]: '♺',
43
- },
44
- timer: {
45
- ...PRESET_TIMER,
46
- },
47
- },
43
+ const list = manager.newListr([...tasks], {
44
+ renderer: input.silent ? 'silent' : 'default',
45
+ rendererOptions: { persistentOutput: true },
46
+ ctx: {},
48
47
  });
49
- manager.add([
50
- {
51
- async task(_context, task) {
52
- return task.newListr([...tasks], {
53
- rendererOptions: {
54
- collapseSubtasks: false,
55
- },
56
- });
57
- },
58
- title: 'Building components',
59
- },
60
- ]);
61
- await manager.runAll();
62
- return ordered;
48
+ const results = await list.run();
49
+ return results;
63
50
  }
64
- async buildComponent(cmp, parentTask) {
65
- return parentTask.newListr([
51
+ async buildComponent(cmp, parentTask, parentContext, dryRun = false) {
52
+ const prereqPlugin = new FilePrerequisitePlugin();
53
+ const list = parentTask.newListr([
66
54
  // Collect all the prerequisites and other build infos
67
55
  // (This is when variables are expanded etc)
68
56
  {
69
57
  async task(ctx) {
70
- // Reset the context to defaults (as apparently the context is shared amongst branches??)
71
- // TODO understand and fix
72
- ctx.skip = false;
73
- //
74
- ctx.parentTask = parentTask;
58
+ // Install the context for this specific component build chain
59
+ ctx.cacheHit = false;
75
60
  ctx.sentinelFile = getSentinelFile(cmp);
76
- ctx.plugin = new FilePrerequisitePlugin();
77
61
  ctx.build = await cmp.toDockerBuild();
78
62
  },
79
63
  title: 'Prepare build context',
@@ -81,7 +65,7 @@ export class BuildComponentsOperation extends AbstractOperation {
81
65
  // Check for sentinal information to see if the build can be skipped
82
66
  {
83
67
  task: async (ctx) => {
84
- ctx.preBuildMeta = await ctx.plugin.meta(cmp, ctx.build.prerequisites, 'pre');
68
+ ctx.preBuildMeta = await prereqPlugin.meta(cmp, ctx.build.prerequisites, 'pre');
85
69
  let lastValue;
86
70
  try {
87
71
  lastValue = (await this.context.monorepo.store.readFile(ctx.sentinelFile)).toString();
@@ -90,10 +74,10 @@ export class BuildComponentsOperation extends AbstractOperation {
90
74
  lastValue = undefined;
91
75
  }
92
76
  if (lastValue) {
93
- const diff = await ctx.plugin.diff(cmp, ctx.build.prerequisites, lastValue, ctx.preBuildMeta);
77
+ const diff = await prereqPlugin.diff(cmp, ctx.build.prerequisites, lastValue, ctx.preBuildMeta);
94
78
  if (!diff) {
95
- ctx.skip = true;
96
- ctx.parentTask.skip(`${ctx.parentTask.title} (cache hit)`);
79
+ ctx.cacheHit = true;
80
+ parentTask.skip(`${parentTask.title} (cache hit)`);
97
81
  }
98
82
  }
99
83
  },
@@ -101,10 +85,9 @@ export class BuildComponentsOperation extends AbstractOperation {
101
85
  },
102
86
  {
103
87
  task: async (ctx, task) => {
104
- if (ctx.skip) {
88
+ if (ctx.cacheHit || ctx.dryRun) {
105
89
  return task.skip();
106
90
  }
107
- await delay(500);
108
91
  const title = `Building image ${ctx.build.name}:${ctx.build.tag}`;
109
92
  task.title = title;
110
93
  const op = new BuildImageOperation((progress) => {
@@ -127,18 +110,26 @@ export class BuildComponentsOperation extends AbstractOperation {
127
110
  // Update sentinel file
128
111
  {
129
112
  task: async (ctx, task) => {
130
- if (ctx.skip) {
113
+ if (ctx.cacheHit || ctx.dryRun) {
131
114
  return task.skip();
132
115
  }
133
- const sentinelValue = await ctx.plugin.meta(cmp, ctx.build.prerequisites, 'post');
116
+ const sentinelValue = await prereqPlugin.meta(cmp, ctx.build.prerequisites, 'post');
134
117
  await this.context.monorepo.store.writeFile(ctx.sentinelFile, sentinelValue);
135
118
  },
136
119
  title: 'Dumping cache info',
137
120
  },
138
- ], {
139
- rendererOptions: {
140
- collapseSubtasks: true,
121
+ {
122
+ // Return build meta data
123
+ async task(ctx) {
124
+ parentContext[cmp.name] = ctx;
125
+ if (ctx.dryRun) {
126
+ parentTask.skip(`${parentTask.title} (dry run)`);
127
+ }
128
+ },
141
129
  },
130
+ ], {
131
+ ctx: { dryRun },
142
132
  });
133
+ return list;
143
134
  }
144
135
  }
@@ -1,5 +1,5 @@
1
1
  import { ContainerInfo } from 'dockerode';
2
- import { Component } from '../../component.js';
2
+ import { Component } from '../../index.js';
3
3
  import { IOperation } from '../../../operations/index.js';
4
4
  export declare class GetComponentContainerOperation implements IOperation<Component, ContainerInfo> {
5
5
  run(component: Component | string): Promise<ContainerInfo>;
@@ -1,6 +1,6 @@
1
1
  import { getContext } from '../../../index.js';
2
2
  import { ListContainersOperation } from '../../../docker/index.js';
3
- import { Component } from '../../component.js';
3
+ import { Component } from '../../index.js';
4
4
  export class GetComponentContainerOperation {
5
5
  async run(component) {
6
6
  const { monorepo } = getContext();
@@ -1,5 +1,4 @@
1
- import { ResultPromise } from 'execa';
2
- import { Writable } from 'node:stream';
1
+ import { Readable } from 'node:stream';
3
2
  import * as z from 'zod';
4
3
  import { AbstractOperation } from '../../../operations/index.js';
5
4
  /**
@@ -10,9 +9,8 @@ declare const schema: z.ZodObject<{
10
9
  script: z.ZodString;
11
10
  workingDir: z.ZodOptional<z.ZodString>;
12
11
  }, 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>;
12
+ export declare class ExecuteLocalCommandOperation extends AbstractOperation<typeof schema, Readable> {
13
+ constructor();
14
+ protected _run(input: z.input<typeof schema>): Promise<Readable>;
17
15
  }
18
16
  export {};
@@ -16,10 +16,8 @@ const schema = z.object({
16
16
  .describe('The working directory for the exec process inside the container'),
17
17
  });
18
18
  export class ExecuteLocalCommandOperation extends AbstractOperation {
19
- out;
20
- constructor(out) {
19
+ constructor() {
21
20
  super(schema);
22
- this.out = out;
23
21
  }
24
22
  async _run(input) {
25
23
  const process = execa(input.script, {
@@ -27,9 +25,6 @@ export class ExecuteLocalCommandOperation extends AbstractOperation {
27
25
  cwd: input.workingDir,
28
26
  shell: true,
29
27
  });
30
- if (this.out) {
31
- process.all?.pipe(this.out);
32
- }
33
- return process;
28
+ return process.all;
34
29
  }
35
30
  }
@@ -0,0 +1,20 @@
1
+ import { Writable } from 'node:stream';
2
+ import { TaskInfo } from '../../index.js';
3
+ import { IOperation } from '../../../operations/index.js';
4
+ export declare enum ExecutorType {
5
+ container = "container",
6
+ local = "local"
7
+ }
8
+ export type RunTasksOperationParams = {
9
+ tasks: Array<string>;
10
+ executor?: ExecutorType | undefined;
11
+ allMatching?: boolean;
12
+ };
13
+ export type TaskWithScript = TaskInfo & {
14
+ script: string;
15
+ };
16
+ export declare class RunTasksOperation implements IOperation<RunTasksOperationParams, Array<TaskInfo>> {
17
+ run(params: RunTasksOperationParams): Promise<Array<TaskInfo>>;
18
+ protected runDocker(task: TaskWithScript, out?: Writable): Promise<void>;
19
+ protected runLocal(task: TaskWithScript): Promise<import("stream").Readable>;
20
+ }
@@ -0,0 +1,82 @@
1
+ import { getContext } from '../../../index.js';
2
+ import { Manager } from '@listr2/manager';
3
+ import { ContainerExecOperation } from '../../../docker/index.js';
4
+ import { EMBCollection, findRunOrder } from '../../index.js';
5
+ import { ExecuteLocalCommandOperation, GetComponentContainerOperation, } from '../index.js';
6
+ export var ExecutorType;
7
+ (function (ExecutorType) {
8
+ ExecutorType["container"] = "container";
9
+ ExecutorType["local"] = "local";
10
+ })(ExecutorType || (ExecutorType = {}));
11
+ export class RunTasksOperation {
12
+ async run(params) {
13
+ const { monorepo } = getContext();
14
+ // First ensure the selection is valid (user can use task IDs or names)
15
+ const collection = new EMBCollection(monorepo.tasks, {
16
+ idField: 'id',
17
+ depField: 'pre',
18
+ });
19
+ const ordered = findRunOrder(params.tasks, collection, {
20
+ onAmbiguous: params.allMatching ? 'runAll' : 'error',
21
+ });
22
+ const runner = new Manager({
23
+ concurrent: false,
24
+ exitOnError: false,
25
+ rendererOptions: {
26
+ collapseSubtasks: false,
27
+ collapseSkips: false,
28
+ },
29
+ });
30
+ const list = runner.newListr(ordered.map((task) => {
31
+ return {
32
+ rendererOptions: {
33
+ persistentOutput: true,
34
+ },
35
+ task: async (context, listrTask) => {
36
+ if (!task.script) {
37
+ return;
38
+ }
39
+ const executor = params.executor ??
40
+ (task.component ? ExecutorType.container : ExecutorType.local);
41
+ if (executor === ExecutorType.container && !task.component) {
42
+ throw new Error('Cannot use the container executor with global tasks');
43
+ }
44
+ switch (executor) {
45
+ case ExecutorType.container: {
46
+ return this.runDocker(task, listrTask.stdout());
47
+ }
48
+ case ExecutorType.local: {
49
+ return this.runLocal(task);
50
+ }
51
+ default: {
52
+ throw new Error(`Unssuported executor type: ${executor}`);
53
+ }
54
+ }
55
+ },
56
+ title: `Running ${task.id}`,
57
+ };
58
+ }));
59
+ await list.run();
60
+ return ordered;
61
+ }
62
+ async runDocker(task, out) {
63
+ const { monorepo } = getContext();
64
+ const containerInfo = await monorepo.run(new GetComponentContainerOperation(), task.component);
65
+ return monorepo.run(new ContainerExecOperation(out), {
66
+ attachStderr: true,
67
+ attachStdout: true,
68
+ container: containerInfo.Id,
69
+ script: task.script,
70
+ });
71
+ }
72
+ async runLocal(task) {
73
+ const { monorepo } = getContext();
74
+ const cwd = task.component
75
+ ? monorepo.component(task.component).rootdir
76
+ : monorepo.rootDir;
77
+ return monorepo.run(new ExecuteLocalCommandOperation(), {
78
+ script: task.script,
79
+ workingDir: cwd,
80
+ });
81
+ }
82
+ }
@@ -1 +1 @@
1
- export * from './RunTaskOperation.js';
1
+ export * from './RunTasksOperation.js';
@@ -1 +1 @@
1
- export * from './RunTaskOperation.js';
1
+ export * from './RunTasksOperation.js';
@@ -25,8 +25,10 @@ export class ComponentDiscoverPlugin extends AbstractPlugin {
25
25
  const name = dirname(path);
26
26
  const component = config.components.find((cmp) => cmp.name === name);
27
27
  const cfg = {
28
- context: name,
29
28
  name,
29
+ docker: {
30
+ context: name,
31
+ },
30
32
  };
31
33
  return component ? deepmerge()(component, cfg) : cfg;
32
34
  });
@@ -1,14 +1,14 @@
1
1
  import { Monorepo, MonorepoConfig } from '../index.js';
2
2
  import { AbstractPlugin } from './plugin.js';
3
3
  export type EmbfileLoaderPluginOptions = {
4
- glob?: string;
4
+ glob?: string | string[];
5
5
  };
6
6
  export declare const EmbfileLoaderPluginDefaultOptions: {
7
7
  glob: string;
8
8
  };
9
- export declare class EmbfileLoaderPlugin extends AbstractPlugin<EmbfileLoaderPluginOptions> {
9
+ export declare class EmbfileLoaderPlugin extends AbstractPlugin<Required<EmbfileLoaderPluginOptions>> {
10
10
  protected monorepo: Monorepo;
11
11
  static name: string;
12
- constructor(config: Partial<EmbfileLoaderPluginOptions>, monorepo: Monorepo);
12
+ constructor(cfg: Partial<EmbfileLoaderPluginOptions>, monorepo: Monorepo);
13
13
  extendConfig(config: MonorepoConfig): Promise<MonorepoConfig>;
14
14
  }
@@ -8,15 +8,19 @@ export const EmbfileLoaderPluginDefaultOptions = {
8
8
  export class EmbfileLoaderPlugin extends AbstractPlugin {
9
9
  monorepo;
10
10
  static name = 'embfiles';
11
- constructor(config, monorepo) {
12
- super({
11
+ constructor(cfg, monorepo) {
12
+ const config = {
13
13
  ...EmbfileLoaderPluginDefaultOptions,
14
- ...config,
15
- }, monorepo);
14
+ ...cfg,
15
+ };
16
+ if (!Array.isArray(config.glob)) {
17
+ config.glob = [config.glob];
18
+ }
19
+ super(config, monorepo);
16
20
  this.monorepo = monorepo;
17
21
  }
18
22
  async extendConfig(config) {
19
- const files = await glob(this.config.glob || EmbfileLoaderPluginDefaultOptions.glob, {
23
+ const files = await glob(this.config.glob, {
20
24
  ...this.config,
21
25
  cwd: config.project.rootDir,
22
26
  });
@@ -10,9 +10,11 @@ import { dirname, join, normalize } from 'node:path';
10
10
  export class EMBStore {
11
11
  monorepo;
12
12
  path;
13
- constructor(monorepo, dirname = '.emb') {
13
+ constructor(monorepo, dirname) {
14
14
  this.monorepo = monorepo;
15
- this.path = this.monorepo.join(dirname);
15
+ // By default, we use the flavor name to build that root of the store
16
+ // so that logs and sentinel files for different flavors are keps separate
17
+ this.path = this.monorepo.join(dirname || '.emb');
16
18
  }
17
19
  async createReadStream(path) {
18
20
  await this.mkdirp(dirname(path));
@@ -45,7 +47,7 @@ export class EMBStore {
45
47
  }
46
48
  }
47
49
  join(path) {
48
- return join(this.path, path);
50
+ return join(this.path, this.monorepo.currentFlavor, path);
49
51
  }
50
52
  async mkdirp(path) {
51
53
  // Avoid getting out of the store by ensuring nothing goes past ../
@@ -0,0 +1,3 @@
1
+ import { Manager } from '@listr2/manager';
2
+ import { ListrBaseClassOptions } from 'listr2';
3
+ export declare function taskManagerFactory<T extends Record<PropertyKey, unknown>>(override?: ListrBaseClassOptions): Manager<T>;
@@ -0,0 +1,20 @@
1
+ import { Manager } from '@listr2/manager';
2
+ import { ListrDefaultRendererLogLevels, PRESET_TIMER, } from 'listr2';
3
+ export function taskManagerFactory(override) {
4
+ return new Manager({
5
+ collectErrors: 'minimal',
6
+ concurrent: false,
7
+ exitOnError: true,
8
+ rendererOptions: {
9
+ collapseErrors: false,
10
+ collapseSubtasks: false,
11
+ icon: {
12
+ [ListrDefaultRendererLogLevels.SKIPPED_WITH_COLLAPSE]: '♺',
13
+ },
14
+ timer: {
15
+ ...PRESET_TIMER,
16
+ },
17
+ },
18
+ ...override,
19
+ });
20
+ }
@@ -3,5 +3,6 @@ export type TaskInfo = {
3
3
  description?: string;
4
4
  id: string;
5
5
  name: string;
6
- script: string;
6
+ script?: string;
7
+ pre?: Array<string>;
7
8
  };
@@ -0,0 +1,34 @@
1
+ type DepList = readonly string[] | string[] | undefined;
2
+ type CollectionConfig<IDK extends PropertyKey, DPK extends PropertyKey> = {
3
+ idField: IDK;
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
+ };
8
+ type AmbiguityPolicy = 'error' | 'runAll';
9
+ export declare class EMBCollection<T extends Partial<Record<DPK, DepList>> & Record<IDK, string> & {
10
+ name: string;
11
+ }, IDK extends keyof T, DPK extends keyof T> {
12
+ private items;
13
+ readonly idField: IDK;
14
+ readonly depField: DPK;
15
+ private byId;
16
+ private byName;
17
+ constructor(items: Iterable<T>, cfg: CollectionConfig<IDK, DPK>);
18
+ /** All items (stable array iteration) */
19
+ get all(): Iterable<T>;
20
+ idOf(t: T): string;
21
+ depsOf(t: T): readonly string[];
22
+ matches(ref: string, opts?: {
23
+ multiple?: false;
24
+ }): T;
25
+ matches(ref: string, opts: {
26
+ multiple: true;
27
+ }): T[];
28
+ }
29
+ export declare function findRunOrder<T extends Partial<Record<DPK, DepList>> & Record<IDK, string> & {
30
+ name: string;
31
+ }, IDK extends keyof T, DPK extends keyof T>(selection: readonly string[], collection: EMBCollection<T, IDK, DPK>, { onAmbiguous }?: {
32
+ onAmbiguous?: AmbiguityPolicy | undefined;
33
+ }): T[];
34
+ export {};