UNPKG

@atomist/sdm

Version:

Atomist Software Delivery Machine SDK

241 lines 9.91 kB
"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.AbstractSoftwareDeliveryMachine = void 0; const string_1 = require("@atomist/automation-client/lib/internal/util/string"); const logger_1 = require("@atomist/automation-client/lib/util/logger"); const _ = require("lodash"); const goalContribution_1 = require("../../api/dsl/goalContribution"); const ReportProgress_1 = require("../../api/goal/progress/ReportProgress"); const ConfigurationValues_1 = require("../../api/machine/ConfigurationValues"); const Registerable_1 = require("../../api/machine/Registerable"); const commonPushTests_1 = require("../../api/mapping/support/commonPushTests"); const PushRules_1 = require("../../api/mapping/support/PushRules"); const goalApprovalRequestVote_1 = require("../../api/registration/goalApprovalRequestVote"); const DefaultGoalImplementationMapper_1 = require("../goal/DefaultGoalImplementationMapper"); const goalSetListener_1 = require("../listener/goalSetListener"); const logInterpreters_1 = require("../log/logInterpreters"); const HandlerRegistrationManagerSupport_1 = require("./HandlerRegistrationManagerSupport"); const ListenerRegistrationManagerSupport_1 = require("./ListenerRegistrationManagerSupport"); /** * Abstract support class for implementing a SoftwareDeliveryMachine. */ class AbstractSoftwareDeliveryMachine extends ListenerRegistrationManagerSupport_1.ListenerRegistrationManagerSupport { /** * Construct a new software delivery machine, with zero or * more goal setters. * @param {string} name * @param configuration automation client configuration we're running in * @param {GoalSetter} goalSetters tell me what to do on a push. Hint: start with "whenPushSatisfies(...)" */ constructor(name, configuration, goalSetters) { super(); this.name = name; this.configuration = configuration; this.extensionPacks = []; this.registrationManager = new HandlerRegistrationManagerSupport_1.HandlerRegistrationManagerSupport(this); this.disposalGoalSetters = []; this.goalApprovalRequestVoters = []; this.goalApprovalRequestVoteDecisionManager = goalApprovalRequestVote_1.UnanimousGoalApprovalRequestVoteDecisionManager; Registerable_1.registrableManager().register(this); // If we didn't get any goal setters don't register a mapping if (goalSetters.length > 0) { this.pushMap = new PushRules_1.PushRules("Goal setters", _.flatten(goalSetters)); } // Register the goal completion listener to update goal set state this.addGoalCompletionListener(goalSetListener_1.GoalSetGoalCompletionListener); } get goalFulfillmentMapper() { if (!this.fulfillmentMapper) { this.fulfillmentMapper = new DefaultGoalImplementationMapper_1.DefaultGoalImplementationMapper(); } return this.fulfillmentMapper; } /** * Return the PushMapping that will be used on pushes. * Useful in testing goal setting. * @return {PushMapping<Goals>} */ get pushMapping() { return this.pushMap; } /** * Provide the implementation for a goal. * The SDM will run it as soon as the goal is ready (all preconditions are met). * If you provide a PushTest, then the SDM can assign different implementations * to the same goal based on the code in the project. * @param {string} implementationName * @param {Goal} goal * @param {ExecuteGoal} goalExecutor * @param options PushTest to narrow matching & InterpretLog that can handle * the log from the goalExecutor function * @return {this} */ addGoalImplementation(implementationName, goal, goalExecutor, options) { const implementation = { implementationName, goal, goalExecutor, pushTest: _.get(options, "pushTest") || commonPushTests_1.AnyPush, logInterpreter: _.get(options, "logInterpreter") || logInterpreters_1.LogSuppressor, progressReporter: _.get(options, "progressReporter") || ReportProgress_1.NoProgressReport, projectListeners: _.get(options, "projectListeners") || [], }; this.goalFulfillmentMapper.addImplementation(implementation); return this; } addGoalApprovalRequestVoter(vote) { this.goalApprovalRequestVoters.push(vote); return this; } setGoalApprovalRequestVoteDecisionManager(manager) { this.goalApprovalRequestVoteDecisionManager = manager; return this; } addCommand(cmd) { if (this.shouldRegister(cmd)) { this.registrationManager.addCommand(cmd); } return this; } addGeneratorCommand(gen) { if (this.shouldRegister(gen)) { this.registrationManager.addGeneratorCommand(gen); } return this; } addCodeTransformCommand(ct) { if (this.shouldRegister(ct)) { this.registrationManager.addCodeTransformCommand(ct); } return this; } addCodeInspectionCommand(cir) { if (this.shouldRegister(cir)) { this.registrationManager.addCodeInspectionCommand(cir); } return this; } addEvent(e) { this.registrationManager.addEvent(e); return this; } addIngester(i) { if (typeof i === "string") { this.registrationManager.addIngester({ ingester: i, }); } else { this.registrationManager.addIngester(i); } return this; } /** * Declare that a goal will become successful based on something outside. * For instance, ArtifactGoal succeeds because of an ImageLink event. * This tells the SDM that it does not need to run anything when this * goal becomes ready. */ addGoalSideEffect(goal, sideEffectName, registration, pushTest = commonPushTests_1.AnyPush) { this.goalFulfillmentMapper.addSideEffect({ goal, sideEffectName, pushTest, registration, }); return this; } addGoalContributions(goalContributions) { if (!this.pushMap) { this.pushMap = goalContributions; } else { this.pushMap = goalContribution_1.enrichGoalSetters(this.pushMap, goalContributions); } return this; } withPushRules(contributor, ...contributors) { return this.addGoalContributions(goalContribution_1.goalContributors(contributor, ...contributors)); } addExtensionPacks(...packs) { for (const pack of packs) { const found = this.extensionPacks.find(existing => existing.name === pack.name && existing.vendor === pack.vendor); if (!!found) { pack.name = `${pack.name}-${string_1.guid().slice(0, 7)}`; } this.addExtensionPack(pack); if (!!pack.goalContributions) { this.addGoalContributions(pack.goalContributions); } } return this; } addExtensionPack(pack) { logger_1.logger.debug("Adding extension pack '%s' version %s from %s", pack.name, pack.version, pack.vendor); ConfigurationValues_1.validateConfigurationValues(this.configuration, pack); pack.configure(this); this.extensionPacks.push(pack); return this; } /** * Invoke StartupListeners. */ async notifyStartupListeners() { const i = { addressAdmin: this.configuration.sdm.adminAddressChannels || (async (msg) => { logger_1.logger.debug("startup: %j", msg); }), sdm: this, }; // Register the startup listener to schedule the triggered listeners // It is important we schedule the triggers after the startup listeners are done! this.startupListeners.push(async () => this.scheduleTriggeredListeners()); // Execute startupListeners in registration order await this.startupListeners.map(l => l(i)).reduce(p => p.then(), Promise.resolve()); } /** * Schedule the triggered listeners */ scheduleTriggeredListeners() { const i = { addressAdmin: this.configuration.sdm.adminAddressChannels || (async (msg) => { logger_1.logger.debug("trigger: %j", msg); }), sdm: this, }; this.triggeredListeners.forEach(t => { if (t.trigger && t.trigger.cron) { const cj = require("cron"); const cron = new cj.CronJob({ cronTime: t.trigger.cron, onTick: () => t.listener(i), unrefTimeout: true, }); cron.start(); } if (t.trigger && t.trigger.interval) { setInterval(() => t.listener(i), t.trigger.interval).unref(); } }); } shouldRegister(cm) { return !!cm.registerWhen ? cm.registerWhen(this.configuration) : true; } } exports.AbstractSoftwareDeliveryMachine = AbstractSoftwareDeliveryMachine; //# sourceMappingURL=AbstractSoftwareDeliveryMachine.js.map