From b51bc8e5428b6d588e8b3e8549001e594982fbcf Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Tue, 26 May 2020 19:08:11 -0700 Subject: [PATCH] fix(app-delivery): could not use PipelineDeployStackAction more than once in a Stage The PipelineDeployStackAction class hard-coded the names of the CloudFormation actions it created for preparing and executing the ChangeSet. Which meant this composite action could never be used more than once in the same stage (as that would result in errors saying the action names were duplicated). Allow overriding the names of the actions to make it possible to be used more than once in the same CodePipeline stage. Fixes #3984 Fixes #8183 --- .../lib/pipeline-deploy-stack-action.ts | 18 ++++++++- .../test/test.pipeline-deploy-stack-action.ts | 39 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts index 713b662808ad4..03685cfc9c413 100644 --- a/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/lib/pipeline-deploy-stack-action.ts @@ -32,6 +32,13 @@ export interface PipelineDeployStackActionProps { */ readonly createChangeSetRunOrder?: number; + /** + * The name of the CodePipeline action creating the ChangeSet. + * + * @default 'ChangeSet' + */ + readonly createChangeSetActionName?: string; + /** * The runOrder for the CodePipeline action executing the ChangeSet. * @@ -39,6 +46,13 @@ export interface PipelineDeployStackActionProps { */ readonly executeChangeSetRunOrder?: number; + /** + * The name of the CodePipeline action creating the ChangeSet. + * + * @default 'Execute' + */ + readonly executeChangeSetActionName?: string; + /** * IAM role to assume when deploying changes. * @@ -116,7 +130,7 @@ export class PipelineDeployStackAction implements codepipeline.IAction { const changeSetName = props.changeSetName || 'CDK-CodePipeline-ChangeSet'; const capabilities = cfnCapabilities(props.adminPermissions, props.capabilities); this.prepareChangeSetAction = new cpactions.CloudFormationCreateReplaceChangeSetAction({ - actionName: 'ChangeSet', + actionName: props.createChangeSetActionName ?? 'ChangeSet', changeSetName, runOrder: createChangeSetRunOrder, stackName: props.stack.stackName, @@ -126,7 +140,7 @@ export class PipelineDeployStackAction implements codepipeline.IAction { capabilities, }); this.executeChangeSetAction = new cpactions.CloudFormationExecuteChangeSetAction({ - actionName: 'Execute', + actionName: props.executeChangeSetActionName ?? 'Execute', changeSetName, runOrder: executeChangeSetRunOrder, stackName: this.stack.stackName, diff --git a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts index d765eb887c14a..918279b480b30 100644 --- a/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts +++ b/packages/@aws-cdk/app-delivery/test/test.pipeline-deploy-stack-action.ts @@ -1,4 +1,4 @@ -import { expect, haveResource, isSuperObject } from '@aws-cdk/assert'; +import { expect, haveResource, haveResourceLike, isSuperObject } from '@aws-cdk/assert'; import * as cfn from '@aws-cdk/aws-cloudformation'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; @@ -406,6 +406,43 @@ export = nodeunit.testCase({ ); test.done(); }, + + 'allows overriding the ChangeSet and Execute action names'(test: nodeunit.Test) { + const stack = getTestStack(); + const selfUpdatingPipeline = createSelfUpdatingStack(stack); + selfUpdatingPipeline.pipeline.addStage({ + stageName: 'Deploy', + actions: [ + new PipelineDeployStackAction({ + input: selfUpdatingPipeline.synthesizedApp, + adminPermissions: true, + stack, + createChangeSetActionName: 'Prepare', + executeChangeSetActionName: 'Deploy', + }), + ], + }); + + expect(stack).to(haveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: [ + {}, + {}, + { + Name: 'Deploy', + Actions: [ + { + Name: 'Prepare', + }, + { + Name: 'Deploy', + }, + ], + }, + ], + })); + + test.done(); + }, }); class FakeAction implements codepipeline.IAction {