@atomist/sdm-core
Version:
Atomist Software Delivery Machine - Implementation
323 lines • 14.2 kB
JavaScript
;
/*
* 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