UNPKG

@docker/actions-toolkit

Version:
377 lines 13.8 kB
"use strict"; /** * Copyright 2023 actions-toolkit authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Bake = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const sync_1 = require("csv-parse/sync"); const buildx_1 = require("./buildx"); const context_1 = require("../context"); const exec_1 = require("../exec"); const util_1 = require("../util"); class Bake { constructor(opts) { this.buildx = (opts === null || opts === void 0 ? void 0 : opts.buildx) || new buildx_1.Buildx(); this.metadataFilename = `bake-metadata-${util_1.Util.generateRandomString()}.json`; } getMetadataFilePath() { return path_1.default.join(context_1.Context.tmpDir(), this.metadataFilename); } resolveMetadata() { const metadataFile = this.getMetadataFilePath(); if (!fs_1.default.existsSync(metadataFile)) { return undefined; } const content = fs_1.default.readFileSync(metadataFile, { encoding: 'utf-8' }).trim(); if (content === 'null') { return undefined; } return JSON.parse(content); } resolveRefs(metadata) { if (!metadata) { metadata = this.resolveMetadata(); if (!metadata) { return undefined; } } const refs = new Array(); for (const key in metadata) { if ('buildx.build.ref' in metadata[key]) { refs.push(metadata[key]['buildx.build.ref']); } } return refs.length > 0 ? refs : undefined; } resolveWarnings(metadata) { if (!metadata) { metadata = this.resolveMetadata(); if (!metadata) { return undefined; } } if ('buildx.build.warnings' in metadata) { return metadata['buildx.build.warnings']; } return undefined; } getDefinition(cmdOpts, execOptions) { return __awaiter(this, void 0, void 0, function* () { execOptions = execOptions || { ignoreReturnCode: true }; execOptions.ignoreReturnCode = true; if (cmdOpts.githubToken) { execOptions.env = Object.assign({}, process.env, { BUILDX_BAKE_GIT_AUTH_TOKEN: cmdOpts.githubToken }); } const args = ['bake']; let remoteDef; const files = []; const sources = [...(cmdOpts.files || []), cmdOpts.source]; if (sources) { for (const source of sources.map(v => (v ? v.trim() : ''))) { if (source.length == 0) { continue; } if (!util_1.Util.isValidRef(source)) { files.push(source); continue; } if (remoteDef) { throw new Error(`Only one remote bake definition can be defined`); } remoteDef = source; } } if (remoteDef) { args.push(remoteDef); } for (const file of files) { args.push('--file', file); } if (cmdOpts.overrides) { for (const override of cmdOpts.overrides) { args.push('--set', override); } } if (cmdOpts.allow) { for (const allow of cmdOpts.allow) { args.push('--allow', allow); } } if (cmdOpts.call) { args.push('--call', cmdOpts.call); } if (cmdOpts.load) { args.push('--load'); } if (cmdOpts.noCache) { args.push('--no-cache'); } if (cmdOpts.provenance) { args.push('--provenance', cmdOpts.provenance); } if (cmdOpts.push) { args.push('--push'); } if (cmdOpts.sbom) { args.push('--sbom', cmdOpts.sbom); } const printCmd = yield this.buildx.getCommand([...args, '--print', ...(cmdOpts.targets || [])]); return yield exec_1.Exec.getExecOutput(printCmd.command, printCmd.args, execOptions).then(res => { var _a, _b, _c; if (res.stderr.length > 0 && res.exitCode != 0) { throw new Error(`cannot parse bake definitions: ${(_c = (_b = (_a = res.stderr.match(/(.*)\s*$/)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : 'unknown error'}`); } return Bake.parseDefinition(res.stdout.trim()); }); }); } static parseDefinition(dt) { const definition = JSON.parse(dt); // convert to composable attributes: https://github.com/docker/buildx/pull/2758 for (const name in definition.target) { const target = definition.target[name]; if (target['attest'] && Array.isArray(target['attest'])) { target['attest'] = target['attest'].map((item) => { return Bake.parseAttestEntry(item); }); } if (target['cache-from'] && Array.isArray(target['cache-from'])) { target['cache-from'] = target['cache-from'].map((item) => { return Bake.parseCacheEntry(item); }); } if (target['cache-to'] && Array.isArray(target['cache-to'])) { target['cache-to'] = target['cache-to'].map((item) => { return Bake.parseCacheEntry(item); }); } if (target['output'] && Array.isArray(target['output'])) { target['output'] = target['output'].map((item) => { return Bake.parseExportEntry(item); }); } if (target['secret'] && Array.isArray(target['secret'])) { target['secret'] = target['secret'].map((item) => { return Bake.parseSecretEntry(item); }); } if (target['ssh'] && Array.isArray(target['ssh'])) { target['ssh'] = target['ssh'].map((item) => { return Bake.parseSSHEntry(item); }); } } return definition; } static parseAttestEntry(item) { if (typeof item !== 'string') { return item; } const attestEntry = { type: '' }; const fields = (0, sync_1.parse)(item, { relaxColumnCount: true, skipEmptyLines: true })[0]; for (const field of fields) { const [key, value] = field .toString() .split(/(?<=^[^=]+?)=/) .map((item) => item.trim()); switch (key) { case 'type': attestEntry.type = value; break; case 'disabled': attestEntry.disabled = util_1.Util.parseBool(value); break; default: attestEntry[key] = value; } } return attestEntry; } static parseCacheEntry(item) { if (typeof item !== 'string') { return item; } const cacheEntry = { type: '' }; const fields = (0, sync_1.parse)(item, { relaxColumnCount: true, skipEmptyLines: true })[0]; if (fields.length === 1 && !fields[0].includes('=')) { cacheEntry.type = 'registry'; cacheEntry.ref = fields[0]; return cacheEntry; } for (const field of fields) { const [key, value] = field .toString() .split(/(?<=^[^=]+?)=/) .map((item) => item.trim()); switch (key) { case 'type': cacheEntry.type = value; break; default: cacheEntry[key] = value; } } return cacheEntry; } static parseExportEntry(item) { if (typeof item !== 'string') { return item; } const exportEntry = { type: '' }; const fields = (0, sync_1.parse)(item, { relaxColumnCount: true, skipEmptyLines: true })[0]; if (fields.length === 1 && fields[0] === item && !item.startsWith('type=')) { if (item !== '-') { exportEntry.type = 'local'; exportEntry.dest = item; return exportEntry; } exportEntry.type = 'tar'; exportEntry.dest = item; return exportEntry; } for (const field of fields) { const [key, value] = field .toString() .split(/(?<=^[^=]+?)=/) .map((item) => item.trim()); switch (key) { case 'type': exportEntry.type = value; break; default: exportEntry[key] = value; } } return exportEntry; } static parseSecretEntry(item) { if (typeof item !== 'string') { return item; } const secretEntry = {}; const fields = (0, sync_1.parse)(item, { relaxColumnCount: true, skipEmptyLines: true })[0]; let typ = ''; for (const field of fields) { const [key, value] = field .toString() .split(/(?<=^[^=]+?)=/) .map((item) => item.trim()); switch (key) { case 'type': typ = value; break; case 'id': secretEntry.id = value; break; case 'source': case 'src': secretEntry.src = value; break; case 'env': secretEntry.env = value; break; } } if (typ === 'env' && !secretEntry.env) { secretEntry.env = secretEntry.src; secretEntry.src = undefined; } return secretEntry; } static parseSSHEntry(item) { if (typeof item !== 'string') { return item; } const sshEntry = {}; const [key, value] = item.split('=', 2); sshEntry.id = key; if (value) { sshEntry.paths = value.split(','); } return sshEntry; } static hasLocalExporter(def) { return Bake.hasExporterType('local', Bake.exporters(def)); } static hasTarExporter(def) { return Bake.hasExporterType('tar', Bake.exporters(def)); } static hasDockerExporter(def, load) { return load || Bake.hasExporterType('docker', Bake.exporters(def)); } static hasExporterType(name, exporters) { for (const exporter of exporters) { if (exporter.type == name) { return true; } } return false; } static exporters(def) { const exporters = new Array(); for (const key in def.target) { const target = def.target[key]; if (target.output) { for (const output of target.output) { exporters.push(Bake.parseExportEntry(output)); } } } return exporters; } static hasGitAuthTokenSecret(def) { for (const key in def.target) { const target = def.target[key]; if (target.secret) { for (const secret of target.secret) { if (Bake.parseSecretEntry(secret).id === 'GIT_AUTH_TOKEN') { return true; } } } } return false; } } exports.Bake = Bake; //# sourceMappingURL=bake.js.map