UNPKG

@atomist/sdm

Version:

Atomist Software Delivery Machine SDK

164 lines (132 loc) 5.33 kB
/* * 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. */ import { BaseContext, GitHubStatusContext } from "./GitHubContext"; import { GoalEnvironment, IndependentOfEnvironment } from "./support/environment"; /** * Core data for a goal */ export interface GoalDefinition { /** * Must be unique among goals * Should be camel case */ uniqueName: string; /** * Optional environment for this goal to run in. * This is meant to allow for logical grouping of goals from code, testing and production etc. */ environment?: GoalEnvironment; displayName?: string; plannedDescription?: string; requestedDescription?: string; completedDescription?: string; workingDescription?: string; failedDescription?: string; waitingForApprovalDescription?: string; waitingForPreApprovalDescription?: string; canceledDescription?: string; stoppedDescription?: string; skippedDescription?: string; // when set to true, this goal will execute in its own container/client isolated?: boolean; // when set to true, this goal requires approval before it is marked success approvalRequired?: boolean; // when set to true, this goal requires pre approval before it is requested preApprovalRequired?: boolean; // when set to true, this goal can be retried in case of failure retryFeasible?: boolean; } /** * Represents a delivery action, such as Build or Deploy. */ export class Goal { public readonly context: GitHubStatusContext; public readonly definition: GoalDefinition; get environment(): string { return this.definition.environment; } get successDescription(): string { return this.definition.completedDescription || `Complete: ${this.name}`; } get inProcessDescription(): string { return this.definition.workingDescription || `Working: ${this.name}`; } get failureDescription(): string { return this.definition.failedDescription || `Failed: ${this.name}`; } get plannedDescription(): string { return this.definition.plannedDescription || `Planned: ${this.name}`; } get requestedDescription(): string { return this.definition.requestedDescription || `Ready: ${this.name}`; } get waitingForApprovalDescription(): string { return this.definition.waitingForApprovalDescription || `Approval required: ${this.name}`; } get waitingForPreApprovalDescription(): string { return this.definition.waitingForPreApprovalDescription || `Start required: ${this.name}`; } get canceledDescription(): string { return this.definition.canceledDescription || `Canceled: ${this.name}`; } get stoppedDescription(): string { return this.definition.stoppedDescription || `Stopped: ${this.name}`; } get skippedDescription(): string { return this.definition.skippedDescription || `Skipped: ${this.name}`; } get name(): string { return this.definition.displayName || this.definition.uniqueName; } get uniqueName(): string { return this.definition.uniqueName; } constructor(definition: GoalDefinition) { this.definition = validateGoalDefinition(definition); // Default environment if hasn't been provided if (!this.definition.environment) { this.definition.environment = IndependentOfEnvironment; } this.context = BaseContext + this.definition.environment + this.definition.uniqueName; } } export class GoalWithPrecondition extends Goal { public readonly dependsOn: Goal[]; constructor(definition: GoalDefinition, ...dependsOn: Goal[]) { super(definition); this.dependsOn = dependsOn; } } export function isGoalDefinition(f: Goal | GoalDefinition): f is GoalDefinition { return !!(f as GoalDefinition).uniqueName; } export function hasPreconditions(goal: Goal): goal is GoalWithPrecondition { return !!(goal as GoalWithPrecondition).dependsOn; } const UniqueNameRegExp = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/i; function validateGoalDefinition(gd: GoalDefinition): GoalDefinition { // First replace all spaces and _ with - const uniqueName = gd.uniqueName.replace(/ /g, "-").replace(/_/g, "-"); // Now validate the part in front of # against regexp if (!UniqueNameRegExp.test(uniqueName.split("#")[0])) { throw new Error( `Goal uniqueName '${gd.uniqueName}' must consist of lower case alphanumeric characters or '-', and must start and ` + `end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '${UniqueNameRegExp}')`, ); } gd.uniqueName = uniqueName; return gd; }