@enspirit/emb 0.3.0 → 0.3.1

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 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.3.0 darwin-x64 node-v22.12.0
17
+ @enspirit/emb/0.3.1 darwin-x64 node-v22.12.0
18
18
  $ emb --help [COMMAND]
19
19
  USAGE
20
20
  $ emb COMMAND
@@ -9,19 +9,31 @@ export default class TasksIndex extends BaseCommand {
9
9
  async run() {
10
10
  const { flags } = await this.parse(TasksIndex);
11
11
  const { monorepo: { tasks }, } = await getContext();
12
+ const sortedTasks = tasks.toSorted((a, b) => {
13
+ const ac = a.component;
14
+ const bc = b.component;
15
+ // Put null/undefined first
16
+ if (!ac && bc) {
17
+ return -1;
18
+ }
19
+ if (Boolean(ac) && !bc) {
20
+ return 1;
21
+ }
22
+ // Compare components (if both not null)
23
+ if (Boolean(ac) && Boolean(bc)) {
24
+ const cmp = ac.localeCompare(bc);
25
+ if (cmp !== 0) {
26
+ return cmp;
27
+ }
28
+ }
29
+ // Compare names as fallback
30
+ return a.name.localeCompare(b.name);
31
+ });
12
32
  if (!flags.json) {
13
33
  printTable({
14
34
  ...TABLE_DEFAULTS,
15
35
  columns: ['name', 'component', 'description', 'id'],
16
- data: tasks.toSorted((a, b) => {
17
- if (a.component === b.component) {
18
- return a.name < b.name ? -1 : 1;
19
- }
20
- if (!a.component && b.component) {
21
- return -1;
22
- }
23
- return 0;
24
- }),
36
+ data: sortedTasks,
25
37
  });
26
38
  }
27
39
  return tasks;
@@ -1,3 +1,4 @@
1
+ import { Writable } from 'node:stream';
1
2
  import * as z from 'zod';
2
3
  import { AbstractOperation } from '../../../operations/index.js';
3
4
  /**
@@ -13,7 +14,7 @@ export declare const BuildImageOperationInputSchema: z.ZodObject<{
13
14
  target: z.ZodOptional<z.ZodString>;
14
15
  }, z.core.$strip>;
15
16
  export declare class BuildImageOperation extends AbstractOperation<typeof BuildImageOperationInputSchema, Array<unknown>> {
16
- private observer?;
17
- constructor(observer?: ((progress: string) => void) | undefined);
17
+ private out?;
18
+ constructor(out?: Writable | undefined);
18
19
  protected _run(input: z.input<typeof BuildImageOperationInputSchema>): Promise<Array<unknown>>;
19
20
  }
@@ -30,13 +30,14 @@ export const BuildImageOperationInputSchema = z.object({
30
30
  target: z.string().optional().describe('Target build stage'),
31
31
  });
32
32
  export class BuildImageOperation extends AbstractOperation {
33
- observer;
34
- constructor(observer) {
33
+ out;
34
+ constructor(out) {
35
35
  super(BuildImageOperationInputSchema);
36
- this.observer = observer;
36
+ this.out = out;
37
37
  }
38
38
  async _run(input) {
39
39
  const logStream = await this.context.monorepo.store.createWriteStream(`logs/docker/build/${input.tag}.log`);
40
+ this.out?.write('Sending build context to Docker\n');
40
41
  const stream = await this.context.docker.buildImage({
41
42
  context: input.context,
42
43
  src: [...input.src],
@@ -48,6 +49,7 @@ export class BuildImageOperation extends AbstractOperation {
48
49
  target: input.target,
49
50
  version: '2',
50
51
  });
52
+ this.out?.write('Starting build\n');
51
53
  return new Promise((resolve, reject) => {
52
54
  this.context.docker.modem.followProgress(stream, (err, traces) => {
53
55
  logStream.close();
@@ -62,7 +64,7 @@ export class BuildImageOperation extends AbstractOperation {
62
64
  const { vertexes } = await decodeBuildkitStatusResponse(trace.aux);
63
65
  vertexes.forEach((v) => {
64
66
  // logStream.write(JSON.stringify(v) + '\n');
65
- this.observer?.(v.name);
67
+ this.out?.write(v.name + '\n');
66
68
  });
67
69
  }
68
70
  catch (error) {
@@ -1,4 +1,5 @@
1
- import { readdir, stat, statfs } from 'node:fs/promises';
1
+ import { fdir as Fdir } from 'fdir';
2
+ import { stat, statfs } from 'node:fs/promises';
2
3
  import { join } from 'node:path';
3
4
  import pMap from 'p-map';
4
5
  import { GitPrerequisitePlugin } from '../../prerequisites/index.js';
@@ -24,7 +25,7 @@ class DockerImageResourceBuilder {
24
25
  get component() {
25
26
  return this.buildContext.component;
26
27
  }
27
- async build() {
28
+ async build(out) {
28
29
  // Ensure the folder exists
29
30
  await statfs(this.context);
30
31
  const imageName = [
@@ -32,7 +33,11 @@ class DockerImageResourceBuilder {
32
33
  this.config.tag || this.component.name,
33
34
  ].join('/');
34
35
  const tagName = this.config.tag || this.monorepo.defaults.docker?.tag || 'latest';
35
- const sources = await readdir(this.context, { recursive: true });
36
+ const crawler = new Fdir();
37
+ const sources = await crawler
38
+ .withRelativePaths()
39
+ .crawl(this.context)
40
+ .withPromise();
36
41
  const buildParams = {
37
42
  context: this.context,
38
43
  dockerfile: this.config.dockerfile || 'Dockerfile',
@@ -52,7 +57,7 @@ class DockerImageResourceBuilder {
52
57
  };
53
58
  return {
54
59
  input: buildParams,
55
- operation: new BuildImageOperation(),
60
+ operation: new BuildImageOperation(out),
56
61
  };
57
62
  }
58
63
  async mustBuild(sentinel) {
@@ -1,3 +1,4 @@
1
+ import { PRESET_TIMER, } from 'listr2';
1
2
  import * as z from 'zod';
2
3
  import { EMBCollection, findRunOrder, taskManagerFactory, } from '../../index.js';
3
4
  import { ResourceFactory, } from '../../resources/ResourceFactory.js';
@@ -63,6 +64,9 @@ export class BuildResourcesOperation extends AbstractOperation {
63
64
  rendererOptions: {
64
65
  collapseSkips: true,
65
66
  collapseSubtasks: true,
67
+ timer: {
68
+ ...PRESET_TIMER,
69
+ },
66
70
  },
67
71
  ctx: {},
68
72
  });
@@ -106,7 +110,7 @@ export class BuildResourcesOperation extends AbstractOperation {
106
110
  if (ctx.cacheHit && !ctx.force && !ctx.dryRun) {
107
111
  return skip('[cache hit]');
108
112
  }
109
- const { input, operation } = await ctx.builder.build();
113
+ const { input, operation } = await ctx.builder.build(task.stdout());
110
114
  ctx.builderInput = input;
111
115
  if (ctx.dryRun) {
112
116
  return skip('[dry run]');
@@ -1,4 +1,5 @@
1
1
  import { Component, Monorepo, ResourceInfo } from '../../index.js';
2
+ import { Writable } from 'node:stream';
2
3
  import { IOperation } from '../../operations/types.js';
3
4
  export type ResourceBuildContext = {
4
5
  config: ResourceInfo;
@@ -10,7 +11,15 @@ export type SentinelData<T = void> = {
10
11
  data: T;
11
12
  };
12
13
  export type ResourceBuilderInfo<I, O, D = unknown> = {
13
- build(): Promise<{
14
+ /**
15
+ * Returns input and operation required to actually
16
+ * build the resources.
17
+ * This allows the dry-run mechanism to be implemented outside
18
+ * resource builder implementations
19
+ *
20
+ * @param out The Writable to use to write logs
21
+ */
22
+ build(out?: Writable): Promise<{
14
23
  input: I;
15
24
  operation: IOperation<I, O>;
16
25
  }>;
@@ -268,10 +268,12 @@
268
268
  "shell.js"
269
269
  ]
270
270
  },
