From 39fe11bc1b0d12920111331dca560150006a0733 Mon Sep 17 00:00:00 2001 From: Jan W Date: Thu, 25 Nov 2021 02:50:09 +0100 Subject: [PATCH] fix(codepipeline): cannot trigger on all tags anymore in EcrSourceAction (#17270) The EcrSourceAction could previously be used to trigger on changes to all tags of an image. As part of the fix aws#13818, the imageTag was defaulted to latest if not provided. Therefore it was no longer possible to call the underlying onCloudTrailImagePushed function with an undefined imageTag to watch changes on all tags. Reintroduce triggering on all tags by passing an empty string as the imageTag. Fixes aws#13818 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/ecr/source-action.ts | 5 +- .../test/ecr/ecr-source-action.test.ts | 73 +++++++++++++++++++ .../integ.pipeline-ecr-source.expected.json | 2 +- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index eb40c994ccd98..01c878ca9e139 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -36,6 +36,7 @@ export interface EcrSourceVariables { export interface EcrSourceActionProps extends codepipeline.CommonAwsActionProps { /** * The image tag that will be checked for changes. + * Provide an empty string to trigger on changes to any tag. * * @default 'latest' */ @@ -95,7 +96,7 @@ export class EcrSourceAction extends Action { this.props.repository.onCloudTrailImagePushed(Names.nodeUniqueId(stage.pipeline.node) + 'SourceEventRule', { target: new targets.CodePipeline(stage.pipeline), - imageTag: this.props.imageTag ?? 'latest', + imageTag: this.props.imageTag === '' ? undefined : (this.props.imageTag ?? 'latest'), }); // the Action Role also needs to write to the Pipeline's bucket @@ -104,7 +105,7 @@ export class EcrSourceAction extends Action { return { configuration: { RepositoryName: this.props.repository.repositoryName, - ImageTag: this.props.imageTag, + ImageTag: this.props.imageTag ? this.props.imageTag : undefined, // `''` is falsy in JS/TS }, }; } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts index b51a566d4ef14..99160cdd4193a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/ecr/ecr-source-action.test.ts @@ -1,4 +1,5 @@ import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as codepipeline from '@aws-cdk/aws-codepipeline'; import * as ecr from '@aws-cdk/aws-ecr'; @@ -60,6 +61,78 @@ describe('ecr source action', () => { }); + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + 'EventPattern': { + 'detail': { + 'requestParameters': { + 'imageTag': ['latest'], + }, + }, + }, + }); + }); + + test('watches all tags when imageTag provided as empty string', () => { + const stack = new Stack(); + + const sourceOutput = new codepipeline.Artifact(); + const ecrSourceAction = new cpactions.EcrSourceAction({ + actionName: 'Source', + output: sourceOutput, + repository: ecr.Repository.fromRepositoryName(stack, 'Repo', 'repo'), + imageTag: '', + }); + + new codepipeline.Pipeline(stack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ecrSourceAction], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'Build', + project: new codebuild.PipelineProject(stack, 'MyProject'), + input: sourceOutput, + environmentVariables: { + ImageDigest: { value: ecrSourceAction.variables.imageDigest }, + }, + }), + ], + }, + ], + }); + + expect(stack).toHaveResourceLike('AWS::Events::Rule', { + 'EventPattern': { + 'source': [ + 'aws.ecr', + ], + 'detail': { + 'requestParameters': { + 'imageTag': ABSENT, + }, + }, + }, + }); + + expect(stack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + 'Stages': [ + { + 'Name': 'Source', + 'Actions': [ + { + 'Name': 'Source', + 'Configuration': { + 'ImageTag': ABSENT, + }, + }, + ], + }, + ], + }); }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json index c200ab454d71a..53c605d58da68 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-ecr-source.expected.json @@ -415,4 +415,4 @@ } } } -} \ No newline at end of file +}