@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
269 lines • 12.3 kB
JavaScript
"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.mergeOptions = exports.getGoalDefinitionFrom = exports.goal = exports.GoalWithFulfillment = exports.FulfillableGoalWithRegistrationsAndListeners = exports.FulfillableGoalWithRegistrations = exports.FulfillableGoal = exports.isSideEffect = exports.isImplementation = void 0;
const configuration_1 = require("@atomist/automation-client/lib/configuration");
const _ = require("lodash");
const sdmGoal_1 = require("../../api-helper/goal/sdmGoal");
const logInterpreters_1 = require("../../api-helper/log/logInterpreters");
const Registerable_1 = require("../machine/Registerable");
const commonPushTests_1 = require("../mapping/support/commonPushTests");
const ServiceRegistration_1 = require("../registration/ServiceRegistration");
const createGoal_1 = require("./common/createGoal");
const Goal_1 = require("./Goal");
const GoalNameGenerator_1 = require("./GoalNameGenerator");
const environment_1 = require("./support/environment");
function isImplementation(f) {
return !!f && !!f.goalExecutor && true;
}
exports.isImplementation = isImplementation;
function isSideEffect(f) {
return !isImplementation(f);
}
exports.isSideEffect = isSideEffect;
/**
* Goal that registers goal implementations, side effects and callbacks on the
* current SDM. No additional registration with the SDM is needed.
*/
class FulfillableGoal extends Goal_1.GoalWithPrecondition {
constructor(definitionOrGoal, ...dependsOn) {
super(Goal_1.isGoalDefinition(definitionOrGoal) ? definitionOrGoal : definitionOrGoal.definition, ...dependsOn);
this.definitionOrGoal = definitionOrGoal;
this.fulfillments = [];
this.callbacks = [];
this.projectListeners = [];
this.goalListeners = [];
Registerable_1.registerRegistrable(this);
}
register(sdm) {
this.sdm = sdm;
this.fulfillments.forEach(f => this.registerFulfillment(f));
this.callbacks.forEach(cb => this.registerCallback(cb));
this.goalListeners.forEach(gl => sdm.addGoalExecutionListener(gl));
}
withProjectListener(listener) {
this.projectListeners.push(listener);
return this;
}
withExecutionListener(listener) {
const wrappedListener = async (gi) => {
if (gi.goalEvent.uniqueName === this.uniqueName) {
return listener(gi);
}
};
if (this.sdm) {
this.sdm.addGoalExecutionListener(wrappedListener);
}
this.goalListeners.push(wrappedListener);
return this;
}
withService(registration) {
this.addFulfillmentCallback({
goal: this,
callback: async (goalEvent, repoContext) => {
const service = await registration.service(goalEvent, repoContext);
if (!!service) {
const data = sdmGoal_1.goalData(goalEvent);
const servicesData = {};
_.set(servicesData, `${ServiceRegistration_1.ServiceRegistrationGoalDataKey}.${registration.name}`, service);
goalEvent.data = JSON.stringify(_.merge(data, servicesData));
}
return goalEvent;
},
});
return this;
}
addFulfillmentCallback(cb) {
if (this.sdm) {
this.registerCallback(cb);
}
this.callbacks.push(cb);
return this;
}
addFulfillment(fulfillment) {
if (this.sdm) {
this.registerFulfillment(fulfillment);
}
this.fulfillments.push(fulfillment);
return this;
}
registerFulfillment(fulfillment) {
if (isImplementation(fulfillment)) {
let goalExecutor = fulfillment.goalExecutor;
// Wrap the ExecuteGoal instance with WaitRules if provided
if (Goal_1.isGoalDefinition(this.definitionOrGoal) && !!this.definitionOrGoal.preCondition) {
goalExecutor = createGoal_1.createPredicatedGoalExecutor(this.definitionOrGoal.uniqueName, goalExecutor, this.definitionOrGoal.preCondition);
}
if (Goal_1.isGoalDefinition(this.definitionOrGoal) && !!this.definitionOrGoal.retryCondition) {
goalExecutor = createGoal_1.createRetryingGoalExecutor(this.definitionOrGoal.uniqueName, goalExecutor, this.definitionOrGoal.retryCondition);
}
this.sdm.addGoalImplementation(fulfillment.name, this, goalExecutor, {
pushTest: fulfillment.pushTest || commonPushTests_1.AnyPush,
progressReporter: fulfillment.progressReporter,
logInterpreter: fulfillment.logInterpreter,
projectListeners: this.projectListeners,
});
}
else if (isSideEffect(fulfillment)) {
this.sdm.addGoalSideEffect(this, fulfillment.name, fulfillment.registration, fulfillment.pushTest);
}
}
async plan(pli, goals) {
return undefined;
}
registerCallback(cb) {
this.sdm.goalFulfillmentMapper.addFulfillmentCallback(cb);
}
}
exports.FulfillableGoal = FulfillableGoal;
/**
* Goal that accepts registrations of R.
*/
class FulfillableGoalWithRegistrations extends FulfillableGoal {
constructor(definitionOrGoal, ...dependsOn) {
super(definitionOrGoal, ...dependsOn);
this.definitionOrGoal = definitionOrGoal;
this.registrations = [];
}
with(registration) {
this.registrations.push(registration);
return this;
}
}
exports.FulfillableGoalWithRegistrations = FulfillableGoalWithRegistrations;
/**
* Goal that accepts registrations of R and listeners of L.
*/
class FulfillableGoalWithRegistrationsAndListeners extends FulfillableGoalWithRegistrations {
constructor(definitionOrGoal, ...dependsOn) {
super(definitionOrGoal, ...dependsOn);
this.definitionOrGoal = definitionOrGoal;
this.listeners = [];
}
withListener(listener) {
this.listeners.push(listener);
return this;
}
}
exports.FulfillableGoalWithRegistrationsAndListeners = FulfillableGoalWithRegistrationsAndListeners;
/**
* Generic goal that can be used with a GoalDefinition.
* Register goal implementations or side effects to this goal instance.
*/
class GoalWithFulfillment extends FulfillableGoal {
withCallback(cb) {
this.addFulfillmentCallback(cb);
return this;
}
with(fulfillment) {
this.addFulfillment(fulfillment);
return this;
}
}
exports.GoalWithFulfillment = GoalWithFulfillment;
/**
* Creates a new GoalWithFulfillment instance using conventions if overwrites aren't provided
*
* Call this from your machine.ts where you configure your sdm to create a custom goal.
*
* Caution: if you wrap this in another function, then you MUST provide details.uniqueName,
* because the default is based on where in the code this `goal` function is called.
*
* @param details It is highly recommended that you supply at least uniqueName.
* @param goalExecutor
* @param options
*/
function goal(details = {}, goalExecutor, options) {
const def = getGoalDefinitionFrom(details, GoalNameGenerator_1.DefaultGoalNameGenerator.generateName(details.displayName || "goal"));
const g = new GoalWithFulfillment(def);
if (!!goalExecutor) {
const optsToUse = Object.assign({ pushTest: commonPushTests_1.AnyPush, logInterpreter: logInterpreters_1.LogSuppressor }, (!!options ? options : {}));
g.with(Object.assign({ name: def.uniqueName, goalExecutor }, optsToUse));
if (!!optsToUse.plan) {
g.plan = optsToUse.plan;
}
}
return g;
}
exports.goal = goal;
/**
* Construct a PredicatedGoalDefinition from the provided goalDetails
* @param goalDetails
* @param uniqueName
* @param definition
*/
// tslint:disable:cyclomatic-complexity
function getGoalDefinitionFrom(goalDetails, uniqueName, definition) {
if (typeof goalDetails === "string") {
return Object.assign(Object.assign({}, (definition || {})), { uniqueName: goalDetails || uniqueName });
}
else {
const defaultDefinition = Object.assign({}, (definition || {}));
const goalDetailsToUse = goalDetails || {};
if (!!goalDetailsToUse.descriptions) {
defaultDefinition.canceledDescription = goalDetailsToUse.descriptions.canceled || defaultDefinition.canceledDescription;
defaultDefinition.completedDescription = goalDetailsToUse.descriptions.completed || defaultDefinition.completedDescription;
defaultDefinition.failedDescription = goalDetailsToUse.descriptions.failed || defaultDefinition.failedDescription;
defaultDefinition.plannedDescription = goalDetailsToUse.descriptions.planned || defaultDefinition.plannedDescription;
defaultDefinition.requestedDescription = goalDetailsToUse.descriptions.requested || defaultDefinition.requestedDescription;
defaultDefinition.stoppedDescription = goalDetailsToUse.descriptions.stopped || defaultDefinition.stoppedDescription;
defaultDefinition.waitingForApprovalDescription =
goalDetailsToUse.descriptions.waitingForApproval || defaultDefinition.waitingForApprovalDescription;
defaultDefinition.waitingForPreApprovalDescription =
goalDetailsToUse.descriptions.waitingForPreApproval || defaultDefinition.waitingForPreApprovalDescription;
defaultDefinition.workingDescription = goalDetailsToUse.descriptions.inProcess || defaultDefinition.workingDescription;
}
return Object.assign(Object.assign({}, defaultDefinition), { displayName: goalDetailsToUse.displayName || defaultDefinition.displayName, uniqueName: goalDetailsToUse.uniqueName || uniqueName, environment: getEnvironment(goalDetailsToUse), approvalRequired: goalDetailsToUse.approval || defaultDefinition.approvalRequired, preApprovalRequired: goalDetailsToUse.preApproval || defaultDefinition.preApprovalRequired, retryFeasible: goalDetailsToUse.retry || defaultDefinition.retryFeasible, isolated: goalDetailsToUse.isolate || defaultDefinition.isolated, preCondition: goalDetailsToUse.preCondition });
}
}
exports.getGoalDefinitionFrom = getGoalDefinitionFrom;
/**
* Merge Goal configuration options into a final options object.
* Starts off by merging the explicitly provided options over the provided defaults; finally merges the configuration
* values at the given configuration path (prefixed with sdm.) over the previous merge.
* @param defaults
* @param explicit
* @param configurationPath
*/
function mergeOptions(defaults, explicit, configurationPath) {
const options = _.merge(_.cloneDeep(defaults), explicit || {});
if (!!configurationPath) {
const configurationOptions = configuration_1.configurationValue(`sdm.${configurationPath}`, {});
return _.merge(options, configurationOptions);
}
return options;
}
exports.mergeOptions = mergeOptions;
function getEnvironment(details) {
if (details && details.environment && typeof details.environment === "string") {
switch (details.environment) {
case "testing":
return environment_1.StagingEnvironment;
case "production":
return environment_1.ProductionEnvironment;
default:
return environment_1.IndependentOfEnvironment;
}
}
else if (details && typeof details.environment !== "string") {
return details.environment;
}
else {
return environment_1.IndependentOfEnvironment;
}
}
//# sourceMappingURL=GoalWithFulfillment.js.map