271
- "config:print": {
272
- "aliases": [],
271
+ "containers": {
272
+ "aliases": [
273
+ "ps"
274
+ ],
273
275
  "args": {},
274
- "description": "Print the current config.",
276
+ "description": "List docker containers.",
275
277
  "examples": [
276
278
  "<%= config.bin %> <%= command.id %>"
277
279
  ],
@@ -283,21 +285,22 @@
283
285
  "allowNo": false,
284
286
  "type": "boolean"
285
287
  },
286
- "flavor": {
287
- "description": "Specify the flavor to use.",
288
- "name": "flavor",
288
+ "all": {
289
+ "char": "a",
290
+ "description": "Retun all containers. By default, only running containers are shown",
291
+ "name": "all",
289
292
  "required": false,
290
- "hasDynamicHelp": false,
291
- "multiple": false,
292
- "type": "option"
293
+ "allowNo": false,
294
+ "type": "boolean"
293
295
  }
294
296
  },
295
297
  "hasDynamicHelp": false,
296
298
  "hiddenAliases": [],
297
- "id": "config:print",
299
+ "id": "containers",
298
300
  "pluginAlias": "@enspirit/emb",
299
301
  "pluginName": "@enspirit/emb",
300
302
  "pluginType": "core",
303
+ "strict": true,
301
304
  "enableJsonFlag": true,
302
305
  "isESM": true,
303
306
  "relativePath": [
@@ -305,16 +308,14 @@
305
308
  "src",
306
309
  "cli",
307
310
  "commands",
308
- "config",
309
- "print.js"
311
+ "containers",
312
+ "index.js"
310
313
  ]
311
314
  },
