@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
276 lines • 11.5 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.goalSetState = exports.storeGoalSet = exports.constructGoalSet = exports.descriptionFromState = exports.constructProvenance = exports.storeGoal = exports.constructSdmGoal = exports.constructSdmGoalImplementation = exports.goalCorrespondsToSdmGoal = exports.updateGoal = exports.environmentFromGoal = void 0;
const GraphClient_1 = require("@atomist/automation-client/lib/spi/graph/GraphClient");
const _ = require("lodash");
const omitEmpty = require("omit-empty");
const sprintf_js_1 = require("sprintf-js");
const Goal_1 = require("../../api/goal/Goal");
const SdmGoalMessage_1 = require("../../api/goal/SdmGoalMessage");
const types_1 = require("../../typings/types");
function environmentFromGoal(goal) {
return goal.definition.environment.replace(/\/$/, ""); // remove trailing slash at least
}
exports.environmentFromGoal = environmentFromGoal;
async function updateGoal(ctx, before, params) {
const description = params.description;
const approval = params.approved ? constructProvenance(ctx) :
!!before ? before.approval : undefined;
const data = params.data ?
params.data :
!!before ? before.data : undefined;
before.version = (before.version || 1) + 1;
const sdmGoal = Object.assign(Object.assign({}, eventToMessage(before)), { state: params.state === "success" && !!before && before.approvalRequired ? types_1.SdmGoalState.waiting_for_approval : params.state, phase: params.phase, description, url: params.url ? params.url : before.url, externalUrls: params.externalUrls ? params.externalUrls : before.externalUrls, approval, ts: Date.now(), provenance: [constructProvenance(ctx)].concat(!!before ? before.provenance : []), error: _.get(params, "error.message"), data, push: cleanPush(before.push), version: before.version });
await storeGoal(ctx, sdmGoal);
}
exports.updateGoal = updateGoal;
function eventToMessage(event) {
return Object.assign(Object.assign({}, event), { repo: {
name: event.repo.name,
owner: event.repo.owner,
providerId: event.repo.providerId,
}, id: undefined });
}
function goalCorrespondsToSdmGoal(goal, sdmGoal) {
return goal.name === sdmGoal.name && environmentFromGoal(goal) === sdmGoal.environment;
}
exports.goalCorrespondsToSdmGoal = goalCorrespondsToSdmGoal;
function constructSdmGoalImplementation(gi, registration) {
return {
method: SdmGoalMessage_1.SdmGoalFulfillmentMethod.Sdm,
name: gi.implementationName,
registration,
};
}
exports.constructSdmGoalImplementation = constructSdmGoalImplementation;
function constructSdmGoal(ctx, parameters) {
const { goalSet, goal, goalSetId, state, id, providerId, url } = parameters;
const fulfillment = parameters.fulfillment || {
method: SdmGoalMessage_1.SdmGoalFulfillmentMethod.Other,
name: "unknown",
registration: "unknown",
};
if (!id.branch) {
throw new Error(sprintf_js_1.sprintf("Please provide a branch in the RemoteRepoRef %j", parameters));
}
if (!id.sha) {
throw new Error(sprintf_js_1.sprintf("Please provide a sha in the RemoteRepoRef %j", parameters));
}
const preConditions = [];
const description = descriptionFromState(goal, state);
const environment = environmentFromGoal(goal);
if (Goal_1.hasPreconditions(goal)) {
preConditions.push(...goal.dependsOn.map(d => ({
goalSet,
name: d.name,
uniqueName: d.uniqueName,
environment: environmentFromGoal(d),
})));
}
const retryFeasible = goal.definition.retryFeasible ? goal.definition.retryFeasible : false;
return {
goalSet,
registration: ctx.context.name,
goalSetId,
name: goal.name,
uniqueName: goal.uniqueName,
environment,
fulfillment,
sha: id.sha,
branch: id.branch,
repo: {
name: id.repo,
owner: id.owner,
providerId,
},
state,
description,
descriptions: {
planned: goal.plannedDescription,
requested: goal.requestedDescription,
inProcess: goal.inProcessDescription,
completed: goal.successDescription,
failed: goal.failureDescription,
canceled: goal.canceledDescription,
stopped: goal.stoppedDescription,
skipped: goal.skippedDescription,
waitingForApproval: goal.waitingForApprovalDescription,
waitingForPreApproval: goal.waitingForPreApprovalDescription,
},
url,
externalKey: goal.context,
ts: Date.now(),
approvalRequired: goal.definition.approvalRequired ? goal.definition.approvalRequired : false,
preApprovalRequired: goal.definition.preApprovalRequired ? goal.definition.preApprovalRequired : false,
retryFeasible,
provenance: [constructProvenance(ctx)],
preConditions,
parameters: !!goal.definition.parameters ?
JSON.stringify(goal.definition.parameters) : undefined,
version: 1,
};
}
exports.constructSdmGoal = constructSdmGoal;
async function storeGoal(ctx, sdmGoal) {
const newGoal = omitEmpty(sdmGoal, { omitZero: false });
delete (newGoal).push;
await ctx.graphClient.mutate({
name: "UpdateSdmGoal",
variables: {
goal: newGoal,
},
options: GraphClient_1.MutationNoCacheOptions,
});
return sdmGoal;
}
exports.storeGoal = storeGoal;
function constructProvenance(ctx) {
return {
registration: ctx.context.name,
version: ctx.context.version,
name: ctx.context.operation,
correlationId: ctx.correlationId,
ts: Date.now(),
};
}
exports.constructProvenance = constructProvenance;
function descriptionFromState(goal, state, goalEvent) {
switch (state) {
case types_1.SdmGoalState.planned:
return _.get(goalEvent, "descriptions.planned", goal.plannedDescription);
case types_1.SdmGoalState.requested:
return _.get(goalEvent, "descriptions.requested", goal.requestedDescription);
case types_1.SdmGoalState.in_process:
return _.get(goalEvent, "descriptions.inProcess", goal.inProcessDescription);
case types_1.SdmGoalState.waiting_for_approval:
return _.get(goalEvent, "descriptions.waitingForApproval", goal.waitingForApprovalDescription);
case types_1.SdmGoalState.waiting_for_pre_approval:
return _.get(goalEvent, "descriptions.waitingForPreApproval", goal.waitingForPreApprovalDescription);
case types_1.SdmGoalState.success:
return _.get(goalEvent, "descriptions.completed", goal.successDescription);
case types_1.SdmGoalState.failure:
return _.get(goalEvent, "descriptions.failed", goal.failureDescription);
case types_1.SdmGoalState.skipped:
return _.get(goalEvent, "descriptions.skipped", goal.skippedDescription);
case types_1.SdmGoalState.canceled:
return _.get(goalEvent, "descriptions.canceled", goal.canceledDescription);
case types_1.SdmGoalState.stopped:
return _.get(goalEvent, "descriptions.stopped", goal.stoppedDescription);
default:
throw new Error("Unknown goal state " + state);
}
}
exports.descriptionFromState = descriptionFromState;
function constructGoalSet(ctx, goalSetId, goalSet, sdmGoals, tags, push) {
let repo;
if (!!push) {
repo = {
name: push.repo.name,
owner: push.repo.owner,
providerId: push.repo.org.provider.providerId,
};
}
else if (!!sdmGoals && sdmGoals.length > 0) {
const goal = sdmGoals.find(g => !!g.repo);
if (!!goal) {
repo = {
name: goal.repo.name,
owner: goal.repo.owner,
providerId: goal.repo.providerId,
};
}
}
const sdmGoalSet = {
sha: push.after.sha,
branch: push.branch,
goalSetId,
goalSet,
ts: Date.now(),
repo,
state: goalSetState(sdmGoals),
goals: sdmGoals.map(g => ({
name: g.name,
uniqueName: g.uniqueName,
})),
provenance: constructProvenance(ctx),
tags,
};
return sdmGoalSet;
}
exports.constructGoalSet = constructGoalSet;
async function storeGoalSet(ctx, goalSet) {
await ctx.graphClient.mutate({
name: "UpdateSdmGoalSet",
variables: {
goalSet: omitEmpty(goalSet, { omitZero: false }),
},
options: GraphClient_1.MutationNoCacheOptions,
});
}
exports.storeGoalSet = storeGoalSet;
function goalSetState(goals) {
if (goals.some(g => g.state === types_1.SdmGoalState.failure)) {
return types_1.SdmGoalState.failure;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.canceled)) {
return types_1.SdmGoalState.canceled;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.stopped)) {
return types_1.SdmGoalState.stopped;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.in_process)) {
return types_1.SdmGoalState.in_process;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.waiting_for_pre_approval)) {
return types_1.SdmGoalState.waiting_for_pre_approval;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.waiting_for_approval)) {
return types_1.SdmGoalState.waiting_for_approval;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.pre_approved)) {
return types_1.SdmGoalState.pre_approved;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.approved)) {
return types_1.SdmGoalState.approved;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.requested)) {
return types_1.SdmGoalState.requested;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.planned)) {
return types_1.SdmGoalState.planned;
}
else if (goals.some(g => g.state === types_1.SdmGoalState.skipped)) {
return types_1.SdmGoalState.skipped;
}
else if (goals.every(g => g.state === types_1.SdmGoalState.success)) {
return types_1.SdmGoalState.success;
}
else {
const unknowns = goals.filter(g => g.state !== types_1.SdmGoalState.success).map(g => `${g.name}:${g.state}`);
throw new Error("Unknown goal state(s): " + JSON.stringify(unknowns));
}
}
exports.goalSetState = goalSetState;
function cleanPush(push) {
const newPush = _.cloneDeep(push);
if (!!newPush && !!newPush.goals) {
delete newPush.goals;
}
return newPush;
}
//# sourceMappingURL=storeGoals.js.map