@enspirit/emb 0.1.0 → 0.1.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.1.0 darwin-x64 node-v22.12.0
17
+ @enspirit/emb/0.1.1 darwin-x64 node-v22.12.0
18
18
  $ emb --help [COMMAND]
19
19
  USAGE
20
20
  $ emb COMMAND
@@ -83,6 +83,10 @@ export interface DefaultsConfig {
83
83
  };
84
84
  }
85
85
  export interface ComponentConfig {
86
+ /**
87
+ * Path to the component's root folder (relative to root of monorepo)
88
+ */
89
+ rootDir?: string;
86
90
  /**
87
91
  * A description of the component.
88
92
  */
@@ -144,6 +144,10 @@
144
144
  "type": "object",
145
145
  "required": [],
146
146
  "properties": {
147
+ "rootDir": {
148
+ "type": "string",
149
+ "description": "Path to the component's root folder (relative to root of monorepo)"
150
+ },
147
151
  "description": {
148
152
  "type": "string",
149
153
  "minLength": 1,
@@ -43,6 +43,9 @@ export const validateEmbfile = async (pathOrObject) => {
43
43
  if (!validate) {
44
44
  throw new Error('Could not find the JSON schema validator for Embfile');
45
45
  }
46
+ if (!component) {
47
+ return {};
48
+ }
46
49
  if (!validate(component)) {
47
50
  ajv.errors?.forEach((err) => console.error(err));
48
51
  throw new Error(`Your .emb.yml is incorrect`);
@@ -1,14 +1,20 @@
1
- import { stat } from 'node:fs/promises';
1
+ import { stat, statfs } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import pMap from 'p-map';
2
4
  import { GitPrerequisitePlugin } from '../../prerequisites/index.js';
3
5
  import { ResourceFactory, } from '../../monorepo/resources/ResourceFactory.js';
4
6
  import { BuildImageOperation } from '../operations/index.js';
5
7
  const DockerImageOpFactory = async ({ config, component, monorepo }) => {
6
8
  const fromConfig = (config.params || {});
7
- const plugin = new GitPrerequisitePlugin();
8
- const sources = await plugin.collect(component);
9
9
  const context = fromConfig.context
10
- ? component.join(fromConfig.context)
11
- : component.rootDir;
10
+ ? fromConfig.context[0] === '/'
11
+ ? monorepo.join(fromConfig.context)
12
+ : component.join(fromConfig.context)
13
+ : monorepo.join(component.rootDir);
14
+ // Ensure the folder exists
15
+ await statfs(context);
16
+ const plugin = new GitPrerequisitePlugin();
17
+ const sources = await plugin.collect(context);
12
18
  const buildParams = {
13
19
  context,
14
20
  dockerfile: fromConfig.dockerfile || 'Dockerfile',
@@ -24,13 +30,13 @@ const DockerImageOpFactory = async ({ config, component, monorepo }) => {
24
30
  target: fromConfig.target,
25
31
  };
26
32
  const lastUpdatedInfo = async (sources) => {
27
- const stats = await Promise.all(sources.map(async (s) => {
28
- const stats = await stat(component.join(s.path));
33
+ const stats = await pMap(sources, async (s) => {
34
+ const stats = await stat(join(context, s.path));
29
35
  return {
30
36
  time: stats.mtime,
31
37
  path: s.path,
32
38
  };
33
- }));
39
+ }, { concurrency: 30 });
34
40
  if (stats.length === 0) {
35
41
  return 0;
36
42
  }
@@ -1,19 +1,17 @@
1
1
  import { ComponentConfig, ComponentFlavorConfig } from '../config/schema.js';
2
2
  import { ComponentFlavors, Monorepo, Resources, Tasks } from './index.js';
3
- import { FilePrerequisite } from '../prerequisites/index.js';
4
3
  export declare class Component implements ComponentConfig {
5
4
  readonly name: string;
6
5
  readonly config: ComponentConfig;
7
6
  protected monorepo: Monorepo;
7
+ readonly rootDir: string;
8
8
  readonly tasks: Tasks;
9
9
  readonly resources: Resources;
10
10
  readonly flavors: ComponentFlavors;
11
11
  constructor(name: string, config: ComponentConfig, monorepo: Monorepo);
12
- get rootDir(): string;
13
12
  flavor(name: string, mustExist?: boolean): ComponentFlavorConfig;
14
13
  cloneWith(config: Partial<ComponentConfig>): ComponentConfig;
15
14
  toJSON(): ComponentConfig;
16
15
  withFlavor(name: string): Component;
17
- getPrerequisites(): Promise<Array<FilePrerequisite>>;
18
16
  join(path: string): string;
19
17
  }
@@ -1,11 +1,11 @@
1
1
  import jsonpatch from 'fast-json-patch';
2
2
  import { join } from 'node:path';
3
3
  import { toIdentifedHash, } from './index.js';
4
- import { GitPrerequisitePlugin } from '../prerequisites/index.js';
5
4
  export class Component {
6
5
  name;
7
6
  config;
8
7
  monorepo;
8
+ rootDir;
9
9
  tasks;
10
10
  resources;
11
11
  flavors;
@@ -13,15 +13,13 @@ export class Component {
13
13
  this.name = name;
14
14
  this.config = config;
15
15
  this.monorepo = monorepo;
16
+ this.rootDir = config.rootDir || name;
16
17
  this.tasks = toIdentifedHash(config.tasks || {}, this.name);
17
18
  this.resources = toIdentifedHash(
18
19
  // Due to the schema.json -> typescript conversion weirdness
19
20
  config.resources || {}, this.name);
20
21
  this.flavors = toIdentifedHash(config.flavors || {}, this.name);
21
22
  }
22
- get rootDir() {
23
- return this.monorepo.join(this.name);
24
- }
25
23
  flavor(name, mustExist = true) {
26
24
  const flavor = this.flavors[name];
27
25
  if (!flavor && mustExist) {
@@ -50,12 +48,7 @@ export class Component {
50
48
  }, original);
51
49
  return new Component(this.name, patched, this.monorepo);
52
50
  }
53
- async getPrerequisites() {
54
- // TODO: move this to config with potential overridzs
55
- const plugin = new GitPrerequisitePlugin();
56
- return plugin.collect(this);
57
- }
58
51
  join(path) {
59
- return join(this.rootDir, path);
52
+ return this.monorepo.join(join(this.rootDir, path));
60
53
  }
61
54
  }
@@ -12,7 +12,6 @@ export class Monorepo {
12
12
  initialized = false;
13
13
  constructor(config, defaultFlavor = 'default') {
14
14
  this.defaultFlavor = defaultFlavor;
15
- console.log('WEIRD BECAUSE, adnsod', defaultFlavor);
16
15
  this._config = new MonorepoConfig(config);
17
16
  }
18
17
  get config() {
@@ -32,7 +32,10 @@ export class EmbfileLoaderPlugin extends AbstractPlugin {
32
32
  const embfile = await join(config.project.rootDir, path);
33
33
  const component = await validateEmbfile(embfile);
34
34
  const original = config.components[name];
35
- const newComponent = deepmerge()(original || {}, component);
35
+ const newComponent = deepmerge()(original || {}, {
36
+ ...component,
37
+ rootDir,
38
+ });
36
39
  return config.with({
37
40
  components: {
38
41
  [name]: newComponent,
@@ -1,5 +1,4 @@
1
- import { Component } from '../monorepo/index.js';
2
1
  import { FilePrerequisite, PrerequisitePlugin, PrerequisiteType } from './types.js';
3
2
  export declare class GitPrerequisitePlugin implements PrerequisitePlugin<PrerequisiteType.file, FilePrerequisite> {
4
- collect(component: Component): Promise<Array<FilePrerequisite>>;
3
+ collect(path: string): Promise<Array<FilePrerequisite>>;
5
4
  }
@@ -1,9 +1,9 @@
1
1
  import { simpleGit } from 'simple-git';
2
2
  import { PrerequisiteType, } from './types.js';
3
3
  export class GitPrerequisitePlugin {
4
- async collect(component) {
5
- const repo = simpleGit(component.rootDir);
6
- return (await repo.raw('ls-files', component.rootDir))
4
+ async collect(path) {
5
+ const repo = simpleGit(path);
6
+ return (await repo.raw('ls-files', path))
7
7
  .split('\n')
8
8
  .map((s) => s.trim())
9
9
  .filter(Boolean)
@@ -18,9 +18,9 @@ export interface FilePrerequisite extends Prerequisite<PrerequisiteType.file> {
18
18
  }
19
19
  export interface PrerequisitePlugin<T extends PrerequisiteType, P extends Prerequisite<T>, Output = unknown, Changes = unknown> {
20
20
  /**
21
- * Collect/discover prerequisistes for a specific component
21
+ * Collect/discover prerequisistes for a path (relative to the monorepo root)
22
22
  */
23
- collect?(component: Component): Promise<Array<P>>;
23
+ collect?(path: string): Promise<Array<P>>;
24
24
  /**
25
25
  * Returns the list of changes between the last collection and the new
26
26
  * collection.
@@ -168,10 +168,12 @@
168
168
  "index.js"
169
169
  ]
170
170
  },
171
- "config:print": {
172
- "aliases": [],
171
+ "containers": {
172
+ "aliases": [
173
+ "ps"
174
+ ],
173
175
  "args": {},
174
- "description": "Print the current config.",
176
+ "description": "List docker containers.",
175
177
  "examples": [
176
178
  "<%= config.bin %> <%= command.id %>"
177
179
  ],
@@ -183,21 +185,22 @@
183
185
  "allowNo": false,
184
186
  "type": "boolean"
185
187
  },
186
- "flavor": {
187
- "description": "Specify the flavor to use.",
188
- "name": "flavor",
188
+ "all": {
189
+ "char": "a",
190
+ "description": "Retun all containers. By default, only running containers are shown",
191
+ "name": "all",
189
192
  "required": false,
190
- "hasDynamicHelp": false,
191
- "multiple": false,
192
- "type": "option"
193
+ "allowNo": false,
194
+ "type": "boolean"
193
195
  }
194
196
  },
195
197
  "hasDynamicHelp": false,
196
198
  "hiddenAliases": [],
197
- "id": "config:print",
199
+ "id": "containers",
198
200
  "pluginAlias": "@enspirit/emb",
199
201
  "pluginName": "@enspirit/emb",
200
202
  "pluginType": "core",
203
+ "strict": true,
201
204
  "enableJsonFlag": true,
202
205
  "isESM": true,
203
206
  "relativePath": [
@@ -205,16 +208,14 @@
205
208
  "src",
206
209
  "cli",
207
210
  "commands",
208
- "config",
209
- "print.js"
211
+ "containers",
212
+ "index.js"
210
213
  ]
211
214
  },
212
- "containers": {
213
- "aliases": [
214
- "ps"
215
- ],
215
+ "containers:prune": {
216
+ "aliases": [],
216
217
  "args": {},
217
- "description": "List docker containers.",
218
+ "description": "Prune containers.",
218
219
  "examples": [
219
220
  "<%= config.bin %> <%= command.id %>"
220
221
  ],
@@ -225,19 +226,11 @@
225
226
  "name": "json",
226
227
  "allowNo": false,
227
228
  "type": "boolean"
228
- },
229
- "all": {
230
- "char": "a",
231
- "description": "Retun all containers. By default, only running containers are shown",
232
- "name": "all",
233
- "required": false,
234
- "allowNo": false,
235
- "type": "boolean"
236
229
  }
237
230
  },
238
231
  "hasDynamicHelp": false,
239
232
  "hiddenAliases": [],
240
- "id": "containers",
233
+ "id": "containers:prune",
241
234
  "pluginAlias": "@enspirit/emb",
242
235
  "pluginName": "@enspirit/emb",
243
236
  "pluginType": "core",
@@ -250,13 +243,13 @@
250
243
  "cli",
251
244
  "commands",
252
245
  "containers",
253
- "index.js"
246
+ "prune.js"
254
247
  ]
255
248
  },
256
- "containers:prune": {
249
+ "config:print": {
257
250
  "aliases": [],
258
251
  "args": {},
259
- "description": "Prune containers.",
252
+ "description": "Print the current config.",
260
253
  "examples": [
261
254
  "<%= config.bin %> <%= command.id %>"
262
255
  ],
@@ -267,15 +260,22 @@
267
260
  "name": "json",
268
261
  "allowNo": false,
269
262
  "type": "boolean"
263
+ },
264
+ "flavor": {
265
+ "description": "Specify the flavor to use.",
266
+ "name": "flavor",
267
+ "required": false,
268
+ "hasDynamicHelp": false,
269
+ "multiple": false,
270
+ "type": "option"
270
271
  }
271
272
  },
272
273
  "hasDynamicHelp": false,
273
274
  "hiddenAliases": [],
274
- "id": "containers:prune",
275
+ "id": "config:print",
275
276
  "pluginAlias": "@enspirit/emb",
276
277
  "pluginName": "@enspirit/emb",
277
278
  "pluginType": "core",
278
- "strict": true,
279
279
  "enableJsonFlag": true,
280
280
  "isESM": true,
281
281
  "relativePath": [
@@ -283,8 +283,8 @@
283
283
  "src",
284
284
  "cli",
285
285
  "commands",
286
- "containers",
287
- "prune.js"
286
+ "config",
287
+ "print.js"
288
288
  ]
289
289
  },
290
290
  "images:delete": {
@@ -413,12 +413,18 @@
413
413
  "prune.js"
414
414
  ]
415
415
  },
416
- "tasks": {
416
+ "resources:build": {
417
417
  "aliases": [],
418
- "args": {},
419
- "description": "List tasks.",
418
+ "args": {
419
+ "component": {
420
+ "description": "List of resources to build (defaults to all)",
421
+ "name": "component",
422
+ "required": false
423
+ }
424
+ },
425
+ "description": "Build the resources of the monorepo",
420
426
  "examples": [
421
- "<%= config.bin %> <%= command.id %>"
427
+ "<%= config.bin %> <%= command.id %> build --flavor development"
422
428
  ],
423
429
  "flags": {
424
430
  "json": {
@@ -427,15 +433,38 @@
427
433
  "name": "json",
428
434
  "allowNo": false,
429
435
  "type": "boolean"
436
+ },
437
+ "flavor": {
438
+ "description": "Specify the flavor to use.",
439
+ "name": "flavor",
440
+ "required": false,
441
+ "hasDynamicHelp": false,
442
+ "multiple": false,
443
+ "type": "option"
444
+ },
445
+ "dry-run": {
446
+ "description": "Do not build the resources but only produce build meta information",
447
+ "name": "dry-run",
448
+ "required": false,
449
+ "allowNo": false,
450
+ "type": "boolean"
451
+ },
452
+ "force": {
453
+ "char": "f",
454
+ "description": "Bypass the cache and force the build",
455
+ "name": "force",
456
+ "required": false,
457
+ "allowNo": false,
458
+ "type": "boolean"
430
459
  }
431
460
  },
432
461
  "hasDynamicHelp": false,
433
462
  "hiddenAliases": [],
434
- "id": "tasks",
463
+ "id": "resources:build",
435
464
  "pluginAlias": "@enspirit/emb",
436
465
  "pluginName": "@enspirit/emb",
437
466
  "pluginType": "core",
438
- "strict": true,
467
+ "strict": false,
439
468
  "enableJsonFlag": true,
440
469
  "isESM": true,
441
470
  "relativePath": [
@@ -443,20 +472,14 @@
443
472
  "src",
444
473
  "cli",
445
474
  "commands",
446
- "tasks",
447
- "index.js"
475
+ "resources",
476
+ "build.js"
448
477
  ]
449
478
  },
450
- "tasks:run": {
479
+ "resources": {
451
480
  "aliases": [],
452
- "args": {
453
- "task": {
454
- "description": "List of tasks to run. You can provide either ids or names (eg: component:task or task)",
455
- "name": "task",
456
- "required": true
457
- }
458
- },
459
- "description": "Run tasks.",
481
+ "args": {},
482
+ "description": "List resources.",
460
483
  "examples": [
461
484
  "<%= config.bin %> <%= command.id %>"
462
485
  ],
@@ -468,33 +491,21 @@
468
491
  "allowNo": false,
469
492
  "type": "boolean"
470
493
  },
471
- "executor": {
472
- "char": "x",
473
- "description": "Where to run the task. (experimental!)",
474
- "name": "executor",
494
+ "flavor": {
495
+ "description": "Specify the flavor to use.",
496
+ "name": "flavor",
497
+ "required": false,
475
498
  "hasDynamicHelp": false,
476
499
  "multiple": false,
477
- "options": [
478
- "container",
479
- "local"
480
- ],
481
500
  "type": "option"
482
- },
483
- "all-matching": {
484
- "char": "a",
485
- "description": "Run all tasks matching (when multiple matches)",
486
- "name": "all-matching",
487
- "allowNo": false,
488
- "type": "boolean"
489
501
  }
490
502
  },
491
503
  "hasDynamicHelp": false,
492
504
  "hiddenAliases": [],
493
- "id": "tasks:run",
505
+ "id": "resources",
494
506
  "pluginAlias": "@enspirit/emb",
495
507
  "pluginName": "@enspirit/emb",
496
508
  "pluginType": "core",
497
- "strict": false,
498
509
  "enableJsonFlag": true,
499
510
  "isESM": true,
500
511
  "relativePath": [
@@ -502,22 +513,16 @@
502
513
  "src",
503
514
  "cli",
504
515
  "commands",
505
- "tasks",
506
- "run.js"
516
+ "resources",
517
+ "index.js"
507
518
  ]
508
519
  },
509
- "resources:build": {
520
+ "tasks": {
510
521
  "aliases": [],
511
- "args": {
512
- "component": {
513
- "description": "List of resources to build (defaults to all)",
514
- "name": "component",
515
- "required": false
516
- }
517
- },
518
- "description": "Build the resources of the monorepo",
522
+ "args": {},
523
+ "description": "List tasks.",
519
524
  "examples": [
520
- "<%= config.bin %> <%= command.id %> build --flavor development"
525
+ "<%= config.bin %> <%= command.id %>"
521
526
  ],
522
527
  "flags": {
523
528
  "json": {
@@ -526,38 +531,15 @@
526
531
  "name": "json",
527
532
  "allowNo": false,
528
533
  "type": "boolean"
529
- },
530
- "flavor": {
531
- "description": "Specify the flavor to use.",
532
- "name": "flavor",
533
- "required": false,
534
- "hasDynamicHelp": false,
535
- "multiple": false,
536
- "type": "option"
537
- },
538
- "dry-run": {
539
- "description": "Do not build the resources but only produce build meta information",
540
- "name": "dry-run",
541
- "required": false,
542
- "allowNo": false,
543
- "type": "boolean"
544
- },
545
- "force": {
546
- "char": "f",
547
- "description": "Bypass the cache and force the build",
548
- "name": "force",
549
- "required": false,
550
- "allowNo": false,
551
- "type": "boolean"
552
534
  }
553
535
  },
554
536
  "hasDynamicHelp": false,
555
537
  "hiddenAliases": [],
556
- "id": "resources:build",
538
+ "id": "tasks",
557
539
  "pluginAlias": "@enspirit/emb",
558
540
  "pluginName": "@enspirit/emb",
559
541
  "pluginType": "core",
560
- "strict": false,
542
+ "strict": true,
561
543
  "enableJsonFlag": true,
562
544
  "isESM": true,
563
545
  "relativePath": [
@@ -565,14 +547,20 @@
565
547
  "src",
566
548
  "cli",
567
549
  "commands",
568
- "resources",
569
- "build.js"
550
+ "tasks",
551
+ "index.js"
570
552
  ]
571
553
  },
572
- "resources": {
554
+ "tasks:run": {
573
555
  "aliases": [],
574
- "args": {},
575
- "description": "List resources.",
556
+ "args": {
557
+ "task": {
558
+ "description": "List of tasks to run. You can provide either ids or names (eg: component:task or task)",
559
+ "name": "task",
560
+ "required": true
561
+ }
562
+ },
563
+ "description": "Run tasks.",
576
564
  "examples": [
577
565
  "<%= config.bin %> <%= command.id %>"
578
566
  ],
@@ -584,21 +572,33 @@
584
572
  "allowNo": false,
585
573
  "type": "boolean"
586
574
  },
587
- "flavor": {
588
- "description": "Specify the flavor to use.",
589
- "name": "flavor",
590
- "required": false,
575
+ "executor": {
576
+ "char": "x",
577
+ "description": "Where to run the task. (experimental!)",
578
+ "name": "executor",
591
579
  "hasDynamicHelp": false,
592
580
  "multiple": false,
581
+ "options": [
582
+ "container",
583
+ "local"
584
+ ],
593
585
  "type": "option"
586
+ },
587
+ "all-matching": {
588
+ "char": "a",
589
+ "description": "Run all tasks matching (when multiple matches)",
590
+ "name": "all-matching",
591
+ "allowNo": false,
592
+ "type": "boolean"
594
593
  }
595
594
  },
596
595
  "hasDynamicHelp": false,
597
596
  "hiddenAliases": [],
598
- "id": "resources",
597
+ "id": "tasks:run",
599
598
  "pluginAlias": "@enspirit/emb",
600
599
  "pluginName": "@enspirit/emb",
601
600
  "pluginType": "core",
601
+ "strict": false,
602
602
  "enableJsonFlag": true,
603
603
  "isESM": true,
604
604
  "relativePath": [
@@ -606,10 +606,10 @@
606
606
  "src",
607
607
  "cli",
608
608
  "commands",
609
- "resources",
610
- "index.js"
609
+ "tasks",
610
+ "run.js"
611
611
  ]
612
612
  }
613
613
  },
614
- "version": "0.1.0"
614
+ "version": "0.1.1"
615
615
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@enspirit/emb",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.1.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",