UNPKG

@enspirit/emb

Version:

A replacement for our Makefile-for-monorepos

68 lines (67 loc) 2.27 kB
import { execa } from 'execa'; export const DefaultGetContainerOptions = { mustBeRunning: true, mustBeUnique: true, }; export class DockerComposeClient { monorepo; services; constructor(monorepo) { this.monorepo = monorepo; } async init() { await this.loadContainers(); } async isService(component) { await this.init(); return this.services?.has(component); } async getContainer(serviceName, options = DefaultGetContainerOptions) { const getOptions = { ...DefaultGetContainerOptions, ...options }; await this.loadContainers(); const service = this.services?.get(serviceName); if (!service) { throw new Error(`No compose service found with name ${serviceName}`); } const containers = getOptions.mustBeRunning ? service.containers.filter((c) => c.State === 'running') : service.containers; if (containers.length === 0) { throw new Error(`No container found for service ${serviceName}`); } if (containers.length > 1 && getOptions.mustBeUnique) { throw new Error(`Multiple containers found`); } return containers[0].ID; } async loadContainers(force = false) { if (this.services && !force) { return; } const { stdout: servicesOutput } = await execa({ cwd: this.monorepo.rootDir, }) `docker compose config --services`; const services = servicesOutput .split('\n') .map((l) => l.trim()) .reduce((services, name) => { services.set(name, { name, containers: [] }); return services; }, new Map()); const { stdout } = await execa({ cwd: this.monorepo.rootDir, }) `docker compose ps -a --format json`; if (!stdout.trim()) { this.services = services; return; } this.services = stdout .split('\n') .map((l) => JSON.parse(l)) .reduce((services, entry) => { const svc = services.get(entry.Service); svc?.containers.push(entry); return services; }, services); } }