docker/src/lib.js

266 lines
8.2 KiB
JavaScript

import * as core from '@actions/core';
import * as github from '@actions/github';
import * as child_process from 'child_process';
import * as fs from 'fs';
import {Base64} from 'js-base64';
import * as path from 'path';
export function processAdditionalRegistries(targetRegistries) {
const additionalRegistries = core.getInput('additional_registries');
if (additionalRegistries != null && additionalRegistries.length > 0) {
const additionalRegistriesArr = additionalRegistries.split(',');
for (let registry of additionalRegistriesArr) {
registry = registry.trim();
if (!registry.includes(':')) {
registry += ':';
}
targetRegistries.push(registry);
}
}
}
export function addCiRegistryAuth(ci_registry, registryAuthJson) {
if (!core.getBooleanInput('add_ci_registry_auth')) {
return;
}
if (ci_registry === false || ci_registry.length <= 0) {
console.log('WARNING: add_ci_registry_auth enabled but ci_registry is not set');
return;
}
const argCiRegistryPassword = (core.getInput('ci_registry_password') ?? '').trim();
if (argCiRegistryPassword == null || argCiRegistryPassword.length <= 0) {
console.log('WARNING: add_ci_registry_auth enabled but ci_registry_password env is empty');
return;
}
registryAuthJson.auths[ci_registry] = {'auth': Base64.encode('token:' + argCiRegistryPassword)};
}
export function mergeArgRegistryAuthJson(registryAuthJson) {
const argRegistryAuthJson = process.env['REGISTRY_AUTH_JSON'];
if (argRegistryAuthJson != null && argRegistryAuthJson.trim().length > 0) {
try {
const argRegistryAuth = JSON.parse(argRegistryAuthJson);
if (argRegistryAuth.auth != null) {
for (const key in argRegistryAuth.auth) {
if (argRegistryAuth.auth.hasOwnProperty(key)) {
registryAuthJson[key] = argRegistryAuth.auth[key];
}
}
}
}
catch (error) {
console.log('Failed to parse registry auth json', error);
core.setFailed(error.message);
process.exit(1);
}
}
}
export function writeRegistryAuthJson(registryAuthJson, targetFile) {
fs.mkdirSync(path.dirname(targetFile), {recursive: true});
const jsonContents = JSON.stringify(registryAuthJson, null, 2);
// create and log a censored copy if enabled
if (core.getBooleanInput('debug_log_auth_json')) {
const copy = JSON.parse(jsonContents);
for (const registry in copy.auths) {
if (copy.auths.hasOwnProperty(registry)) {
let credentials = copy.auths[registry].auth;
if (credentials != null) {
// truncate credentials to avoid leaking sensitive information
if (credentials.length > 16) {
credentials = credentials.substr(0, 16) + '...';
}
else {
credentials = '***censored***';
}
copy.auths[registry].auth = credentials;
}
}
}
console.log('debug_log_auth_json:', copy);
}
fs.writeFileSync(targetFile, JSON.stringify(registryAuthJson, null, 2));
}
function isNonEmptyStr(str) {
return str != null && str !== 'false' && str.length > 0;
}
export function collectTags(information) {
const tags = [];
let foundSemverTag = false;
let tagPrefix = (core.getInput('tag_prefix') ?? '').trim();
let tagSuffix = (core.getInput('tag_suffix') ?? '').trim();
let tagCommitPrefix = (core.getInput('tag_commit_prefix') ?? '').trim();
// handle semver
if (core.getBooleanInput('tag_semver_major') && isNonEmptyStr(information.semver_major)) {
tags.push(tagPrefix + information.semver_major);
foundSemverTag = true;
}
if (core.getBooleanInput('tag_semver_minor') && isNonEmptyStr(information.semver_minor)) {
tags.push(tagPrefix + information.semver_minor);
foundSemverTag = true;
}
if (core.getBooleanInput('tag_semver_patch') && isNonEmptyStr(information.semver_patch)) {
tags.push(tagPrefix + information.semver_patch);
foundSemverTag = true;
}
// handle git tag/branch
if (core.getBooleanInput('tag_ref_normalized_enable') && foundSemverTag === false) {
if (isNonEmptyStr(information.git_tag)) {
// TODO normalize tag from git for docker
tags.push(tagPrefix + information.git_tag + tagSuffix);
}
if (isNonEmptyStr(information.git_current_branch)) {
// TODO normalize branch from git for docker
tags.push(tagPrefix + information.git_current_branch + tagSuffix);
}
}
// handle commit sha
if (core.getBooleanInput('tag_commit_enable') && isNonEmptyStr(github.context.sha)) {
tags.push(tagPrefix + tagCommitPrefix + github.context.sha + tagSuffix);
}
return tags;
}
export function prepareDestinations(registries, tags) {
const destinations = [];
registries.forEach((registry) => {
tags.forEach((tag) => {
destinations.push(registry + tag);
});
});
return destinations;
}
export function getDockerContextDir() {
if (isNonEmptyStr(core.getInput('docker_context_dir'))) {
return core.getInput('docker_context_dir');
}
else {
return process.env['GITHUB_WORKSPACE'];
}
}
export function prepareDockerArgs(destinations) {
let dockerArgs = (core.getInput('docker_args') ?? '').trim();
if (dockerArgs.length > 0) {
dockerArgs = [dockerArgs];
}
else {
dockerArgs = [];
}
if (isNonEmptyStr(core.getInput('dockerfile'))) {
dockerArgs.unshift('--file ' + core.getInput('dockerfile'));
}
dockerArgs.unshift(getDockerContextDir());
if (isNonEmptyStr(core.getInput('docker_multiarch'))) {
if (!core.getBooleanInput('use_buildx')) {
throw new Error('Unsupported configuration: Cannot build multiarch without enabling buildx');
}
let archList = (core.getInput('docker_multiarch'));
if (archList === 'true' || archList === '1') {
archList = 'linux/amd64,linux/arm64';
}
if (archList.length > 0) {
dockerArgs.push('--platform ' + archList);
}
}
if (core.getBooleanInput('squash_layers')) {
dockerArgs.push('--squash');
}
destinations.forEach(dest => {
dockerArgs.push('--tag ' + dest);
});
if (isNonEmptyStr(core.getInput('additional_registry_destinations'))) {
dockerArgs.push(core.getInput('additional_registry_destinations'));
}
if (isNonEmptyStr(core.getInput('build_args'))) {
let buildArgs = core.getInput('build_args')
.split('\n')
.map(s => s.trim())
.map(s => {
const equalIndex = s.indexOf('=');
const key = s.substring(0, equalIndex);
const value = s.substring(equalIndex + 1);
return {
key,
value
};
});
console.log('parsed build_args as: ', JSON.stringify(buildArgs, null, 2));
buildArgs.forEach(arg => {
dockerArgs.push(`--build-arg ${arg.key}="${arg.value}"`);
});
}
return dockerArgs;
}
export function executeDockerBuild(dockerArgs, destinations) {
const dockerArgsStr = dockerArgs.join(' ');
const isBuildX = core.getBooleanInput('use_buildx');
let dockerSubCmd = isBuildX ? 'buildx build' : 'build';
if (core.getBooleanInput('docker_push')) {
dockerSubCmd += ' --push';
}
if (core.getBooleanInput('docker_pull')) {
dockerSubCmd += ' --pull';
}
const execStr = `docker ${dockerSubCmd} ${dockerArgsStr}`;
console.log(`executing: ${execStr}`);
const proc = child_process.spawnSync(execStr, {
shell: true,
stdio: 'inherit',
cwd : getDockerContextDir()
});
// push for legacy builder
// if (!isBuildX && core.getBooleanInput('docker_push')) {
// destinations.forEach(dst => {
// const pushProc = child_process.spawnSync('docker push ' + dst, {
// shell: true,
// stdio: 'inherit',
// cwd : getDockerContextDir()
// });
// if (pushProc.status != null && pushProc.status > 0) {
// throw new Error('docker push ' + dst + ' failed');
// }
// });
// }
if (proc.status != null && proc.status > 0) {
throw new Error('docker build failed');
}
if (proc.error != null) {
throw proc.error;
}
}
export function isTrueString(str) {
return str === '1'
|| str === 'true'
|| str === 'True'
|| str === 'TRUE';
}