diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts index 67356826d9b90..a14f52ffbfb15 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts @@ -75,7 +75,7 @@ export interface CodePipelineProps { readonly crossAccountKeys?: boolean; /** - * CDK CLI version to use in self-mutation and asset publishing steps + * CDK CLI version to use in self-mutation step * * If you want to lock the CDK CLI version used in the pipeline, by steps * that are automatically generated for you, specify the version here. @@ -97,6 +97,20 @@ export interface CodePipelineProps { */ readonly cliVersion?: string; + /** + * CDK CLI version to use in asset publishing steps + * + * If you want to lock the `cdk-assets` version used in the pipeline, by steps + * that are automatically generated for you, specify the version here. + * + * We recommend you do not specify this value, as not specifying it always + * uses the latest CLI version which is backwards compatible with old versions. + * + * @see https://www.npmjs.com/package/cdk-assets + * @default - Latest version + */ + readonly cdkAssetsCliVersion?: string; + /** * Whether the pipeline will update itself * @@ -403,6 +417,7 @@ export class CodePipeline extends PipelineBase { private readonly singlePublisherPerAssetType: boolean; private readonly cliVersion?: string; + private readonly cdkAssetsCliVersion: string; constructor(scope: Construct, id: string, private readonly props: CodePipelineProps) { super(scope, id, props); @@ -411,6 +426,7 @@ export class CodePipeline extends PipelineBase { this.dockerCredentials = props.dockerCredentials ?? []; this.singlePublisherPerAssetType = !(props.publishAssetsInParallel ?? true); this.cliVersion = props.cliVersion ?? preferredCliVersion(); + this.cdkAssetsCliVersion = props.cdkAssetsCliVersion ?? 'latest'; this.useChangeSets = props.useChangeSets ?? true; this.stackOutputs = new StackOutputsMap(this); this.usePipelineRoleForActions = props.usePipelineRoleForActions ?? false; @@ -881,7 +897,7 @@ export class CodePipeline extends PipelineBase { const script = new CodeBuildStep(node.id, { commands, installCommands: [ - 'npm install -g cdk-assets@latest', + `npm install -g cdk-assets@${this.cdkAssetsCliVersion}`, ], input: this._cloudAssemblyFileSet, buildEnvironment: { 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 1c3372d9990f7..2f9586f06041e 100644 --- a/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline.test.ts @@ -210,6 +210,32 @@ test.each([ }); }); +test.each([ + [undefined, 'latest'], + ['9.9.9', '9.9.9'], +])('When I request cdk-assets version %p I get %p', (requested, expected) => { + const pipelineStack = new cdk.Stack(app, 'PipelineStack', { env: PIPELINE_ENV }); + const pipe = new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk', { + cdkAssetsCliVersion: requested, + }); + + pipe.addStage(new FileAssetApp(pipelineStack, 'App', {})); + + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', { + Source: { + BuildSpec: Match.serializedJson(Match.objectLike({ + phases: { + install: { + commands: [ + `npm install -g cdk-assets@${expected}`, + ], + }, + }, + })), + }, + }); +}); + test('CodeBuild action role has the right AssumeRolePolicyDocument', () => { const pipelineStack = new cdk.Stack(app, 'PipelineStack', { env: PIPELINE_ENV }); new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk');