feat(build): add support for selective builds, platform override and build timeout
This commit is contained in:
@@ -4,7 +4,7 @@ import { logger } from './tsdocker.logging.js';
|
||||
import { Dockerfile } from './classes.dockerfile.js';
|
||||
import { DockerRegistry } from './classes.dockerregistry.js';
|
||||
import { RegistryStorage } from './classes.registrystorage.js';
|
||||
import type { ITsDockerConfig } from './interfaces/index.js';
|
||||
import type { ITsDockerConfig, IBuildCommandOptions } from './interfaces/index.js';
|
||||
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash',
|
||||
@@ -90,9 +90,10 @@ export class TsDockerManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all discovered Dockerfiles in dependency order
|
||||
* Builds discovered Dockerfiles in dependency order.
|
||||
* When options.patterns is provided, only matching Dockerfiles (and their dependencies) are built.
|
||||
*/
|
||||
public async build(): Promise<Dockerfile[]> {
|
||||
public async build(options?: IBuildCommandOptions): Promise<Dockerfile[]> {
|
||||
if (this.dockerfiles.length === 0) {
|
||||
await this.discoverDockerfiles();
|
||||
}
|
||||
@@ -102,16 +103,63 @@ export class TsDockerManager {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Determine which Dockerfiles to build
|
||||
let toBuild = this.dockerfiles;
|
||||
|
||||
if (options?.patterns && options.patterns.length > 0) {
|
||||
// Filter to matching Dockerfiles
|
||||
const matched = this.dockerfiles.filter((df) => {
|
||||
const basename = plugins.path.basename(df.filePath);
|
||||
return options.patterns!.some((pattern) => {
|
||||
if (pattern.includes('*') || pattern.includes('?')) {
|
||||
// Convert glob pattern to regex
|
||||
const regexStr = '^' + pattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$';
|
||||
return new RegExp(regexStr).test(basename);
|
||||
}
|
||||
return basename === pattern;
|
||||
});
|
||||
});
|
||||
|
||||
if (matched.length === 0) {
|
||||
logger.log('warn', `No Dockerfiles matched patterns: ${options.patterns.join(', ')}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Resolve dependency chain and preserve topological order
|
||||
toBuild = this.resolveWithDependencies(matched, this.dockerfiles);
|
||||
logger.log('info', `Matched ${matched.length} Dockerfile(s), building ${toBuild.length} (including dependencies)`);
|
||||
}
|
||||
|
||||
// Check if buildx is needed
|
||||
if (this.config.platforms && this.config.platforms.length > 1) {
|
||||
if (options?.platform || (this.config.platforms && this.config.platforms.length > 1)) {
|
||||
await this.ensureBuildx();
|
||||
}
|
||||
|
||||
logger.log('info', `Building ${this.dockerfiles.length} Dockerfiles...`);
|
||||
await Dockerfile.buildDockerfiles(this.dockerfiles);
|
||||
logger.log('info', `Building ${toBuild.length} Dockerfiles...`);
|
||||
await Dockerfile.buildDockerfiles(toBuild, {
|
||||
platform: options?.platform,
|
||||
timeout: options?.timeout,
|
||||
});
|
||||
logger.log('success', 'All Dockerfiles built successfully');
|
||||
|
||||
return this.dockerfiles;
|
||||
return toBuild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a set of target Dockerfiles to include all their local base image dependencies,
|
||||
* preserving the original topological build order.
|
||||
*/
|
||||
private resolveWithDependencies(targets: Dockerfile[], allSorted: Dockerfile[]): Dockerfile[] {
|
||||
const needed = new Set<Dockerfile>();
|
||||
const addWithDeps = (df: Dockerfile) => {
|
||||
if (needed.has(df)) return;
|
||||
needed.add(df);
|
||||
if (df.localBaseImageDependent && df.localBaseDockerfile) {
|
||||
addWithDeps(df.localBaseDockerfile);
|
||||
}
|
||||
};
|
||||
for (const df of targets) addWithDeps(df);
|
||||
return allSorted.filter((df) => needed.has(df));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user