feat(core): Introduce per-invocation TsDockerSession and session-aware local registry and build orchestration; stream and parse buildx output for improved logging and visibility; detect Docker topology and add CI-safe cleanup; update README with multi-arch, parallel-build, caching, and local registry usage and new CLI flags.
This commit is contained in:
@@ -6,6 +6,7 @@ import { DockerRegistry } from './classes.dockerregistry.js';
|
||||
import { RegistryStorage } from './classes.registrystorage.js';
|
||||
import { TsDockerCache } from './classes.tsdockercache.js';
|
||||
import { DockerContext } from './classes.dockercontext.js';
|
||||
import { TsDockerSession } from './classes.tsdockersession.js';
|
||||
import type { ITsDockerConfig, IBuildCommandOptions } from './interfaces/index.js';
|
||||
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
@@ -20,6 +21,7 @@ export class TsDockerManager {
|
||||
public config: ITsDockerConfig;
|
||||
public projectInfo: any;
|
||||
public dockerContext: DockerContext;
|
||||
public session!: TsDockerSession;
|
||||
private dockerfiles: Dockerfile[] = [];
|
||||
|
||||
constructor(config: ITsDockerConfig) {
|
||||
@@ -77,6 +79,9 @@ export class TsDockerManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Create session identity (unique ports, names for CI concurrency)
|
||||
this.session = await TsDockerSession.create();
|
||||
|
||||
logger.log('info', `Prepared TsDockerManager with ${this.registryStorage.getAllRegistries().length} registries`);
|
||||
}
|
||||
|
||||
@@ -98,6 +103,10 @@ export class TsDockerManager {
|
||||
this.dockerfiles = await Dockerfile.readDockerfiles(this);
|
||||
this.dockerfiles = await Dockerfile.sortDockerfiles(this.dockerfiles);
|
||||
this.dockerfiles = await Dockerfile.mapDockerfiles(this.dockerfiles);
|
||||
// Inject session into each Dockerfile
|
||||
for (const df of this.dockerfiles) {
|
||||
df.session = this.session;
|
||||
}
|
||||
return this.dockerfiles;
|
||||
}
|
||||
|
||||
@@ -187,7 +196,7 @@ export class TsDockerManager {
|
||||
|
||||
const total = toBuild.length;
|
||||
const overallStart = Date.now();
|
||||
await Dockerfile.startLocalRegistry(this.dockerContext.contextInfo?.isRootless);
|
||||
await Dockerfile.startLocalRegistry(this.session, this.dockerContext.contextInfo?.isRootless);
|
||||
|
||||
try {
|
||||
if (options?.parallel) {
|
||||
@@ -240,7 +249,7 @@ export class TsDockerManager {
|
||||
}
|
||||
// Push ALL images to local registry (skip if already pushed via buildx)
|
||||
if (!df.localRegistryTag) {
|
||||
await Dockerfile.pushToLocalRegistry(df);
|
||||
await Dockerfile.pushToLocalRegistry(this.session, df);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,19 +289,19 @@ export class TsDockerManager {
|
||||
|
||||
// Push ALL images to local registry (skip if already pushed via buildx)
|
||||
if (!dockerfileArg.localRegistryTag) {
|
||||
await Dockerfile.pushToLocalRegistry(dockerfileArg);
|
||||
await Dockerfile.pushToLocalRegistry(this.session, dockerfileArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await Dockerfile.stopLocalRegistry();
|
||||
await Dockerfile.stopLocalRegistry(this.session);
|
||||
}
|
||||
|
||||
logger.log('info', `Total build time: ${formatDuration(Date.now() - overallStart)}`);
|
||||
cache.save();
|
||||
} else {
|
||||
// === STANDARD MODE: build all via static helper ===
|
||||
await Dockerfile.buildDockerfiles(toBuild, {
|
||||
await Dockerfile.buildDockerfiles(toBuild, this.session, {
|
||||
platform: options?.platform,
|
||||
timeout: options?.timeout,
|
||||
noCache: options?.noCache,
|
||||
@@ -329,7 +338,7 @@ export class TsDockerManager {
|
||||
* Ensures Docker buildx is set up for multi-architecture builds
|
||||
*/
|
||||
private async ensureBuildx(): Promise<void> {
|
||||
const builderName = this.dockerContext.getBuilderName();
|
||||
const builderName = this.dockerContext.getBuilderName() + (this.session?.config.builderSuffix || '');
|
||||
const platforms = this.config.platforms?.join(', ') || 'default';
|
||||
logger.log('info', `Setting up Docker buildx [${platforms}]...`);
|
||||
logger.log('info', `Builder: ${builderName}`);
|
||||
@@ -394,7 +403,7 @@ export class TsDockerManager {
|
||||
}
|
||||
|
||||
// Start local registry (reads from persistent .nogit/docker-registry/)
|
||||
await Dockerfile.startLocalRegistry(this.dockerContext.contextInfo?.isRootless);
|
||||
await Dockerfile.startLocalRegistry(this.session, this.dockerContext.contextInfo?.isRootless);
|
||||
try {
|
||||
// Push each Dockerfile to each registry via OCI copy
|
||||
for (const dockerfile of this.dockerfiles) {
|
||||
@@ -403,7 +412,7 @@ export class TsDockerManager {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await Dockerfile.stopLocalRegistry();
|
||||
await Dockerfile.stopLocalRegistry(this.session);
|
||||
}
|
||||
|
||||
logger.log('success', 'All images pushed successfully');
|
||||
@@ -446,11 +455,11 @@ export class TsDockerManager {
|
||||
logger.log('info', '');
|
||||
logger.log('info', '=== TEST PHASE ===');
|
||||
|
||||
await Dockerfile.startLocalRegistry(this.dockerContext.contextInfo?.isRootless);
|
||||
await Dockerfile.startLocalRegistry(this.session, this.dockerContext.contextInfo?.isRootless);
|
||||
try {
|
||||
await Dockerfile.testDockerfiles(this.dockerfiles);
|
||||
} finally {
|
||||
await Dockerfile.stopLocalRegistry();
|
||||
await Dockerfile.stopLocalRegistry(this.session);
|
||||
}
|
||||
|
||||
logger.log('success', 'All tests completed');
|
||||
@@ -490,4 +499,16 @@ export class TsDockerManager {
|
||||
public getDockerfiles(): Dockerfile[] {
|
||||
return this.dockerfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up session-specific resources.
|
||||
* In CI, removes the session-specific buildx builder to avoid accumulation.
|
||||
*/
|
||||
public async cleanup(): Promise<void> {
|
||||
if (this.session?.config.isCI && this.session.config.builderSuffix) {
|
||||
const builderName = this.dockerContext.getBuilderName() + this.session.config.builderSuffix;
|
||||
logger.log('info', `CI cleanup: removing buildx builder ${builderName}`);
|
||||
await smartshellInstance.execSilent(`docker buildx rm ${builderName} 2>/dev/null || true`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user