@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
191 lines • 8.35 kB
JavaScript
;
/*
* 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.RepositoryDrivenContainer = exports.repositoryDrivenContainer = exports.hasRepositoryGoals = void 0;
const configuration_1 = require("@atomist/automation-client/lib/configuration");
const camelcaseKeys = require("camelcase-keys");
const yaml = require("js-yaml");
const _ = require("lodash");
const os = require("os");
const Goal_1 = require("../../../api/goal/Goal");
const GoalInvocation_1 = require("../../../api/goal/GoalInvocation");
const GoalNameGenerator_1 = require("../../../api/goal/GoalNameGenerator");
const GoalWithFulfillment_1 = require("../../../api/goal/GoalWithFulfillment");
const PushTest_1 = require("../../../api/mapping/PushTest");
const pushTestUtils_1 = require("../../../api/mapping/support/pushTestUtils");
const mapPushTests_1 = require("../../machine/yaml/mapPushTests");
const array_1 = require("../../util/misc/array");
const goalCaching_1 = require("../cache/goalCaching");
const container_1 = require("./container");
const docker_1 = require("./docker");
exports.hasRepositoryGoals = PushTest_1.pushTest("has SDM goals", async (pli) => {
return (await pli.project.getFiles(".atomist/*goals.{yml,yaml}")).length > 0;
});
function repositoryDrivenContainer(options = {}) {
return new RepositoryDrivenContainer(options.tests || {});
}
exports.repositoryDrivenContainer = repositoryDrivenContainer;
class RepositoryDrivenContainer extends GoalWithFulfillment_1.FulfillableGoal {
constructor(tests) {
super({ uniqueName: "repository-driven-goal" });
this.tests = tests;
this.addFulfillment({
progressReporter: container_1.ContainerProgressReporter,
goalExecutor: async (gi) => {
const registration = gi.parameters.registration;
const c = new container_1.Container({ displayName: this.definition.displayName });
c.register = () => {
};
c.addFulfillment = () => c;
c.addFulfillmentCallback = () => c;
c.withProjectListener = () => c;
c.with(registration);
return docker_1.executeDockerJob(c, registration)(gi);
},
name: GoalNameGenerator_1.DefaultGoalNameGenerator.generateName(`container-docker-${this.definition.displayName}`),
});
this.withProjectListener({
name: "cache-restore",
events: [GoalInvocation_1.GoalProjectListenerEvent.before],
listener: async (p, gi, e) => {
const registration = gi.parameters.registration;
if (registration.input && registration.input.length > 0) {
await goalCaching_1.cacheRestore({ entries: registration.input }).listener(p, gi, e);
}
},
}).withProjectListener({
name: "cache-put",
events: [GoalInvocation_1.GoalProjectListenerEvent.after],
listener: async (p, gi, e) => {
const registration = gi.parameters.registration;
if (registration.output && registration.output.length > 0) {
await goalCaching_1.cachePut({ entries: registration.output }).listener(p, gi, e);
}
},
});
}
async plan(pli, goals) {
const configYamls = (await pli.project.getFiles(".atomist/*goals.{yml,yaml}"))
.sort((f1, f2) => f1.path.localeCompare(f2.path));
const plan = {};
for (const configYaml of configYamls) {
const configs = yaml.safeLoadAll(await configYaml.getContent());
for (const config of configs) {
for (const k in config) {
if (config.hasOwnProperty(k)) {
const value = config[k];
const v = camelcaseKeys(value, { deep: true });
const test = pushTestUtils_1.and(...array_1.toArray(await mapPushTests_1.mapTests(v.test, this.tests, {})));
if (await test.mapping(pli)) {
const plannedGoals = array_1.toArray(mapGoals(v.goals, {}));
plan[k] = {
goals: plannedGoals,
dependsOn: v.dependsOn,
};
}
}
}
}
}
await configuration_1.resolvePlaceholders(plan, value => resolvePlaceholder(value, pli));
return plan;
}
}
exports.RepositoryDrivenContainer = RepositoryDrivenContainer;
function mapGoals(goals, additionalGoals) {
if (Array.isArray(goals)) {
return array_1.toArray(goals).map(g => mapGoals(g, additionalGoals));
}
else {
if (!!goals.containers) {
const name = _.get(goals, "containers.name") || _.get(goals, "containers[0].name");
return mapPlannedGoal(name, goals, array_1.toArray(goals.containers), array_1.toArray(goals.volumes));
}
else if (!!goals.script) {
const script = goals.script;
return mapPlannedGoal(script.name, script, [{
name: script.name,
image: script.image || "ubuntu:latest",
command: script.command,
args: script.args,
}], []);
}
else {
throw new Error(`Unable to construct goal from '${JSON.stringify(goals)}'`);
}
}
}
function mapPlannedGoal(name, details, containers, volumes) {
const gd = new Goal_1.Goal({ uniqueName: name, displayName: name });
return {
details: {
displayName: gd.definition.displayName,
descriptions: {
planned: gd.plannedDescription,
requested: gd.requestedDescription,
inProcess: gd.inProcessDescription,
completed: gd.successDescription,
failed: gd.failureDescription,
canceled: gd.canceledDescription,
stopped: gd.stoppedDescription,
waitingForApproval: gd.waitingForApprovalDescription,
waitingForPreApproval: gd.waitingForPreApprovalDescription,
},
retry: details.retry,
preApproval: details.preApproval,
approval: details.approval,
},
parameters: {
registration: {
containers,
volumes,
input: details.input,
output: details.output,
},
},
};
}
const PlaceholderExpression = /\$\{([.a-zA-Z_-]+)([.:0-9a-zA-Z-_ \" ]+)*\}/g;
async function resolvePlaceholder(value, pli) {
if (!PlaceholderExpression.test(value)) {
return value;
}
PlaceholderExpression.lastIndex = 0;
let currentValue = value;
let result;
// tslint:disable-next-line:no-conditional-assignment
while (result = PlaceholderExpression.exec(currentValue)) {
const fm = result[0];
let envValue = _.get(pli, result[1]);
if (result[1] === "home") {
envValue = os.userInfo().homedir;
}
const defaultValue = result[2] ? result[2].trim().slice(1) : undefined;
if (envValue) {
currentValue = currentValue.split(fm).join(envValue);
}
else if (defaultValue) {
currentValue = currentValue.split(fm).join(defaultValue);
}
else {
throw new Error(`Placeholder '${result[1]}' can't be resolved`);
}
PlaceholderExpression.lastIndex = 0;
}
return currentValue;
}
//# sourceMappingURL=repositoryDrivenContainer.js.map