diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 238fa51dbc710..42b0a435242e1 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -341,6 +341,16 @@ testingStage.addApplication(new MyApplication2(this, 'MyApp2', { })); ``` +Even more, adding a manual approval action or reserving space for some extra sequential actions +between 'Prepare' and 'Execute' ChangeSet actions is possible. + +```ts + pipeline.addApplicationStage(new MyApplication(this, 'Production'), { + manualApprovals: true, + extraRunOrderSpace: 1, + }); +``` + ## Adding validations to the pipeline You can add any type of CodePipeline Action to the pipeline in order to validate diff --git a/packages/@aws-cdk/pipelines/lib/stage.ts b/packages/@aws-cdk/pipelines/lib/stage.ts index 3f93c28808075..c7b090b3f8d02 100644 --- a/packages/@aws-cdk/pipelines/lib/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/stage.ts @@ -76,6 +76,7 @@ export class CdkStage extends CoreConstruct { */ public addApplication(appStage: Stage, options: AddStageOptions = {}) { const asm = appStage.synth(); + const extraRunOrderSpace = options.extraRunOrderSpace ?? 0; if (asm.stacks.length === 0) { // If we don't check here, a more puzzling "stage contains no actions" @@ -88,8 +89,8 @@ export class CdkStage extends CoreConstruct { stack => stack.dependencies.map(d => d.id)); for (const stacks of sortedTranches) { - const runOrder = this.nextSequentialRunOrder(2); // We need 2 actions - let executeRunOrder = runOrder + 1; + const runOrder = this.nextSequentialRunOrder(extraRunOrderSpace + 2); // 2 actions for Prepare/Execute ChangeSet + let executeRunOrder = runOrder + extraRunOrderSpace + 1; // If we need to insert a manual approval action, then what's the executeRunOrder // now is where we add a manual approval step, and we allocate 1 more runOrder @@ -371,6 +372,15 @@ export interface AddStageOptions { * @default false */ readonly manualApprovals?: boolean; + /** + * Add room for extra actions + * + * You can use this to make extra room in the runOrder sequence between the + * changeset 'prepare' and 'execute' actions and insert your own actions there. + * + * @default 0 + */ + readonly extraRunOrderSpace?: number; } /** diff --git a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts index ddd38e7a3a9c2..fcfede261208a 100644 --- a/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts +++ b/packages/@aws-cdk/pipelines/test/stack-ordering.test.ts @@ -78,6 +78,37 @@ test('manual approval is inserted in correct location', () => { }); }); +test('extra space for sequential intermediary actions is reserved', () => { + // WHEN + pipeline.addApplicationStage(new TwoStackApp(app, 'MyApp'), { + extraRunOrderSpace: 1, + }); + + // THEN + expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: arrayWith({ + Name: 'MyApp', + Actions: sortedByRunOrder([ + objectLike({ + Name: 'Stack1.Prepare', + RunOrder: 1, + }), + objectLike({ + Name: 'Stack1.Deploy', + RunOrder: 3, + }), + objectLike({ + Name: 'Stack2.Prepare', + RunOrder: 4, + }), + objectLike({ + Name: 'Stack2.Deploy', + RunOrder: 6, + }), + ]), + }), + }); +}); class TwoStackApp extends Stage { constructor(scope: Construct, id: string, props?: StageProps) {