diff --git a/changelog.md b/changelog.md index 94a83a7..1d96b38 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2024-11-17 - 4.1.37 - fix(docker) +Enhanced base image extraction logic from Dockerfile + +- Improved dockerBaseImage to accurately extract base images considering ARG variables. +- Added support for parsing Dockerfile content without external libraries. +- Enhanced error handling for missing FROM instructions. + ## 2024-11-17 - 4.1.36 - fix(docker) Improve logging for Dockerfile build order with base image details. diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 6a4a73f..deaea7c 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@ship.zone/npmci', - version: '4.1.36', + version: '4.1.37', description: 'A tool to streamline Node.js and Docker workflows within CI environments, particularly GitLab CI, providing various CI/CD utilities.' } diff --git a/ts/manager.docker/mod.classes.dockerfile.ts b/ts/manager.docker/mod.classes.dockerfile.ts index e84f47d..e146294 100644 --- a/ts/manager.docker/mod.classes.dockerfile.ts +++ b/ts/manager.docker/mod.classes.dockerfile.ts @@ -102,8 +102,11 @@ export class Dockerfile { // Log the sorted order sortedDockerfiles.forEach((dockerfile, index) => { - logger.log('info', `Build order ${index + 1}: ${dockerfile.cleanTag} - with base image ${dockerfile.baseImage}`); + logger.log( + 'info', + `Build order ${index + 1}: ${dockerfile.cleanTag} + with base image ${dockerfile.baseImage}` + ); }); return sortedDockerfiles; @@ -171,12 +174,62 @@ export class Dockerfile { } /** - * returns the docker base image for a Dockerfile + * Extracts the base image from a Dockerfile content without using external libraries. + * @param dockerfileContentArg The content of the Dockerfile as a string. + * @returns The base image specified in the first FROM instruction. */ public static dockerBaseImage(dockerfileContentArg: string): string { - const baseImageRegex = /FROM\s([a-zA-z0-9\/\-\:]*)\n?/; - const regexResultArray = baseImageRegex.exec(dockerfileContentArg); - return regexResultArray[1]; + const lines = dockerfileContentArg.split(/\r?\n/); + const args: { [key: string]: string } = {}; + + for (const line of lines) { + const trimmedLine = line.trim(); + + // Skip empty lines and comments + if (trimmedLine === '' || trimmedLine.startsWith('#')) { + continue; + } + + // Match ARG instructions + const argMatch = trimmedLine.match(/^ARG\s+([^\s=]+)(?:=(.*))?$/i); + if (argMatch) { + const argName = argMatch[1]; + const argValue = argMatch[2] !== undefined ? argMatch[2] : process.env[argName] || ''; + args[argName] = argValue; + continue; + } + + // Match FROM instructions + const fromMatch = trimmedLine.match(/^FROM\s+(.+?)(?:\s+AS\s+[^\s]+)?$/i); + if (fromMatch) { + let baseImage = fromMatch[1].trim(); + + // Substitute variables in the base image name + baseImage = Dockerfile.substituteVariables(baseImage, args); + + return baseImage; + } + } + + throw new Error('No FROM instruction found in Dockerfile'); + } + + /** + * Substitutes variables in a string, supporting default values like ${VAR:-default}. + * @param str The string containing variables. + * @param vars The object containing variable values. + * @returns The string with variables substituted. + */ + private static substituteVariables(str: string, vars: { [key: string]: string }): string { + return str.replace(/\${([^}:]+)(:-([^}]+))?}/g, (_, varName, __, defaultValue) => { + if (vars[varName] !== undefined) { + return vars[varName]; + } else if (defaultValue !== undefined) { + return defaultValue; + } else { + return ''; + } + }); } /**