diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json index 47f968ddcf5c6..0bf8a1eca3dbc 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.assets.json @@ -1,7 +1,8 @@ { - "version": "40.0.0", + "version": "41.0.0", "files": { - "694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18": { + "a41837dbefd99eb379b4aee82e9ecd25ce286233e8cae49a43a93648cdc325b5": { + "displayName": "EcrRepoLookupStack Template", "source": { "path": "EcrRepoLookupStack.template.json", "packaging": "file" @@ -9,7 +10,7 @@ "destinations": { "12345678-test-region": { "bucketName": "cdk-hnb659fds-assets-12345678-test-region", - "objectKey": "694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18.json", + "objectKey": "a41837dbefd99eb379b4aee82e9ecd25ce286233e8cae49a43a93648cdc325b5.json", "region": "test-region", "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-test-region" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json index b65cf5070c986..4efda87695843 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupStack.template.json @@ -101,6 +101,23 @@ ] ] } + }, + "DummyRepoArn": { + "Value": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ecr:us-east-1:123456789012:repository/DUMMY_ARN" + ] + ] + } + }, + "IsDummy": { + "Value": "true" } }, "Parameters": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json index 6c5f894f4afdb..92cb7d6ccc053 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.assets.json @@ -1,7 +1,8 @@ { - "version": "40.0.0", + "version": "41.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3 Template", "source": { "path": "EcrRepoLookupTestDefaultTestDeployAssert7F088AF3.template.json", "packaging": "file" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out index 1e02a2deb191b..188478b55560e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"40.0.0"} \ No newline at end of file +{"version":"41.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json index d7ae2c83ea6d2..04e3a7d37b671 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/integ.json @@ -1,6 +1,6 @@ { "enableLookups": true, - "version": "40.0.0", + "version": "41.0.0", "testCases": { "EcrRepoLookupTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json index b81823774aa1a..6eb37ed5917fa 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "40.0.0", + "version": "42.0.0", "artifacts": { "EcrRepoLookupStack.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-test-region", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-test-region", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/694b1f59a97a2cabd43348095c6983d394ce506020298a3a62f3067ae6ce7e18.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-test-region/a41837dbefd99eb379b4aee82e9ecd25ce286233e8cae49a43a93648cdc325b5.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -106,6 +106,18 @@ "data": "RepositoryUri" } ], + "/EcrRepoLookupStack/DummyRepoArn": [ + { + "type": "aws:cdk:logicalId", + "data": "DummyRepoArn" + } + ], + "/EcrRepoLookupStack/IsDummy": [ + { + "type": "aws:cdk:logicalId", + "data": "IsDummy" + } + ], "/EcrRepoLookupStack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", @@ -183,7 +195,7 @@ "props": { "dummyValue": [ { - "Arn": "arn:${Token[AWS.Partition.3]}:ecr:us-east-1:123456789012:repository/DUMMY_ARN" + "Arn": "arn:${Token[AWS.Partition.9]}:ecr:us-east-1:123456789012:repository/DUMMY_ARN" } ], "account": "12345678", @@ -195,6 +207,27 @@ ], "lookupRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region" } + }, + { + "key": "cc-api-provider:account=12345678:exactIdentifier=does-not-exist-repo:propertiesToReturn.0=Arn:region=test-region:typeName=AWS$:$:ECR$:$:Repository", + "provider": "cc-api-provider", + "props": { + "dummyValue": [ + { + "Arn": "arn:${Token[AWS.Partition.9]}:ecr:us-east-1:123456789012:repository/DUMMY_ARN" + } + ], + "ignoreErrorOnMissingContext": true, + "account": "12345678", + "region": "test-region", + "typeName": "AWS::ECR::Repository", + "exactIdentifier": "does-not-exist-repo", + "propertiesToReturn": [ + "Arn" + ], + "lookupRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-test-region" + } } - ] + ], + "minimumCliVersion": "2.1006.0" } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json index 721995796f38d..75dcc3e23d98d 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.js.snapshot/tree.json @@ -1 +1 @@ -{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"EcrRepoLookupStack":{"id":"EcrRepoLookupStack","path":"EcrRepoLookupStack","children":{"LookupRepo":{"id":"LookupRepo","path":"EcrRepoLookupStack/LookupRepo","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"Lambda":{"id":"Lambda","path":"EcrRepoLookupStack/Lambda","children":{"ServiceRole":{"id":"ServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole","children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ecr:DescribeImages","ecr:DescribeRepositories"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:us-east-1:123456789012:repository/DUMMY_ARN"]]}}],"Version":"2012-10-17"},"policyName":"LambdaServiceRoleDefaultPolicyDAE46E21","roles":[{"Ref":"LambdaServiceRoleA8ED4D3B"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function(event, context) { return \"Hello, World!\"; }"},"handler":"index.handler","role":{"Fn::GetAtt":["LambdaServiceRoleA8ED4D3B","Arn"]},"runtime":"nodejs20.x"}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"RepositoryUri":{"id":"RepositoryUri","path":"EcrRepoLookupStack/RepositoryUri","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupStack/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupStack/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"EcrRepoLookupTest":{"id":"EcrRepoLookupTest","path":"EcrRepoLookupTest","children":{"DefaultTest":{"id":"DefaultTest","path":"EcrRepoLookupTest/DefaultTest","children":{"Default":{"id":"Default","path":"EcrRepoLookupTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"EcrRepoLookupTest/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}} \ No newline at end of file +{"version":"tree-0.1","tree":{"id":"App","path":"","children":{"EcrRepoLookupStack":{"id":"EcrRepoLookupStack","path":"EcrRepoLookupStack","children":{"LookupRepo":{"id":"LookupRepo","path":"EcrRepoLookupStack/LookupRepo","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"Lambda":{"id":"Lambda","path":"EcrRepoLookupStack/Lambda","children":{"ServiceRole":{"id":"ServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole","children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"EcrRepoLookupStack/Lambda/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DefaultPolicy":{"id":"DefaultPolicy","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy","children":{"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/ServiceRole/DefaultPolicy/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Policy","aws:cdk:cloudformation:props":{"policyDocument":{"Statement":[{"Action":["ecr:DescribeImages","ecr:DescribeRepositories"],"Effect":"Allow","Resource":{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":ecr:us-east-1:123456789012:repository/DUMMY_ARN"]]}}],"Version":"2012-10-17"},"policyName":"LambdaServiceRoleDefaultPolicyDAE46E21","roles":[{"Ref":"LambdaServiceRoleA8ED4D3B"}]}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*","*"]}},"Resource":{"id":"Resource","path":"EcrRepoLookupStack/Lambda/Resource","attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async function(event, context) { return \"Hello, World!\"; }"},"handler":"index.handler","role":{"Fn::GetAtt":["LambdaServiceRoleA8ED4D3B","Arn"]},"runtime":"nodejs20.x"}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"RepositoryUri":{"id":"RepositoryUri","path":"EcrRepoLookupStack/RepositoryUri","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DummyRepo":{"id":"DummyRepo","path":"EcrRepoLookupStack/DummyRepo","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":[]}},"DummyRepoArn":{"id":"DummyRepoArn","path":"EcrRepoLookupStack/DummyRepoArn","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"IsDummy":{"id":"IsDummy","path":"EcrRepoLookupStack/IsDummy","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupStack/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupStack/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"EcrRepoLookupTest":{"id":"EcrRepoLookupTest","path":"EcrRepoLookupTest","children":{"DefaultTest":{"id":"DefaultTest","path":"EcrRepoLookupTest/DefaultTest","children":{"Default":{"id":"Default","path":"EcrRepoLookupTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"EcrRepoLookupTest/DefaultTest/DeployAssert","children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"EcrRepoLookupTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"}}},"constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}},"constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts index 825ecfeedfb41..fa3a1167f7f07 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ecr/test/integ.repository-lookup.ts @@ -27,6 +27,14 @@ new CfnOutput(lookupStack, 'RepositoryUri', { value: lookupRepo.repositoryUri, }); +const dummyRepo = ecr.Repository.fromLookup(lookupStack, 'DummyRepo', { + repositoryArn: 'arn:aws:ecr:us-east-1:123456789012:repository/does-not-exist-repo', + mustExist: false, +}); + +new CfnOutput(lookupStack, 'DummyRepoArn', { value: dummyRepo.repositoryArn }); +new CfnOutput(lookupStack, 'IsDummy', { value: String(ecr.Repository.isLookupDummy(dummyRepo)) }); + new IntegTest(app, 'EcrRepoLookupTest', { enableLookups: true, stackUpdateWorkflow: false, diff --git a/packages/aws-cdk-lib/aws-ecr/README.md b/packages/aws-cdk-lib/aws-ecr/README.md index dcbbedf879b17..f1031debb7996 100644 --- a/packages/aws-cdk-lib/aws-ecr/README.md +++ b/packages/aws-cdk-lib/aws-ecr/README.md @@ -229,6 +229,23 @@ const repositoryFromLookup = ecr.Repository.fromLookup(this, 'ImportedRepoByLook }); ``` +If the target repository is not found in your account when using `Repository.fromLookup()`, an error will be thrown. +To prevent the error in the case, you can receive a dummy repository without the error +by setting `mustExist` to `false`. The dummy repository has a `repositoryArn` of +`arn:{partition}:ecr:us-east-1:123456789012:repository/DUMMY_ARN`. You can check if the +repository is a dummy repository by using the `Repository.isLookupDummy()` method. + +```ts +const dummy = ecr.Repository.fromLookup(this, 'ImportedRepoByLookup', { + repositoryArn: 'arn:aws:ecr:us-east-1:123456789012:repository/does-not-exist-repo', + mustExist: false, +}); + +if (ecr.Repository.isLookupDummy(dummy)) { + // alternative process +} +``` + ## CloudWatch event rules You can publish repository events to a CloudWatch event rule with `onEvent`: diff --git a/packages/aws-cdk-lib/aws-ecr/lib/repository.ts b/packages/aws-cdk-lib/aws-ecr/lib/repository.ts index bdec659547ecc..b6b1ce344316c 100644 --- a/packages/aws-cdk-lib/aws-ecr/lib/repository.ts +++ b/packages/aws-cdk-lib/aws-ecr/lib/repository.ts @@ -23,6 +23,7 @@ import { Arn, ValidationError, UnscopedValidationError, + ArnComponents, } from '../../core'; import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource'; import { AutoDeleteImagesProvider } from '../../custom-resource-handlers/dist/aws-ecr/auto-delete-images-provider.generated'; @@ -620,6 +621,18 @@ export interface RepositoryLookupOptions { * @default - Do not filter on repository ARN */ readonly repositoryArn?: string; + + /** + * Whether to throw an error if the repository was not found. + * + * If it is set to `false` and the repository was not found, a dummy + * repository with the arn 'arn:{partition}:ecr:us-east-1:123456789012:repository/DUMMY_ARN' + * will be returned. You can check if the repository is a dummy repository by using the + * `Repository.isLookupDummy()` method. + * + * @default true + */ + readonly mustExist?: boolean; } export interface RepositoryAttributes { @@ -627,12 +640,24 @@ export interface RepositoryAttributes { readonly repositoryArn: string; } +const dummyArnComponents: ArnComponents = { + service: 'ecr', + region: 'us-east-1', + account: '123456789012', + resource: 'repository', + resourceName: 'DUMMY_ARN', +}; + /** * Define an ECR repository */ export class Repository extends RepositoryBase { /** * Lookup an existing repository + * + * If you set `mustExist` to `false` in `options` and the repository was not found, + * this method will return a dummy repository with the arn 'arn:{partition}:ecr:us-east-1:123456789012:repository/DUMMY_ARN'. + * You can check if the repository is a dummy repository by using the `Repository.isLookupDummy()` method. */ public static fromLookup(scope: Construct, id: string, options: RepositoryLookupOptions): IRepository { if (Token.isUnresolved(options.repositoryName) || Token.isUnresolved(options.repositoryArn)) { @@ -659,15 +684,10 @@ export class Repository extends RepositoryBase { } as cxschema.CcApiContextQuery, dummyValue: [ { - Arn: Stack.of(scope).formatArn({ - service: 'ecr', - region: 'us-east-1', - account: '123456789012', - resource: 'repository', - resourceName: 'DUMMY_ARN', - }), + Arn: Stack.of(scope).formatArn(dummyArnComponents), }, ], + mustExist: options.mustExist, }).value; const repository = response[0]; @@ -679,6 +699,17 @@ export class Repository extends RepositoryBase { }); } + /** + * Checks if the repository returned by the `Repository.fromLookup()` method is a dummy repository, + * i.e., a repository that was not found. + * + * This method can only be used if the `mustExist` option is set to `false` in the `options` + * for the `Repository.fromLookup()` method. + */ + public static isLookupDummy(repository: IRepository): boolean { + return repository.repositoryArn === Stack.of(repository).formatArn(dummyArnComponents); + } + /** * Import a repository */ diff --git a/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts b/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts index 4647b92696121..6b6bcc1d7cffa 100644 --- a/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts +++ b/packages/aws-cdk-lib/aws-ecr/test/repository.test.ts @@ -117,6 +117,61 @@ describe('repository', () => { expect(repo.repositoryArn).toEqual(ecr.Repository.arnForLocalRepository('DUMMY_ARN', stack)); }); + test.each([ + true, + false, + ])('the reverse of mustExist($mustExist) is reflected in ignoreErrorOnMissingContext.', (mustExist) => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'MyStack', { env: { region: 'us-east-1', account: '123456789012' } }); + ecr.Repository.fromLookup(stack, 'MyRepo', { + repositoryName: 'DummyRepo', + mustExist, + }); + + // THEN + expect(app.synth().manifest.missing![0].props).toMatchObject({ + ignoreErrorOnMissingContext: !mustExist, + }); + }); + + test('isLookupDummy method returns false if the lookup repository is not a dummy repository', () => { + const repoArn = 'arn:aws:ecr:us-east-1:123456789012:repository/my-repo'; + // GIVEN + const resultObjs = [ + { + 'Arn': repoArn, + }, + ]; + const value = { + value: resultObjs, + }; + const mock = jest.spyOn(cdk.ContextProvider, 'getValue').mockReturnValue(value); + + // WHEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const repo = ecr.Repository.fromLookup(stack, 'MyRepo', { + repositoryArn: repoArn, + }); + + // THEN + expect(ecr.Repository.isLookupDummy(repo)).toBe(false); + + mock.mockRestore(); + }); + + test('isLookupDummy method returns true if the lookup repository is a dummy repository', () => { + const repoArn = 'arn:aws:ecr:us-east-1:123456789012:repository/does-not-exist-repo'; + // WHEN + const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } }); + const repo = ecr.Repository.fromLookup(stack, 'MyRepo', { + repositoryArn: repoArn, + }); + + // THEN + expect(ecr.Repository.isLookupDummy(repo)).toBe(true); + }); + test('throw error if repository name is a token', () => { // GIVEN const stack = new cdk.Stack(undefined, undefined, { env: { region: 'us-east-1', account: '123456789012' } });