import { buttonForCommand , GitProject , logger , } from "@atomist/automation-client" ; import { CommandHandlerRegistration , PushImpactListenerInvocation , slackQuestionMessage , } from "@atomist/sdm" ; import { Aspect , fingerprintOf , PublishFingerprintsFor , RepoIdentification , sendFingerprintsToAtomistFor , } from "@atomist/sdm-pack-fingerprint" ; export interface SuggestTagData { readonly tag : string ; readonly reason : string ; } export interface TagSuggester extends SuggestTagData { test ( pli ) : Promise < boolean > ; } const SuggestTagType = "suggest-tag" ; const SetFingerprintCommandName = "set-fingerprint" ; type RepoTaggingParams = { url : string ; } & RepoIdentification & SuggestTagData ; /**
 * Add a test to see whether we should suggest a tag to be
 * confirmed by humans via chat.
 * Only works if suggestTagCommand is added to the SDM.
 */ export function suggestTag ( suggester ) { return { name : SuggestTagType , displayName : undefined , extract : async ( ) => [ ] , consolidate : async ( fingerprints , p , pli ) => { const pili = { ... pli , project : p as GitProject , } ; const suggestion = await suggester . test ( pili ) ; return suggestion ? [ fingerprintOf ( { type : SuggestTagType , name : suggestTag . name , data : { tag : suggester . tag , reason : suggester . reason , } , } ) ] : [ ] ; } , toDisplayableFingerprint : fp => fp . data . tag , workflows : [ async ( pli , diffs ) => { if ( diffs . length > 0 ) { if ( diffs . map ( d => d . to ) . some ( to => to . data . tag ) ) { const parameters = { owner : pli . id . owner , repo : pli . id . repo , branch : pli . push . branch , sha : pli . push . after . sha , url : pli . id . url , tag : suggester . tag , reason : suggester . reason , } ; logger . info ( "Creating button for command %s with parameters: %j" , SetFingerprintCommandName , parameters ) ; const askAboutTagging = slackQuestionMessage ( "Tag?" , `This commit looks like it should be tagged with \`${ suggester . tag }\`, because\n_${ suggester . reason }_` , { actions : [ buttonForCommand ( { text : `Tag with ${ suggester . tag }` } , SetFingerprintCommandName , parameters ) ] , } ) ; await pli . addressChannels ( askAboutTagging ) ; } } return [ { abstain : true } ] ; } , ] , } ; } type { string } export const ConfirmedTagType = "confirmed-tag" ; /**
 * Provides Aspect metadata for ConfirmedTag
 */ export const ConfirmedTags = { name : ConfirmedTagType , displayName : "Human confirmed tag" , return { Promise < any [ ] > } extract : async ( ) => [ ] , toDisplayableFingerprint : fp => `${ fp . data . tag } because ${ fp . data . reason }` , } ; param { PublishFingerprintsFor } publisher return { CommandHandlerRegistration < RepoTaggingParams > } export function addSuggestedFingerprintCommand ( publisher = sendFingerprintsToAtomistFor ) { return { name : SetFingerprintCommandName , parameters : { owner : { } , repo : { } , branch : { } , sha : { } , tag : { } , reason : { } , url : { } , } , listener : async ( ci ) => { const fp = fingerprintOf < SuggestTagData > ( { type : ConfirmedTagType , name : ci . parameters . tag , data : { tag : ci . parameters . tag , reason : ci . parameters . reason , } , } ) ; logger . info ( "Publishing fingerprint %j against %j" , fp , ci . parameters ) ; await publisher ( ci , ci . parameters , [ fp ] , { } ) ; } , } ; }