312
- "containers": {
313
- "aliases": [
314
- "ps"
315
- ],
315
+ "containers:prune": {
316
+ "aliases": [],
316
317
  "args": {},
317
- "description": "List docker containers.",
318
+ "description": "Prune containers.",
318
319
  "examples": [
319
320
  "<%= config.bin %> <%= command.id %>"
320
321
  ],
@@ -325,19 +326,11 @@
325
326
  "name": "json",
326
327
  "allowNo": false,
327
328
  "type": "boolean"
328
- },
329
- "all": {
330
- "char": "a",
331
- "description": "Retun all containers. By default, only running containers are shown",
332
- "name": "all",
333
- "required": false,
334
- "allowNo": false,
335
- "type": "boolean"
336
329
  }
337
330
  },
338
331
  "hasDynamicHelp": false,
339
332
  "hiddenAliases": [],
340
- "id": "containers",
333
+ "id": "containers:prune",
341
334
  "pluginAlias": "@enspirit/emb",
342
335
  "pluginName": "@enspirit/emb",
343
336
  "pluginType": "core",
@@ -350,13 +343,13 @@
350
343
  "cli",
351
344
  "commands",
352
345
  "containers",
353
- "index.js"
346
+ "prune.js"
354
347
  ]
355
348
  },
356
- "containers:prune": {
349
+ "config:print": {
357
350
  "aliases": [],
358
351
  "args": {},
359
- "description": "Prune containers.",
352
+ "description": "Print the current config.",
360
353
  "examples": [
361
354
  "<%= config.bin %> <%= command.id %>"
362
355
  ],
@@ -367,15 +360,22 @@
367
360
  "name": "json",
368
361
  "allowNo": false,
369
362
  "type": "boolean"
363
+ },
364
+ "flavor": {
365
+ "description": "Specify the flavor to use.",
366
+ "name": "flavor",
367
+ "required": false,
368
+ "hasDynamicHelp": false,
369
+ "multiple": false,
370
+ "type": "option"
370
371
  }
371
372
  },
372
373
  "hasDynamicHelp": false,
373
374
  "hiddenAliases": [],
374
- "id": "containers:prune",
375
+ "id": "config:print",
375
376
  "pluginAlias": "@enspirit/emb",
376
377
  "pluginName": "@enspirit/emb",
377
378
  "pluginType": "core",
378
- "strict": true,
379
379
  "enableJsonFlag": true,
380
380
  "isESM": true,
381
381
  "relativePath": [
@@ -383,8 +383,8 @@
383
383
  "src",
384
384
  "cli",
385
385
  "commands",
386
- "containers",
387
- "prune.js"
386
+ "config",
387
+ "print.js"
388
388
  ]
389
389
  },
390
390
  "images:delete": {
@@ -718,5 +718,5 @@
718
718
  ]
719
719
  }
720
720
  },
721
- "version": "0.3.0"
721
+ "version": "0.3.1"
722
722
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@enspirit/emb",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.3.1",
5
5
  "keywords": ["monorepo", "docker", "taskrunner", "ci", "docker compose", "sentinel", "makefile"],
6
6
  "author": "Louis Lambeau <louis.lambeau@enspirit.be>",
7
7
  "license": "ISC",
@@ -47,6 +47,7 @@
47
47
  "dotenv": "^17.2.1",
48
48
  "execa": "^9.6.0",
49
49
  "fast-json-patch": "^3.1.1",
50
+ "fdir": "^6.4.6",
50
51
  "find-up": "^7.0.0",
51
52
  "glob": "^11.0.3",
52
53
  "graphlib": "^2.1.8",