UNPKG

@atomist/sdm-core

Version:

Atomist Software Delivery Machine - Implementation

323 lines 14.2 kB
"use strict"; /* * Copyright © 2019 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. */ 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const automation_client_1 = require("@atomist/automation-client"); const configuration_1 = require("@atomist/automation-client/lib/configuration"); const sdm_1 = require("@atomist/sdm"); const yaml = require("js-yaml"); const stringify = require("json-stringify-safe"); const _ = require("lodash"); const goalCaching_1 = require("../../goal/cache/goalCaching"); const item_1 = require("../../goal/common/item"); 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 = (goals, sdm, additionalGoals, goalMakers, additionalTests, extensionTests) => __awaiter(void 0, void 0, void 0, function* () { 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 ? yield mapPushTests_1.mapTests(gc.test, additionalTests, extensionTests) : undefined })); } const g = container_1.container(goals.name, { callback: containerCallback(), containers, 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 = (goals) => __awaiter(void 0, void 0, void 0, function* () { 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 = (goals) => __awaiter(void 0, void 0, void 0, function* () { if (goals.use === "immaterial") { return sdm_1.ImmaterialGoals.andLock().goals; } return undefined; }); const MapLock = (goals) => __awaiter(void 0, void 0, void 0, function* () { if (goals.use === "lock") { return sdm_1.Locking; } return undefined; }); const MapQueue = (goals) => __awaiter(void 0, void 0, void 0, function* () { if (goals.use === "queue") { return new sdm_1.Queue({ fetch: goals.fetch, concurrent: goals.concurrent, }); } return undefined; }); const MapCancel = (goals) => __awaiter(void 0, void 0, void 0, function* () { if (goals.use === "cancel") { return new sdm_1.Cancel({ goals: [], goalNames: array_1.toArray(goals.goals) }); } return undefined; }); const MapAdditional = (goals, sdm, additionalGoals) => __awaiter(void 0, void 0, void 0, function* () { if (!!additionalGoals[goals.use]) { return additionalGoals[goals.use]; } return undefined; }); const MapReferenced = (goals, sdm, additionalGoals, goalMakers, additionalTests, extensionTests) => __awaiter(void 0, void 0, void 0, function* () { const use = goals.use; if (!!use && use.includes("/") && !use.startsWith("@")) { const parameters = goals.parameters || {}; const referencedGoal = yield mapReferencedGoal(sdm, use, parameters); if (!!referencedGoal) { return mapGoals(sdm, _.merge({}, referencedGoal, (goals || {})), additionalGoals, goalMakers, additionalTests, extensionTests); } } return undefined; }); const MapGoalMakers = (goals, sdm, additionalGoals, goalMakers) => __awaiter(void 0, void 0, void 0, function* () { 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 = (goals) => __awaiter(void 0, void 0, void 0, function* () { 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 && use.startsWith("@")) { return item_1.item(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 MapGoals = [ MapContainer, MapExecute, MapImmaterial, MapLock, MapCancel, MapQueue, MapAdditional, MapGoalMakers, MapReferenced, MapFulfillment, ]; function mapGoals(sdm, goals, additionalGoals, goalMakers, additionalTests, extensionTests) { return __awaiter(this, void 0, void 0, function* () { if (Array.isArray(goals)) { const newGoals = []; for (const g of array_1.toArray(goals)) { newGoals.push(yield mapGoals(sdm, g, additionalGoals, goalMakers, additionalTests, extensionTests)); } return newGoals; } else { let goal; for (const mapGoal of MapGoals) { goal = yield 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) { var _a, _b; if (!!((_a = goals) === null || _a === void 0 ? void 0 : _a.input)) { goal.withProjectListener(goalCaching_1.cacheRestore({ entries: array_1.toArray(goals.input) })); } if (!!((_b = goals) === null || _b === void 0 ? void 0 : _b.output)) { goal.withProjectListener(goalCaching_1.cachePut({ entries: array_1.toArray(goals.output) })); } return goal; } function containerCallback() { return (r, p, g, e, ctx) => __awaiter(this, void 0, void 0, function* () { 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 = sdm_1.allSatisfied(...gc.test); } else { test = gc.test; } if (!!test && !(yield 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); }); } function mapReferencedGoal(sdm, goalRef, parameters) { var _a, _b, _c, _d, _e, _f, _g; return __awaiter(this, void 0, void 0, function* () { 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 = yield sdm.configuration.sdm.credentialsResolver.eventHandlerCredentials({ graphClient: sdm.configuration.graphql.client.factory.create(workspaceId, sdm.configuration) }, automation_client_1.GitHubRepoRef.from({ owner: undefined, repo, })); if (!!creds && automation_client_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 = yield client.exchange(url, { method: automation_client_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]; yield 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; }); } function resolvePlaceholderContainerSpecCallback(r, p, g, e, ctx) { return __awaiter(this, void 0, void 0, function* () { yield configuration_1.resolvePlaceholders(r, value => resolvePlaceholder_1.resolvePlaceholder(value, e, ctx, r.parameters)); return r; }); } //# sourceMappingURL=mapGoals.js.map