UNPKG

@atomist/sdm

Version:

Atomist Software Delivery Machine SDK

330 lines 13.5 kB
"use strict"; /* * Copyright © 2020 Atomist, Inc. * * 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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.mapGoals = void 0; const configuration_1 = require("@atomist/automation-client/lib/configuration"); const GitHubRepoRef_1 = require("@atomist/automation-client/lib/operations/common/GitHubRepoRef"); const ProjectOperationCredentials_1 = require("@atomist/automation-client/lib/operations/common/ProjectOperationCredentials"); const httpClient_1 = require("@atomist/automation-client/lib/spi/http/httpClient"); const yaml = require("js-yaml"); const stringify = require("json-stringify-safe"); const _ = require("lodash"); const Cancel_1 = require("../../../api/goal/common/Cancel"); const Immaterial_1 = require("../../../api/goal/common/Immaterial"); const Locking_1 = require("../../../api/goal/common/Locking"); const Queue_1 = require("../../../api/goal/common/Queue"); const pushTestUtils_1 = require("../../../api/mapping/support/pushTestUtils"); const goalCaching_1 = require("../../goal/cache/goalCaching"); const skill_1 = require("../../goal/common/skill"); const action_1 = require("../../goal/container/action"); const container_1 = require("../../goal/container/container"); const execute_1 = require("../../goal/container/execute"); const array_1 = require("../../util/misc/array"); const mapPushTests_1 = require("./mapPushTests"); const resolvePlaceholder_1 = require("./resolvePlaceholder"); const util_1 = require("./util"); const MapContainer = async (goals, sdm, additionalGoals, goalMakers, additionalTests, extensionTests) => { if (!!goals.containers) { if (!goals.name) { throw new Error(`Property 'name' missing on container goal:\n${JSON.stringify(goals, undefined, 2)}`); } const containers = []; for (const gc of goals.containers) { containers.push(Object.assign(Object.assign({}, gc), { name: gc.name.replace(/ /g, "-"), test: !!gc.test ? await mapPushTests_1.mapTests(gc.test, additionalTests, extensionTests) : undefined })); } const g = container_1.container(goals.name, { callback: containerCallback(), containers, initContainers: goals.initContainers, volumes: array_1.toArray(goals.volumes), progressReporter: container_1.ContainerProgressReporter, input: goals.input, output: goals.output, parameters: goals.parameters, fulfillment: goals.fulfillment, }); return g; } return undefined; }; const MapExecute = async (goals) => { if (!!goals.execute) { if (!goals.name) { throw new Error(`Property 'name' missing on execute goal:\n${JSON.stringify(goals, undefined, 2)}`); } const g = goals.execute; return execute_1.execute(g.name, { cmd: g.command || g.cmd, args: array_1.toArray(g.args), secrets: g.secrets, }); } return undefined; }; const MapImmaterial = async (goals) => { if (goals.use === "immaterial") { return Immaterial_1.ImmaterialGoals.andLock().goals; } return undefined; }; const MapLock = async (goals) => { if (goals.use === "lock") { return Locking_1.Locking; } return undefined; }; const MapQueue = async (goals) => { if (goals.use === "queue") { return new Queue_1.Queue({ fetch: goals.fetch, concurrent: goals.concurrent, }); } return undefined; }; const MapCancel = async (goals) => { if (goals.use === "cancel") { return new Cancel_1.Cancel({ goals: [], goalNames: array_1.toArray(goals.goals) }); } return undefined; }; const MapAdditional = async (goals, sdm, additionalGoals) => { if (!!additionalGoals[goals.use]) { return additionalGoals[goals.use]; } return undefined; }; const MapReferenced = async (goals, sdm, additionalGoals, goalMakers, additionalTests, extensionTests) => { const ref = goals.ref; if (!!ref && ref.includes("/")) { const parameters = goals.parameters || {}; const referencedGoal = await mapReferencedGoal(sdm, ref, parameters); if (!!referencedGoal) { return mapGoals(sdm, _.merge({}, referencedGoal, (goals || {})), additionalGoals, goalMakers, additionalTests, extensionTests); } } return undefined; }; const MapGoalMakers = async (goals, sdm, additionalGoals, goalMakers) => { const use = goals.use; if (!!use && !!goalMakers[use]) { const goalMaker = goalMakers[use]; try { return goalMaker(sdm, (goals.parameters || {})); } catch (e) { e.message = `Failed to make goal using ${use}: ${e.message}`; throw e; } } return undefined; }; const MapFulfillment = async (goals) => { const regexp = /([@a-zA-Z-_]*)\/([a-zA-Z-_]*)(?:\/([a-zA-Z-_]*))?@?([a-zA-Z-_0-9\.]*)/i; const use = goals.use; if (!!use) { const match = regexp.exec(use); if (!!match) { return skill_1.skill(match[3].replace(/_/g, " "), `${match[1]}/${match[2]}`, { uniqueName: goals.name || match[3], parameters: goals.parameters, input: goals.input, output: goals.output, secrets: goals.secrets, }); } } return undefined; }; const MapAction = async (goals) => { if (!!goals.action) { return action_1.action({ name: goals.name, image: goals.action, input: goals.input, output: goals.output, parameters: goals.parameters, secrets: goals.secrets, }); } return undefined; }; const MapGoals = [ MapContainer, MapExecute, MapImmaterial, MapLock, MapCancel, MapQueue, MapAdditional, MapGoalMakers, MapReferenced, MapFulfillment, MapAction, ]; async function mapGoals(sdm, goals, additionalGoals, goalMakers, additionalTests, extensionTests) { if (Array.isArray(goals)) { const newGoals = []; for (const g of array_1.toArray(goals)) { newGoals.push(await mapGoals(sdm, g, additionalGoals, goalMakers, additionalTests, extensionTests)); } return newGoals; } else { let goal; for (const mapGoal of MapGoals) { goal = await mapGoal(goals, sdm, additionalGoals, goalMakers, additionalTests, extensionTests); if (!!goal) { if (!Array.isArray(goal)) { addDetails(goal, goals); // Container goal handle their own caching if (!(goal instanceof container_1.Container)) { addCaching(goal, goals); } } return goal; } } } throw new Error(`Unable to construct goal from '${stringify(goals)}'`); } exports.mapGoals = mapGoals; function addDetails(goal, goals) { goal.definition = _.cloneDeep(goal.definition); if (goals.approval !== undefined) { goal.definition.approvalRequired = goals.approval; } if (goals.preApproval !== undefined) { goal.definition.preApprovalRequired = goals.preApproval; } if (goals.retry !== undefined) { goal.definition.retryFeasible = goals.retry; } if (!!goals.descriptions) { const descriptions = goals.descriptions; goal.definition.canceledDescription = descriptions.canceled; goal.definition.completedDescription = descriptions.completed; goal.definition.failedDescription = descriptions.failed; goal.definition.plannedDescription = descriptions.planned; goal.definition.requestedDescription = descriptions.requested; goal.definition.stoppedDescription = descriptions.stopped; goal.definition.waitingForApprovalDescription = descriptions.waitingForApproval; goal.definition.waitingForPreApprovalDescription = descriptions.waitingForPreApproval; goal.definition.workingDescription = descriptions.inProcess; } return goal; } function addCaching(goal, goals) { if (!!(goals === null || goals === void 0 ? void 0 : goals.input)) { goal.withProjectListener(goalCaching_1.cacheRestore({ entries: array_1.toArray(goals.input) })); } if (!!(goals === null || goals === void 0 ? void 0 : goals.output)) { goal.withProjectListener(goalCaching_1.cachePut({ entries: array_1.toArray(goals.output) })); } return goal; } function containerCallback() { return async (r, p, g, e, ctx) => { const pli = Object.assign(Object.assign({}, ctx), { push: e.push, project: p }); const containersToRemove = []; for (const gc of r.containers) { let test; if (Array.isArray(gc.test)) { test = pushTestUtils_1.allSatisfied(...gc.test); } else { test = gc.test; } if (!!test && !(await test.mapping(pli))) { containersToRemove.push(gc); } } const registration = Object.assign(Object.assign({}, r), { containers: r.containers.filter(c => !containersToRemove.includes(c)) }); return resolvePlaceholderContainerSpecCallback(registration, p, g, e, ctx); }; } async function mapReferencedGoal(sdm, goalRef, parameters) { var _a, _b, _c, _d, _e, _f, _g; const regexp = /([a-zA-Z-_]*)\/([a-zA-Z-_]*)(?:\/([a-zA-Z-_]*))?@?([a-zA-Z-_0-9\.]*)/i; const match = regexp.exec(goalRef); if (!match) { return undefined; } const owner = match[1]; const repo = match[2]; const goalName = match[3]; const goalNames = !!goalName ? [goalName] : [repo, repo.replace(/-goal/, "")]; const ref = match[4] || "master"; // Check if we have a github token to authenticate our requests let token = ((_c = (_b = (_a = sdm.configuration) === null || _a === void 0 ? void 0 : _a.sdm) === null || _b === void 0 ? void 0 : _b.github) === null || _c === void 0 ? void 0 : _c.token) || ((_g = (_f = (_e = (_d = sdm.configuration) === null || _d === void 0 ? void 0 : _d.sdm) === null || _e === void 0 ? void 0 : _e.goal) === null || _f === void 0 ? void 0 : _f.yaml) === null || _g === void 0 ? void 0 : _g.token); if (!token) { const workspaceId = _.get(sdm.configuration, "workspaceIds[0]"); if (!!workspaceId) { try { const creds = await sdm.configuration.sdm.credentialsResolver.eventHandlerCredentials({ graphClient: sdm.configuration.graphql.client.factory.create(workspaceId, sdm.configuration) }, GitHubRepoRef_1.GitHubRepoRef.from({ owner: undefined, repo, })); if (!!creds && ProjectOperationCredentials_1.isTokenCredentials(creds)) { token = creds.token; _.set(sdm.configuration, "sdm.goal.yaml.token", token); } } catch (e) { // Intentionally ignore that error here } } } const url = `https://api.github.com/repos/${owner}/${repo}/contents/goal.yaml?ref=${ref}`; try { const cacheKey = `configuration.sdm.goal.definition.cache[${url}]`; const cachedDocuments = _.get(sdm, cacheKey); let documents; if (!!cachedDocuments) { documents = cachedDocuments; } else { const client = sdm.configuration.http.client.factory.create(url); const response = await client.exchange(url, { method: httpClient_1.HttpMethod.Get, headers: Object.assign({}, (!!token ? { Authorization: `Bearer ${token}` } : {})), retry: { retries: 0 }, }); const content = Buffer.from(response.body.content, "base64").toString(); documents = yaml.safeLoadAll(content); _.set(sdm, cacheKey, documents); } for (const document of documents) { for (const key in document) { if (document.hasOwnProperty(key) && goalNames.includes(key)) { const pdg = document[key]; await configuration_1.resolvePlaceholders(pdg, value => resolvePlaceholder_1.resolvePlaceholder(value, undefined, {}, parameters, false)); return util_1.camelCase(pdg); } } } } catch (e) { throw new Error(`Referenced goal '${goalRef}' can not be created: ${e.message}`); } return undefined; } async function resolvePlaceholderContainerSpecCallback(r, p, g, e, ctx) { await configuration_1.resolvePlaceholders(r, value => resolvePlaceholder_1.resolvePlaceholder(value, e, ctx, ctx.parameters)); return r; } //# sourceMappingURL=mapGoals.js.map