diff --git a/.vscode/launch.json b/.vscode/launch.json index 66f6db80dcd14..936bf55717b05 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { // Has convenient settings for attaching to a NodeJS process for debugging purposes // that are NOT the default and otherwise every developers has to configure for diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline.ts index 258b3e80d1bdc..f399a5d004a8e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline.ts @@ -1,60 +1,139 @@ // eslint-disable-next-line import/no-extraneous-dependencies /// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true -import * as sqs from 'aws-cdk-lib/aws-sqs'; -import { App, Stack, StackProps, Stage, StageProps } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; +import { App, Fn, Stack, StackProps, Stage, StageProps } from 'aws-cdk-lib'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as s3 from 'aws-cdk-lib/aws-s3'; import * as pipelines from 'aws-cdk-lib/pipelines'; - +import { Construct } from 'constructs'; class PipelineStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); + const vpc = ec2.Vpc.fromVpcAttributes(this, 'vpc', { + availabilityZones: ['eu-central-1a', 'eu-central-1b', 'eu-central-1c'], + vpcId: Fn.importValue('VPC1-VPC-ID'), + privateSubnetIds: [ + Fn.importValue('VPC1-AZ1Subnet1'), + Fn.importValue('VPC1-AZ2Subnet1'), + Fn.importValue('VPC1-AZ3Subnet1'), + ], + privateSubnetRouteTableIds: [ + Fn.importValue('VPC1-RouteTableIDAZ1'), + Fn.importValue('VPC1-RouteTableIDAZ2'), + Fn.importValue('VPC1-RouteTableIDAZ3'), + ], + }); + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { synth: new pipelines.ShellStep('Synth', { - input: pipelines.CodePipelineSource.gitHub('rix0rrr/cdk-pipelines-demo', 'main'), - commands: [ - 'npm ci', - 'npm run build', - 'npx cdk synth', - ], + input: pipelines.CodePipelineSource.s3( + s3.Bucket.fromBucketName( + this, + 'SourceBucket-' + id, + '290582178775-gitsync', + ), + 'mobility-operations-experience/serviceteam/services/test-cdk-contribution/main/src/' + + 'mobility-operations-experience_serviceteam_services_test-cdk-contribution.zip', + ), + commands: ['npm ci', 'npm run build', 'npx cdk synth'], }), + pipelineName: 'test-cdk-contribution', + selfMutation: false, + synthCodeBuildDefaults: { + vpc: vpc, + }, + allPrepareNodesFirst: true, }); - pipeline.addStage(new AppStage(this, 'Beta')); + // const beta = new AppStage(this, 'Beta'); + // pipeline.addStage(beta, { + // allPrepareNodesFirst: true, + // stackSteps: [ + // { + // stack: beta.stack1, + // changeSet: [new pipelines.ManualApprovalStep('b approve')], // Executed after stack is prepared but before the stack is deployed + // }, + // ], + // }); + // const st=pipeline.addStage(new AppStage(this, 'test'), { + // allPrepareNodesFirst: true, + // postPrepare: [new pipelines.ManualApprovalStep('Approval0')], + // }); + // console.log(st.postPrepare); + const group = pipeline + .addWave('Wave1', { + postPrepare: [new pipelines.ManualApprovalStep('Approval1')], + }); + // group.addPostPrepare(new pipelines.ManualApprovalStep('Approval11')); - const group = pipeline.addWave('Wave1'); - group.addStage(new AppStage(this, 'Prod1')); + // group.addStage(new AppStage2(this, 'Prod1'), { + // // postPrepare: [new pipelines.ManualApprovalStep('Approval13')], + // }); group.addStage(new AppStage(this, 'Prod2')); - const group2 = pipeline.addWave('Wave2'); + const group2 = pipeline.addWave('Wave2', { + // postPrepare: [new pipelines.ManualApprovalStep('Approval2')], + }); group2.addStage(new AppStage(this, 'Prod3')); - group2.addStage(new AppStage(this, 'Prod4')); - group2.addStage(new AppStage(this, 'Prod5')); - group2.addStage(new AppStage(this, 'Prod6')); + // group2.addStage(new AppStage(this, 'Prod4')); + // group2.addStage(new AppStage(this, 'Prod5')); + // group2.addStage(new AppStage(this, 'Prod6')); } + } + class AppStage extends Stage { + public readonly stack1: Stack; + public readonly stack2: Stack; constructor(scope: Construct, id: string, props?: StageProps) { super(scope, id, props); - const stack1 = new Stack(this, 'Stack1'); - const queue1 = new sqs.Queue(stack1, 'Queue'); + this.stack1 = new Stack(this, 'Stack1'); - const stack2 = new Stack(this, 'Stack2'); - new sqs.Queue(stack2, 'OtherQueue', { - deadLetterQueue: { - queue: queue1, - maxReceiveCount: 5, - }, - }); + // const q1=new sqs.Queue(this.stack1, 'Queue'); + this.stack2 = new Stack(this, 'Stack2'); + this.stack2.addDependency(this.stack1); + // new sqs.Queue(this.stack2, 'OtherQueue', { deadLetterQueue: { queue: q1, maxReceiveCount: 1 } }); } + } +// class AppStage3 extends Stage { +// public readonly stack1: Stack; + +// constructor(scope: Construct, id: string, props?: StageProps) { +// super(scope, id, props); + +// this.stack1 = new Stack(this, 'Stack1'); + + +// // new sqs.Queue(this.stack2, 'OtherQueue', { deadLetterQueue: { queue: q1, maxReceiveCount: 1 } }); +// } +// } +// class AppStage4 extends Stage { + +// public readonly stack2: Stack; +// constructor(scope: Construct, id: string, props?: StageProps) { +// super(scope, id, props); + +// // const q1=new sqs.Queue(this.stack1, 'Queue'); +// this.stack2 = new Stack(this, 'Stack2'); +// // new sqs.Queue(this.stack2, 'OtherQueue', { deadLetterQueue: { queue: q1, maxReceiveCount: 1 } }); +// } +// } +// class AppStage2 extends Stage { +// public readonly stack3: Stack; +// constructor(scope: Construct, id: string, props?: StageProps) { +// super(scope, id, props); +// this.stack3 = new Stack(this, 'Stack3'); +// } +// } + const app = new App({ context: { '@aws-cdk/core:newStyleStackSynthesis': '1', }, }); -new PipelineStack(app, 'PipelineStack'); +new PipelineStack(app, 'TestCdkContributionStack'); app.synth(); \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_allPrepareNodesFirst.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_allPrepareNodesFirst.ts new file mode 100644 index 0000000000000..391166fd12628 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_allPrepareNodesFirst.ts @@ -0,0 +1,75 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +/// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true +import { App, Stack, StackProps, Stage, StageProps } from 'aws-cdk-lib'; +import * as sqs from 'aws-cdk-lib/aws-sqs'; +import * as pipelines from 'aws-cdk-lib/pipelines'; +import { Construct } from 'constructs'; + +class PipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.gitHub( + 'rix0rrr/cdk-pipelines-demo', + 'main', + ), + commands: ['npm ci', 'npm run build', 'npx cdk synth'], + }), + allPrepareNodesFirst: true, + }); + + pipeline.addStage(new AppStage(this, 'Beta'), { + }); + + const group = pipeline.addWave('Wave1'); + group.addStage(new AppStage(this, 'Prod1')); + group.addStage(new AppStage(this, 'Prod2')); + + const group2 = pipeline.addWave('Wave2'); + group2.addStage(new AppStage2(this, 'Prod3')); + group2.addStage(new AppStage3(this, 'Prod4')); + } +} + +class AppStage extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + const stack1 = new Stack(this, 'Stack1'); + const queue1 = new sqs.Queue(stack1, 'Queue'); + + const stack2 = new Stack(this, 'Stack2'); + new sqs.Queue(stack2, 'OtherQueue', { + deadLetterQueue: { + queue: queue1, + maxReceiveCount: 5, + }, + }); + } +} + +class AppStage2 extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + new Stack(this, 'Stack1'); + } +} + +class AppStage3 extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + new Stack(this, 'Stack2'); + } +} + +const app = new App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +new PipelineStack(app, 'PipelineWithAllPrepareNodesFirstStack'); +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_postPrepare.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_postPrepare.ts new file mode 100644 index 0000000000000..72ca8de2d3843 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline_with_postPrepare.ts @@ -0,0 +1,79 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +/// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true +import { App, Stack, StackProps, Stage, StageProps } from 'aws-cdk-lib'; +import * as sqs from 'aws-cdk-lib/aws-sqs'; +import * as pipelines from 'aws-cdk-lib/pipelines'; +import { Construct } from 'constructs'; + +class PipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const pipeline = new pipelines.CodePipeline(this, 'PipelineWithPostPrepare', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.gitHub( + 'rix0rrr/cdk-pipelines-demo', + 'main', + ), + commands: ['npm ci', 'npm run build', 'npx cdk synth'], + }), + allPrepareNodesFirst: true, + }); + + pipeline.addStage(new AppStage(this, 'Beta'), { + postPrepare: [new pipelines.ManualApprovalStep('Approval0')], + }); + + const group = pipeline.addWave('Wave1', { + + postPrepare: [new pipelines.ManualApprovalStep('Approval1')], + }); + group.addStage(new AppStage(this, 'Prod1')); + group.addStage(new AppStage(this, 'Prod2')); + + const group2 = pipeline.addWave('Wave2', { postPrepare: [new pipelines.ManualApprovalStep('Approval2')] }); + group2.addStage(new AppStage2(this, 'Prod3')); + group2.addStage(new AppStage3(this, 'Prod4')); + } +} + +class AppStage extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + const stack1 = new Stack(this, 'Stack1'); + const queue1 = new sqs.Queue(stack1, 'Queue'); + + const stack2 = new Stack(this, 'Stack2'); + new sqs.Queue(stack2, 'OtherQueue', { + deadLetterQueue: { + queue: queue1, + maxReceiveCount: 5, + }, + }); + } +} + +class AppStage2 extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + new Stack(this, 'Stack1'); + } +} + +class AppStage3 extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + new Stack(this, 'Stack2'); + } +} + +const app = new App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +new PipelineStack(app, 'PipelineWithPostPrepareStack'); +app.synth(); diff --git a/packages/aws-cdk-lib/pipelines/README.md b/packages/aws-cdk-lib/pipelines/README.md index 4eefcbf3a8991..4d2233f2862ed 100644 --- a/packages/aws-cdk-lib/pipelines/README.md +++ b/packages/aws-cdk-lib/pipelines/README.md @@ -1,6 +1,5 @@ # CDK Pipelines - A construct library for painless Continuous Delivery of CDK applications. CDK Pipelines is an *opinionated construct library*. It is purpose-built to @@ -162,9 +161,9 @@ has been bootstrapped (see below), and then execute deploying the Run the following commands to get the pipeline going: ```console -$ git commit -a -$ git push -$ cdk deploy PipelineStack +git commit -a +git push +cdk deploy PipelineStack ``` Administrative permissions to the account are only necessary up until @@ -565,6 +564,38 @@ class PipelineStack extends Stack { } ``` +#### Deploying with all change sets at first + +Deployment is done by default with `CodePipeline` engine using change sets, +i.e. to first create a change set and then execute it. This allows you to inject +steps that inspect the change set and approve or reject it, but failed deployments +are not retryable and creation of the change set costs time. The change sets tough are +being sorted within the pipeline by its dependencies. This means that some of the change set +might not be at the top level of a stage. Therefore there is the possibility to define, that +every change set is set as the first action (all in parallel) + +The creation of change sets at the top level can be switched on by setting `allPrepareNodesFirst: true`. +`useChangeSets` needs to be activated in order to use this feature. + +```ts +declare const synth: pipelines.ShellStep; + +class PipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth, + + allPrepareNodesFirst: true, + }); + } +} +``` + +It is further possible to add Steps in between the change sets and the deploy nodes (e.g. a manual approval step). This allows inspecting all change sets before deploying the stacks +in the desired order. + ### Validation Every `addStage()` and `addWave()` command takes additional options. As part of these options, @@ -1608,7 +1639,7 @@ $ env CDK_NEW_BOOTSTRAP=1 npx cdk bootstrap \ ``` - Update all impacted stacks in the pipeline to use this new qualifier. -See https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html for more info. +See for more info. ```ts new Stack(this, 'MyStack', { diff --git a/packages/aws-cdk-lib/pipelines/lib/blueprint/stack-deployment.ts b/packages/aws-cdk-lib/pipelines/lib/blueprint/stack-deployment.ts index 5732ec0724fd3..4e6268e22a3ef 100644 --- a/packages/aws-cdk-lib/pipelines/lib/blueprint/stack-deployment.ts +++ b/packages/aws-cdk-lib/pipelines/lib/blueprint/stack-deployment.ts @@ -1,9 +1,10 @@ import * as path from 'path'; -import { AssetType } from './asset-type'; -import { Step } from './step'; import * as cxapi from '../../../cx-api'; import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; import { isAssetManifest } from '../private/cloud-assembly-internals'; +import { AssetType } from './asset-type'; +import { Step } from './step'; + /** * Properties for a `StackDeployment` @@ -91,11 +92,14 @@ export class StackDeployment { /** * Build a `StackDeployment` from a Stack Artifact in a Cloud Assembly. */ - public static fromArtifact(stackArtifact: cxapi.CloudFormationStackArtifact): StackDeployment { + public static fromArtifact( + stackArtifact: cxapi.CloudFormationStackArtifact, + ): StackDeployment { const artRegion = stackArtifact.environment.region; const region = artRegion === cxapi.UNKNOWN_REGION ? undefined : artRegion; const artAccount = stackArtifact.environment.account; - const account = artAccount === cxapi.UNKNOWN_ACCOUNT ? undefined : artAccount; + const account = + artAccount === cxapi.UNKNOWN_ACCOUNT ? undefined : artAccount; return new StackDeployment({ account, @@ -104,7 +108,10 @@ export class StackDeployment { stackArtifactId: stackArtifact.id, constructPath: stackArtifact.hierarchicalId, stackName: stackArtifact.stackName, - absoluteTemplatePath: path.join(stackArtifact.assembly.directory, stackArtifact.templateFile), + absoluteTemplatePath: path.join( + stackArtifact.assembly.directory, + stackArtifact.templateFile, + ), assumeRoleArn: stackArtifact.assumeRoleArn, executionRoleArn: stackArtifact.cloudFormationExecutionRoleArn, assets: extractStackAssets(stackArtifact), @@ -206,6 +213,12 @@ export class StackDeployment { */ public readonly post: Step[] = []; + /** + * Additional steps to run after all of the prepare-nodes in the stage + */ + + public readonly postPrepare: Step[] = []; + private constructor(props: StackDeploymentProps) { this.stackArtifactId = props.stackArtifactId; this.constructPath = props.constructPath; @@ -216,7 +229,9 @@ export class StackDeployment { this.executionRoleArn = props.executionRoleArn; this.stackName = props.stackName; this.absoluteTemplatePath = props.absoluteTemplatePath; - this.templateUrl = props.templateS3Uri ? s3UrlFromUri(props.templateS3Uri, props.region) : undefined; + this.templateUrl = props.templateS3Uri + ? s3UrlFromUri(props.templateS3Uri, props.region) + : undefined; this.assets = new Array(); @@ -242,10 +257,16 @@ export class StackDeployment { * @param changeSet steps executed after stack.prepare and before stack.deploy * @param post steps executed after stack.deploy */ - public addStackSteps(pre: Step[], changeSet: Step[], post: Step[]) { + public addStackSteps( + pre: Step[], + changeSet: Step[], + post: Step[], + postPrepare: Step[], + ) { this.pre.push(...pre); this.changeSet.push(...changeSet); this.post.push(...post); + this.postPrepare.push(...postPrepare); } } diff --git a/packages/aws-cdk-lib/pipelines/lib/blueprint/stage-deployment.ts b/packages/aws-cdk-lib/pipelines/lib/blueprint/stage-deployment.ts index 813e7aacf9f12..78fa4f79d3daa 100644 --- a/packages/aws-cdk-lib/pipelines/lib/blueprint/stage-deployment.ts +++ b/packages/aws-cdk-lib/pipelines/lib/blueprint/stage-deployment.ts @@ -1,9 +1,9 @@ -import { StackDeployment } from './stack-deployment'; -import { StackSteps, Step } from './step'; import * as cdk from '../../../core'; import { CloudFormationStackArtifact } from '../../../cx-api'; import { isStackArtifact } from '../private/cloud-assembly-internals'; import { pipelineSynth } from '../private/construct-internals'; +import { StackDeployment } from './stack-deployment'; +import { StackSteps, Step } from './step'; /** * Properties for a `StageDeployment` @@ -30,6 +30,13 @@ export interface StageDeploymentProps { */ readonly post?: Step[]; + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + * @default - No additional steps + */ + readonly postPrepare?: Step[]; + /** * Instructions for additional steps that are run at the stack level * @@ -56,36 +63,54 @@ export class StageDeployment { if (assembly.stacks.length === 0) { // If we don't check here, a more puzzling "stage contains no actions" // error will be thrown come deployment time. - throw new Error(`The given Stage construct ('${stage.node.path}') should contain at least one Stack`); + throw new Error( + `The given Stage construct ('${stage.node.path}') should contain at least one Stack`, + ); } - const stepFromArtifact = new Map(); + const stepFromArtifact = new Map< + CloudFormationStackArtifact, + StackDeployment + >(); for (const artifact of assembly.stacks) { const step = StackDeployment.fromArtifact(artifact); stepFromArtifact.set(artifact, step); } if (props.stackSteps) { for (const stackstep of props.stackSteps) { - const stackArtifact = assembly.getStackArtifact(stackstep.stack.artifactId); + const stackArtifact = assembly.getStackArtifact( + stackstep.stack.artifactId, + ); const thisStep = stepFromArtifact.get(stackArtifact); if (!thisStep) { - throw new Error('Logic error: we just added a step for this artifact but it disappeared.'); + throw new Error( + 'Logic error: we just added a step for this artifact but it disappeared.', + ); } - thisStep.addStackSteps(stackstep.pre ?? [], stackstep.changeSet ?? [], stackstep.post ?? []); + thisStep.addStackSteps( + stackstep.pre ?? [], + stackstep.changeSet ?? [], + stackstep.post ?? [], + stackstep.postPrepare ?? [], + ); } } for (const artifact of assembly.stacks) { const thisStep = stepFromArtifact.get(artifact); if (!thisStep) { - throw new Error('Logic error: we just added a step for this artifact but it disappeared.'); + throw new Error( + 'Logic error: we just added a step for this artifact but it disappeared.', + ); } const stackDependencies = artifact.dependencies.filter(isStackArtifact); for (const dep of stackDependencies) { const depStep = stepFromArtifact.get(dep); if (!depStep) { - throw new Error(`Stack '${artifact.id}' depends on stack not found in same Stage: '${dep.id}'`); + throw new Error( + `Stack '${artifact.id}' depends on stack not found in same Stage: '${dep.id}'`, + ); } thisStep.addStackDependency(depStep); } @@ -112,6 +137,13 @@ export class StageDeployment { */ public readonly post: Step[]; + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + * @default - No additional steps + */ + public readonly postPrepare: Step[]; + /** * Instructions for additional steps that are run at stack level */ @@ -123,12 +155,16 @@ export class StageDeployment { */ public readonly prepareStep?: boolean; + private constructor( /** The stacks deployed in this stage */ - public readonly stacks: StackDeployment[], props: StageDeploymentProps = {}) { + public readonly stacks: StackDeployment[], + props: StageDeploymentProps = {}, + ) { this.stageName = props.stageName ?? ''; this.pre = props.pre ?? []; this.post = props.post ?? []; + this.postPrepare = props.postPrepare ?? []; this.stackSteps = props.stackSteps ?? []; } @@ -145,4 +181,11 @@ export class StageDeployment { public addPost(...steps: Step[]) { this.post.push(...steps); } + + /** + * Add an additional step to run after all of the stacks in this stage + */ + public addPostPrepare(...steps: Step[]) { + this.postPrepare.push(...steps); + } } \ No newline at end of file diff --git a/packages/aws-cdk-lib/pipelines/lib/blueprint/step.ts b/packages/aws-cdk-lib/pipelines/lib/blueprint/step.ts index 86a6a5d8eca29..6fc586fb68ed5 100644 --- a/packages/aws-cdk-lib/pipelines/lib/blueprint/step.ts +++ b/packages/aws-cdk-lib/pipelines/lib/blueprint/step.ts @@ -1,7 +1,7 @@ -import { FileSet, IFileSetProducer } from './file-set'; -import { StackOutputReference } from './shell-step'; import { Stack, Token } from '../../../core'; import { StepOutput } from '../helpers-internal/step-output'; +import { FileSet, IFileSetProducer } from './file-set'; +import { StackOutputReference } from './shell-step'; /** * A generic Step which can be added to a Pipeline @@ -142,6 +142,13 @@ export interface StackSteps { */ readonly pre?: Step[]; + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + * @default - No additional steps + */ + readonly postPrepare?: Step[]; + /** * Steps that execute after stack is prepared but before stack is deployed * diff --git a/packages/aws-cdk-lib/pipelines/lib/blueprint/wave.ts b/packages/aws-cdk-lib/pipelines/lib/blueprint/wave.ts index 50a9527ead786..1b9a82edac1fa 100644 --- a/packages/aws-cdk-lib/pipelines/lib/blueprint/wave.ts +++ b/packages/aws-cdk-lib/pipelines/lib/blueprint/wave.ts @@ -19,6 +19,14 @@ export interface WaveProps { * @default - No additional steps */ readonly post?: Step[]; + + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + * @default - No additional steps + */ + readonly postPrepare?: Step[]; + } /** @@ -35,16 +43,27 @@ export class Wave { */ public readonly post: Step[]; + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + */ + public readonly postPrepare: Step[]; + /** * The stages that are deployed in this wave */ public readonly stages: StageDeployment[] = []; + constructor( /** Identifier for this Wave */ - public readonly id: string, props: WaveProps = {}) { + public readonly id: string, + props: WaveProps = {}, + ) { this.pre = props.pre ?? []; this.post = props.post ?? []; + this.postPrepare = props.postPrepare ?? []; + } /** @@ -72,6 +91,13 @@ export class Wave { public addPost(...steps: Step[]) { this.post.push(...steps); } + + /** + * Add an additional step to run after all of the stacks in this stage + */ + public addPostPrepare(...steps: Step[]) { + this.postPrepare.push(...steps); + } } /** @@ -92,12 +118,21 @@ export interface AddStageOpts { */ readonly post?: Step[]; + /** + * Additional steps to run after all of the prepare-nodes in the stage. If this property is set allPrepareNodesFirst has to be set to true also. This is the case, because dependency cycle will occour otherwise. + * + * @default - No additional steps + */ + readonly postPrepare?: Step[]; + /** * Instructions for stack level steps * * @default - No additional instructions */ readonly stackSteps?: StackSteps[]; + + } /** @@ -117,4 +152,12 @@ export interface WaveOptions { * @default - No additional steps */ readonly post?: Step[]; + + /** + * Additional steps to run after all of the prepare-nodes in the stage + * + * @default - No additional steps + */ + readonly postPrepare?: Step[]; + } \ No newline at end of file diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts index 92ad511679ebc..fbe47beac94dc 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts @@ -1,3 +1,4 @@ +import { Construct } from 'constructs'; import * as fs from 'fs'; import * as path from 'path'; import { Construct } from 'constructs'; @@ -13,11 +14,11 @@ import * as cpa from '../../../aws-codepipeline-actions'; import * as ec2 from '../../../aws-ec2'; import * as iam from '../../../aws-iam'; import * as s3 from '../../../aws-s3'; -import { Aws, CfnCapabilities, Duration, PhysicalName, Stack, Names } from '../../../core'; +import { Aws, CfnCapabilities, Duration, Names, PhysicalName, Stack } from '../../../core'; import * as cxapi from '../../../cx-api'; import { AssetType, FileSet, IFileSetProducer, ManualApprovalStep, ShellStep, StackAsset, StackDeployment, Step } from '../blueprint'; -import { DockerCredential, dockerCredentialsInstallCommands, DockerCredentialUsage } from '../docker-credentials'; -import { GraphNodeCollection, isGraph, AGraphNode, PipelineGraph } from '../helpers-internal'; +import { DockerCredential, DockerCredentialUsage, dockerCredentialsInstallCommands } from '../docker-credentials'; +import { AGraphNode, GraphNodeCollection, PipelineGraph, isGraph } from '../helpers-internal'; import { PipelineBase } from '../main'; import { AssetSingletonRole } from '../private/asset-singleton-role'; import { CachedFnSub } from '../private/cached-fnsub'; @@ -28,6 +29,12 @@ import { toPosixPath } from '../private/fs'; import { actionName, stackVariableNamespace } from '../private/identifiers'; import { enumerate, flatten, maybeSuffix, noUndefined } from '../private/javascript'; import { writeTemplateConfiguration } from '../private/template-configuration'; +import { ArtifactMap } from './artifact-map'; +import { CodeBuildStep } from './codebuild-step'; +import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; +import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; +import { namespaceStepOutputs } from './private/outputs'; +import { StackOutputsMap } from './stack-outputs-map'; /** * Properties for a `CodePipeline` @@ -244,6 +251,12 @@ export interface CodePipelineProps { * @default - A new S3 bucket will be created. */ readonly artifactBucket?: s3.IBucket; + + /** + * If all "prepare" step should be placed all together as the first actions within a stage/wave + */ + + readonly allPrepareNodesFirst?: boolean; } /** @@ -356,11 +369,12 @@ export class CodePipeline extends PipelineBase { private readonly dockerCredentials: DockerCredential[]; private readonly cachedFnSub = new CachedFnSub(); private stackOutputs: StackOutputsMap; - + private readonly allPrepareNodesFirst: boolean; /** * Asset roles shared for publishing */ - private readonly assetCodeBuildRoles: Map = new Map(); + private readonly assetCodeBuildRoles: Map = + new Map(); /** * This is set to the very first artifact produced in the pipeline @@ -372,7 +386,11 @@ export class CodePipeline extends PipelineBase { private readonly singlePublisherPerAssetType: boolean; private readonly cliVersion?: string; - constructor(scope: Construct, id: string, private readonly props: CodePipelineProps) { + constructor( + scope: Construct, + id: string, + private readonly props: CodePipelineProps, + ) { super(scope, id, props); this.selfMutationEnabled = props.selfMutation ?? true; @@ -381,6 +399,7 @@ export class CodePipeline extends PipelineBase { this.cliVersion = props.cliVersion ?? preferredCliVersion(); this.useChangeSets = props.useChangeSets ?? true; this.stackOutputs = new StackOutputsMap(this); + this.allPrepareNodesFirst = props.allPrepareNodesFirst ?? false; } /** @@ -390,7 +409,9 @@ export class CodePipeline extends PipelineBase { */ public get synthProject(): cb.IProject { if (!this._synthProject) { - throw new Error('Call pipeline.buildPipeline() before reading this property'); + throw new Error( + 'Call pipeline.buildPipeline() before reading this property', + ); } return this._synthProject; } @@ -403,10 +424,14 @@ export class CodePipeline extends PipelineBase { */ public get selfMutationProject(): cb.IProject { if (!this._pipeline) { - throw new Error('Call pipeline.buildPipeline() before reading this property'); + throw new Error( + 'Call pipeline.buildPipeline() before reading this property', + ); } if (!this._selfMutationProject) { - throw new Error('No selfMutationProject since the selfMutation property was set to false'); + throw new Error( + 'No selfMutationProject since the selfMutation property was set to false', + ); } return this._selfMutationProject; } @@ -432,26 +457,45 @@ export class CodePipeline extends PipelineBase { if (this.props.codePipeline) { if (this.props.pipelineName) { - throw new Error('Cannot set \'pipelineName\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'pipelineName' if an existing CodePipeline is given using 'codePipeline'", + ); } if (this.props.crossAccountKeys !== undefined) { - throw new Error('Cannot set \'crossAccountKeys\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'crossAccountKeys' if an existing CodePipeline is given using 'codePipeline'", + ); } if (this.props.enableKeyRotation !== undefined) { - throw new Error('Cannot set \'enableKeyRotation\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'enableKeyRotation' if an existing CodePipeline is given using 'codePipeline'", + ); } if (this.props.reuseCrossRegionSupportStacks !== undefined) { - throw new Error('Cannot set \'reuseCrossRegionSupportStacks\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'reuseCrossRegionSupportStacks' if an existing CodePipeline is given using 'codePipeline'", + ); } if (this.props.role !== undefined) { - throw new Error('Cannot set \'role\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'role' if an existing CodePipeline is given using 'codePipeline'", + ); } if (this.props.artifactBucket !== undefined) { - throw new Error('Cannot set \'artifactBucket\' if an existing CodePipeline is given using \'codePipeline\''); + throw new Error( + "Cannot set 'artifactBucket' if an existing CodePipeline is given using 'codePipeline'", + ); } this._pipeline = this.props.codePipeline; } else { + + if (this.props.allPrepareNodesFirst && this.props.useChangeSets === false) { + throw new Error( + "Cannot set 'allPrepareNodesFirst: true' if 'useChangeSets' is set to false.", + ); + } + this._pipeline = new cp.Pipeline(this, 'Pipeline', { pipelineName: this.props.pipelineName, crossAccountKeys: this.props.crossAccountKeys ?? false, @@ -469,6 +513,7 @@ export class CodePipeline extends PipelineBase { selfMutation: this.selfMutationEnabled, singlePublisherPerAssetType: this.singlePublisherPerAssetType, prepareStep: this.useChangeSets, + allPrepareNodesFirst: this.allPrepareNodesFirst, }); this._cloudAssemblyFileSet = graphFromBp.cloudAssemblyFileSet; @@ -476,12 +521,18 @@ export class CodePipeline extends PipelineBase { // Write a dotfile for the pipeline layout const dotFile = `${Names.uniqueId(this)}.dot`; - fs.writeFileSync(path.join(this.myCxAsmRoot, dotFile), graphFromBp.graph.renderDot().replace(/input\.dot/, dotFile), { encoding: 'utf-8' }); + fs.writeFileSync( + path.join(this.myCxAsmRoot, dotFile), + graphFromBp.graph.renderDot().replace(/input\.dot/, dotFile), + { encoding: 'utf-8' }, + ); } private get myCxAsmRoot(): string { if (!this._myCxAsmRoot) { - throw new Error('Can\'t read \'myCxAsmRoot\' if build deployment not called yet'); + throw new Error( + "Can't read 'myCxAsmRoot' if build deployment not called yet", + ); } return this._myCxAsmRoot; } @@ -500,7 +551,9 @@ export class CodePipeline extends PipelineBase { let beforeSelfMutation = this.selfMutationEnabled; for (const stageNode of flatten(structure.graph.sortedChildren())) { if (!isGraph(stageNode)) { - throw new Error(`Top-level children must be graphs, got '${stageNode}'`); + throw new Error( + `Top-level children must be graphs, got '${stageNode}'`, + ); } // Group our ordered tranches into blocks of 50. @@ -508,10 +561,14 @@ export class CodePipeline extends PipelineBase { const chunks = chunkTranches(50, stageNode.sortedLeaves()); const actionsOverflowStage = chunks.length > 1; for (const [i, tranches] of enumerate(chunks)) { - const stageName = actionsOverflowStage ? `${stageNode.id}.${i + 1}` : stageNode.id; + const stageName = actionsOverflowStage + ? `${stageNode.id}.${i + 1}` + : stageNode.id; const pipelineStage = this.pipeline.addStage({ stageName }); - const sharedParent = new GraphNodeCollection(flatten(tranches)).commonAncestor(); + const sharedParent = new GraphNodeCollection( + flatten(tranches), + ).commonAncestor(); let runOrder = 1; for (const tranche of tranches) { @@ -523,9 +580,10 @@ export class CodePipeline extends PipelineBase { const nodeType = this.nodeTypeFromNode(node); const name = actionName(node, sharedParent); - const variablesNamespace = node.data?.type === 'step' - ? namespaceStepOutputs(node.data.step, pipelineStage, name) - : undefined; + const variablesNamespace = + node.data?.type === 'step' + ? namespaceStepOutputs(node.data.step, pipelineStage, name) + : undefined; const result = factory.produceAction(pipelineStage, { actionName: name, @@ -535,7 +593,9 @@ export class CodePipeline extends PipelineBase { fallbackArtifact: this._fallbackArtifact, pipeline: this, // If this step happens to produce a CodeBuild job, set the default options - codeBuildDefaults: nodeType ? this.codeBuildDefaultsFor(nodeType) : undefined, + codeBuildDefaults: nodeType + ? this.codeBuildDefaultsFor(nodeType) + : undefined, beforeSelfMutation, variablesNamespace, stackOutputsMap: this.stackOutputs, @@ -562,11 +622,16 @@ export class CodePipeline extends PipelineBase { * Some minor state manipulation of CodeBuild projects and pipeline * artifacts. */ - private postProcessNode(node: AGraphNode, result: CodePipelineActionFactoryResult) { + private postProcessNode( + node: AGraphNode, + result: CodePipelineActionFactoryResult, + ) { const nodeType = this.nodeTypeFromNode(node); if (result.project) { - const dockerUsage = dockerUsageFromCodeBuild(nodeType ?? CodeBuildProjectType.STEP); + const dockerUsage = dockerUsageFromCodeBuild( + nodeType ?? CodeBuildProjectType.STEP, + ); if (dockerUsage) { for (const c of this.dockerCredentials) { c.grantRead(result.project, dockerUsage); @@ -581,8 +646,14 @@ export class CodePipeline extends PipelineBase { } } - if (node.data?.type === 'step' && node.data.step.primaryOutput?.primaryOutput && !this._fallbackArtifact) { - this._fallbackArtifact = this.artifacts.toCodePipeline(node.data.step.primaryOutput?.primaryOutput); + if ( + node.data?.type === 'step' && + node.data.step.primaryOutput?.primaryOutput && + !this._fallbackArtifact + ) { + this._fallbackArtifact = this.artifacts.toCodePipeline( + node.data.step.primaryOutput?.primaryOutput, + ); } } @@ -595,7 +666,9 @@ export class CodePipeline extends PipelineBase { case 'group': case 'stack-group': case undefined: - throw new Error(`actionFromNode: did not expect to get group nodes: ${node.data?.type}`); + throw new Error( + `actionFromNode: did not expect to get group nodes: ${node.data?.type}`, + ); case 'self-update': return this.selfMutateAction(); @@ -608,14 +681,22 @@ export class CodePipeline extends PipelineBase { case 'execute': return node.data.withoutChangeSet - ? this.executeDeploymentAction(node.data.stack, node.data.captureOutputs) - : this.executeChangeSetAction(node.data.stack, node.data.captureOutputs); + ? this.executeDeploymentAction( + node.data.stack, + node.data.captureOutputs, + ) + : this.executeChangeSetAction( + node.data.stack, + node.data.captureOutputs, + ); case 'step': return this.actionFromStep(node, node.data.step); default: - throw new Error(`CodePipeline does not support graph nodes of type '${node.data?.type}'. You are probably using a feature this CDK Pipelines implementation does not support.`); + throw new Error( + `CodePipeline does not support graph nodes of type '${node.data?.type}'. You are probably using a feature this CDK Pipelines implementation does not support.`, + ); } } @@ -631,7 +712,10 @@ export class CodePipeline extends PipelineBase { * The rest is expressed in terms of these 3, or in terms of graph nodes * which are handled elsewhere. */ - private actionFromStep(node: AGraphNode, step: Step): ICodePipelineActionFactory { + private actionFromStep( + node: AGraphNode, + step: Step, + ): ICodePipelineActionFactory { const nodeType = this.nodeTypeFromNode(node); // CodePipeline-specific steps first -- this includes Sources @@ -642,9 +726,8 @@ export class CodePipeline extends PipelineBase { // Now built-in steps if (step instanceof ShellStep || step instanceof CodeBuildStep) { // The 'CdkBuildProject' will be the construct ID of the CodeBuild project, necessary for backwards compat - let constructId = nodeType === CodeBuildProjectType.SYNTH - ? 'CdkBuildProject' - : step.id; + let constructId = + nodeType === CodeBuildProjectType.SYNTH ? 'CdkBuildProject' : step.id; return step instanceof CodeBuildStep ? CodeBuildFactory.fromCodeBuildStep(constructId, step) @@ -654,101 +737,174 @@ export class CodePipeline extends PipelineBase { if (step instanceof ManualApprovalStep) { return { produceAction: (stage, options) => { - stage.addAction(new cpa.ManualApprovalAction({ - actionName: options.actionName, - runOrder: options.runOrder, - additionalInformation: step.comment, - })); + stage.addAction( + new cpa.ManualApprovalAction({ + actionName: options.actionName, + runOrder: options.runOrder, + additionalInformation: step.comment, + }), + ); return { runOrdersConsumed: 1 }; }, }; } - throw new Error(`Deployment step '${step}' is not supported for CodePipeline-backed pipelines`); + throw new Error( + `Deployment step '${step}' is not supported for CodePipeline-backed pipelines`, + ); } - private createChangeSetAction(stack: StackDeployment): ICodePipelineActionFactory { + private createChangeSetAction( + stack: StackDeployment, + ): ICodePipelineActionFactory { const changeSetName = 'PipelineChange'; - const templateArtifact = this.artifacts.toCodePipeline(this._cloudAssemblyFileSet!); + const templateArtifact = this.artifacts.toCodePipeline( + this._cloudAssemblyFileSet!, + ); const templateConfigurationPath = this.writeTemplateConfiguration(stack); - const region = stack.region !== Stack.of(this).region ? stack.region : undefined; - const account = stack.account !== Stack.of(this).account ? stack.account : undefined; + const region = + stack.region !== Stack.of(this).region ? stack.region : undefined; + const account = + stack.account !== Stack.of(this).account ? stack.account : undefined; - const relativeTemplatePath = path.relative(this.myCxAsmRoot, stack.absoluteTemplatePath); + const relativeTemplatePath = path.relative( + this.myCxAsmRoot, + stack.absoluteTemplatePath, + ); return { produceAction: (stage, options) => { - stage.addAction(new cpa.CloudFormationCreateReplaceChangeSetAction({ - actionName: options.actionName, - runOrder: options.runOrder, - changeSetName, - stackName: stack.stackName, - templatePath: templateArtifact.atPath(toPosixPath(relativeTemplatePath)), - adminPermissions: true, - role: this.roleFromPlaceholderArn(this.pipeline, region, account, stack.assumeRoleArn), - deploymentRole: this.roleFromPlaceholderArn(this.pipeline, region, account, stack.executionRoleArn), - region: region, - templateConfiguration: templateConfigurationPath - ? templateArtifact.atPath(toPosixPath(templateConfigurationPath)) - : undefined, - cfnCapabilities: [CfnCapabilities.NAMED_IAM, CfnCapabilities.AUTO_EXPAND], - })); + stage.addAction( + new cpa.CloudFormationCreateReplaceChangeSetAction({ + actionName: options.actionName, + runOrder: options.runOrder, + changeSetName, + stackName: stack.stackName, + templatePath: templateArtifact.atPath( + toPosixPath(relativeTemplatePath), + ), + adminPermissions: true, + role: this.roleFromPlaceholderArn( + this.pipeline, + region, + account, + stack.assumeRoleArn, + ), + deploymentRole: this.roleFromPlaceholderArn( + this.pipeline, + region, + account, + stack.executionRoleArn, + ), + region: region, + templateConfiguration: templateConfigurationPath + ? templateArtifact.atPath(toPosixPath(templateConfigurationPath)) + : undefined, + cfnCapabilities: [ + CfnCapabilities.NAMED_IAM, + CfnCapabilities.AUTO_EXPAND, + ], + }), + ); return { runOrdersConsumed: 1 }; }, }; } - private executeChangeSetAction(stack: StackDeployment, captureOutputs: boolean): ICodePipelineActionFactory { + private executeChangeSetAction( + stack: StackDeployment, + captureOutputs: boolean, + ): ICodePipelineActionFactory { const changeSetName = 'PipelineChange'; - const region = stack.region !== Stack.of(this).region ? stack.region : undefined; - const account = stack.account !== Stack.of(this).account ? stack.account : undefined; + const region = + stack.region !== Stack.of(this).region ? stack.region : undefined; + const account = + stack.account !== Stack.of(this).account ? stack.account : undefined; return { produceAction: (stage, options) => { - stage.addAction(new cpa.CloudFormationExecuteChangeSetAction({ - actionName: options.actionName, - runOrder: options.runOrder, - changeSetName, - stackName: stack.stackName, - role: this.roleFromPlaceholderArn(this.pipeline, region, account, stack.assumeRoleArn), - region: region, - variablesNamespace: captureOutputs ? stackVariableNamespace(stack) : undefined, - })); + stage.addAction( + new cpa.CloudFormationExecuteChangeSetAction({ + actionName: options.actionName, + runOrder: options.runOrder, + changeSetName, + stackName: stack.stackName, + role: this.roleFromPlaceholderArn( + this.pipeline, + region, + account, + stack.assumeRoleArn, + ), + region: region, + variablesNamespace: captureOutputs + ? stackVariableNamespace(stack) + : undefined, + }), + ); return { runOrdersConsumed: 1 }; }, }; } - private executeDeploymentAction(stack: StackDeployment, captureOutputs: boolean): ICodePipelineActionFactory { - const templateArtifact = this.artifacts.toCodePipeline(this._cloudAssemblyFileSet!); + private executeDeploymentAction( + stack: StackDeployment, + captureOutputs: boolean, + ): ICodePipelineActionFactory { + const templateArtifact = this.artifacts.toCodePipeline( + this._cloudAssemblyFileSet!, + ); const templateConfigurationPath = this.writeTemplateConfiguration(stack); - const region = stack.region !== Stack.of(this).region ? stack.region : undefined; - const account = stack.account !== Stack.of(this).account ? stack.account : undefined; + const region = + stack.region !== Stack.of(this).region ? stack.region : undefined; + const account = + stack.account !== Stack.of(this).account ? stack.account : undefined; - const relativeTemplatePath = path.relative(this.myCxAsmRoot, stack.absoluteTemplatePath); + const relativeTemplatePath = path.relative( + this.myCxAsmRoot, + stack.absoluteTemplatePath, + ); return { produceAction: (stage, options) => { - stage.addAction(new cpa.CloudFormationCreateUpdateStackAction({ - actionName: options.actionName, - runOrder: options.runOrder, - stackName: stack.stackName, - templatePath: templateArtifact.atPath(toPosixPath(relativeTemplatePath)), - adminPermissions: true, - role: this.roleFromPlaceholderArn(this.pipeline, region, account, stack.assumeRoleArn), - deploymentRole: this.roleFromPlaceholderArn(this.pipeline, region, account, stack.executionRoleArn), - region: region, - templateConfiguration: templateConfigurationPath - ? templateArtifact.atPath(toPosixPath(templateConfigurationPath)) - : undefined, - cfnCapabilities: [CfnCapabilities.NAMED_IAM, CfnCapabilities.AUTO_EXPAND], - variablesNamespace: captureOutputs ? stackVariableNamespace(stack) : undefined, - })); + stage.addAction( + new cpa.CloudFormationCreateUpdateStackAction({ + actionName: options.actionName, + runOrder: options.runOrder, + stackName: stack.stackName, + templatePath: templateArtifact.atPath( + toPosixPath(relativeTemplatePath), + ), + adminPermissions: true, + role: this.roleFromPlaceholderArn( + this.pipeline, + region, + account, + stack.assumeRoleArn, + ), + deploymentRole: this.roleFromPlaceholderArn( + this.pipeline, + region, + account, + stack.executionRoleArn, + ), + region: region, + templateConfiguration: templateConfigurationPath + ? templateArtifact.atPath(toPosixPath(templateConfigurationPath)) + : undefined, + cfnCapabilities: [ + CfnCapabilities.NAMED_IAM, + CfnCapabilities.AUTO_EXPAND, + ], + variablesNamespace: captureOutputs + ? stackVariableNamespace(stack) + : undefined, + }), + ); return { runOrdersConsumed: 1 }; }, @@ -759,16 +915,17 @@ export class CodePipeline extends PipelineBase { const installSuffix = this.cliVersion ? `@${this.cliVersion}` : ''; const pipelineStack = Stack.of(this.pipeline); - const pipelineStackIdentifier = pipelineStack.node.path ?? pipelineStack.stackName; + const pipelineStackIdentifier = + pipelineStack.node.path ?? pipelineStack.stackName; const step = new CodeBuildStep('SelfMutate', { projectName: maybeSuffix(this.props.pipelineName, '-selfupdate'), input: this._cloudAssemblyFileSet, - installCommands: [ - `npm install -g aws-cdk${installSuffix}`, - ], + installCommands: [`npm install -g aws-cdk${installSuffix}`], commands: [ - `cdk -a ${toPosixPath(embeddedAsmPath(this.pipeline))} deploy ${pipelineStackIdentifier} --require-approval=never --verbose`, + `cdk -a ${toPosixPath( + embeddedAsmPath(this.pipeline), + )} deploy ${pipelineStackIdentifier} --require-approval=never --verbose`, ], rolePolicyStatements: [ @@ -778,7 +935,11 @@ export class CodePipeline extends PipelineBase { resources: [`arn:*:iam::${Stack.of(this.pipeline).account}:role/*`], conditions: { 'ForAnyValue:StringEquals': { - 'iam:ResourceTag/aws-cdk:bootstrap-role': ['image-publishing', 'file-publishing', 'deploy'], + 'iam:ResourceTag/aws-cdk:bootstrap-role': [ + 'image-publishing', + 'file-publishing', + 'deploy', + ], }, }, }), @@ -801,38 +962,47 @@ export class CodePipeline extends PipelineBase { }); } - private publishAssetsAction(node: AGraphNode, assets: StackAsset[]): ICodePipelineActionFactory { + private publishAssetsAction( + node: AGraphNode, + assets: StackAsset[], + ): ICodePipelineActionFactory { const installSuffix = this.cliVersion ? `@${this.cliVersion}` : ''; - const commands = assets.map(asset => { - const relativeAssetManifestPath = path.relative(this.myCxAsmRoot, asset.assetManifestPath); - return `cdk-assets --path "${toPosixPath(relativeAssetManifestPath)}" --verbose publish "${asset.assetSelector}"`; + const commands = assets.map((asset) => { + const relativeAssetManifestPath = path.relative( + this.myCxAsmRoot, + asset.assetManifestPath, + ); + return `cdk-assets --path "${toPosixPath( + relativeAssetManifestPath, + )}" --verbose publish "${asset.assetSelector}"`; }); const assetType = assets[0].assetType; - if (assets.some(a => a.assetType !== assetType)) { - throw new Error('All assets in a single publishing step must be of the same type'); + if (assets.some((a) => a.assetType !== assetType)) { + throw new Error( + 'All assets in a single publishing step must be of the same type', + ); } const role = this.obtainAssetCodeBuildRole(assets[0].assetType); - for (const roleArn of assets.flatMap(a => a.assetPublishingRoleArn ? [a.assetPublishingRoleArn] : [])) { + for (const roleArn of assets.flatMap((a) => + a.assetPublishingRoleArn ? [a.assetPublishingRoleArn] : [], + )) { // The ARNs include raw AWS pseudo parameters (e.g., ${AWS::Partition}), which need to be substituted. role.addAssumeRole(this.cachedFnSub.fnSub(roleArn)); - }; + } // The base commands that need to be run const script = new CodeBuildStep(node.id, { commands, - installCommands: [ - `npm install -g cdk-assets${installSuffix}`, - ], + installCommands: [`npm install -g cdk-assets${installSuffix}`], input: this._cloudAssemblyFileSet, buildEnvironment: { - privileged: ( - assets.some(asset => asset.assetType === AssetType.DOCKER_IMAGE) || - this.props.codeBuildDefaults?.buildEnvironment?.privileged - ), + privileged: + assets.some((asset) => asset.assetType === AssetType.DOCKER_IMAGE) || + this.props.codeBuildDefaults?.buildEnvironment?.privileged, }, role, }); @@ -850,7 +1020,9 @@ export class CodePipeline extends PipelineBase { private nodeTypeFromNode(node: AGraphNode) { if (node.data?.type === 'step') { - return !!node.data?.isBuildStep ? CodeBuildProjectType.SYNTH : CodeBuildProjectType.STEP; + return !!node.data?.isBuildStep + ? CodeBuildProjectType.SYNTH + : CodeBuildProjectType.STEP; } if (node.data?.type === 'publish-assets') { return CodeBuildProjectType.ASSETS; @@ -861,7 +1033,9 @@ export class CodePipeline extends PipelineBase { return undefined; } - private codeBuildDefaultsFor(nodeType: CodeBuildProjectType): CodeBuildOptions | undefined { + private codeBuildDefaultsFor( + nodeType: CodeBuildProjectType, + ): CodeBuildOptions | undefined { const defaultOptions: CodeBuildOptions = { buildEnvironment: { buildImage: CDKP_DEFAULT_CODEBUILD_IMAGE, @@ -871,32 +1045,46 @@ export class CodePipeline extends PipelineBase { const typeBasedCustomizations = { [CodeBuildProjectType.SYNTH]: this.props.dockerEnabledForSynth - ? mergeCodeBuildOptions(this.props.synthCodeBuildDefaults, { buildEnvironment: { privileged: true } }) + ? mergeCodeBuildOptions(this.props.synthCodeBuildDefaults, { + buildEnvironment: { privileged: true }, + }) : this.props.synthCodeBuildDefaults, - [CodeBuildProjectType.ASSETS]: this.props.assetPublishingCodeBuildDefaults, + [CodeBuildProjectType.ASSETS]: + this.props.assetPublishingCodeBuildDefaults, - [CodeBuildProjectType.SELF_MUTATE]: this.props.dockerEnabledForSelfMutation - ? mergeCodeBuildOptions(this.props.selfMutationCodeBuildDefaults, { buildEnvironment: { privileged: true } }) + [CodeBuildProjectType.SELF_MUTATE]: this.props + .dockerEnabledForSelfMutation + ? mergeCodeBuildOptions(this.props.selfMutationCodeBuildDefaults, { + buildEnvironment: { privileged: true }, + }) : this.props.selfMutationCodeBuildDefaults, [CodeBuildProjectType.STEP]: {}, }; const dockerUsage = dockerUsageFromCodeBuild(nodeType); - const dockerCommands = dockerUsage !== undefined - ? dockerCredentialsInstallCommands(dockerUsage, this.dockerCredentials, 'both') - : []; - const typeBasedDockerCommands = dockerCommands.length > 0 ? { - partialBuildSpec: cb.BuildSpec.fromObject({ - version: '0.2', - phases: { - pre_build: { - commands: dockerCommands, - }, - }, - }), - } : {}; + const dockerCommands = + dockerUsage !== undefined + ? dockerCredentialsInstallCommands( + dockerUsage, + this.dockerCredentials, + 'both', + ) + : []; + const typeBasedDockerCommands = + dockerCommands.length > 0 + ? { + partialBuildSpec: cb.BuildSpec.fromObject({ + version: '0.2', + phases: { + pre_build: { + commands: dockerCommands, + }, + }, + }), + } + : {}; return mergeCodeBuildOptions( defaultOptions, @@ -906,31 +1094,53 @@ export class CodePipeline extends PipelineBase { ); } - private roleFromPlaceholderArn(scope: Construct, region: string | undefined, - account: string | undefined, arn: string): iam.IRole; - private roleFromPlaceholderArn(scope: Construct, region: string | undefined, - account: string | undefined, arn: string | undefined): iam.IRole | undefined; - private roleFromPlaceholderArn(scope: Construct, region: string | undefined, - account: string | undefined, arn: string | undefined): iam.IRole | undefined { - - if (!arn) { return undefined; } + private roleFromPlaceholderArn( + scope: Construct, + region: string | undefined, + account: string | undefined, + arn: string + ): iam.IRole; + private roleFromPlaceholderArn( + scope: Construct, + region: string | undefined, + account: string | undefined, + arn: string | undefined + ): iam.IRole | undefined; + private roleFromPlaceholderArn( + scope: Construct, + region: string | undefined, + account: string | undefined, + arn: string | undefined, + ): iam.IRole | undefined { + if (!arn) { + return undefined; + } // Use placeholder arn as construct ID. const id = arn; // https://github.com/aws/aws-cdk/issues/7255 - let existingRole = scope.node.tryFindChild(`ImmutableRole${id}`) as iam.IRole; - if (existingRole) { return existingRole; } + let existingRole = scope.node.tryFindChild( + `ImmutableRole${id}`, + ) as iam.IRole; + if (existingRole) { + return existingRole; + } // For when #7255 is fixed. existingRole = scope.node.tryFindChild(id) as iam.IRole; - if (existingRole) { return existingRole; } + if (existingRole) { + return existingRole; + } const arnToImport = cxapi.EnvironmentPlaceholders.replace(arn, { region: region ?? Aws.REGION, accountId: account ?? Aws.ACCOUNT_ID, partition: Aws.PARTITION, }); - return iam.Role.fromRoleArn(scope, id, arnToImport, { mutable: false, addGrantsToResources: true }); + return iam.Role.fromRoleArn(scope, id, arnToImport, { + mutable: false, + addGrantsToResources: true, + }); } /** @@ -938,8 +1148,12 @@ export class CodePipeline extends PipelineBase { * * Currently only supports tags. */ - private writeTemplateConfiguration(stack: StackDeployment): string | undefined { - if (Object.keys(stack.tags).length === 0) { return undefined; } + private writeTemplateConfiguration( + stack: StackDeployment, + ): string | undefined { + if (Object.keys(stack.tags).length === 0) { + return undefined; + } const absConfigPath = `${stack.absoluteTemplatePath}.config.json`; const relativeConfigPath = path.relative(this.myCxAsmRoot, absConfigPath); @@ -970,23 +1184,28 @@ export class CodePipeline extends PipelineBase { const stack = Stack.of(this); const rolePrefix = assetType === AssetType.DOCKER_IMAGE ? 'Docker' : 'File'; - const assetRole = new AssetSingletonRole(this.assetsScope, `${rolePrefix}Role`, { - roleName: PhysicalName.GENERATE_IF_NEEDED, - assumedBy: new iam.CompositePrincipal( - new iam.ServicePrincipal('codebuild.amazonaws.com'), - new iam.AccountPrincipal(stack.account), - ), - }); + const assetRole = new AssetSingletonRole( + this.assetsScope, + `${rolePrefix}Role`, + { + roleName: PhysicalName.GENERATE_IF_NEEDED, + assumedBy: new iam.CompositePrincipal( + new iam.ServicePrincipal('codebuild.amazonaws.com'), + new iam.AccountPrincipal(stack.account), + ), + }, + ); // Grant pull access for any ECR registries and secrets that exist if (assetType === AssetType.DOCKER_IMAGE) { - this.dockerCredentials.forEach(reg => reg.grantRead(assetRole, DockerCredentialUsage.ASSET_PUBLISHING)); + this.dockerCredentials.forEach((reg) => + reg.grantRead(assetRole, DockerCredentialUsage.ASSET_PUBLISHING), + ); } this.assetCodeBuildRoles.set(assetType, assetRole); return assetRole; } - } function dockerUsageFromCodeBuild(cbt: CodeBuildProjectType): DockerCredentialUsage | undefined { diff --git a/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-graph.ts b/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-graph.ts index cad9fe7769c1a..f1195a9d32727 100644 --- a/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-graph.ts +++ b/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-graph.ts @@ -1,7 +1,20 @@ -import { DependencyBuilders, Graph, GraphNode, GraphNodeCollection } from './graph'; -import { PipelineQueries } from './pipeline-queries'; -import { AssetType, FileSet, StackAsset, StackDeployment, StageDeployment, Step, Wave } from '../blueprint'; +import { + AssetType, + FileSet, + StackAsset, + StackDeployment, + StageDeployment, + Step, + Wave, +} from '../blueprint'; import { PipelineBase } from '../main/pipeline-base'; +import { + DependencyBuilders, + Graph, + GraphNode, + GraphNodeCollection, +} from './graph'; +import { PipelineQueries } from './pipeline-queries'; export interface PipelineGraphProps { /** @@ -32,6 +45,12 @@ export interface PipelineGraphProps { * @default true */ readonly prepareStep?: boolean; + + /** + * If all "prepare" step should be placed all together as the first actions within a stage/wave + */ + + readonly allPrepareNodesFirst?: boolean; } /** @@ -43,7 +62,7 @@ export class PipelineGraph { /** * A Step object that may be used as the producer of FileSets that should not be represented in the graph */ - public static readonly NO_STEP: Step = new class extends Step { }('NO_STEP'); + public static readonly NO_STEP: Step = new (class extends Step {})('NO_STEP'); public readonly graph: AGraph = Graph.of('', { type: 'group' }); public readonly cloudAssemblyFileSet: FileSet; @@ -54,24 +73,31 @@ export class PipelineGraph { private readonly assetNodesByType = new Map(); private readonly synthNode?: AGraphNode; private readonly selfMutateNode?: AGraphNode; - private readonly stackOutputDependencies = new DependencyBuilders(); + private readonly stackOutputDependencies = + new DependencyBuilders(); /** Mapping steps to depbuilders, satisfied by the step itself */ private readonly nodeDependencies = new DependencyBuilders(); private readonly publishTemplate: boolean; private readonly prepareStep: boolean; private readonly singlePublisher: boolean; + private readonly allPrepareNodesFirst: boolean; private lastPreparationNode?: AGraphNode; private _fileAssetCtr = 0; private _dockerAssetCtr = 0; - constructor(public readonly pipeline: PipelineBase, props: PipelineGraphProps = {}) { + constructor( + public readonly pipeline: PipelineBase, + props: PipelineGraphProps = {}, + ) { this.publishTemplate = props.publishTemplate ?? false; this.prepareStep = props.prepareStep ?? true; this.singlePublisher = props.singlePublisherPerAssetType ?? false; this.queries = new PipelineQueries(pipeline); + this.allPrepareNodesFirst = props.allPrepareNodesFirst ?? false; + if (pipeline.synth instanceof Step) { this.synthNode = this.addBuildStep(pipeline.synth); if (this.synthNode?.data?.type === 'step') { @@ -82,7 +108,9 @@ export class PipelineGraph { const cloudAssembly = pipeline.synth.primaryOutput?.primaryOutput; if (!cloudAssembly) { - throw new Error(`The synth step must produce the cloud assembly artifact, but doesn't: ${pipeline.synth}`); + throw new Error( + `The synth step must produce the cloud assembly artifact, but doesn't: ${pipeline.synth}`, + ); } this.cloudAssemblyFileSet = cloudAssembly; @@ -97,7 +125,7 @@ export class PipelineGraph { this.lastPreparationNode = this.selfMutateNode; } - const waves = pipeline.waves.map(w => this.addWave(w)); + const waves = pipeline.waves.map((w) => this.addWave(w)); // Make sure the waves deploy sequentially for (let i = 1; i < waves.length; i++) { @@ -116,26 +144,60 @@ export class PipelineGraph { } private addWave(wave: Wave): AGraph { + if (wave.postPrepare.length > 0 && this.allPrepareNodesFirst === false) { + throw new Error( + '"postPrepare" is set, but property "allPrepareNodesFirst" is not set to "true"', + ); + } + // If the wave only has one Stage in it, don't add an additional Graph around it - const retGraph: AGraph = wave.stages.length === 1 - ? this.addStage(wave.stages[0]) - : Graph.of(wave.id, { type: 'group' }, wave.stages.map(s => this.addStage(s))); + const retGraph: AGraph = + wave.stages.length === 1 + ? this.addStage( + wave.stages[0], + wave.postPrepare ?? [], + ) + : Graph.of( + wave.id, + { type: 'group' }, + wave.stages.map((s) => + this.addStage( + s, + wave.postPrepare ?? [], + ), + ), + ); this.addPrePost(wave.pre, wave.post, retGraph); + // this.addPostPrepare(wave.postPrepare, retGraph); retGraph.dependOn(this.lastPreparationNode); this.graph.add(retGraph); return retGraph; } - private addStage(stage: StageDeployment): AGraph { + private addStage( + stage: StageDeployment, + wavePostPrepareSteps: Step[], + ): AGraph { const retGraph: AGraph = Graph.of(stage.stageName, { type: 'group' }); - + const prepareNodes = new GraphNodeCollection(new Array()); const stackGraphs = new Map(); + if (stage.postPrepare.length > 0 && this.allPrepareNodesFirst === false) { + throw new Error( + '"postPrepare" is set, but property "allPrepareNodesFirst" is not set to "true"', + ); + } + for (const stack of stage.stacks) { - const stackGraph: AGraph = Graph.of(this.simpleStackName(stack.stackName, stage.stageName), { type: 'stack-group', stack }); - const prepareNode: AGraphNode | undefined = this.prepareStep ? aGraphNode('Prepare', { type: 'prepare', stack }) : undefined; + const stackGraph: AGraph = Graph.of( + this.simpleStackName(stack.stackName, stage.stageName), + { type: 'stack-group', stack }, + ); + const prepareNode: AGraphNode | undefined = this.prepareStep + ? aGraphNode('Prepare-' + stack.stackName, { type: 'prepare', stack }) + : undefined; const deployNode: AGraphNode = aGraphNode('Deploy', { type: 'execute', stack, @@ -149,8 +211,43 @@ export class PipelineGraph { // node or node collection that represents first point of contact in each stack let firstDeployNode; if (prepareNode) { - stackGraph.add(prepareNode); - deployNode.dependOn(prepareNode); + prepareNodes.nodes.push(prepareNode); + // retGraph.add(prepareNode); + + if (this.allPrepareNodesFirst) { + retGraph.add(prepareNode); + } else { + stackGraph.add(prepareNode); + + // this.addPostPrepare(stage.postPrepare, stackGraph); + } + + const postPrepareNodesWave = this.addPostPrepare( + wavePostPrepareSteps ?? [], + retGraph, + ); + if (postPrepareNodesWave.nodes.length > 0) { + for (const n of postPrepareNodesWave.nodes) { + deployNode.dependOn(n); + n.dependOn(prepareNode); + } + } else { + deployNode.dependOn(prepareNode); + } + + const postPrepareNodes = this.addPostPrepare( + stage.postPrepare, + retGraph, + ); + if (postPrepareNodes.nodes.length > 0) { + for (const n of postPrepareNodes.nodes) { + deployNode.dependOn(n); + n.dependOn(prepareNode); + } + } else { + deployNode.dependOn(prepareNode); + } + firstDeployNode = prepareNode; } else { firstDeployNode = deployNode; @@ -159,9 +256,16 @@ export class PipelineGraph { // add changeset steps at the stack level if (stack.changeSet.length > 0) { if (prepareNode) { - this.addChangeSetNode(stack.changeSet, prepareNode, deployNode, stackGraph); + this.addChangeSetNode( + stack.changeSet, + prepareNode, + deployNode, + stackGraph, + ); } else { - throw new Error(`Cannot use \'changeSet\' steps for stack \'${stack.stackName}\': the pipeline does not support them or they have been disabled`); + throw new Error( + `Cannot use \'changeSet\' steps for stack \'${stack.stackName}\': the pipeline does not support them or they have been disabled`, + ); } } @@ -175,12 +279,16 @@ export class PipelineGraph { const cloudAssembly = this.cloudAssemblyFileSet; - firstDeployNode.dependOn(this.addStepNode(cloudAssembly.producer, retGraph)); + firstDeployNode.dependOn( + this.addStepNode(cloudAssembly.producer, retGraph), + ); // add the template asset if (this.publishTemplate) { if (!stack.templateAsset) { - throw new Error(`"publishTemplate" is enabled, but stack ${stack.stackArtifactId} does not have a template asset`); + throw new Error( + `"publishTemplate" is enabled, but stack ${stack.stackArtifactId} does not have a template asset`, + ); } firstDeployNode.dependOn(this.publishAsset(stack.templateAsset)); @@ -215,11 +323,17 @@ export class PipelineGraph { } this.addPrePost(stage.pre, stage.post, retGraph); - + // this.addPostPrepare(stage.addPostPrepare,) + // this.addPostPrepare(stage.postPrepare, retGraph); return retGraph; } - private addChangeSetNode(changeSet: Step[], prepareNode: AGraphNode, deployNode: AGraphNode, graph: AGraph) { + private addChangeSetNode( + changeSet: Step[], + prepareNode: AGraphNode, + deployNode: AGraphNode, + graph: AGraph, + ) { for (const c of changeSet) { const changeSetNode = this.addStepNode(c, graph); changeSetNode?.dependOn(prepareNode); @@ -227,6 +341,17 @@ export class PipelineGraph { } } + private addPostPrepare(postPrepare: Step[], parent: AGraph) { + const currentNodes = new GraphNodeCollection(parent.nodes); + const postPrepareNodes = new GraphNodeCollection(new Array()); + for (const p of postPrepare) { + const preNode = this.addStepNode(p, parent); + postPrepareNodes?.dependOn(...currentNodes.nodes); + postPrepareNodes.nodes.push(preNode!); + } + return postPrepareNodes; + } + private addPrePost(pre: Step[], post: Step[], parent: AGraph) { const currentNodes = new GraphNodeCollection(parent.nodes); const preNodes = new GraphNodeCollection(new Array()); @@ -257,10 +382,14 @@ export class PipelineGraph { * Adds all dependencies for that Node to the same Step as well. */ private addStepNode(step: Step, parent: AGraph) { - if (step === PipelineGraph.NO_STEP) { return undefined; } + if (step === PipelineGraph.NO_STEP) { + return undefined; + } const previous = this.added.get(step); - if (previous) { return previous; } + if (previous) { + return previous; + } const node: AGraphNode = aGraphNode(step.id, { type: 'step', step }); @@ -302,25 +431,38 @@ export class PipelineGraph { // May need to do this more than once to recursively add all missing producers let attempts = 20; while (attempts-- > 0) { - const unsatisfied = this.nodeDependencies.unsatisfiedBuilders().filter(([s]) => s !== PipelineGraph.NO_STEP); - if (unsatisfied.length === 0) { return; } + const unsatisfied = this.nodeDependencies + .unsatisfiedBuilders() + .filter(([s]) => s !== PipelineGraph.NO_STEP); + if (unsatisfied.length === 0) { + return; + } for (const [step, builder] of unsatisfied) { // Add a new node for this step to the parent of the "leftmost" consumer. - const leftMostConsumer = new GraphNodeCollection(builder.consumers).first(); + const leftMostConsumer = new GraphNodeCollection( + builder.consumers, + ).first(); const parent = leftMostConsumer.parentGraph; if (!parent) { - throw new Error(`Consumer doesn't have a parent graph: ${leftMostConsumer}`); + throw new Error( + `Consumer doesn't have a parent graph: ${leftMostConsumer}`, + ); } this.addStepNode(step, parent); } } const unsatisfied = this.nodeDependencies.unsatisfiedBuilders(); - throw new Error([ - 'Recursion depth too large while adding dependency nodes:', - unsatisfied.map(([step, builder]) => `${builder.consumersAsString()} awaiting ${step}.`), - ].join(' ')); + throw new Error( + [ + 'Recursion depth too large while adding dependency nodes:', + unsatisfied.map( + ([step, builder]) => + `${builder.consumersAsString()} awaiting ${step}.`, + ), + ].join(' '), + ); } private publishAsset(stackAsset: StackAsset): AGraphNode { @@ -330,14 +472,22 @@ export class PipelineGraph { if (assetNode) { // If there's already a node publishing this asset, add as a new publishing // destination to the same node. - } else if (this.singlePublisher && this.assetNodesByType.has(stackAsset.assetType)) { + } else if ( + this.singlePublisher && + this.assetNodesByType.has(stackAsset.assetType) + ) { // If we're doing a single node per type, lookup by that assetNode = this.assetNodesByType.get(stackAsset.assetType)!; } else { // Otherwise add a new one - const id = stackAsset.assetType === AssetType.FILE - ? (this.singlePublisher ? 'FileAsset' : `FileAsset${++this._fileAssetCtr}`) - : (this.singlePublisher ? 'DockerAsset' : `DockerAsset${++this._dockerAssetCtr}`); + const id = + stackAsset.assetType === AssetType.FILE + ? this.singlePublisher + ? 'FileAsset' + : `FileAsset${++this._fileAssetCtr}` + : this.singlePublisher + ? 'DockerAsset' + : `DockerAsset${++this._dockerAssetCtr}`; assetNode = aGraphNode(id, { type: 'publish-assets', assets: [] }); assetsGraph.add(assetNode); @@ -352,7 +502,9 @@ export class PipelineGraph { throw new Error(`${assetNode} has the wrong data.type: ${data?.type}`); } - if (!data.assets.some(a => a.assetSelector === stackAsset.assetSelector)) { + if ( + !data.assets.some((a) => a.assetSelector === stackAsset.assetSelector) + ) { data.assets.push(stackAsset); } @@ -378,8 +530,7 @@ type GraphAnnotation = // Explicitly disable exhaustiveness checking on GraphAnnotation. This forces all consumers to adding // a 'default' clause which allows us to extend this list in the future. // The code below looks weird, 'type' must be a non-enumerable type that is not assignable to 'string'. - | { readonly type: { error: 'you must add a default case to your switch' } } - ; + | { readonly type: { error: 'you must add a default case to your switch' } }; interface ExecuteAnnotation { readonly type: 'execute'; @@ -412,4 +563,4 @@ function aGraphNode(id: string, x: GraphAnnotation): AGraphNode { function stripPrefix(s: string, prefix: string) { return s.startsWith(prefix) ? s.slice(prefix.length) : s; -} \ No newline at end of file +} diff --git a/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-queries.ts b/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-queries.ts index 3d6fa25f11937..f1e0bdb800701 100644 --- a/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-queries.ts +++ b/packages/aws-cdk-lib/pipelines/lib/helpers-internal/pipeline-queries.ts @@ -1,4 +1,4 @@ -import { Step, StackOutputReference, StackDeployment, StackAsset, StageDeployment } from '../blueprint'; +import { StackAsset, StackDeployment, StackOutputReference, StageDeployment, Step } from '../blueprint'; import { PipelineBase } from '../main/pipeline-base'; /** @@ -14,11 +14,11 @@ export class PipelineQueries { public stackOutputsReferenced(stack: StackDeployment): string[] { const steps = new Array(); for (const wave of this.pipeline.waves) { - steps.push(...wave.pre, ...wave.post); + steps.push(...wave.pre, ...wave.post, ...wave.postPrepare); for (const stage of wave.stages) { - steps.push(...stage.pre, ...stage.post); + steps.push(...stage.pre, ...stage.post, ...stage.postPrepare); for (const stackDeployment of stage.stacks) { - steps.push(...stackDeployment.pre, ...stackDeployment.changeSet, ...stackDeployment.post); + steps.push(...stackDeployment.pre, ...stackDeployment.changeSet, ...stackDeployment.post, ...stackDeployment.postPrepare); } } } diff --git a/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-graph.test.ts b/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-graph.test.ts index b8d4dc53957af..2ec801a0ffed1 100644 --- a/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-graph.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-graph.test.ts @@ -3,7 +3,7 @@ import * as cdkp from '../../../lib'; import { ManualApprovalStep, Step } from '../../../lib'; import { Graph, GraphNode, PipelineGraph } from '../../../lib/helpers-internal'; import { flatten } from '../../../lib/private/javascript'; -import { AppWithOutput, AppWithExposedStacks, OneStackApp, TestApp } from '../../testhelpers/test-app'; +import { AppWithExposedStacks, AppWithOutput, OneStackApp, TestApp } from '../../testhelpers/test-app'; let app: TestApp; @@ -114,6 +114,44 @@ describe('blueprint with wave and stage', () => { ]); }); + test('postPrepare and prepareNodes are added correctly inside stack graph', () => { + // GIVEN + const appWithExposedStacks = new AppWithExposedStacks(app, 'Gamma'); + + blueprint.waves[0].addStage(appWithExposedStacks, { + postPrepare: [ + new cdkp.ManualApprovalStep('Step1'), + // new cdkp.ManualApprovalStep('Step2'), + // new cdkp.ManualApprovalStep('Step3'), + ], + // stackSteps: [ + // { + // stack, + // pre: [ + // new cdkp.ManualApprovalStep('Step1'), + // new cdkp.ManualApprovalStep('Step2'), + // new cdkp.ManualApprovalStep('Step3'), + // ], + // changeSet: [new cdkp.ManualApprovalStep('Manual Approval')], + // post: [new cdkp.ManualApprovalStep('Post Approval')], + // }, + // ], + }); + + // WHEN + const graph = new PipelineGraph(blueprint).graph; + console.log(graph); + // THEN + expect(childrenAt(graph, 'Wave', 'Gamma', 'Stack1')).toEqual([ + 'Prepare-Gamma-Stack1', + 'Step1', + 'Step2', + 'Step3', + 'Deploy', + + ]); + }); + test('pre, changeSet, and post are added correctly inside stack graph', () => { // GIVEN const appWithExposedStacks = new AppWithExposedStacks(app, 'Gamma'); diff --git a/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts b/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts index fd7e6ab9d1ccc..eaf0fe9f82923 100644 --- a/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/blueprint/helpers-internal/pipeline-queries.test.ts @@ -57,17 +57,17 @@ describe('pipeline-queries', () => { }, { description: 'output referenced in stack pre step', - additionalSetup: () => stackDeployment.addStackSteps([step], [], []), + additionalSetup: () => stackDeployment.addStackSteps([step], [], [], []), expectedResultGetter: () => [outputName], }, { description: 'output referenced in stack changeSet step', - additionalSetup: () => stackDeployment.addStackSteps([], [step], []), + additionalSetup: () => stackDeployment.addStackSteps([], [step], [], []), expectedResultGetter: () => [outputName], }, { description: 'output referenced in stack post step', - additionalSetup: () => stackDeployment.addStackSteps([], [], [step]), + additionalSetup: () => stackDeployment.addStackSteps([], [], [step], []), expectedResultGetter: () => [outputName], }, { diff --git a/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts b/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts index e4d90032b6a9f..a697a630e65c4 100644 --- a/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts @@ -1,5 +1,5 @@ import { Construct } from 'constructs'; -import { Template, Annotations, Match } from '../../../assertions'; +import { Annotations, Match, Template } from '../../../assertions'; import * as ccommit from '../../../aws-codecommit'; import { Pipeline } from '../../../aws-codepipeline'; import * as iam from '../../../aws-iam'; @@ -9,7 +9,7 @@ import * as cdk from '../../../core'; import { Stack } from '../../../core'; import * as cdkp from '../../lib'; import { CodePipeline } from '../../lib'; -import { PIPELINE_ENV, TestApp, ModernTestGitHubNpmPipeline, FileAssetApp, TwoStackApp, StageWithStackOutput } from '../testhelpers'; +import { FileAssetApp, ModernTestGitHubNpmPipeline, PIPELINE_ENV, StageWithStackOutput, TestApp, TwoStackApp } from '../testhelpers'; let app: TestApp; diff --git a/packages/aws-cdk-lib/pipelines/test/compliance/basic-behavior.test.ts b/packages/aws-cdk-lib/pipelines/test/compliance/basic-behavior.test.ts index 75d58084dadfb..81421fd1a837c 100644 --- a/packages/aws-cdk-lib/pipelines/test/compliance/basic-behavior.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/compliance/basic-behavior.test.ts @@ -1,10 +1,10 @@ /* eslint-disable import/no-extraneous-dependencies */ +import { Construct } from 'constructs'; import * as fs from 'fs'; import * as path from 'path'; -import { Construct } from 'constructs'; import { Capture, Match, Template } from '../../../assertions'; import { Stack, Stage, StageProps, Tags } from '../../../core'; -import { behavior, LegacyTestGitHubNpmPipeline, OneStackApp, BucketStack, PIPELINE_ENV, TestApp, ModernTestGitHubNpmPipeline, stringLike } from '../testhelpers'; +import { BucketStack, LegacyTestGitHubNpmPipeline, ModernTestGitHubNpmPipeline, OneStackApp, PIPELINE_ENV, TestApp, behavior, stringLike } from '../testhelpers'; let app: TestApp; let pipelineStack: Stack; diff --git a/packages/cdk-cli-wrapper/.jsii b/packages/cdk-cli-wrapper/.jsii new file mode 100644 index 0000000000000..62a6bd84aa219 --- /dev/null +++ b/packages/cdk-cli-wrapper/.jsii @@ -0,0 +1,1528 @@ +{ + "author": { + "name": "Amazon Web Services", + "organization": true, + "roles": [ + "author" + ], + "url": "https://aws.amazon.com" + }, + "description": "CDK CLI Wrapper Library", + "docs": { + "stability": "experimental" + }, + "homepage": "https://github.com/aws/aws-cdk", + "jsiiVersion": "5.0.2 (build fc559a8)", + "keywords": [ + "aws", + "cdk" + ], + "license": "Apache-2.0", + "metadata": { + "jsii": { + "compiledWithDeprecationWarnings": true, + "pacmak": { + "hasDefaultInterfaces": true + }, + "rosetta": { + "strict": true + } + } + }, + "name": "cdk-cli-wrapper", + "readme": { + "markdown": "# cdk-cli-wrapper\n\n\n---\n\n![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge)\n\n> The APIs of higher level constructs in this module are experimental and under active development.\n> They are subject to non-backward compatible changes or removal in any future version. These are\n> not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be\n> announced in the release notes. This means that while you may use them, you may need to update\n> your source code when upgrading to a newer version of this package.\n\n---\n\n\n\nCDK CLI Wrapper Library.\n\nInternal only for now.\n\n## Overview\n\nThis package provides a library which wraps the CDK CLI, allowing you to interact with the CLI programmatically.\n\nCurrently this package provides wrappers for:\n\n- `cdk deploy`\n- `cdk synth`\n- `cdk destroy`\n- `cdk list`\n\n## Usage\n\nFirst create a new `CdkCliWrapper` with the directory in which you want to execute commands,\nand optionally any environment variables that you want to include in the execution environment.\n\n```ts\nnew CdkCliWrapper({\n directory: '/path/to/project',\n env: {\n KEY: 'value',\n },\n});\n```\n\n### deploy\n\n```ts\nconst cdk = new CdkCliWrapper({\n directory: '/project/path',\n});\n\ncdk.deploy({\n app: 'node bin/my-app.js',\n stacks: ['my-test-stack'],\n});\n```\n\n### synth\n\n```ts\nconst cdk = new CdkCliWrapper({\n directory: '/project/path',\n});\n\ncdk.synth({\n app: 'node bin/my-app.js',\n stacks: ['my-test-stack'],\n});\n```\n\n### destroy\n\n```ts\nconst cdk = new CdkCliWrapper({\n directory: '/project/path',\n});\n\ncdk.destroy({\n app: 'node bin/my-app.js',\n stacks: ['my-test-stack'],\n});\n```\n\n### list\n\n```ts\nconst cdk = new CdkCliWrapper({\n directory: '/project/path',\n});\n\ncdk.list({\n app: 'node bin/my-app.js',\n stacks: ['*'],\n});\n```\n" + }, + "repository": { + "directory": "packages/cdk-cli-wrapper", + "type": "git", + "url": "https://github.com/aws/aws-cdk.git" + }, + "schema": "jsii/0.10.0", + "targets": { + "dotnet": { + "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/main/logo/default-256-dark.png", + "namespace": "Amazon.CDK.CdkCliWrapper", + "packageId": "Amazon.CDK.CdkCliWrapper" + }, + "java": { + "maven": { + "artifactId": "cdk-cli-wrapper", + "groupId": "software.amazon.awscdk" + }, + "package": "software.amazon.awscdk.cdkcliwrapper" + }, + "js": { + "npm": "cdk-cli-wrapper" + }, + "python": { + "classifiers": [ + "Framework :: AWS CDK", + "Framework :: AWS CDK :: 2" + ], + "distName": "aws-cdk.cdk-cli-wrapper", + "module": "aws_cdk.cdk_cli_wrapper" + } + }, + "types": { + "cdk-cli-wrapper.CdkCliWrapper": { + "assembly": "cdk-cli-wrapper", + "docs": { + "stability": "experimental", + "summary": "Provides a programmatic interface for interacting with the CDK CLI by wrapping the CLI with exec." + }, + "fqn": "cdk-cli-wrapper.CdkCliWrapper", + "initializer": { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 130 + }, + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.CdkCliWrapperOptions" + } + } + ] + }, + "interfaces": [ + "cdk-cli-wrapper.ICdk" + ], + "kind": "class", + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 124 + }, + "methods": [ + { + "docs": { + "stability": "experimental", + "summary": "cdk deploy." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 162 + }, + "name": "deploy", + "overrides": "cdk-cli-wrapper.ICdk", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.DeployOptions" + } + } + ] + }, + { + "docs": { + "stability": "experimental", + "summary": "cdk destroy." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 192 + }, + "name": "destroy", + "overrides": "cdk-cli-wrapper.ICdk", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.DestroyOptions" + } + } + ] + }, + { + "docs": { + "stability": "experimental", + "summary": "cdk list." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 147 + }, + "name": "list", + "overrides": "cdk-cli-wrapper.ICdk", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.ListOptions" + } + } + ], + "returns": { + "type": { + "primitive": "string" + } + } + }, + { + "docs": { + "stability": "experimental", + "summary": "cdk synth." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 209 + }, + "name": "synth", + "overrides": "cdk-cli-wrapper.ICdk", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.SynthOptions" + } + } + ] + }, + { + "docs": { + "remarks": "The CLI has a pretty slow startup time because of all the modules it needs to load,\nBypass it to be quicker!", + "stability": "experimental", + "summary": "Do a CDK synth, mimicking the CLI (without actually using it)." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 230 + }, + "name": "synthFast", + "overrides": "cdk-cli-wrapper.ICdk", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.SynthFastOptions" + } + } + ] + } + ], + "name": "CdkCliWrapper", + "symbolId": "lib/cdk-wrapper:CdkCliWrapper" + }, + "cdk-cli-wrapper.CdkCliWrapperOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "AWS CDK client that provides an API to programatically execute the CDK CLI by wrapping calls to exec the CLI." + }, + "fqn": "cdk-cli-wrapper.CdkCliWrapperOptions", + "kind": "interface", + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 90 + }, + "name": "CdkCliWrapperOptions", + "properties": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "The directory to run the cdk commands from." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 94 + }, + "name": "directory", + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "'aws-cdk/bin/cdk'", + "stability": "experimental", + "summary": "The path to the cdk executable." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 110 + }, + "name": "cdkExecutable", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "- no additional env vars", + "stability": "experimental", + "summary": "Additional environment variables to set in the execution environment that will be running the cdk commands." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 103 + }, + "name": "env", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Show the output from running the CDK CLI." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 117 + }, + "name": "showOutput", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/cdk-wrapper:CdkCliWrapperOptions" + }, + "cdk-cli-wrapper.DefaultCdkOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Default CDK CLI options that apply to all commands." + }, + "fqn": "cdk-cli-wrapper.DefaultCdkOptions", + "kind": "interface", + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 24 + }, + "name": "DefaultCdkOptions", + "properties": [ + { + "abstract": true, + "docs": { + "default": "- false", + "remarks": "Requried if `stacks` is not set", + "stability": "experimental", + "summary": "Deploy all stacks." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 41 + }, + "name": "all", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- read from cdk.json", + "stability": "experimental", + "summary": "command-line for executing your app or a cloud assembly directory e.g. \"node bin/my-app.js\" or \"cdk.out\"." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 51 + }, + "name": "app", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Include \"aws:asset:*\" CloudFormation metadata for resources that use assets." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 171 + }, + "name": "assetMetadata", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- read from AWS_CA_BUNDLE environment variable", + "stability": "experimental", + "summary": "Path to CA certificate to use when validating HTTPS requests." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 143 + }, + "name": "caBundlePath", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Show colors and other style from console output." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 201 + }, + "name": "color", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- no additional context", + "stability": "experimental", + "summary": "Additional context." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 66 + }, + "name": "context", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "enable emission of additional debugging information, such as creation stack traces of tokens." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 120 + }, + "name": "debug", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- guess EC2 instance status", + "stability": "experimental", + "summary": "Force trying to fetch EC2 instance credentials." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 150 + }, + "name": "ec2Creds", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Ignores synthesis errors, which will likely produce an invalid output." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 97 + }, + "name": "ignoreErrors", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Use JSON output instead of YAML when templates are printed to STDOUT." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 105 + }, + "name": "json", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "remarks": "Synthesis fails if this is disabled and context lookups need\nto be performed", + "stability": "experimental", + "summary": "Perform context lookups." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 90 + }, + "name": "lookups", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Show relevant notices." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 194 + }, + "name": "notices", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "cdk.out", + "stability": "experimental", + "summary": "Emits the synthesized cloud assembly into a directory." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 187 + }, + "name": "output", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Include \"aws:cdk:path\" CloudFormation metadata for each resource." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 164 + }, + "name": "pathMetadata", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- no profile is used", + "stability": "experimental", + "summary": "Use the indicated AWS profile as the default environment." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 127 + }, + "name": "profile", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "- no proxy", + "remarks": "Will read from\nHTTPS_PROXY environment if specified", + "stability": "experimental", + "summary": "Use the indicated proxy." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 135 + }, + "name": "proxy", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "- use the bootstrap cfn-exec role", + "stability": "experimental", + "summary": "Role to pass to CloudFormation for deployment." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 59 + }, + "name": "roleArn", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "- []", + "remarks": "Requried if `all` is not set", + "stability": "experimental", + "summary": "List of stacks to deploy." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 32 + }, + "name": "stacks", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "array" + } + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "remarks": "Needed for local debugging the source files with SAM CLI", + "stability": "experimental", + "summary": "Copy assets to the output directory." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 180 + }, + "name": "staging", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Do not construct stacks with warnings." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 80 + }, + "name": "strict", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Print trace for stack warnings." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 73 + }, + "name": "trace", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "show debug logs." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 112 + }, + "name": "verbose", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Include \"AWS::CDK::Metadata\" resource in synthesized templates." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 157 + }, + "name": "versionReporting", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/commands/common:DefaultCdkOptions" + }, + "cdk-cli-wrapper.DeployOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Options to use with cdk deploy." + }, + "fqn": "cdk-cli-wrapper.DeployOptions", + "interfaces": [ + "cdk-cli-wrapper.DefaultCdkOptions" + ], + "kind": "interface", + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 6 + }, + "name": "DeployOptions", + "properties": [ + { + "abstract": true, + "docs": { + "default": "- auto generate a name", + "remarks": "If not provided, a name will be generated automatically.", + "stability": "experimental", + "summary": "Optional name to use for the CloudFormation change set." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 34 + }, + "name": "changeSetName", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Whether we are on a CI system." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 96 + }, + "name": "ci", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Only perform action on the given stack." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 12 + }, + "name": "exclusively", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Whether to execute the ChangeSet Not providing `execute` parameter will result in execution of ChangeSet." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 68 + }, + "name": "execute", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Always deploy, even if templates are identical." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 40 + }, + "name": "force", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "- no notifications", + "stability": "experimental", + "summary": "ARNs of SNS topics that CloudFormation will notify with stack related events." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 54 + }, + "name": "notificationArns", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "array" + } + } + }, + { + "abstract": true, + "docs": { + "default": "- Outputs are not written to any file", + "stability": "experimental", + "summary": "Path to file where stack outputs will be written after a successful deploy as JSON." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 89 + }, + "name": "outputsFile", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "{}", + "stability": "experimental", + "summary": "Additional parameters for CloudFormation at deploy time." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 74 + }, + "name": "parameters", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "StackActivityProgress.EVENTS", + "remarks": "The default in the CLI is StackActivityProgress.BAR, but\nsince the cli-wrapper will most likely be run in automation it makes\nmore sense to set the default to StackActivityProgress.EVENTS", + "stability": "experimental", + "summary": "Display mode for stack activity events." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 107 + }, + "name": "progress", + "optional": true, + "type": { + "fqn": "cdk-cli-wrapper.StackActivityProgress" + } + }, + { + "abstract": true, + "docs": { + "default": "RequireApproval.Never", + "stability": "experimental", + "summary": "What kind of security changes require approval." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 61 + }, + "name": "requireApproval", + "optional": true, + "type": { + "fqn": "cdk-cli-wrapper.RequireApproval" + } + }, + { + "abstract": true, + "docs": { + "default": "- do not reuse assets", + "stability": "experimental", + "summary": "Reuse the assets with the given asset IDs." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 26 + }, + "name": "reuseAssets", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "array" + } + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "stability": "experimental", + "summary": "Rollback failed deployments." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 47 + }, + "name": "rollback", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "CDKToolkit", + "stability": "experimental", + "summary": "Name of the toolkit stack to use/deploy." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 19 + }, + "name": "toolkitStackName", + "optional": true, + "type": { + "primitive": "string" + } + }, + { + "abstract": true, + "docs": { + "default": "true", + "remarks": "If not set, all parameters must be specified for every deployment.", + "stability": "experimental", + "summary": "Use previous values for unspecified parameters." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 83 + }, + "name": "usePreviousParameters", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/commands/deploy:DeployOptions" + }, + "cdk-cli-wrapper.DestroyOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Options to use with cdk destroy." + }, + "fqn": "cdk-cli-wrapper.DestroyOptions", + "interfaces": [ + "cdk-cli-wrapper.DefaultCdkOptions" + ], + "kind": "interface", + "locationInModule": { + "filename": "lib/commands/destroy.ts", + "line": 6 + }, + "name": "DestroyOptions", + "properties": [ + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Only destroy the given stack." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/destroy.ts", + "line": 19 + }, + "name": "exclusively", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Do not ask for permission before destroying stacks." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/destroy.ts", + "line": 12 + }, + "name": "force", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/commands/destroy:DestroyOptions" + }, + "cdk-cli-wrapper.Environment": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "deprecated": "Use raw property bags instead (object literals, `Map`, etc... )", + "stability": "deprecated", + "summary": "Additional environment variables to set in the execution environment." + }, + "fqn": "cdk-cli-wrapper.Environment", + "kind": "interface", + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 77 + }, + "name": "Environment", + "symbolId": "lib/cdk-wrapper:Environment" + }, + "cdk-cli-wrapper.ICdk": { + "assembly": "cdk-cli-wrapper", + "docs": { + "stability": "experimental", + "summary": "AWS CDK CLI operations." + }, + "fqn": "cdk-cli-wrapper.ICdk", + "kind": "interface", + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 7 + }, + "methods": [ + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "cdk deploy." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 12 + }, + "name": "deploy", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.DeployOptions" + } + } + ] + }, + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "cdk destroy." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 22 + }, + "name": "destroy", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.DestroyOptions" + } + } + ] + }, + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "cdk list." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 27 + }, + "name": "list", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.ListOptions" + } + } + ], + "returns": { + "type": { + "primitive": "string" + } + } + }, + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "cdk synth." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 17 + }, + "name": "synth", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.SynthOptions" + } + } + ] + }, + { + "abstract": true, + "docs": { + "stability": "experimental", + "summary": "cdk synth fast." + }, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 32 + }, + "name": "synthFast", + "parameters": [ + { + "name": "options", + "type": { + "fqn": "cdk-cli-wrapper.SynthFastOptions" + } + } + ] + } + ], + "name": "ICdk", + "symbolId": "lib/cdk-wrapper:ICdk" + }, + "cdk-cli-wrapper.ListOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Options for cdk list." + }, + "fqn": "cdk-cli-wrapper.ListOptions", + "interfaces": [ + "cdk-cli-wrapper.DefaultCdkOptions" + ], + "kind": "interface", + "locationInModule": { + "filename": "lib/commands/list.ts", + "line": 6 + }, + "name": "ListOptions", + "properties": [ + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Display environment information for each stack." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/list.ts", + "line": 12 + }, + "name": "long", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/commands/list:ListOptions" + }, + "cdk-cli-wrapper.RequireApproval": { + "assembly": "cdk-cli-wrapper", + "docs": { + "stability": "experimental", + "summary": "In what scenarios should the CLI ask for approval." + }, + "fqn": "cdk-cli-wrapper.RequireApproval", + "kind": "enum", + "locationInModule": { + "filename": "lib/commands/common.ts", + "line": 4 + }, + "members": [ + { + "docs": { + "stability": "experimental", + "summary": "Never ask for approval." + }, + "name": "NEVER" + }, + { + "docs": { + "stability": "experimental", + "summary": "Prompt for approval for any type of change to the stack." + }, + "name": "ANYCHANGE" + }, + { + "docs": { + "stability": "experimental", + "summary": "Only prompt for approval if there are security related changes." + }, + "name": "BROADENING" + } + ], + "name": "RequireApproval", + "symbolId": "lib/commands/common:RequireApproval" + }, + "cdk-cli-wrapper.StackActivityProgress": { + "assembly": "cdk-cli-wrapper", + "docs": { + "stability": "experimental", + "summary": "Supported display modes for stack deployment activity." + }, + "fqn": "cdk-cli-wrapper.StackActivityProgress", + "kind": "enum", + "locationInModule": { + "filename": "lib/commands/deploy.ts", + "line": 113 + }, + "members": [ + { + "docs": { + "stability": "experimental", + "summary": "Displays a progress bar with only the events for the resource currently being deployed." + }, + "name": "BAR" + }, + { + "docs": { + "stability": "experimental", + "summary": "Displays complete history with all CloudFormation stack events." + }, + "name": "EVENTS" + } + ], + "name": "StackActivityProgress", + "symbolId": "lib/commands/deploy:StackActivityProgress" + }, + "cdk-cli-wrapper.SynthFastOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Options for synthing and bypassing the CDK CLI." + }, + "fqn": "cdk-cli-wrapper.SynthFastOptions", + "kind": "interface", + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 38 + }, + "name": "SynthFastOptions", + "properties": [ + { + "abstract": true, + "docs": { + "remarks": "e.g. \"node 'bin/my-app.ts'\"\nor 'go run main.go'", + "stability": "experimental", + "summary": "The command to use to execute the app. This is typically the same thing that normally gets passed to `--app`." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 47 + }, + "name": "execCmd", + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "array" + } + } + }, + { + "abstract": true, + "docs": { + "default": "- no additional context", + "stability": "experimental", + "summary": "Additional context." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 61 + }, + "name": "context", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "- no additional env", + "stability": "experimental", + "summary": "Additional environment variables to set in the execution environment." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 69 + }, + "name": "env", + "optional": true, + "type": { + "collection": { + "elementtype": { + "primitive": "string" + }, + "kind": "map" + } + } + }, + { + "abstract": true, + "docs": { + "default": "cdk.out", + "stability": "experimental", + "summary": "Emits the synthesized cloud assembly into a directory." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/cdk-wrapper.ts", + "line": 54 + }, + "name": "output", + "optional": true, + "type": { + "primitive": "string" + } + } + ], + "symbolId": "lib/cdk-wrapper:SynthFastOptions" + }, + "cdk-cli-wrapper.SynthOptions": { + "assembly": "cdk-cli-wrapper", + "datatype": true, + "docs": { + "stability": "experimental", + "summary": "Options to use with cdk synth." + }, + "fqn": "cdk-cli-wrapper.SynthOptions", + "interfaces": [ + "cdk-cli-wrapper.DefaultCdkOptions" + ], + "kind": "interface", + "locationInModule": { + "filename": "lib/commands/synth.ts", + "line": 6 + }, + "name": "SynthOptions", + "properties": [ + { + "abstract": true, + "docs": { + "default": "false", + "stability": "experimental", + "summary": "Only synthesize the given stack." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/synth.ts", + "line": 27 + }, + "name": "exclusively", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "false;", + "stability": "experimental", + "summary": "Do not output CloudFormation Template to stdout." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/synth.ts", + "line": 20 + }, + "name": "quiet", + "optional": true, + "type": { + "primitive": "boolean" + } + }, + { + "abstract": true, + "docs": { + "default": "true;", + "stability": "experimental", + "summary": "After synthesis, validate stacks with the \"validateOnSynth\" attribute set (can also be controlled with CDK_VALIDATION)." + }, + "immutable": true, + "locationInModule": { + "filename": "lib/commands/synth.ts", + "line": 14 + }, + "name": "validation", + "optional": true, + "type": { + "primitive": "boolean" + } + } + ], + "symbolId": "lib/commands/synth:SynthOptions" + } + }, + "version": "0.0.0", + "fingerprint": "7DPD0yMgHZTMx1AEyOkTee0ioLeClu0VVOoQhq0450o=" +} \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/.warnings.jsii.js b/packages/cdk-cli-wrapper/.warnings.jsii.js new file mode 100644 index 0000000000000..6561cc1d41e13 --- /dev/null +++ b/packages/cdk-cli-wrapper/.warnings.jsii.js @@ -0,0 +1,73 @@ +function cdk_cli_wrapper_ICdk(p) { +} +function cdk_cli_wrapper_SynthFastOptions(p) { +} +function cdk_cli_wrapper_Environment(p) { +} +function cdk_cli_wrapper_CdkCliWrapperOptions(p) { +} +function cdk_cli_wrapper_CdkCliWrapper(p) { +} +function cdk_cli_wrapper_SynthOptions(p) { +} +function cdk_cli_wrapper_RequireApproval(p) { +} +function cdk_cli_wrapper_DefaultCdkOptions(p) { +} +function cdk_cli_wrapper_DeployOptions(p) { + if (p == null) + return; + visitedObjects.add(p); + try { + if (!visitedObjects.has(p.progress)) + cdk_cli_wrapper_StackActivityProgress(p.progress); + if (!visitedObjects.has(p.requireApproval)) + cdk_cli_wrapper_RequireApproval(p.requireApproval); + } + finally { + visitedObjects.delete(p); + } +} +function cdk_cli_wrapper_StackActivityProgress(p) { +} +function cdk_cli_wrapper_DestroyOptions(p) { +} +function cdk_cli_wrapper_ListOptions(p) { +} +function print(name, deprecationMessage) { + const deprecated = process.env.JSII_DEPRECATED; + const deprecationMode = ["warn", "fail", "quiet"].includes(deprecated) ? deprecated : "warn"; + const message = `${name} is deprecated.\n ${deprecationMessage.trim()}\n This API will be removed in the next major release.`; + switch (deprecationMode) { + case "fail": + throw new DeprecationError(message); + case "warn": + console.warn("[WARNING]", message); + break; + } +} +function getPropertyDescriptor(obj, prop) { + const descriptor = Object.getOwnPropertyDescriptor(obj, prop); + if (descriptor) { + return descriptor; + } + const proto = Object.getPrototypeOf(obj); + const prototypeDescriptor = proto && getPropertyDescriptor(proto, prop); + if (prototypeDescriptor) { + return prototypeDescriptor; + } + return {}; +} +const visitedObjects = new Set(); +class DeprecationError extends Error { + constructor(...args) { + super(...args); + Object.defineProperty(this, "name", { + configurable: false, + enumerable: true, + value: "DeprecationError", + writable: false, + }); + } +} +module.exports = { print, getPropertyDescriptor, DeprecationError, cdk_cli_wrapper_ICdk, cdk_cli_wrapper_SynthFastOptions, cdk_cli_wrapper_Environment, cdk_cli_wrapper_CdkCliWrapperOptions, cdk_cli_wrapper_CdkCliWrapper, cdk_cli_wrapper_SynthOptions, cdk_cli_wrapper_RequireApproval, cdk_cli_wrapper_DefaultCdkOptions, cdk_cli_wrapper_DeployOptions, cdk_cli_wrapper_StackActivityProgress, cdk_cli_wrapper_DestroyOptions, cdk_cli_wrapper_ListOptions }; diff --git a/packages/cdk-cli-wrapper/lib/cdk-wrapper.d.ts b/packages/cdk-cli-wrapper/lib/cdk-wrapper.d.ts new file mode 100644 index 0000000000000..f3f69e35a9ad2 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/cdk-wrapper.d.ts @@ -0,0 +1,139 @@ +import { DeployOptions, DestroyOptions, SynthOptions, ListOptions } from './commands'; +/** + * AWS CDK CLI operations + */ +export interface ICdk { + /** + * cdk deploy + */ + deploy(options: DeployOptions): void; + /** + * cdk synth + */ + synth(options: SynthOptions): void; + /** + * cdk destroy + */ + destroy(options: DestroyOptions): void; + /** + * cdk list + */ + list(options: ListOptions): string; + /** + * cdk synth fast + */ + synthFast(options: SynthFastOptions): void; +} +/** + * Options for synthing and bypassing the CDK CLI + */ +export interface SynthFastOptions { + /** + * The command to use to execute the app. + * This is typically the same thing that normally + * gets passed to `--app` + * + * e.g. "node 'bin/my-app.ts'" + * or 'go run main.go' + */ + readonly execCmd: string[]; + /** + * Emits the synthesized cloud assembly into a directory + * + * @default cdk.out + */ + readonly output?: string; + /** + * Additional context + * + * @default - no additional context + */ + readonly context?: Record; + /** + * Additional environment variables to set in the + * execution environment + * + * @default - no additional env + */ + readonly env?: { + [name: string]: string; + }; +} +/** + * Additional environment variables to set in the execution environment + * + * @deprecated Use raw property bags instead (object literals, `Map`, etc... ) + */ +export interface Environment { + /** + * This index signature is not usable in non-TypeScript/JavaScript languages. + * + * @jsii ignore + */ + [key: string]: string | undefined; +} +/** + * AWS CDK client that provides an API to programatically execute the CDK CLI + * by wrapping calls to exec the CLI + */ +export interface CdkCliWrapperOptions { + /** + * The directory to run the cdk commands from + */ + readonly directory: string; + /** + * Additional environment variables to set + * in the execution environment that will be running + * the cdk commands + * + * @default - no additional env vars + */ + readonly env?: { + [name: string]: string; + }; + /** + * The path to the cdk executable + * + * @default 'aws-cdk/bin/cdk' + */ + readonly cdkExecutable?: string; + /** + * Show the output from running the CDK CLI + * + * @default false + */ + readonly showOutput?: boolean; +} +/** + * Provides a programmatic interface for interacting with the CDK CLI by + * wrapping the CLI with exec + */ +export declare class CdkCliWrapper implements ICdk { + private readonly directory; + private readonly env?; + private readonly cdk; + private readonly showOutput; + constructor(options: CdkCliWrapperOptions); + private validateArgs; + list(options: ListOptions): string; + /** + * cdk deploy + */ + deploy(options: DeployOptions): void; + /** + * cdk destroy + */ + destroy(options: DestroyOptions): void; + /** + * cdk synth + */ + synth(options: SynthOptions): void; + /** + * Do a CDK synth, mimicking the CLI (without actually using it) + * + * The CLI has a pretty slow startup time because of all the modules it needs to load, + * Bypass it to be quicker! + */ + synthFast(options: SynthFastOptions): void; + private createDefaultArguments; +} diff --git a/packages/cdk-cli-wrapper/lib/cdk-wrapper.js b/packages/cdk-cli-wrapper/lib/cdk-wrapper.js new file mode 100644 index 0000000000000..21758ec69e37d --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/cdk-wrapper.js @@ -0,0 +1,229 @@ +"use strict"; +var _a; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CdkCliWrapper = void 0; +const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); +const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); +const commands_1 = require("./commands"); +const utils_1 = require("./utils"); +/** + * Provides a programmatic interface for interacting with the CDK CLI by + * wrapping the CLI with exec + */ +class CdkCliWrapper { + constructor(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_CdkCliWrapperOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, CdkCliWrapper); + } + throw error; + } + this.directory = options.directory; + this.env = options.env; + this.showOutput = options.showOutput ?? false; + try { + this.cdk = options.cdkExecutable ?? 'cdk'; + } + catch { + throw new Error(`could not resolve path to cdk executable: "${options.cdkExecutable ?? 'cdk'}"`); + } + } + validateArgs(options) { + if (!options.stacks && !options.all) { + throw new Error('one of "app" or "stacks" must be provided'); + } + } + list(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_ListOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, this.list); + } + throw error; + } + const listCommandArgs = [ + ...renderBooleanArg('long', options.long), + ...this.createDefaultArguments(options), + ]; + return (0, utils_1.exec)([this.cdk, 'ls', ...listCommandArgs], { + cwd: this.directory, + verbose: this.showOutput, + env: this.env, + }); + } + /** + * cdk deploy + */ + deploy(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_DeployOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, this.deploy); + } + throw error; + } + const deployCommandArgs = [ + ...renderBooleanArg('ci', options.ci), + ...renderBooleanArg('execute', options.execute), + ...renderBooleanArg('exclusively', options.exclusively), + ...renderBooleanArg('force', options.force), + ...renderBooleanArg('previous-parameters', options.usePreviousParameters), + ...renderBooleanArg('rollback', options.rollback), + ...renderBooleanArg('staging', options.staging), + ...options.reuseAssets ? renderArrayArg('--reuse-assets', options.reuseAssets) : [], + ...options.notificationArns ? renderArrayArg('--notification-arns', options.notificationArns) : [], + ...options.parameters ? renderMapArrayArg('--parameters', options.parameters) : [], + ...options.outputsFile ? ['--outputs-file', options.outputsFile] : [], + ...options.requireApproval ? ['--require-approval', options.requireApproval] : [], + ...options.changeSetName ? ['--change-set-name', options.changeSetName] : [], + ...options.toolkitStackName ? ['--toolkit-stack-name', options.toolkitStackName] : [], + ...options.progress ? ['--progress', options.progress] : ['--progress', commands_1.StackActivityProgress.EVENTS], + ...this.createDefaultArguments(options), + ]; + (0, utils_1.exec)([this.cdk, 'deploy', ...deployCommandArgs], { + cwd: this.directory, + verbose: this.showOutput, + env: this.env, + }); + } + /** + * cdk destroy + */ + destroy(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_DestroyOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, this.destroy); + } + throw error; + } + const destroyCommandArgs = [ + ...renderBooleanArg('force', options.force), + ...renderBooleanArg('exclusively', options.exclusively), + ...this.createDefaultArguments(options), + ]; + (0, utils_1.exec)([this.cdk, 'destroy', ...destroyCommandArgs], { + cwd: this.directory, + verbose: this.showOutput, + env: this.env, + }); + } + /** + * cdk synth + */ + synth(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_SynthOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, this.synth); + } + throw error; + } + const synthCommandArgs = [ + ...renderBooleanArg('validation', options.validation), + ...renderBooleanArg('quiet', options.quiet), + ...renderBooleanArg('exclusively', options.exclusively), + ...this.createDefaultArguments(options), + ]; + (0, utils_1.exec)([this.cdk, 'synth', ...synthCommandArgs], { + cwd: this.directory, + verbose: this.showOutput, + env: this.env, + }); + } + /** + * Do a CDK synth, mimicking the CLI (without actually using it) + * + * The CLI has a pretty slow startup time because of all the modules it needs to load, + * Bypass it to be quicker! + */ + synthFast(options) { + try { + jsiiDeprecationWarnings.cdk_cli_wrapper_SynthFastOptions(options); + } + catch (error) { + if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { + Error.captureStackTrace(error, this.synthFast); + } + throw error; + } + (0, utils_1.exec)(options.execCmd, { + cwd: this.directory, + verbose: this.showOutput, + env: { + CDK_CONTEXT_JSON: JSON.stringify(options.context), + CDK_OUTDIR: options.output, + ...this.env, + ...options.env, + }, + }); + } + createDefaultArguments(options) { + this.validateArgs(options); + const stacks = options.stacks ?? []; + return [ + ...options.app ? ['--app', options.app] : [], + ...renderBooleanArg('strict', options.strict), + ...renderBooleanArg('trace', options.trace), + ...renderBooleanArg('lookups', options.lookups), + ...renderBooleanArg('ignore-errors', options.ignoreErrors), + ...renderBooleanArg('json', options.json), + ...renderBooleanArg('verbose', options.verbose), + ...renderBooleanArg('debug', options.debug), + ...renderBooleanArg('ec2creds', options.ec2Creds), + ...renderBooleanArg('version-reporting', options.versionReporting), + ...renderBooleanArg('path-metadata', options.pathMetadata), + ...renderBooleanArg('asset-metadata', options.assetMetadata), + ...renderBooleanArg('notices', options.notices), + ...renderBooleanArg('color', options.color), + ...options.context ? renderMapArrayArg('--context', options.context) : [], + ...options.profile ? ['--profile', options.profile] : [], + ...options.proxy ? ['--proxy', options.proxy] : [], + ...options.caBundlePath ? ['--ca-bundle-path', options.caBundlePath] : [], + ...options.roleArn ? ['--role-arn', options.roleArn] : [], + ...options.output ? ['--output', options.output] : [], + ...stacks, + ...options.all ? ['--all'] : [], + ]; + } +} +_a = JSII_RTTI_SYMBOL_1; +CdkCliWrapper[_a] = { fqn: "cdk-cli-wrapper.CdkCliWrapper", version: "0.0.0" }; +exports.CdkCliWrapper = CdkCliWrapper; +function renderMapArrayArg(flag, parameters) { + const params = []; + for (const [key, value] of Object.entries(parameters)) { + params.push(`${key}=${value}`); + } + return renderArrayArg(flag, params); +} +function renderArrayArg(flag, values) { + let args = []; + for (const value of values ?? []) { + args.push(flag, value); + } + return args; +} +function renderBooleanArg(val, arg) { + if (arg) { + return [`--${val}`]; + } + else if (arg === undefined) { + return []; + } + else { + return [`--no-${val}`]; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RrLXdyYXBwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjZGstd3JhcHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx5Q0FBZ0k7QUFDaEksbUNBQStCO0FBc0gvQjs7O0dBR0c7QUFDSCxNQUFhLGFBQWE7SUFNeEIsWUFBWSxPQUE2Qjs7Ozs7OytDQU45QixhQUFhOzs7O1FBT3RCLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUNuQyxJQUFJLENBQUMsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDdkIsSUFBSSxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVSxJQUFJLEtBQUssQ0FBQztRQUM5QyxJQUFJO1lBQ0YsSUFBSSxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsYUFBYSxJQUFJLEtBQUssQ0FBQztTQUMzQztRQUFDLE1BQU07WUFDTixNQUFNLElBQUksS0FBSyxDQUFDLDhDQUE4QyxPQUFPLENBQUMsYUFBYSxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7U0FDbEc7S0FDRjtJQUVPLFlBQVksQ0FBQyxPQUEwQjtRQUM3QyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO1NBQzlEO0tBQ0Y7SUFFTSxJQUFJLENBQUMsT0FBb0I7Ozs7Ozs7Ozs7UUFDOUIsTUFBTSxlQUFlLEdBQWE7WUFDaEMsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQztZQUN6QyxHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUM7U0FDeEMsQ0FBQztRQUVGLE9BQU8sSUFBQSxZQUFJLEVBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxHQUFHLGVBQWUsQ0FBQyxFQUFFO1lBQ2hELEdBQUcs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ekYsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBQzVCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQ3JELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksS0FBSyxFQUFFLENBQUMsQ0FBQztLQUNoQztJQUNELE9BQU8sY0FBYyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztBQUN0QyxDQUFDO0FBRUQsU0FBUyxjQUFjLENBQUMsSUFBWSxFQUFFLE1BQWlCO0lBQ3JELElBQUksSUFBSSxHQUFhLEVBQUUsQ0FBQztJQUN4QixLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sSUFBSSxFQUFFLEVBQUU7UUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7S0FDeEI7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxTQUFTLGdCQUFnQixDQUFDLEdBQVcsRUFBRSxHQUFhO0lBQ2xELElBQUksR0FBRyxFQUFFO1FBQ1AsT0FBTyxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUMsQ0FBQztLQUNyQjtTQUFNLElBQUksR0FBRyxLQUFLLFNBQVMsRUFBRTtRQUM1QixPQUFPLEVBQUUsQ0FBQztLQUNYO1NBQU07UUFDTCxPQUFPLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0tBQ3hCO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlZmF1bHRDZGtPcHRpb25zLCBEZXBsb3lPcHRpb25zLCBEZXN0cm95T3B0aW9ucywgU3ludGhPcHRpb25zLCBMaXN0T3B0aW9ucywgU3RhY2tBY3Rpdml0eVByb2dyZXNzIH0gZnJvbSAnLi9jb21tYW5kcyc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAnLi91dGlscyc7XG5cbi8qKlxuICogQVdTIENESyBDTEkgb3BlcmF0aW9uc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIElDZGsge1xuXG4gIC8qKlxuICAgKiBjZGsgZGVwbG95XG4gICAqL1xuICBkZXBsb3kob3B0aW9uczogRGVwbG95T3B0aW9ucyk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIGNkayBzeW50aFxuICAgKi9cbiAgc3ludGgob3B0aW9uczogU3ludGhPcHRpb25zKTogdm9pZDtcblxuICAvKipcbiAgICogY2RrIGRlc3Ryb3lcbiAgICovXG4gIGRlc3Ryb3kob3B0aW9uczogRGVzdHJveU9wdGlvbnMpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBjZGsgbGlzdFxuICAgKi9cbiAgbGlzdChvcHRpb25zOiBMaXN0T3B0aW9ucyk6IHN0cmluZztcblxuICAvKipcbiAgICogY2RrIHN5bnRoIGZhc3RcbiAgICovXG4gIHN5bnRoRmFzdChvcHRpb25zOiBTeW50aEZhc3RPcHRpb25zKTogdm9pZDtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBzeW50aGluZyBhbmQgYnlwYXNzaW5nIHRoZSBDREsgQ0xJXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3ludGhGYXN0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgY29tbWFuZCB0byB1c2UgdG8gZXhlY3V0ZSB0aGUgYXBwLlxuICAgKiBUaGlzIGlzIHR5cGljYWxseSB0aGUgc2FtZSB0aGluZyB0aGF0IG5vcm1hbGx5XG4gICAqIGdldHMgcGFzc2VkIHRvIGAtLWFwcGBcbiAgICpcbiAgICogZS5nLiBcIm5vZGUgJ2Jpbi9teS1hcHAudHMnXCJcbiAgICogb3IgJ2dvIHJ1biBtYWluLmdvJ1xuICAgKi9cbiAgcmVhZG9ubHkgZXhlY0NtZDogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBzeW50aGVzaXplZCBjbG91ZCBhc3NlbWJseSBpbnRvIGEgZGlyZWN0b3J5XG4gICAqXG4gICAqIEBkZWZhdWx0IGNkay5vdXRcbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dD86IHN0cmluZyxcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBjb250ZXh0XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYWRkaXRpb25hbCBjb250ZXh0XG4gICAqL1xuICByZWFkb25seSBjb250ZXh0PzogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gc2V0IGluIHRoZVxuICAgKiBleGVjdXRpb24gZW52aXJvbm1lbnRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBhZGRpdGlvbmFsIGVudlxuICAgKi9cbiAgcmVhZG9ubHkgZW52PzogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nOyB9LFxufVxuXG4vKipcbiAqIEFkZGl0aW9uYWwgZW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIHNldCBpbiB0aGUgZXhlY3V0aW9uIGVudmlyb25tZW50XG4gKlxuICogQGRlcHJlY2F0ZWQgVXNlIHJhdyBwcm9wZXJ0eSBiYWdzIGluc3RlYWQgKG9iamVjdCBsaXRlcmFscywgYE1hcDxTdHJpbmcsT2JqZWN0PmAsIGV0Yy4uLiApXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW52aXJvbm1lbnQge1xuICAvKipcbiAgICogVGhpcyBpbmRleCBzaWduYXR1cmUgaXMgbm90IHVzYWJsZSBpbiBub24tVHlwZVNjcmlwdC9KYXZhU2NyaXB0IGxhbmd1YWdlcy5cbiAgICpcbiAgICogQGpzaWkgaWdub3JlXG4gICAqL1xuICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWRcbn1cblxuLyoqXG4gKiBBV1MgQ0RLIGNsaWVudCB0aGF0IHByb3ZpZGVzIGFuIEFQSSB0byBwcm9ncmFtYXRpY2FsbHkgZXhlY3V0ZSB0aGUgQ0RLIENMSVxuICogYnkgd3JhcHBpbmcgY2FsbHMgdG8gZXhlYyB0aGUgQ0xJXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2RrQ2xpV3JhcHBlck9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSB0byBydW4gdGhlIGNkayBjb21tYW5kcyBmcm9tXG4gICAqL1xuICByZWFkb25seSBkaXJlY3Rvcnk6IHN0cmluZyxcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gc2V0XG4gICAqIGluIHRoZSBleGVjdXRpb24gZW52aXJvbm1lbnQgdGhhdCB3aWxsIGJlIHJ1bm5pbmdcbiAgICogdGhlIGNkayBjb21tYW5kc1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGFkZGl0aW9uYWwgZW52IHZhcnNcbiAgICovXG4gIHJlYWRvbmx5IGVudj86IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9LFxuXG4gIC8qKlxuICAgKiBUaGUgcGF0aCB0byB0aGUgY2RrIGV4ZWN1dGFibGVcbiAgICpcbiAgICogQGRlZmF1bHQgJ2F3cy1jZGsvYmluL2NkaydcbiAgICovXG4gIHJlYWRvbmx5IGNka0V4ZWN1dGFibGU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFNob3cgdGhlIG91dHB1dCBmcm9tIHJ1bm5pbmcgdGhlIENESyBDTElcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNob3dPdXRwdXQ/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIFByb3ZpZGVzIGEgcHJvZ3JhbW1hdGljIGludGVyZmFjZSBmb3IgaW50ZXJhY3Rpbmcgd2l0aCB0aGUgQ0RLIENMSSBieVxuICogd3JhcHBpbmcgdGhlIENMSSB3aXRoIGV4ZWNcbiAqL1xuZXhwb3J0IGNsYXNzIENka0NsaVdyYXBwZXIgaW1wbGVtZW50cyBJQ2RrIHtcbiAgcHJpdmF0ZSByZWFkb25seSBkaXJlY3Rvcnk6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBlbnY/OiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQ7IH07XG4gIHByaXZhdGUgcmVhZG9ubHkgY2RrOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2hvd091dHB1dDogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBDZGtDbGlXcmFwcGVyT3B0aW9ucykge1xuICAgIHRoaXMuZGlyZWN0b3J5ID0gb3B0aW9ucy5kaXJlY3Rvcnk7XG4gICAgdGhpcy5lbnYgPSBvcHRpb25zLmVudjtcbiAgICB0aGlzLnNob3dPdXRwdXQgPSBvcHRpb25zLnNob3dPdXRwdXQgPz8gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuY2RrID0gb3B0aW9ucy5jZGtFeGVjdXRhYmxlID8/ICdjZGsnO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBjb3VsZCBub3QgcmVzb2x2ZSBwYXRoIHRvIGNkayBleGVjdXRhYmxlOiBcIiR7b3B0aW9ucy5jZGtFeGVjdXRhYmxlID8/ICdjZGsnfVwiYCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZUFyZ3Mob3B0aW9uczogRGVmYXVsdENka09wdGlvbnMpOiB2b2lkIHtcbiAgICBpZiAoIW9wdGlvbnMuc3RhY2tzICYmICFvcHRpb25zLmFsbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdvbmUgb2YgXCJhcHBcIiBvciBcInN0YWNrc1wiIG11c3QgYmUgcHJvdmlkZWQnKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgbGlzdChvcHRpb25zOiBMaXN0T3B0aW9ucyk6IHN0cmluZyB7XG4gICAgY29uc3QgbGlzdENvbW1hbmRBcmdzOiBzdHJpbmdbXSA9IFtcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ2xvbmcnLCBvcHRpb25zLmxvbmcpLFxuICAgICAgLi4udGhpcy5jcmVhdGVEZWZhdWx0QXJndW1lbnRzKG9wdGlvbnMpLFxuICAgIF07XG5cbiAgICByZXR1cm4gZXhlYyhbdGhpcy5jZGssICdscycsIC4uLmxpc3RDb21tYW5kQXJnc10sIHtcbiAgICAgIGN3ZDogdGhpcy5kaXJlY3RvcnksXG4gICAgICB2ZXJib3NlOiB0aGlzLnNob3dPdXRwdXQsXG4gICAgICBlbnY6IHRoaXMuZW52LFxuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBjZGsgZGVwbG95XG4gICAqL1xuICBwdWJsaWMgZGVwbG95KG9wdGlvbnM6IERlcGxveU9wdGlvbnMpOiB2b2lkIHtcbiAgICBjb25zdCBkZXBsb3lDb21tYW5kQXJnczogc3RyaW5nW10gPSBbXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdjaScsIG9wdGlvbnMuY2kpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnZXhlY3V0ZScsIG9wdGlvbnMuZXhlY3V0ZSksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdleGNsdXNpdmVseScsIG9wdGlvbnMuZXhjbHVzaXZlbHkpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnZm9yY2UnLCBvcHRpb25zLmZvcmNlKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ3ByZXZpb3VzLXBhcmFtZXRlcnMnLCBvcHRpb25zLnVzZVByZXZpb3VzUGFyYW1ldGVycyksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdyb2xsYmFjaycsIG9wdGlvbnMucm9sbGJhY2spLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnc3RhZ2luZycsIG9wdGlvbnMuc3RhZ2luZyksXG4gICAgICAuLi5vcHRpb25zLnJldXNlQXNzZXRzID8gcmVuZGVyQXJyYXlBcmcoJy0tcmV1c2UtYXNzZXRzJywgb3B0aW9ucy5yZXVzZUFzc2V0cykgOiBbXSxcbiAgICAgIC4uLm9wdGlvbnMubm90aWZpY2F0aW9uQXJucyA/IHJlbmRlckFycmF5QXJnKCctLW5vdGlmaWNhdGlvbi1hcm5zJywgb3B0aW9ucy5ub3RpZmljYXRpb25Bcm5zKSA6IFtdLFxuICAgICAgLi4ub3B0aW9ucy5wYXJhbWV0ZXJzID8gcmVuZGVyTWFwQXJyYXlBcmcoJy0tcGFyYW1ldGVycycsIG9wdGlvbnMucGFyYW1ldGVycykgOiBbXSxcbiAgICAgIC4uLm9wdGlvbnMub3V0cHV0c0ZpbGUgPyBbJy0tb3V0cHV0cy1maWxlJywgb3B0aW9ucy5vdXRwdXRzRmlsZV0gOiBbXSxcbiAgICAgIC4uLm9wdGlvbnMucmVxdWlyZUFwcHJvdmFsID8gWyctLXJlcXVpcmUtYXBwcm92YWwnLCBvcHRpb25zLnJlcXVpcmVBcHByb3ZhbF0gOiBbXSxcbiAgICAgIC4uLm9wdGlvbnMuY2hhbmdlU2V0TmFtZSA/IFsnLS1jaGFuZ2Utc2V0LW5hbWUnLCBvcHRpb25zLmNoYW5nZVNldE5hbWVdIDogW10sXG4gICAgICAuLi5vcHRpb25zLnRvb2xraXRTdGFja05hbWUgPyBbJy0tdG9vbGtpdC1zdGFjay1uYW1lJywgb3B0aW9ucy50b29sa2l0U3RhY2tOYW1lXSA6IFtdLFxuICAgICAgLi4ub3B0aW9ucy5wcm9ncmVzcyA/IFsnLS1wcm9ncmVzcycsIG9wdGlvbnMucHJvZ3Jlc3NdIDogWyctLXByb2dyZXNzJywgU3RhY2tBY3Rpdml0eVByb2dyZXNzLkVWRU5UU10sXG4gICAgICAuLi50aGlzLmNyZWF0ZURlZmF1bHRBcmd1bWVudHMob3B0aW9ucyksXG4gICAgXTtcblxuICAgIGV4ZWMoW3RoaXMuY2RrLCAnZGVwbG95JywgLi4uZGVwbG95Q29tbWFuZEFyZ3NdLCB7XG4gICAgICBjd2Q6IHRoaXMuZGlyZWN0b3J5LFxuICAgICAgdmVyYm9zZTogdGhpcy5zaG93T3V0cHV0LFxuICAgICAgZW52OiB0aGlzLmVudixcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBjZGsgZGVzdHJveVxuICAgKi9cbiAgcHVibGljIGRlc3Ryb3kob3B0aW9uczogRGVzdHJveU9wdGlvbnMpOiB2b2lkIHtcbiAgICBjb25zdCBkZXN0cm95Q29tbWFuZEFyZ3M6IHN0cmluZ1tdID0gW1xuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnZm9yY2UnLCBvcHRpb25zLmZvcmNlKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ2V4Y2x1c2l2ZWx5Jywgb3B0aW9ucy5leGNsdXNpdmVseSksXG4gICAgICAuLi50aGlzLmNyZWF0ZURlZmF1bHRBcmd1bWVudHMob3B0aW9ucyksXG4gICAgXTtcblxuICAgIGV4ZWMoW3RoaXMuY2RrLCAnZGVzdHJveScsIC4uLmRlc3Ryb3lDb21tYW5kQXJnc10sIHtcbiAgICAgIGN3ZDogdGhpcy5kaXJlY3RvcnksXG4gICAgICB2ZXJib3NlOiB0aGlzLnNob3dPdXRwdXQsXG4gICAgICBlbnY6IHRoaXMuZW52LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIGNkayBzeW50aFxuICAgKi9cbiAgcHVibGljIHN5bnRoKG9wdGlvbnM6IFN5bnRoT3B0aW9ucyk6IHZvaWQge1xuICAgIGNvbnN0IHN5bnRoQ29tbWFuZEFyZ3M6IHN0cmluZ1tdID0gW1xuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygndmFsaWRhdGlvbicsIG9wdGlvbnMudmFsaWRhdGlvbiksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdxdWlldCcsIG9wdGlvbnMucXVpZXQpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnZXhjbHVzaXZlbHknLCBvcHRpb25zLmV4Y2x1c2l2ZWx5KSxcbiAgICAgIC4uLnRoaXMuY3JlYXRlRGVmYXVsdEFyZ3VtZW50cyhvcHRpb25zKSxcbiAgICBdO1xuXG4gICAgZXhlYyhbdGhpcy5jZGssICdzeW50aCcsIC4uLnN5bnRoQ29tbWFuZEFyZ3NdLCB7XG4gICAgICBjd2Q6IHRoaXMuZGlyZWN0b3J5LFxuICAgICAgdmVyYm9zZTogdGhpcy5zaG93T3V0cHV0LFxuICAgICAgZW52OiB0aGlzLmVudixcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEbyBhIENESyBzeW50aCwgbWltaWNraW5nIHRoZSBDTEkgKHdpdGhvdXQgYWN0dWFsbHkgdXNpbmcgaXQpXG4gICAqXG4gICAqIFRoZSBDTEkgaGFzIGEgcHJldHR5IHNsb3cgc3RhcnR1cCB0aW1lIGJlY2F1c2Ugb2YgYWxsIHRoZSBtb2R1bGVzIGl0IG5lZWRzIHRvIGxvYWQsXG4gICAqIEJ5cGFzcyBpdCB0byBiZSBxdWlja2VyIVxuICAgKi9cbiAgcHVibGljIHN5bnRoRmFzdChvcHRpb25zOiBTeW50aEZhc3RPcHRpb25zKTogdm9pZCB7XG4gICAgZXhlYyhvcHRpb25zLmV4ZWNDbWQsIHtcbiAgICAgIGN3ZDogdGhpcy5kaXJlY3RvcnksXG4gICAgICB2ZXJib3NlOiB0aGlzLnNob3dPdXRwdXQsXG4gICAgICBlbnY6IHtcbiAgICAgICAgQ0RLX0NPTlRFWFRfSlNPTjogSlNPTi5zdHJpbmdpZnkob3B0aW9ucy5jb250ZXh0KSxcbiAgICAgICAgQ0RLX09VVERJUjogb3B0aW9ucy5vdXRwdXQsXG4gICAgICAgIC4uLnRoaXMuZW52LFxuICAgICAgICAuLi5vcHRpb25zLmVudixcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZURlZmF1bHRBcmd1bWVudHMob3B0aW9uczogRGVmYXVsdENka09wdGlvbnMpOiBzdHJpbmdbXSB7XG4gICAgdGhpcy52YWxpZGF0ZUFyZ3Mob3B0aW9ucyk7XG4gICAgY29uc3Qgc3RhY2tzID0gb3B0aW9ucy5zdGFja3MgPz8gW107XG4gICAgcmV0dXJuIFtcbiAgICAgIC4uLm9wdGlvbnMuYXBwID8gWyctLWFwcCcsIG9wdGlvbnMuYXBwXSA6IFtdLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnc3RyaWN0Jywgb3B0aW9ucy5zdHJpY3QpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygndHJhY2UnLCBvcHRpb25zLnRyYWNlKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ2xvb2t1cHMnLCBvcHRpb25zLmxvb2t1cHMpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnaWdub3JlLWVycm9ycycsIG9wdGlvbnMuaWdub3JlRXJyb3JzKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ2pzb24nLCBvcHRpb25zLmpzb24pLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygndmVyYm9zZScsIG9wdGlvbnMudmVyYm9zZSksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdkZWJ1ZycsIG9wdGlvbnMuZGVidWcpLFxuICAgICAgLi4ucmVuZGVyQm9vbGVhbkFyZygnZWMyY3JlZHMnLCBvcHRpb25zLmVjMkNyZWRzKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ3ZlcnNpb24tcmVwb3J0aW5nJywgb3B0aW9ucy52ZXJzaW9uUmVwb3J0aW5nKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ3BhdGgtbWV0YWRhdGEnLCBvcHRpb25zLnBhdGhNZXRhZGF0YSksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdhc3NldC1tZXRhZGF0YScsIG9wdGlvbnMuYXNzZXRNZXRhZGF0YSksXG4gICAgICAuLi5yZW5kZXJCb29sZWFuQXJnKCdub3RpY2VzJywgb3B0aW9ucy5ub3RpY2VzKSxcbiAgICAgIC4uLnJlbmRlckJvb2xlYW5BcmcoJ2NvbG9yJywgb3B0aW9ucy5jb2xvciksXG4gICAgICAuLi5vcHRpb25zLmNvbnRleHQgPyByZW5kZXJNYXBBcnJheUFyZygnLS1jb250ZXh0Jywgb3B0aW9ucy5jb250ZXh0KSA6IFtdLFxuICAgICAgLi4ub3B0aW9ucy5wcm9maWxlID8gWyctLXByb2ZpbGUnLCBvcHRpb25zLnByb2ZpbGVdIDogW10sXG4gICAgICAuLi5vcHRpb25zLnByb3h5ID8gWyctLXByb3h5Jywgb3B0aW9ucy5wcm94eV0gOiBbXSxcbiAgICAgIC4uLm9wdGlvbnMuY2FCdW5kbGVQYXRoID8gWyctLWNhLWJ1bmRsZS1wYXRoJywgb3B0aW9ucy5jYUJ1bmRsZVBhdGhdIDogW10sXG4gICAgICAuLi5vcHRpb25zLnJvbGVBcm4gPyBbJy0tcm9sZS1hcm4nLCBvcHRpb25zLnJvbGVBcm5dIDogW10sXG4gICAgICAuLi5vcHRpb25zLm91dHB1dCA/IFsnLS1vdXRwdXQnLCBvcHRpb25zLm91dHB1dF0gOiBbXSxcbiAgICAgIC4uLnN0YWNrcyxcbiAgICAgIC4uLm9wdGlvbnMuYWxsID8gWyctLWFsbCddIDogW10sXG4gICAgXTtcbiAgfVxufVxuXG5mdW5jdGlvbiByZW5kZXJNYXBBcnJheUFyZyhmbGFnOiBzdHJpbmcsIHBhcmFtZXRlcnM6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZCB9KTogc3RyaW5nW10ge1xuICBjb25zdCBwYXJhbXM6IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHBhcmFtZXRlcnMpKSB7XG4gICAgcGFyYW1zLnB1c2goYCR7a2V5fT0ke3ZhbHVlfWApO1xuICB9XG4gIHJldHVybiByZW5kZXJBcnJheUFyZyhmbGFnLCBwYXJhbXMpO1xufVxuXG5mdW5jdGlvbiByZW5kZXJBcnJheUFyZyhmbGFnOiBzdHJpbmcsIHZhbHVlcz86IHN0cmluZ1tdKTogc3RyaW5nW10ge1xuICBsZXQgYXJnczogc3RyaW5nW10gPSBbXTtcbiAgZm9yIChjb25zdCB2YWx1ZSBvZiB2YWx1ZXMgPz8gW10pIHtcbiAgICBhcmdzLnB1c2goZmxhZywgdmFsdWUpO1xuICB9XG4gIHJldHVybiBhcmdzO1xufVxuXG5mdW5jdGlvbiByZW5kZXJCb29sZWFuQXJnKHZhbDogc3RyaW5nLCBhcmc/OiBib29sZWFuKTogc3RyaW5nW10ge1xuICBpZiAoYXJnKSB7XG4gICAgcmV0dXJuIFtgLS0ke3ZhbH1gXTtcbiAgfSBlbHNlIGlmIChhcmcgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBbXTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gW2AtLW5vLSR7dmFsfWBdO1xuICB9XG59XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/common.d.ts b/packages/cdk-cli-wrapper/lib/commands/common.d.ts new file mode 100644 index 0000000000000..25a86432d628e --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/common.d.ts @@ -0,0 +1,178 @@ +/** + * In what scenarios should the CLI ask for approval + */ +export declare enum RequireApproval { + /** + * Never ask for approval + */ + NEVER = "never", + /** + * Prompt for approval for any type of change to the stack + */ + ANYCHANGE = "any-change", + /** + * Only prompt for approval if there are security related changes + */ + BROADENING = "broadening" +} +/** + * Default CDK CLI options that apply to all commands + */ +export interface DefaultCdkOptions { + /** + * List of stacks to deploy + * + * Requried if `all` is not set + * + * @default - [] + */ + readonly stacks?: string[]; + /** + * Deploy all stacks + * + * Requried if `stacks` is not set + * + * @default - false + */ + readonly all?: boolean; + /** + * command-line for executing your app or a cloud assembly directory + * e.g. "node bin/my-app.js" + * or + * "cdk.out" + * + * @default - read from cdk.json + */ + readonly app?: string; + /** + * Role to pass to CloudFormation for deployment + * + * @default - use the bootstrap cfn-exec role + */ + readonly roleArn?: string; + /** + * Additional context + * + * @default - no additional context + */ + readonly context?: { + [name: string]: string; + }; + /** + * Print trace for stack warnings + * + * @default false + */ + readonly trace?: boolean; + /** + * Do not construct stacks with warnings + * + * @default false + */ + readonly strict?: boolean; + /** + * Perform context lookups. + * + * Synthesis fails if this is disabled and context lookups need + * to be performed + * + * @default true + */ + readonly lookups?: boolean; + /** + * Ignores synthesis errors, which will likely produce an invalid output + * + * @default false + */ + readonly ignoreErrors?: boolean; + /** + * Use JSON output instead of YAML when templates are printed + * to STDOUT + * + * @default false + */ + readonly json?: boolean; + /** + * show debug logs + * + * @default false + */ + readonly verbose?: boolean; + /** + * enable emission of additional debugging information, such as creation stack + * traces of tokens + * + * @default false + */ + readonly debug?: boolean; + /** + * Use the indicated AWS profile as the default environment + * + * @default - no profile is used + */ + readonly profile?: string; + /** + * Use the indicated proxy. Will read from + * HTTPS_PROXY environment if specified + * + * @default - no proxy + */ + readonly proxy?: string; + /** + * Path to CA certificate to use when validating HTTPS + * requests. + * + * @default - read from AWS_CA_BUNDLE environment variable + */ + readonly caBundlePath?: string; + /** + * Force trying to fetch EC2 instance credentials + * + * @default - guess EC2 instance status + */ + readonly ec2Creds?: boolean; + /** + * Include "AWS::CDK::Metadata" resource in synthesized templates + * + * @default true + */ + readonly versionReporting?: boolean; + /** + * Include "aws:cdk:path" CloudFormation metadata for each resource + * + * @default true + */ + readonly pathMetadata?: boolean; + /** + * Include "aws:asset:*" CloudFormation metadata for resources that use assets + * + * @default true + */ + readonly assetMetadata?: boolean; + /** + * Copy assets to the output directory + * + * Needed for local debugging the source files with SAM CLI + * + * @default false + */ + readonly staging?: boolean; + /** + * Emits the synthesized cloud assembly into a directory + * + * @default cdk.out + */ + readonly output?: string; + /** + * Show relevant notices + * + * @default true + */ + readonly notices?: boolean; + /** + * Show colors and other style from console output + * + * @default true + */ + readonly color?: boolean; +} diff --git a/packages/cdk-cli-wrapper/lib/commands/common.js b/packages/cdk-cli-wrapper/lib/commands/common.js new file mode 100644 index 0000000000000..a9377bcc06ace --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/common.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RequireApproval = void 0; +/** + * In what scenarios should the CLI ask for approval + */ +var RequireApproval; +(function (RequireApproval) { + /** + * Never ask for approval + */ + RequireApproval["NEVER"] = "never"; + /** + * Prompt for approval for any type of change to the stack + */ + RequireApproval["ANYCHANGE"] = "any-change"; + /** + * Only prompt for approval if there are security related changes + */ + RequireApproval["BROADENING"] = "broadening"; +})(RequireApproval = exports.RequireApproval || (exports.RequireApproval = {})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY29tbW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOztHQUVHO0FBQ0gsSUFBWSxlQWVYO0FBZkQsV0FBWSxlQUFlO0lBQ3pCOztPQUVHO0lBQ0gsa0NBQWUsQ0FBQTtJQUVmOztPQUVHO0lBQ0gsMkNBQXdCLENBQUE7SUFFeEI7O09BRUc7SUFDSCw0Q0FBeUIsQ0FBQTtBQUMzQixDQUFDLEVBZlcsZUFBZSxHQUFmLHVCQUFlLEtBQWYsdUJBQWUsUUFlMUIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEluIHdoYXQgc2NlbmFyaW9zIHNob3VsZCB0aGUgQ0xJIGFzayBmb3IgYXBwcm92YWxcbiAqL1xuZXhwb3J0IGVudW0gUmVxdWlyZUFwcHJvdmFsIHtcbiAgLyoqXG4gICAqIE5ldmVyIGFzayBmb3IgYXBwcm92YWxcbiAgICovXG4gIE5FVkVSID0gJ25ldmVyJyxcblxuICAvKipcbiAgICogUHJvbXB0IGZvciBhcHByb3ZhbCBmb3IgYW55IHR5cGUgIG9mIGNoYW5nZSB0byB0aGUgc3RhY2tcbiAgICovXG4gIEFOWUNIQU5HRSA9ICdhbnktY2hhbmdlJyxcblxuICAvKipcbiAgICogT25seSBwcm9tcHQgZm9yIGFwcHJvdmFsIGlmIHRoZXJlIGFyZSBzZWN1cml0eSByZWxhdGVkIGNoYW5nZXNcbiAgICovXG4gIEJST0FERU5JTkcgPSAnYnJvYWRlbmluZydcbn1cblxuLyoqXG4gKiBEZWZhdWx0IENESyBDTEkgb3B0aW9ucyB0aGF0IGFwcGx5IHRvIGFsbCBjb21tYW5kc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIERlZmF1bHRDZGtPcHRpb25zIHtcbiAgLyoqXG4gICAqIExpc3Qgb2Ygc3RhY2tzIHRvIGRlcGxveVxuICAgKlxuICAgKiBSZXF1cmllZCBpZiBgYWxsYCBpcyBub3Qgc2V0XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gW11cbiAgICovXG4gIHJlYWRvbmx5IHN0YWNrcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBEZXBsb3kgYWxsIHN0YWNrc1xuICAgKlxuICAgKiBSZXF1cmllZCBpZiBgc3RhY2tzYCBpcyBub3Qgc2V0XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFsbD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIGNvbW1hbmQtbGluZSBmb3IgZXhlY3V0aW5nIHlvdXIgYXBwIG9yIGEgY2xvdWQgYXNzZW1ibHkgZGlyZWN0b3J5XG4gICAqIGUuZy4gXCJub2RlIGJpbi9teS1hcHAuanNcIlxuICAgKiBvclxuICAgKiBcImNkay5vdXRcIlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHJlYWQgZnJvbSBjZGsuanNvblxuICAgKi9cbiAgcmVhZG9ubHkgYXBwPzogc3RyaW5nO1xuXG5cbiAgLyoqXG4gICAqIFJvbGUgdG8gcGFzcyB0byBDbG91ZEZvcm1hdGlvbiBmb3IgZGVwbG95bWVudFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHVzZSB0aGUgYm9vdHN0cmFwIGNmbi1leGVjIHJvbGVcbiAgICovXG4gIHJlYWRvbmx5IHJvbGVBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgY29udGV4dFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGFkZGl0aW9uYWwgY29udGV4dFxuICAgKi9cbiAgcmVhZG9ubHkgY29udGV4dD86IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9O1xuXG4gIC8qKlxuICAgKiBQcmludCB0cmFjZSBmb3Igc3RhY2sgd2FybmluZ3NcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHRyYWNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRG8gbm90IGNvbnN0cnVjdCBzdGFja3Mgd2l0aCB3YXJuaW5nc1xuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgc3RyaWN0PzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUGVyZm9ybSBjb250ZXh0IGxvb2t1cHMuXG4gICAqXG4gICAqIFN5bnRoZXNpcyBmYWlscyBpZiB0aGlzIGlzIGRpc2FibGVkIGFuZCBjb250ZXh0IGxvb2t1cHMgbmVlZFxuICAgKiB0byBiZSBwZXJmb3JtZWRcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgbG9va3Vwcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAgKiBJZ25vcmVzIHN5bnRoZXNpcyBlcnJvcnMsIHdoaWNoIHdpbGwgbGlrZWx5IHByb2R1Y2UgYW4gaW52YWxpZCBvdXRwdXRcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGlnbm9yZUVycm9ycz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFVzZSBKU09OIG91dHB1dCBpbnN0ZWFkIG9mIFlBTUwgd2hlbiB0ZW1wbGF0ZXMgYXJlIHByaW50ZWRcbiAgICogdG8gU1RET1VUXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBqc29uPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogc2hvdyBkZWJ1ZyBsb2dzXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSB2ZXJib3NlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogZW5hYmxlIGVtaXNzaW9uIG9mIGFkZGl0aW9uYWwgZGVidWdnaW5nIGluZm9ybWF0aW9uLCBzdWNoIGFzIGNyZWF0aW9uIHN0YWNrXG4gICAqIHRyYWNlcyBvZiB0b2tlbnNcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGRlYnVnPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogVXNlIHRoZSBpbmRpY2F0ZWQgQVdTIHByb2ZpbGUgYXMgdGhlIGRlZmF1bHQgZW52aXJvbm1lbnRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBwcm9maWxlIGlzIHVzZWRcbiAgICovXG4gIHJlYWRvbmx5IHByb2ZpbGU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFVzZSB0aGUgaW5kaWNhdGVkIHByb3h5LiBXaWxsIHJlYWQgZnJvbVxuICAgKiBIVFRQU19QUk9YWSBlbnZpcm9ubWVudCBpZiBzcGVjaWZpZWRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBwcm94eVxuICAgKi9cbiAgcmVhZG9ubHkgcHJveHk/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFBhdGggdG8gQ0EgY2VydGlmaWNhdGUgdG8gdXNlIHdoZW4gdmFsaWRhdGluZyBIVFRQU1xuICAgKiByZXF1ZXN0cy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSByZWFkIGZyb20gQVdTX0NBX0JVTkRMRSBlbnZpcm9ubWVudCB2YXJpYWJsZVxuICAgKi9cbiAgcmVhZG9ubHkgY2FCdW5kbGVQYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGb3JjZSB0cnlpbmcgdG8gZmV0Y2ggRUMyIGluc3RhbmNlIGNyZWRlbnRpYWxzXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZ3Vlc3MgRUMyIGluc3RhbmNlIHN0YXR1c1xuICAgKi9cbiAgcmVhZG9ubHkgZWMyQ3JlZHM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJbmNsdWRlIFwiQVdTOjpDREs6Ok1ldGFkYXRhXCIgcmVzb3VyY2UgaW4gc3ludGhlc2l6ZWQgdGVtcGxhdGVzXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHZlcnNpb25SZXBvcnRpbmc/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJbmNsdWRlIFwiYXdzOmNkazpwYXRoXCIgQ2xvdWRGb3JtYXRpb24gbWV0YWRhdGEgZm9yIGVhY2ggcmVzb3VyY2VcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgcGF0aE1ldGFkYXRhPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogSW5jbHVkZSBcImF3czphc3NldDoqXCIgQ2xvdWRGb3JtYXRpb24gbWV0YWRhdGEgZm9yIHJlc291cmNlcyB0aGF0IHVzZSBhc3NldHNcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXRNZXRhZGF0YT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENvcHkgYXNzZXRzIHRvIHRoZSBvdXRwdXQgZGlyZWN0b3J5XG4gICAqXG4gICAqIE5lZWRlZCBmb3IgbG9jYWwgZGVidWdnaW5nIHRoZSBzb3VyY2UgZmlsZXMgd2l0aCBTQU0gQ0xJXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBzdGFnaW5nPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRW1pdHMgdGhlIHN5bnRoZXNpemVkIGNsb3VkIGFzc2VtYmx5IGludG8gYSBkaXJlY3RvcnlcbiAgICpcbiAgICogQGRlZmF1bHQgY2RrLm91dFxuICAgKi9cbiAgcmVhZG9ubHkgb3V0cHV0Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTaG93IHJlbGV2YW50IG5vdGljZXNcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgbm90aWNlcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFNob3cgY29sb3JzIGFuZCBvdGhlciBzdHlsZSBmcm9tIGNvbnNvbGUgb3V0cHV0XG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGNvbG9yPzogYm9vbGVhbjtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/deploy.d.ts b/packages/cdk-cli-wrapper/lib/commands/deploy.d.ts new file mode 100644 index 0000000000000..ea46aa88ee335 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/deploy.d.ts @@ -0,0 +1,109 @@ +import { DefaultCdkOptions, RequireApproval } from './common'; +/** + * Options to use with cdk deploy + */ +export interface DeployOptions extends DefaultCdkOptions { + /** + * Only perform action on the given stack + * + * @default false + */ + readonly exclusively?: boolean; + /** + * Name of the toolkit stack to use/deploy + * + * @default CDKToolkit + */ + readonly toolkitStackName?: string; + /** + * Reuse the assets with the given asset IDs + * + * @default - do not reuse assets + */ + readonly reuseAssets?: string[]; + /** + * Optional name to use for the CloudFormation change set. + * If not provided, a name will be generated automatically. + * + * @default - auto generate a name + */ + readonly changeSetName?: string; + /** + * Always deploy, even if templates are identical. + * @default false + */ + readonly force?: boolean; + /** + * Rollback failed deployments + * + * @default true + */ + readonly rollback?: boolean; + /** + * ARNs of SNS topics that CloudFormation will notify with stack related events + * + * @default - no notifications + */ + readonly notificationArns?: string[]; + /** + * What kind of security changes require approval + * + * @default RequireApproval.Never + */ + readonly requireApproval?: RequireApproval; + /** + * Whether to execute the ChangeSet + * Not providing `execute` parameter will result in execution of ChangeSet + * @default true + */ + readonly execute?: boolean; + /** + * Additional parameters for CloudFormation at deploy time + * @default {} + */ + readonly parameters?: { + [name: string]: string; + }; + /** + * Use previous values for unspecified parameters + * + * If not set, all parameters must be specified for every deployment. + * + * @default true + */ + readonly usePreviousParameters?: boolean; + /** + * Path to file where stack outputs will be written after a successful deploy as JSON + * @default - Outputs are not written to any file + */ + readonly outputsFile?: string; + /** + * Whether we are on a CI system + * + * @default false + */ + readonly ci?: boolean; + /** + * Display mode for stack activity events + * + * The default in the CLI is StackActivityProgress.BAR, but + * since the cli-wrapper will most likely be run in automation it makes + * more sense to set the default to StackActivityProgress.EVENTS + * + * @default StackActivityProgress.EVENTS + */ + readonly progress?: StackActivityProgress; +} +/** + * Supported display modes for stack deployment activity + */ +export declare enum StackActivityProgress { + /** + * Displays a progress bar with only the events for the resource currently being deployed + */ + BAR = "bar", + /** + * Displays complete history with all CloudFormation stack events + */ + EVENTS = "events" +} diff --git a/packages/cdk-cli-wrapper/lib/commands/deploy.js b/packages/cdk-cli-wrapper/lib/commands/deploy.js new file mode 100644 index 0000000000000..e0899dfc397ec --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/deploy.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.StackActivityProgress = void 0; +/** + * Supported display modes for stack deployment activity + */ +var StackActivityProgress; +(function (StackActivityProgress) { + /** + * Displays a progress bar with only the events for the resource currently being deployed + */ + StackActivityProgress["BAR"] = "bar"; + /** + * Displays complete history with all CloudFormation stack events + */ + StackActivityProgress["EVENTS"] = "events"; +})(StackActivityProgress = exports.StackActivityProgress || (exports.StackActivityProgress = {})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwbG95LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQTZHQTs7R0FFRztBQUNILElBQVkscUJBVVg7QUFWRCxXQUFZLHFCQUFxQjtJQUMvQjs7T0FFRztJQUNILG9DQUFXLENBQUE7SUFFWDs7T0FFRztJQUNILDBDQUFpQixDQUFBO0FBQ25CLENBQUMsRUFWVyxxQkFBcUIsR0FBckIsNkJBQXFCLEtBQXJCLDZCQUFxQixRQVVoQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlZmF1bHRDZGtPcHRpb25zLCBSZXF1aXJlQXBwcm92YWwgfSBmcm9tICcuL2NvbW1vbic7XG5cbi8qKlxuICogT3B0aW9ucyB0byB1c2Ugd2l0aCBjZGsgZGVwbG95XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGVwbG95T3B0aW9ucyBleHRlbmRzIERlZmF1bHRDZGtPcHRpb25zIHtcbiAgLyoqXG4gICAqIE9ubHkgcGVyZm9ybSBhY3Rpb24gb24gdGhlIGdpdmVuIHN0YWNrXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBleGNsdXNpdmVseT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIHRvb2xraXQgc3RhY2sgdG8gdXNlL2RlcGxveVxuICAgKlxuICAgKiBAZGVmYXVsdCBDREtUb29sa2l0XG4gICAqL1xuICByZWFkb25seSB0b29sa2l0U3RhY2tOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXVzZSB0aGUgYXNzZXRzIHdpdGggdGhlIGdpdmVuIGFzc2V0IElEc1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIGRvIG5vdCByZXVzZSBhc3NldHNcbiAgICovXG4gIHJlYWRvbmx5IHJldXNlQXNzZXRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE9wdGlvbmFsIG5hbWUgdG8gdXNlIGZvciB0aGUgQ2xvdWRGb3JtYXRpb24gY2hhbmdlIHNldC5cbiAgICogSWYgbm90IHByb3ZpZGVkLCBhIG5hbWUgd2lsbCBiZSBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBhdXRvIGdlbmVyYXRlIGEgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgY2hhbmdlU2V0TmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogQWx3YXlzIGRlcGxveSwgZXZlbiBpZiB0ZW1wbGF0ZXMgYXJlIGlkZW50aWNhbC5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGZvcmNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUm9sbGJhY2sgZmFpbGVkIGRlcGxveW1lbnRzXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHJvbGxiYWNrPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQVJOcyBvZiBTTlMgdG9waWNzIHRoYXQgQ2xvdWRGb3JtYXRpb24gd2lsbCBub3RpZnkgd2l0aCBzdGFjayByZWxhdGVkIGV2ZW50c1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIG5vdGlmaWNhdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IG5vdGlmaWNhdGlvbkFybnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogV2hhdCBraW5kIG9mIHNlY3VyaXR5IGNoYW5nZXMgcmVxdWlyZSBhcHByb3ZhbFxuICAgKlxuICAgKiBAZGVmYXVsdCBSZXF1aXJlQXBwcm92YWwuTmV2ZXJcbiAgICovXG4gIHJlYWRvbmx5IHJlcXVpcmVBcHByb3ZhbD86IFJlcXVpcmVBcHByb3ZhbDtcblxuICAvKipcbiAgICogV2hldGhlciB0byBleGVjdXRlIHRoZSBDaGFuZ2VTZXRcbiAgICogTm90IHByb3ZpZGluZyBgZXhlY3V0ZWAgcGFyYW1ldGVyIHdpbGwgcmVzdWx0IGluIGV4ZWN1dGlvbiBvZiBDaGFuZ2VTZXRcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgZXhlY3V0ZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgcGFyYW1ldGVycyBmb3IgQ2xvdWRGb3JtYXRpb24gYXQgZGVwbG95IHRpbWVcbiAgICogQGRlZmF1bHQge31cbiAgICovXG4gIHJlYWRvbmx5IHBhcmFtZXRlcnM/OiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogVXNlIHByZXZpb3VzIHZhbHVlcyBmb3IgdW5zcGVjaWZpZWQgcGFyYW1ldGVyc1xuICAgKlxuICAgKiBJZiBub3Qgc2V0LCBhbGwgcGFyYW1ldGVycyBtdXN0IGJlIHNwZWNpZmllZCBmb3IgZXZlcnkgZGVwbG95bWVudC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgdXNlUHJldmlvdXNQYXJhbWV0ZXJzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUGF0aCB0byBmaWxlIHdoZXJlIHN0YWNrIG91dHB1dHMgd2lsbCBiZSB3cml0dGVuIGFmdGVyIGEgc3VjY2Vzc2Z1bCBkZXBsb3kgYXMgSlNPTlxuICAgKiBAZGVmYXVsdCAtIE91dHB1dHMgYXJlIG5vdCB3cml0dGVuIHRvIGFueSBmaWxlXG4gICAqL1xuICByZWFkb25seSBvdXRwdXRzRmlsZT86IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB3ZSBhcmUgb24gYSBDSSBzeXN0ZW1cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGNpPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRGlzcGxheSBtb2RlIGZvciBzdGFjayBhY3Rpdml0eSBldmVudHNcbiAgICpcbiAgICogVGhlIGRlZmF1bHQgaW4gdGhlIENMSSBpcyBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuQkFSLCBidXRcbiAgICogc2luY2UgdGhlIGNsaS13cmFwcGVyIHdpbGwgbW9zdCBsaWtlbHkgYmUgcnVuIGluIGF1dG9tYXRpb24gaXQgbWFrZXNcbiAgICogbW9yZSBzZW5zZSB0byBzZXQgdGhlIGRlZmF1bHQgdG8gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkVWRU5UU1xuICAgKlxuICAgKiBAZGVmYXVsdCBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuRVZFTlRTXG4gICAqL1xuICByZWFkb25seSBwcm9ncmVzcz86IFN0YWNrQWN0aXZpdHlQcm9ncmVzcztcbn1cblxuLyoqXG4gKiBTdXBwb3J0ZWQgZGlzcGxheSBtb2RlcyBmb3Igc3RhY2sgZGVwbG95bWVudCBhY3Rpdml0eVxuICovXG5leHBvcnQgZW51bSBTdGFja0FjdGl2aXR5UHJvZ3Jlc3Mge1xuICAvKipcbiAgICogRGlzcGxheXMgYSBwcm9ncmVzcyBiYXIgd2l0aCBvbmx5IHRoZSBldmVudHMgZm9yIHRoZSByZXNvdXJjZSBjdXJyZW50bHkgYmVpbmcgZGVwbG95ZWRcbiAgICovXG4gIEJBUiA9ICdiYXInLFxuXG4gIC8qKlxuICAgKiBEaXNwbGF5cyBjb21wbGV0ZSBoaXN0b3J5IHdpdGggYWxsIENsb3VkRm9ybWF0aW9uIHN0YWNrIGV2ZW50c1xuICAgKi9cbiAgRVZFTlRTID0gJ2V2ZW50cycsXG59XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/destroy.d.ts b/packages/cdk-cli-wrapper/lib/commands/destroy.d.ts new file mode 100644 index 0000000000000..d981fba122309 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/destroy.d.ts @@ -0,0 +1,18 @@ +import { DefaultCdkOptions } from './common'; +/** + * Options to use with cdk destroy + */ +export interface DestroyOptions extends DefaultCdkOptions { + /** + * Do not ask for permission before destroying stacks + * + * @default false + */ + readonly force?: boolean; + /** + * Only destroy the given stack + * + * @default false + */ + readonly exclusively?: boolean; +} diff --git a/packages/cdk-cli-wrapper/lib/commands/destroy.js b/packages/cdk-cli-wrapper/lib/commands/destroy.js new file mode 100644 index 0000000000000..cc24c854836f0 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/destroy.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVzdHJveS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRlc3Ryb3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlZmF1bHRDZGtPcHRpb25zIH0gZnJvbSAnLi9jb21tb24nO1xuXG4vKipcbiAqIE9wdGlvbnMgdG8gdXNlIHdpdGggY2RrIGRlc3Ryb3lcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXN0cm95T3B0aW9ucyBleHRlbmRzIERlZmF1bHRDZGtPcHRpb25zIHtcbiAgLyoqXG4gICAqIERvIG5vdCBhc2sgZm9yIHBlcm1pc3Npb24gYmVmb3JlIGRlc3Ryb3lpbmcgc3RhY2tzXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBmb3JjZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE9ubHkgZGVzdHJveSB0aGUgZ2l2ZW4gc3RhY2tcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGV4Y2x1c2l2ZWx5PzogYm9vbGVhbjtcbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/index.d.ts b/packages/cdk-cli-wrapper/lib/commands/index.d.ts new file mode 100644 index 0000000000000..33e0e77569a92 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/index.d.ts @@ -0,0 +1,5 @@ +export * from './synth'; +export * from './common'; +export * from './deploy'; +export * from './destroy'; +export * from './list'; diff --git a/packages/cdk-cli-wrapper/lib/commands/index.js b/packages/cdk-cli-wrapper/lib/commands/index.js new file mode 100644 index 0000000000000..871721b05f45d --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/index.js @@ -0,0 +1,22 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./synth"), exports); +__exportStar(require("./common"), exports); +__exportStar(require("./deploy"), exports); +__exportStar(require("./destroy"), exports); +__exportStar(require("./list"), exports); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMENBQXdCO0FBQ3hCLDJDQUF5QjtBQUN6QiwyQ0FBeUI7QUFDekIsNENBQTBCO0FBQzFCLHlDQUF1QiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vc3ludGgnO1xuZXhwb3J0ICogZnJvbSAnLi9jb21tb24nO1xuZXhwb3J0ICogZnJvbSAnLi9kZXBsb3knO1xuZXhwb3J0ICogZnJvbSAnLi9kZXN0cm95JztcbmV4cG9ydCAqIGZyb20gJy4vbGlzdCc7XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/list.d.ts b/packages/cdk-cli-wrapper/lib/commands/list.d.ts new file mode 100644 index 0000000000000..acc752155affb --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/list.d.ts @@ -0,0 +1,12 @@ +import { DefaultCdkOptions } from './common'; +/** + * Options for cdk list + */ +export interface ListOptions extends DefaultCdkOptions { + /** + *Display environment information for each stack + * + * @default false + */ + readonly long?: boolean; +} diff --git a/packages/cdk-cli-wrapper/lib/commands/list.js b/packages/cdk-cli-wrapper/lib/commands/list.js new file mode 100644 index 0000000000000..0912bb75d266f --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/list.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImxpc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlZmF1bHRDZGtPcHRpb25zIH0gZnJvbSAnLi9jb21tb24nO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGNkayBsaXN0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdE9wdGlvbnMgZXh0ZW5kcyBEZWZhdWx0Q2RrT3B0aW9ucyB7XG4gIC8qKlxuICAgKkRpc3BsYXkgZW52aXJvbm1lbnQgaW5mb3JtYXRpb24gZm9yIGVhY2ggc3RhY2tcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGxvbmc/OiBib29sZWFuO1xufVxuIl19 \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/commands/synth.d.ts b/packages/cdk-cli-wrapper/lib/commands/synth.d.ts new file mode 100644 index 0000000000000..16a66236889d4 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/synth.d.ts @@ -0,0 +1,24 @@ +import { DefaultCdkOptions } from './common'; +/** + * Options to use with cdk synth + */ +export interface SynthOptions extends DefaultCdkOptions { + /** + * After synthesis, validate stacks with the "validateOnSynth" + * attribute set (can also be controlled with CDK_VALIDATION) + * + * @default true; + */ + readonly validation?: boolean; + /** + * Do not output CloudFormation Template to stdout + * @default false; + */ + readonly quiet?: boolean; + /** + * Only synthesize the given stack + * + * @default false + */ + readonly exclusively?: boolean; +} diff --git a/packages/cdk-cli-wrapper/lib/commands/synth.js b/packages/cdk-cli-wrapper/lib/commands/synth.js new file mode 100644 index 0000000000000..c8a5cc4d5430f --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/commands/synth.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ludGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzeW50aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVmYXVsdENka09wdGlvbnMgfSBmcm9tICcuL2NvbW1vbic7XG5cbi8qKlxuICogT3B0aW9ucyB0byB1c2Ugd2l0aCBjZGsgc3ludGhcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTeW50aE9wdGlvbnMgZXh0ZW5kcyBEZWZhdWx0Q2RrT3B0aW9ucyB7XG5cbiAgLyoqXG4gICAqIEFmdGVyIHN5bnRoZXNpcywgdmFsaWRhdGUgc3RhY2tzIHdpdGggdGhlIFwidmFsaWRhdGVPblN5bnRoXCJcbiAgICogYXR0cmlidXRlIHNldCAoY2FuIGFsc28gYmUgY29udHJvbGxlZCB3aXRoIENES19WQUxJREFUSU9OKVxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlO1xuICAgKi9cbiAgcmVhZG9ubHkgdmFsaWRhdGlvbj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIERvIG5vdCBvdXRwdXQgQ2xvdWRGb3JtYXRpb24gVGVtcGxhdGUgdG8gc3Rkb3V0XG4gICAqIEBkZWZhdWx0IGZhbHNlO1xuICAgKi9cbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPbmx5IHN5bnRoZXNpemUgdGhlIGdpdmVuIHN0YWNrXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBleGNsdXNpdmVseT86IGJvb2xlYW47XG59XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/index.d.ts b/packages/cdk-cli-wrapper/lib/index.d.ts new file mode 100644 index 0000000000000..a7ee3249f4cbe --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/index.d.ts @@ -0,0 +1,2 @@ +export * from './cdk-wrapper'; +export * from './commands'; diff --git a/packages/cdk-cli-wrapper/lib/index.js b/packages/cdk-cli-wrapper/lib/index.js new file mode 100644 index 0000000000000..0cd43d0f9a0a3 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/index.js @@ -0,0 +1,19 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./cdk-wrapper"), exports); +__exportStar(require("./commands"), exports); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsZ0RBQThCO0FBQzlCLDZDQUEyQiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vY2RrLXdyYXBwZXInO1xuZXhwb3J0ICogZnJvbSAnLi9jb21tYW5kcyc7XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/lib/utils.d.ts b/packages/cdk-cli-wrapper/lib/utils.d.ts new file mode 100644 index 0000000000000..1b087b5d46a9a --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/utils.d.ts @@ -0,0 +1,9 @@ +/** + * Our own execute function which doesn't use shells and strings. + */ +export declare function exec(commandLine: string[], options?: { + cwd?: string; + json?: boolean; + verbose?: boolean; + env?: any; +}): any; diff --git a/packages/cdk-cli-wrapper/lib/utils.js b/packages/cdk-cli-wrapper/lib/utils.js new file mode 100644 index 0000000000000..e31979dd6d753 --- /dev/null +++ b/packages/cdk-cli-wrapper/lib/utils.js @@ -0,0 +1,44 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.exec = void 0; +// Helper functions for CDK Exec +const child_process_1 = require("child_process"); +/** + * Our own execute function which doesn't use shells and strings. + */ +function exec(commandLine, options = {}) { + const proc = (0, child_process_1.spawnSync)(commandLine[0], commandLine.slice(1), { + stdio: ['ignore', 'pipe', options.verbose ? 'inherit' : 'pipe'], + env: { + ...process.env, + ...options.env, + }, + cwd: options.cwd, + }); + if (proc.error) { + throw proc.error; + } + if (proc.status !== 0) { + if (process.stderr) { // will be 'null' in verbose mode + process.stderr.write(proc.stderr); + } + throw new Error(`Command exited with ${proc.status ? `status ${proc.status}` : `signal ${proc.signal}`}`); + } + const output = proc.stdout.toString('utf-8').trim(); + try { + if (options.json) { + if (output.length === 0) { + return {}; + } + return JSON.parse(output); + } + return output; + } + catch { + // eslint-disable-next-line no-console + console.error('Not JSON: ' + output); + throw new Error('Command output is not JSON'); + } +} +exports.exec = exec; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnQ0FBZ0M7QUFDaEMsaURBQTBDO0FBRTFDOztHQUVHO0FBQ0gsU0FBZ0IsSUFBSSxDQUFDLFdBQXFCLEVBQUUsVUFBMEUsRUFBRztJQUN2SCxNQUFNLElBQUksR0FBRyxJQUFBLHlCQUFTLEVBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUU7UUFDM0QsS0FBSyxFQUFFLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUMvRCxHQUFHLEVBQUU7WUFDSCxHQUFHLE9BQU8sQ0FBQyxHQUFHO1lBQ2QsR0FBRyxPQUFPLENBQUMsR0FBRztTQUNmO1FBQ0QsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHO0tBQ2pCLENBQUMsQ0FBQztJQUVILElBQUksSUFBSSxDQUFDLEtBQUssRUFBRTtRQUFFLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQztLQUFFO0lBQ3JDLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFDckIsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsaUNBQWlDO1lBQ3JELE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNuQztRQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7S0FDM0c7SUFFRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUVwRCxJQUFJO1FBQ0YsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFO1lBQ2hCLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7Z0JBQUUsT0FBTyxFQUFFLENBQUM7YUFBRTtZQUV2QyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7U0FDM0I7UUFDRCxPQUFPLE1BQU0sQ0FBQztLQUNmO0lBQUMsTUFBTTtRQUNOLHNDQUFzQztRQUN0QyxPQUFPLENBQUMsS0FBSyxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsQ0FBQztRQUNyQyxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7S0FDL0M7QUFDSCxDQUFDO0FBaENELG9CQWdDQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEhlbHBlciBmdW5jdGlvbnMgZm9yIENESyBFeGVjXG5pbXBvcnQgeyBzcGF3blN5bmMgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcblxuLyoqXG4gKiBPdXIgb3duIGV4ZWN1dGUgZnVuY3Rpb24gd2hpY2ggZG9lc24ndCB1c2Ugc2hlbGxzIGFuZCBzdHJpbmdzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXhlYyhjb21tYW5kTGluZTogc3RyaW5nW10sIG9wdGlvbnM6IHsgY3dkPzogc3RyaW5nLCBqc29uPzogYm9vbGVhbiwgdmVyYm9zZT86IGJvb2xlYW4sIGVudj86IGFueSB9ID0geyB9KTogYW55IHtcbiAgY29uc3QgcHJvYyA9IHNwYXduU3luYyhjb21tYW5kTGluZVswXSwgY29tbWFuZExpbmUuc2xpY2UoMSksIHtcbiAgICBzdGRpbzogWydpZ25vcmUnLCAncGlwZScsIG9wdGlvbnMudmVyYm9zZSA/ICdpbmhlcml0JyA6ICdwaXBlJ10sIC8vIGluaGVyaXQgU1RERVJSIGluIHZlcmJvc2UgbW9kZVxuICAgIGVudjoge1xuICAgICAgLi4ucHJvY2Vzcy5lbnYsXG4gICAgICAuLi5vcHRpb25zLmVudixcbiAgICB9LFxuICAgIGN3ZDogb3B0aW9ucy5jd2QsXG4gIH0pO1xuXG4gIGlmIChwcm9jLmVycm9yKSB7IHRocm93IHByb2MuZXJyb3I7IH1cbiAgaWYgKHByb2Muc3RhdHVzICE9PSAwKSB7XG4gICAgaWYgKHByb2Nlc3Muc3RkZXJyKSB7IC8vIHdpbGwgYmUgJ251bGwnIGluIHZlcmJvc2UgbW9kZVxuICAgICAgcHJvY2Vzcy5zdGRlcnIud3JpdGUocHJvYy5zdGRlcnIpO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvbW1hbmQgZXhpdGVkIHdpdGggJHtwcm9jLnN0YXR1cyA/IGBzdGF0dXMgJHtwcm9jLnN0YXR1c31gIDogYHNpZ25hbCAke3Byb2Muc2lnbmFsfWB9YCk7XG4gIH1cblxuICBjb25zdCBvdXRwdXQgPSBwcm9jLnN0ZG91dC50b1N0cmluZygndXRmLTgnKS50cmltKCk7XG5cbiAgdHJ5IHtcbiAgICBpZiAob3B0aW9ucy5qc29uKSB7XG4gICAgICBpZiAob3V0cHV0Lmxlbmd0aCA9PT0gMCkgeyByZXR1cm4ge307IH1cblxuICAgICAgcmV0dXJuIEpTT04ucGFyc2Uob3V0cHV0KTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbiAgfSBjYXRjaCB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmVycm9yKCdOb3QgSlNPTjogJyArIG91dHB1dCk7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb21tYW5kIG91dHB1dCBpcyBub3QgSlNPTicpO1xuICB9XG59XG4iXX0= \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/test/cdk-wrapper.test.d.ts b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.d.ts new file mode 100644 index 0000000000000..cb0ff5c3b541f --- /dev/null +++ b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/cdk-cli-wrapper/test/cdk-wrapper.test.js b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.js new file mode 100644 index 0000000000000..768822b56a363 --- /dev/null +++ b/packages/cdk-cli-wrapper/test/cdk-wrapper.test.js @@ -0,0 +1,408 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const child_process = require("child_process"); +const cdk_wrapper_1 = require("../lib/cdk-wrapper"); +const commands_1 = require("../lib/commands"); +let spawnSyncMock; +beforeEach(() => { + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); +}); +afterEach(() => { + jest.resetAllMocks(); + jest.restoreAllMocks(); + jest.clearAllMocks(); +}); +test('default deploy', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['deploy', '--progress', 'events', '--app', 'node bin/my-app.js', 'test-stack1'], expect.objectContaining({ + env: expect.anything(), + cwd: '/project', + })); +}); +test('deploy with all arguments', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + ci: false, + json: true, + color: false, + debug: false, + force: true, + proxy: 'https://proxy', + trace: false, + output: 'cdk.out', + strict: false, + execute: true, + lookups: false, + notices: true, + profile: 'my-profile', + roleArn: 'arn:aws:iam::1111111111:role/my-role', + staging: false, + verbose: true, + ec2Creds: true, + rollback: false, + exclusively: true, + outputsFile: 'outputs.json', + reuseAssets: [ + 'asset1234', + 'asset5678', + ], + caBundlePath: '/some/path', + ignoreErrors: false, + pathMetadata: false, + assetMetadata: true, + changeSetName: 'my-change-set', + requireApproval: commands_1.RequireApproval.NEVER, + toolkitStackName: 'Toolkit', + versionReporting: true, + usePreviousParameters: true, + progress: commands_1.StackActivityProgress.BAR, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), expect.arrayContaining([ + 'deploy', + '--no-strict', + '--no-trace', + '--no-lookups', + '--no-ignore-errors', + '--json', + '--verbose', + '--no-debug', + '--ec2creds', + '--version-reporting', + '--no-path-metadata', + '--asset-metadata', + '--notices', + '--no-color', + '--profile', 'my-profile', + '--proxy', 'https://proxy', + '--ca-bundle-path', '/some/path', + '--role-arn', 'arn:aws:iam::1111111111:role/my-role', + '--output', 'cdk.out', + '--no-ci', + '--execute', + '--exclusively', + '--force', + '--no-rollback', + '--no-staging', + '--reuse-assets', 'asset1234', + '--reuse-assets', 'asset5678', + '--outputs-file', 'outputs.json', + '--require-approval', 'never', + '--change-set-name', 'my-change-set', + '--toolkit-stack-name', 'Toolkit', + '--previous-parameters', + '--progress', 'bar', + '--app', + 'node bin/my-app.js', + 'test-stack1', + ]), expect.objectContaining({ + env: expect.anything(), + stdio: ['ignore', 'pipe', 'pipe'], + cwd: '/project', + })); +}); +test('can parse boolean arguments', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + json: true, + color: false, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), [ + 'deploy', + '--progress', 'events', + '--app', + 'node bin/my-app.js', + '--json', + '--no-color', + 'test-stack1', + ], expect.objectContaining({ + env: expect.anything(), + stdio: ['ignore', 'pipe', 'pipe'], + cwd: '/project', + })); +}); +test('can parse parameters', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + parameters: { + 'myparam': 'test', + 'test-stack1:myotherparam': 'test', + }, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), [ + 'deploy', + '--parameters', 'myparam=test', + '--parameters', 'test-stack1:myotherparam=test', + '--progress', 'events', + '--app', + 'node bin/my-app.js', + 'test-stack1', + ], expect.objectContaining({ + env: expect.anything(), + cwd: '/project', + })); +}); +test('can parse context', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + context: { + 'myContext': 'value', + 'test-stack1:OtherContext': 'otherValue', + }, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), [ + 'deploy', + '--progress', 'events', + '--app', + 'node bin/my-app.js', + '--context', 'myContext=value', + '--context', 'test-stack1:OtherContext=otherValue', + 'test-stack1', + ], expect.objectContaining({ + env: expect.anything(), + cwd: '/project', + })); +}); +test('can parse array arguments', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + notificationArns: [ + 'arn:aws:us-east-1:1111111111:some:resource', + 'arn:aws:us-east-1:1111111111:some:other-resource', + ], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), [ + 'deploy', + '--notification-arns', 'arn:aws:us-east-1:1111111111:some:resource', + '--notification-arns', 'arn:aws:us-east-1:1111111111:some:other-resource', + '--progress', 'events', + '--app', + 'node bin/my-app.js', + 'test-stack1', + ], expect.objectContaining({ + env: expect.anything(), + cwd: '/project', + })); +}); +test('can provide additional environment', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.deploy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['deploy', '--progress', 'events', '--app', 'node bin/my-app.js', 'test-stack1'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); +}); +test('default synth', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.synth({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['synth', '--app', 'node bin/my-app.js', 'test-stack1'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); +}); +test('synth arguments', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.destroy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['destroy', '--app', 'node bin/my-app.js', 'test-stack1'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); +}); +test('destroy arguments', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.destroy({ + app: 'node bin/my-app.js', + stacks: ['test-stack1'], + force: true, + exclusively: false, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['destroy', '--force', '--no-exclusively', '--app', 'node bin/my-app.js', 'test-stack1'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); +}); +test('default ls', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.list({ + app: 'node bin/my-app.js', + stacks: ['*'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['ls', '--app', 'node bin/my-app.js', '*'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); +}); +test('ls arguments', () => { + // WHEN + spawnSyncMock = jest.spyOn(child_process, 'spawnSync').mockReturnValue({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('test-stack1\ntest-stack2'), + pid: 123, + output: ['stdout', 'stderr'], + signal: null, + }); + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + const list = cdk.list({ + app: 'node bin/my-app.js', + stacks: ['*'], + long: true, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith(expect.stringMatching(/cdk/), ['ls', '--long', '--app', 'node bin/my-app.js', '*'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + }), + cwd: '/project', + })); + expect(list).toEqual('test-stack1\ntest-stack2'); +}); +test('can synth fast', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + env: { + KEY: 'value', + }, + }); + cdk.synthFast({ + execCmd: ['node', 'bin/my-app.js'], + output: 'cdk.output', + env: { + OTHERKEY: 'othervalue', + }, + context: { + CONTEXT: 'value', + }, + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith('node', ['bin/my-app.js'], expect.objectContaining({ + env: expect.objectContaining({ + KEY: 'value', + OTHERKEY: 'othervalue', + CDK_OUTDIR: 'cdk.output', + CDK_CONTEXT_JSON: '{\"CONTEXT\":\"value\"}', + }), + cwd: '/project', + })); +}); +test('can show output', () => { + // WHEN + const cdk = new cdk_wrapper_1.CdkCliWrapper({ + directory: '/project', + showOutput: true, + }); + cdk.synthFast({ + execCmd: ['node', 'bin/my-app.js'], + }); + // THEN + expect(spawnSyncMock).toHaveBeenCalledWith('node', ['bin/my-app.js'], expect.objectContaining({ + env: expect.anything(), + stdio: ['ignore', 'pipe', 'inherit'], + cwd: '/project', + })); +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RrLXdyYXBwZXIudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNkay13cmFwcGVyLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSwrQ0FBK0M7QUFDL0Msb0RBQW1EO0FBQ25ELDhDQUF5RTtBQUN6RSxJQUFJLGFBQStCLENBQUM7QUFFcEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUNkLGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsQ0FBQyxlQUFlLENBQUM7UUFDckUsTUFBTSxFQUFFLENBQUM7UUFDVCxNQUFNLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDN0IsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQzdCLEdBQUcsRUFBRSxHQUFHO1FBQ1IsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQztRQUM1QixNQUFNLEVBQUUsSUFBSTtLQUNiLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxDQUFDLEdBQUcsRUFBRTtJQUNiLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUNyQixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDdkIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0FBQ3ZCLENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLGdCQUFnQixFQUFFLEdBQUcsRUFBRTtJQUMxQixPQUFPO0lBQ1AsTUFBTSxHQUFHLEdBQUcsSUFBSSwyQkFBYSxDQUFDO1FBQzVCLFNBQVMsRUFBRSxVQUFVO0tBQ3RCLENBQUMsQ0FBQztJQUNILEdBQUcsQ0FBQyxNQUFNLENBQUM7UUFDVCxHQUFHLEVBQUUsb0JBQW9CO1FBQ3pCLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQztLQUN4QixDQUFDLENBQUM7SUFFSCxPQUFPO0lBQ1AsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLG9CQUFv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LENBQUM7SUFFSCxPQUFPO0lBQ1AsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLG9CQUFvQixDQUN4QyxNQUFNLEVBQ04sQ0FBQyxlQUFlLENBQUMsRUFDakIsTUFBTSxDQUFDLGdCQUFnQixDQUFDO1FBQ3RCLEdBQUcsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ3RCLEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDO1FBQ3BDLEdBQUcsRUFBRSxVQUFVO0tBQ2hCLENBQUMsQ0FDSCxDQUFDO0FBQ0osQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjaGlsZF9wcm9jZXNzIGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgQ2RrQ2xpV3JhcHBlciB9IGZyb20gJy4uL2xpYi9jZGstd3JhcHBlcic7XG5pbXBvcnQgeyBSZXF1aXJlQXBwcm92YWwsIFN0YWNrQWN0aXZpdHlQcm9ncmVzcyB9IGZyb20gJy4uL2xpYi9jb21tYW5kcyc7XG5sZXQgc3Bhd25TeW5jTW9jazogamVzdC5TcHlJbnN0YW5jZTtcblxuYmVmb3JlRWFjaCgoKSA9PiB7XG4gIHNwYXduU3luY01vY2sgPSBqZXN0LnNweU9uKGNoaWxkX3Byb2Nlc3MsICdzcGF3blN5bmMnKS5tb2NrUmV0dXJuVmFsdWUoe1xuICAgIHN0YXR1czogMCxcbiAgICBzdGRlcnI6IEJ1ZmZlci5mcm9tKCdzdGRlcnInKSxcbiAgICBzdGRvdXQ6IEJ1ZmZlci5mcm9tKCdzdGRvdXQnKSxcbiAgICBwaWQ6IDEyMyxcbiAgICBvdXRwdXQ6IFsnc3Rkb3V0JywgJ3N0ZGVyciddLFxuICAgIHNpZ25hbDogbnVsbCxcbiAgfSk7XG59KTtcblxuYWZ0ZXJFYWNoKCgpID0+IHtcbiAgamVzdC5yZXNldEFsbE1vY2tzKCk7XG4gIGplc3QucmVzdG9yZUFsbE1vY2tzKCk7XG4gIGplc3QuY2xlYXJBbGxNb2NrcygpO1xufSk7XG5cbnRlc3QoJ2RlZmF1bHQgZGVwbG95JywgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IGNkayA9IG5ldyBDZGtDbGlXcmFwcGVyKHtcbiAgICBkaXJlY3Rvcnk6ICcvcHJvamVjdCcsXG4gIH0pO1xuICBjZGsuZGVwbG95KHtcbiAgICBhcHA6ICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgIHN0YWNrczogWyd0ZXN0LXN0YWNrMSddLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL2Nkay8pLFxuICAgIFsnZGVwbG95JywgJy0tcHJvZ3Jlc3MnLCAnZXZlbnRzJywgJy0tYXBwJywgJ25vZGUgYmluL215LWFwcC5qcycsICd0ZXN0LXN0YWNrMSddLFxuICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIGVudjogZXhwZWN0LmFueXRoaW5nKCksXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcblxudGVzdCgnZGVwbG95IHdpdGggYWxsIGFyZ3VtZW50cycsICgpID0+IHtcbiAgLy8gV0hFTlxuICBjb25zdCBjZGsgPSBuZXcgQ2RrQ2xpV3JhcHBlcih7XG4gICAgZGlyZWN0b3J5OiAnL3Byb2plY3QnLFxuICB9KTtcbiAgY2RrLmRlcGxveSh7XG4gICAgYXBwOiAnbm9kZSBiaW4vbXktYXBwLmpzJyxcbiAgICBzdGFja3M6IFsndGVzdC1zdGFjazEnXSxcbiAgICBjaTogZmFsc2UsXG4gICAganNvbjogdHJ1ZSxcbiAgICBjb2xvcjogZmFsc2UsXG4gICAgZGVidWc6IGZhbHNlLFxuICAgIGZvcmNlOiB0cnVlLFxuICAgIHByb3h5OiAnaHR0cHM6Ly9wcm94eScsXG4gICAgdHJhY2U6IGZhbHNlLFxuICAgIG91dHB1dDogJ2Nkay5vdXQnLFxuICAgIHN0cmljdDogZmFsc2UsXG4gICAgZXhlY3V0ZTogdHJ1ZSxcbiAgICBsb29rdXBzOiBmYWxzZSxcbiAgICBub3RpY2VzOiB0cnVlLFxuICAgIHByb2ZpbGU6ICdteS1wcm9maWxlJyxcbiAgICByb2xlQXJuOiAnYXJuOmF3czppYW06OjExMTExMTExMTE6cm9sZS9teS1yb2xlJyxcbiAgICBzdGFnaW5nOiBmYWxzZSxcbiAgICB2ZXJib3NlOiB0cnVlLFxuICAgIGVjMkNyZWRzOiB0cnVlLFxuICAgIHJvbGxiYWNrOiBmYWxzZSxcbiAgICBleGNsdXNpdmVseTogdHJ1ZSxcbiAgICBvdXRwdXRzRmlsZTogJ291dHB1dHMuanNvbicsXG4gICAgcmV1c2VBc3NldHM6IFtcbiAgICAgICdhc3NldDEyMzQnLFxuICAgICAgJ2Fzc2V0NTY3OCcsXG4gICAgXSxcbiAgICBjYUJ1bmRsZVBhdGg6ICcvc29tZS9wYXRoJyxcbiAgICBpZ25vcmVFcnJvcnM6IGZhbHNlLFxuICAgIHBhdGhNZXRhZGF0YTogZmFsc2UsXG4gICAgYXNzZXRNZXRhZGF0YTogdHJ1ZSxcbiAgICBjaGFuZ2VTZXROYW1lOiAnbXktY2hhbmdlLXNldCcsXG4gICAgcmVxdWlyZUFwcHJvdmFsOiBSZXF1aXJlQXBwcm92YWwuTkVWRVIsXG4gICAgdG9vbGtpdFN0YWNrTmFtZTogJ1Rvb2xraXQnLFxuICAgIHZlcnNpb25SZXBvcnRpbmc6IHRydWUsXG4gICAgdXNlUHJldmlvdXNQYXJhbWV0ZXJzOiB0cnVlLFxuICAgIHByb2dyZXNzOiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuQkFSLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL2Nkay8pLFxuICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgJ2RlcGxveScsXG4gICAgICAnLS1uby1zdHJpY3QnLFxuICAgICAgJy0tbm8tdHJhY2UnLFxuICAgICAgJy0tbm8tbG9va3VwcycsXG4gICAgICAnLS1uby1pZ25vcmUtZXJyb3JzJyxcbiAgICAgICctLWpzb24nLFxuICAgICAgJy0tdmVyYm9zZScsXG4gICAgICAnLS1uby1kZWJ1ZycsXG4gICAgICAnLS1lYzJjcmVkcycsXG4gICAgICAnLS12ZXJzaW9uLXJlcG9ydGluZycsXG4gICAgICAnLS1uby1wYXRoLW1ldGFkYXRhJyxcbiAgICAgICctLWFzc2V0LW1ldGFkYXRhJyxcbiAgICAgICctLW5vdGljZXMnLFxuICAgICAgJy0tbm8tY29sb3InLFxuICAgICAgJy0tcHJvZmlsZScsICdteS1wcm9maWxlJyxcbiAgICAgICctLXByb3h5JywgJ2h0dHBzOi8vcHJveHknLFxuICAgICAgJy0tY2EtYnVuZGxlLXBhdGgnLCAnL3NvbWUvcGF0aCcsXG4gICAgICAnLS1yb2xlLWFybicsICdhcm46YXdzOmlhbTo6MTExMTExMTExMTpyb2xlL215LXJvbGUnLFxuICAgICAgJy0tb3V0cHV0JywgJ2Nkay5vdXQnLFxuICAgICAgJy0tbm8tY2knLFxuICAgICAgJy0tZXhlY3V0ZScsXG4gICAgICAnLS1leGNsdXNpdmVseScsXG4gICAgICAnLS1mb3JjZScsXG4gICAgICAnLS1uby1yb2xsYmFjaycsXG4gICAgICAnLS1uby1zdGFnaW5nJyxcbiAgICAgICctLXJldXNlLWFzc2V0cycsICdhc3NldDEyMzQnLFxuICAgICAgJy0tcmV1c2UtYXNzZXRzJywgJ2Fzc2V0NTY3OCcsXG4gICAgICAnLS1vdXRwdXRzLWZpbGUnLCAnb3V0cHV0cy5qc29uJyxcbiAgICAgICctLXJlcXVpcmUtYXBwcm92YWwnLCAnbmV2ZXInLFxuICAgICAgJy0tY2hhbmdlLXNldC1uYW1lJywgJ215LWNoYW5nZS1zZXQnLFxuICAgICAgJy0tdG9vbGtpdC1zdGFjay1uYW1lJywgJ1Rvb2xraXQnLFxuICAgICAgJy0tcHJldmlvdXMtcGFyYW1ldGVycycsXG4gICAgICAnLS1wcm9ncmVzcycsICdiYXInLFxuICAgICAgJy0tYXBwJyxcbiAgICAgICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgICAgJ3Rlc3Qtc3RhY2sxJyxcbiAgICBdKSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5hbnl0aGluZygpLFxuICAgICAgc3RkaW86IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddLFxuICAgICAgY3dkOiAnL3Byb2plY3QnLFxuICAgIH0pLFxuICApO1xufSk7XG5cbnRlc3QoJ2NhbiBwYXJzZSBib29sZWFuIGFyZ3VtZW50cycsICgpID0+IHtcbiAgLy8gV0hFTlxuICBjb25zdCBjZGsgPSBuZXcgQ2RrQ2xpV3JhcHBlcih7XG4gICAgZGlyZWN0b3J5OiAnL3Byb2plY3QnLFxuICB9KTtcbiAgY2RrLmRlcGxveSh7XG4gICAgYXBwOiAnbm9kZSBiaW4vbXktYXBwLmpzJyxcbiAgICBzdGFja3M6IFsndGVzdC1zdGFjazEnXSxcbiAgICBqc29uOiB0cnVlLFxuICAgIGNvbG9yOiBmYWxzZSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9jZGsvKSxcbiAgICBbXG4gICAgICAnZGVwbG95JyxcbiAgICAgICctLXByb2dyZXNzJywgJ2V2ZW50cycsXG4gICAgICAnLS1hcHAnLFxuICAgICAgJ25vZGUgYmluL215LWFwcC5qcycsXG4gICAgICAnLS1qc29uJyxcbiAgICAgICctLW5vLWNvbG9yJyxcbiAgICAgICd0ZXN0LXN0YWNrMScsXG4gICAgXSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5hbnl0aGluZygpLFxuICAgICAgc3RkaW86IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddLFxuICAgICAgY3dkOiAnL3Byb2plY3QnLFxuICAgIH0pLFxuICApO1xufSk7XG5cbnRlc3QoJ2NhbiBwYXJzZSBwYXJhbWV0ZXJzJywgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IGNkayA9IG5ldyBDZGtDbGlXcmFwcGVyKHtcbiAgICBkaXJlY3Rvcnk6ICcvcHJvamVjdCcsXG4gIH0pO1xuICBjZGsuZGVwbG95KHtcbiAgICBhcHA6ICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgIHN0YWNrczogWyd0ZXN0LXN0YWNrMSddLFxuICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICdteXBhcmFtJzogJ3Rlc3QnLFxuICAgICAgJ3Rlc3Qtc3RhY2sxOm15b3RoZXJwYXJhbSc6ICd0ZXN0JyxcbiAgICB9LFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL2Nkay8pLFxuICAgIFtcbiAgICAgICdkZXBsb3knLFxuICAgICAgJy0tcGFyYW1ldGVycycsICdteXBhcmFtPXRlc3QnLFxuICAgICAgJy0tcGFyYW1ldGVycycsICd0ZXN0LXN0YWNrMTpteW90aGVycGFyYW09dGVzdCcsXG4gICAgICAnLS1wcm9ncmVzcycsICdldmVudHMnLFxuICAgICAgJy0tYXBwJyxcbiAgICAgICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgICAgJ3Rlc3Qtc3RhY2sxJyxcbiAgICBdLFxuICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIGVudjogZXhwZWN0LmFueXRoaW5nKCksXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcblxudGVzdCgnY2FuIHBhcnNlIGNvbnRleHQnLCAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgfSk7XG4gIGNkay5kZXBsb3koe1xuICAgIGFwcDogJ25vZGUgYmluL215LWFwcC5qcycsXG4gICAgc3RhY2tzOiBbJ3Rlc3Qtc3RhY2sxJ10sXG4gICAgY29udGV4dDoge1xuICAgICAgJ215Q29udGV4dCc6ICd2YWx1ZScsXG4gICAgICAndGVzdC1zdGFjazE6T3RoZXJDb250ZXh0JzogJ290aGVyVmFsdWUnLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIFRIRU5cbiAgZXhwZWN0KHNwYXduU3luY01vY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvY2RrLyksXG4gICAgW1xuICAgICAgJ2RlcGxveScsXG4gICAgICAnLS1wcm9ncmVzcycsICdldmVudHMnLFxuICAgICAgJy0tYXBwJyxcbiAgICAgICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgICAgJy0tY29udGV4dCcsICdteUNvbnRleHQ9dmFsdWUnLFxuICAgICAgJy0tY29udGV4dCcsICd0ZXN0LXN0YWNrMTpPdGhlckNvbnRleHQ9b3RoZXJWYWx1ZScsXG4gICAgICAndGVzdC1zdGFjazEnLFxuICAgIF0sXG4gICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgZW52OiBleHBlY3QuYW55dGhpbmcoKSxcbiAgICAgIGN3ZDogJy9wcm9qZWN0JyxcbiAgICB9KSxcbiAgKTtcbn0pO1xuXG50ZXN0KCdjYW4gcGFyc2UgYXJyYXkgYXJndW1lbnRzJywgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IGNkayA9IG5ldyBDZGtDbGlXcmFwcGVyKHtcbiAgICBkaXJlY3Rvcnk6ICcvcHJvamVjdCcsXG4gIH0pO1xuICBjZGsuZGVwbG95KHtcbiAgICBhcHA6ICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgIHN0YWNrczogWyd0ZXN0LXN0YWNrMSddLFxuICAgIG5vdGlmaWNhdGlvbkFybnM6IFtcbiAgICAgICdhcm46YXdzOnVzLWVhc3QtMToxMTExMTExMTExOnNvbWU6cmVzb3VyY2UnLFxuICAgICAgJ2Fybjphd3M6dXMtZWFzdC0xOjExMTExMTExMTE6c29tZTpvdGhlci1yZXNvdXJjZScsXG4gICAgXSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9jZGsvKSxcbiAgICBbXG4gICAgICAnZGVwbG95JyxcbiAgICAgICctLW5vdGlmaWNhdGlvbi1hcm5zJywgJ2Fybjphd3M6dXMtZWFzdC0xOjExMTExMTExMTE6c29tZTpyZXNvdXJjZScsXG4gICAgICAnLS1ub3RpZmljYXRpb24tYXJucycsICdhcm46YXdzOnVzLWVhc3QtMToxMTExMTExMTExOnNvbWU6b3RoZXItcmVzb3VyY2UnLFxuICAgICAgJy0tcHJvZ3Jlc3MnLCAnZXZlbnRzJyxcbiAgICAgICctLWFwcCcsXG4gICAgICAnbm9kZSBiaW4vbXktYXBwLmpzJyxcbiAgICAgICd0ZXN0LXN0YWNrMScsXG4gICAgXSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5hbnl0aGluZygpLFxuICAgICAgY3dkOiAnL3Byb2plY3QnLFxuICAgIH0pLFxuICApO1xufSk7XG5cbnRlc3QoJ2NhbiBwcm92aWRlIGFkZGl0aW9uYWwgZW52aXJvbm1lbnQnLCAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgICBlbnY6IHtcbiAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICB9LFxuICB9KTtcbiAgY2RrLmRlcGxveSh7XG4gICAgYXBwOiAnbm9kZSBiaW4vbXktYXBwLmpzJyxcbiAgICBzdGFja3M6IFsndGVzdC1zdGFjazEnXSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9jZGsvKSxcbiAgICBbJ2RlcGxveScsICctLXByb2dyZXNzJywgJ2V2ZW50cycsICctLWFwcCcsICdub2RlIGJpbi9teS1hcHAuanMnLCAndGVzdC1zdGFjazEnXSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgS0VZOiAndmFsdWUnLFxuICAgICAgfSksXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcblxudGVzdCgnZGVmYXVsdCBzeW50aCcsICgpID0+IHtcbiAgLy8gV0hFTlxuICBjb25zdCBjZGsgPSBuZXcgQ2RrQ2xpV3JhcHBlcih7XG4gICAgZGlyZWN0b3J5OiAnL3Byb2plY3QnLFxuICAgIGVudjoge1xuICAgICAgS0VZOiAndmFsdWUnLFxuICAgIH0sXG4gIH0pO1xuICBjZGsuc3ludGgoe1xuICAgIGFwcDogJ25vZGUgYmluL215LWFwcC5qcycsXG4gICAgc3RhY2tzOiBbJ3Rlc3Qtc3RhY2sxJ10sXG4gIH0pO1xuXG4gIC8vIFRIRU5cbiAgZXhwZWN0KHNwYXduU3luY01vY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvY2RrLyksXG4gICAgWydzeW50aCcsICctLWFwcCcsICdub2RlIGJpbi9teS1hcHAuanMnLCAndGVzdC1zdGFjazEnXSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgS0VZOiAndmFsdWUnLFxuICAgICAgfSksXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcblxudGVzdCgnc3ludGggYXJndW1lbnRzJywgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IGNkayA9IG5ldyBDZGtDbGlXcmFwcGVyKHtcbiAgICBkaXJlY3Rvcnk6ICcvcHJvamVjdCcsXG4gICAgZW52OiB7XG4gICAgICBLRVk6ICd2YWx1ZScsXG4gICAgfSxcbiAgfSk7XG4gIGNkay5kZXN0cm95KHtcbiAgICBhcHA6ICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgIHN0YWNrczogWyd0ZXN0LXN0YWNrMSddLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL2Nkay8pLFxuICAgIFsnZGVzdHJveScsICctLWFwcCcsICdub2RlIGJpbi9teS1hcHAuanMnLCAndGVzdC1zdGFjazEnXSxcbiAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBlbnY6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgS0VZOiAndmFsdWUnLFxuICAgICAgfSksXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcblxudGVzdCgnZGVzdHJveSBhcmd1bWVudHMnLCAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgICBlbnY6IHtcbiAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICB9LFxuICB9KTtcbiAgY2RrLmRlc3Ryb3koe1xuICAgIGFwcDogJ25vZGUgYmluL215LWFwcC5qcycsXG4gICAgc3RhY2tzOiBbJ3Rlc3Qtc3RhY2sxJ10sXG4gICAgZm9yY2U6IHRydWUsXG4gICAgZXhjbHVzaXZlbHk6IGZhbHNlLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL2Nkay8pLFxuICAgIFsnZGVzdHJveScsICctLWZvcmNlJywgJy0tbm8tZXhjbHVzaXZlbHknLCAnLS1hcHAnLCAnbm9kZSBiaW4vbXktYXBwLmpzJywgJ3Rlc3Qtc3RhY2sxJ10sXG4gICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgZW52OiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICAgIH0pLFxuICAgICAgY3dkOiAnL3Byb2plY3QnLFxuICAgIH0pLFxuICApO1xufSk7XG5cbnRlc3QoJ2RlZmF1bHQgbHMnLCAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgICBlbnY6IHtcbiAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICB9LFxuICB9KTtcbiAgY2RrLmxpc3Qoe1xuICAgIGFwcDogJ25vZGUgYmluL215LWFwcC5qcycsXG4gICAgc3RhY2tzOiBbJyonXSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9jZGsvKSxcbiAgICBbJ2xzJywgJy0tYXBwJywgJ25vZGUgYmluL215LWFwcC5qcycsICcqJ10sXG4gICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgZW52OiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICAgIH0pLFxuICAgICAgY3dkOiAnL3Byb2plY3QnLFxuICAgIH0pLFxuICApO1xufSk7XG5cbnRlc3QoJ2xzIGFyZ3VtZW50cycsICgpID0+IHtcbiAgLy8gV0hFTlxuICBzcGF3blN5bmNNb2NrID0gamVzdC5zcHlPbihjaGlsZF9wcm9jZXNzLCAnc3Bhd25TeW5jJykubW9ja1JldHVyblZhbHVlKHtcbiAgICBzdGF0dXM6IDAsXG4gICAgc3RkZXJyOiBCdWZmZXIuZnJvbSgnc3RkZXJyJyksXG4gICAgc3Rkb3V0OiBCdWZmZXIuZnJvbSgndGVzdC1zdGFjazFcXG50ZXN0LXN0YWNrMicpLFxuICAgIHBpZDogMTIzLFxuICAgIG91dHB1dDogWydzdGRvdXQnLCAnc3RkZXJyJ10sXG4gICAgc2lnbmFsOiBudWxsLFxuICB9KTtcbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgICBlbnY6IHtcbiAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICB9LFxuICB9KTtcbiAgY29uc3QgbGlzdCA9IGNkay5saXN0KHtcbiAgICBhcHA6ICdub2RlIGJpbi9teS1hcHAuanMnLFxuICAgIHN0YWNrczogWycqJ10sXG4gICAgbG9uZzogdHJ1ZSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9jZGsvKSxcbiAgICBbJ2xzJywgJy0tbG9uZycsICctLWFwcCcsICdub2RlIGJpbi9teS1hcHAuanMnLCAnKiddLFxuICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIGVudjogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBLRVk6ICd2YWx1ZScsXG4gICAgICB9KSxcbiAgICAgIGN3ZDogJy9wcm9qZWN0JyxcbiAgICB9KSxcbiAgKTtcblxuICBleHBlY3QobGlzdCkudG9FcXVhbCgndGVzdC1zdGFjazFcXG50ZXN0LXN0YWNrMicpO1xufSk7XG5cbnRlc3QoJ2NhbiBzeW50aCBmYXN0JywgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IGNkayA9IG5ldyBDZGtDbGlXcmFwcGVyKHtcbiAgICBkaXJlY3Rvcnk6ICcvcHJvamVjdCcsXG4gICAgZW52OiB7XG4gICAgICBLRVk6ICd2YWx1ZScsXG4gICAgfSxcbiAgfSk7XG4gIGNkay5zeW50aEZhc3Qoe1xuICAgIGV4ZWNDbWQ6IFsnbm9kZScsICdiaW4vbXktYXBwLmpzJ10sXG4gICAgb3V0cHV0OiAnY2RrLm91dHB1dCcsXG4gICAgZW52OiB7XG4gICAgICBPVEhFUktFWTogJ290aGVydmFsdWUnLFxuICAgIH0sXG4gICAgY29udGV4dDoge1xuICAgICAgQ09OVEVYVDogJ3ZhbHVlJyxcbiAgICB9LFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChzcGF3blN5bmNNb2NrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAnbm9kZScsXG4gICAgWydiaW4vbXktYXBwLmpzJ10sXG4gICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgZW52OiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIEtFWTogJ3ZhbHVlJyxcbiAgICAgICAgT1RIRVJLRVk6ICdvdGhlcnZhbHVlJyxcbiAgICAgICAgQ0RLX09VVERJUjogJ2Nkay5vdXRwdXQnLFxuICAgICAgICBDREtfQ09OVEVYVF9KU09OOiAne1xcXCJDT05URVhUXFxcIjpcXFwidmFsdWVcXFwifScsXG4gICAgICB9KSxcbiAgICAgIGN3ZDogJy9wcm9qZWN0JyxcbiAgICB9KSxcbiAgKTtcbn0pO1xuXG50ZXN0KCdjYW4gc2hvdyBvdXRwdXQnLCAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgY2RrID0gbmV3IENka0NsaVdyYXBwZXIoe1xuICAgIGRpcmVjdG9yeTogJy9wcm9qZWN0JyxcbiAgICBzaG93T3V0cHV0OiB0cnVlLFxuICB9KTtcbiAgY2RrLnN5bnRoRmFzdCh7XG4gICAgZXhlY0NtZDogWydub2RlJywgJ2Jpbi9teS1hcHAuanMnXSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3Qoc3Bhd25TeW5jTW9jaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgJ25vZGUnLFxuICAgIFsnYmluL215LWFwcC5qcyddLFxuICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIGVudjogZXhwZWN0LmFueXRoaW5nKCksXG4gICAgICBzdGRpbzogWydpZ25vcmUnLCAncGlwZScsICdpbmhlcml0J10sXG4gICAgICBjd2Q6ICcvcHJvamVjdCcsXG4gICAgfSksXG4gICk7XG59KTtcbiJdfQ== \ No newline at end of file diff --git a/packages/cdk-cli-wrapper/tsconfig.json b/packages/cdk-cli-wrapper/tsconfig.json new file mode 100644 index 0000000000000..52f5c6e529175 --- /dev/null +++ b/packages/cdk-cli-wrapper/tsconfig.json @@ -0,0 +1,47 @@ +{ + "compilerOptions": { + "declarationMap": false, + "inlineSourceMap": true, + "inlineSources": true, + "alwaysStrict": true, + "declaration": true, + "experimentalDecorators": true, + "incremental": true, + "lib": [ + "es2020" + ], + "module": "CommonJS", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": false, + "target": "ES2020", + "composite": true, + "tsBuildInfoFile": "tsconfig.tsbuildinfo" + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + ".types-compat" + ], + "references": [ + { + "path": "../../tools/@aws-cdk/cdk-build-tools" + }, + { + "path": "../../tools/@aws-cdk/pkglint" + } + ], + "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore" +} \ No newline at end of file