UNPKG

@atomist/sdm-core

Version:

Atomist Software Delivery Machine - Implementation

240 lines (223 loc) 9.26 kB
/* * Copyright © 2019 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 { buttonForCommand, GitHubRepoRef, guid, Maker, MappedParameter, MappedParameters, menuForCommand, Parameter, Parameters, } from "@atomist/automation-client"; import { CommandHandlerRegistration, fetchGoalsForCommit, GitHubRepoTargets, RepoTargetingParameters, RepoTargets, SdmGoalState, slackFooter, slackSuccessMessage, slackWarningMessage, SoftwareDeliveryMachine, toRepoTargetingParametersMaker, updateGoal, } from "@atomist/sdm"; import { bold, codeLine, italic, SlackMessage, } from "@atomist/slack-messages"; import * as _ from "lodash"; import { fetchBranchTips, tipOfBranch, } from "../../util/graph/queryCommits"; enum SdmGoalStateOrder { planned, requested, waiting_for_pre_approval, pre_approved, in_process, waiting_for_approval, approved, success, failure, stopped, skipped, canceled, } @Parameters() class SetGoalStateParameters { @MappedParameter(MappedParameters.GitHubRepositoryProvider) public providerId: string; @Parameter({ required: false }) public goal: string; @Parameter({ required: false }) public state: SdmGoalState; @Parameter({ required: false }) public msgId: string; @Parameter({ required: false, type: "boolean" }) public cancel: boolean; } export function setGoalStateCommand(sdm: SoftwareDeliveryMachine, repoTargets: Maker<RepoTargets> = GitHubRepoTargets) : CommandHandlerRegistration<SetGoalStateParameters & RepoTargetingParameters> { return { name: "SetGoalState", description: "Set state of a particular goal", intent: [`set goal state ${sdm.configuration.name.replace("@", "")}`], paramsMaker: toRepoTargetingParametersMaker(SetGoalStateParameters, repoTargets), listener: async chi => { if (!chi.parameters.msgId) { chi.parameters.msgId = guid(); } let repoData; try { repoData = await fetchBranchTips(chi.context, { providerId: chi.parameters.providerId, owner: chi.parameters.targets.repoRef.owner, repo: chi.parameters.targets.repoRef.repo, }); } catch (e) { return chi.context.messageClient.respond( slackWarningMessage( "Set Goal State", `Repository ${bold(`${ chi.parameters.targets.repoRef.owner}/${chi.parameters.targets.repoRef.repo}`)} not found`, chi.context), { id: chi.parameters.msgId }); } const branch = chi.parameters.targets.repoRef.branch || repoData.defaultBranch; let sha; try { sha = chi.parameters.targets.repoRef.sha || tipOfBranch(repoData, branch); } catch (e) { return chi.context.messageClient.respond( slackWarningMessage( "Set Goal State", `Branch ${bold(branch)} not found on ${bold(`${ chi.parameters.targets.repoRef.owner}/${chi.parameters.targets.repoRef.repo}`)}`, chi.context), { id: chi.parameters.msgId }); } const id = GitHubRepoRef.from({ owner: chi.parameters.targets.repoRef.owner, repo: chi.parameters.targets.repoRef.repo, sha, branch, }); const newParams = { ...chi.parameters, targets: { owner: id.owner, repo: id.repo, branch: id.branch, sha: id.sha, }, } as any; if (chi.parameters.cancel) { return chi.context.messageClient.respond( slackSuccessMessage( "Set Goal State", "Successfully canceled setting goal state"), { id: chi.parameters.msgId }); } else if (!chi.parameters.goal) { const goals = await fetchGoalsForCommit(chi.context, id, chi.parameters.providerId); const goalSets = _.groupBy(goals, "goalSetId"); const optionsGroups = _.map(goalSets, (v, k) => { return { text: k.slice(0, 7), options: v.map(g => ({ text: `${g.name} - ${g.state}`, value: JSON.stringify({ id: (g as any).id, name: g.name, state: g.state }), })).sort((o1, o2) => o1.text.localeCompare(o2.text)), }; }); const msg: SlackMessage = { attachments: [{ title: "Select Goal", text: `Please select one of the following goals on ${ codeLine(sha.slice(0, 7))} of ${bold(`${id.owner}/${id.repo}/${branch}`)}:`, actions: [ menuForCommand({ text: "Goals", options: optionsGroups, }, "SetGoalState", "goal", newParams), buttonForCommand( { text: "Cancel" }, "SetGoalState", { ...newParams, cancel: true }), ], fallback: "Select Goal", footer: slackFooter(), }], }; return chi.context.messageClient.respond(msg, { id: chi.parameters.msgId }); } else if (!chi.parameters.state) { const goal = JSON.parse(chi.parameters.goal); const states = _.map(SdmGoalState, v => ({ text: v, value: v })) .sort((s1, s2) => { return SdmGoalStateOrder[s1.value] - SdmGoalStateOrder[s2.value]; }); const msg: SlackMessage = { attachments: [{ title: "Select Goal State", text: `Please select the desired state of goal ${italic(goal.name)} on ${codeLine(sha.slice(0, 7))} of ${ bold(`${id.owner}/${id.repo}/${branch}`)}:`, actions: [ menuForCommand({ text: "Goal States", options: [ { text: "current state", options: states.filter(s => s.value === goal.state) }, { text: "available states", options: states.filter(s => s.value !== goal.state) }, ], }, "SetGoalState", "state", newParams), buttonForCommand( { text: "Cancel" }, "SetGoalState", { ...newParams, cancel: true }), ], fallback: "Select Goal", footer: slackFooter(), }], }; return chi.context.messageClient.respond(msg, { id: chi.parameters.msgId }); } else { const goal = JSON.parse(chi.parameters.goal); const goals = await fetchGoalsForCommit(chi.context, id, chi.parameters.providerId); const sdmGoal = goals.find(g => (g as any).id === goal.id); await updateGoal(chi.context, sdmGoal, { state: chi.parameters.state, description: sdmGoal.description, }); return chi.context.messageClient.respond( slackSuccessMessage( "Set Goal State", `Successfully set state of ${italic(goal.name)} on ${codeLine(sha.slice(0, 7))} of ${ bold(`${id.owner}/${id.repo}/${branch}`)} to ${italic(chi.parameters.state)}`), { id: chi.parameters.msgId }); } }, }; }