fix(docker): Enhanced base image extraction logic from Dockerfile

This commit is contained in:
Philipp Kunz 2024-11-17 01:01:22 +01:00
parent 43eb19f772
commit 75a0e8a7d8
3 changed files with 67 additions and 7 deletions

View File

@ -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.

View File

@ -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.'
}

View File

@ -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 '';
}
});
}
/**