Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const enableNoThrowDefaultErrorIn = [
'aws-cloudtrail',
'aws-cloudwatch',
'aws-cloudwatch-actions',
'aws-ecr',
'aws-elasticloadbalancing',
'aws-elasticloadbalancingv2',
'aws-elasticloadbalancingv2-actions',
Expand Down
32 changes: 17 additions & 15 deletions packages/aws-cdk-lib/aws-ecr/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
TokenComparison,
CustomResource,
Aws,
ValidationError,
UnscopedValidationError,
} from '../../core';
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';
import { AutoDeleteImagesProvider } from '../../custom-resource-handlers/dist/aws-ecr/auto-delete-images-provider.generated';
Expand Down Expand Up @@ -630,7 +632,7 @@ export class Repository extends RepositoryBase {
// repository names can include "/" (e.g. foo/bar/myrepo) and it is impossible to
// parse the name from an ARN using CloudFormation's split/select.
if (Token.isUnresolved(repositoryArn)) {
throw new Error('"repositoryArn" is a late-bound value, and therefore "repositoryName" is required. Use `fromRepositoryAttributes` instead');
throw new UnscopedValidationError('"repositoryArn" is a late-bound value, and therefore "repositoryName" is required. Use `fromRepositoryAttributes` instead');
}

validateRepositoryArn();
Expand All @@ -655,7 +657,7 @@ export class Repository extends RepositoryBase {
const splitArn = repositoryArn.split(':');

if (!splitArn[splitArn.length - 1].startsWith('repository/')) {
throw new Error(`Repository arn should be in the format 'arn:<PARTITION>:ecr:<REGION>:<ACCOUNT>:repository/<NAME>', got ${repositoryArn}.`);
throw new UnscopedValidationError(`Repository arn should be in the format 'arn:<PARTITION>:ecr:<REGION>:<ACCOUNT>:repository/<NAME>', got ${repositoryArn}.`);
}
}
}
Expand Down Expand Up @@ -707,7 +709,7 @@ export class Repository extends RepositoryBase {
}

if (errors.length > 0) {
throw new Error(`Invalid ECR repository name (value: ${repositoryName})${EOL}${errors.join(EOL)}`);
throw new UnscopedValidationError(`Invalid ECR repository name (value: ${repositoryName})${EOL}${errors.join(EOL)}`);
}
}

Expand Down Expand Up @@ -754,10 +756,10 @@ export class Repository extends RepositoryBase {
});

if (props.emptyOnDelete && props.removalPolicy !== RemovalPolicy.DESTROY) {
throw new Error('Cannot use \'emptyOnDelete\' property on a repository without setting removal policy to \'DESTROY\'.');
throw new ValidationError('Cannot use \'emptyOnDelete\' property on a repository without setting removal policy to \'DESTROY\'.', this);
} else if (props.emptyOnDelete == undefined && props.autoDeleteImages) {
if (props.removalPolicy !== RemovalPolicy.DESTROY) {
throw new Error('Cannot use \'autoDeleteImages\' property on a repository without setting removal policy to \'DESTROY\'.');
throw new ValidationError('Cannot use \'autoDeleteImages\' property on a repository without setting removal policy to \'DESTROY\'.', this);
}
this.enableAutoDeleteImages();
}
Expand Down Expand Up @@ -801,28 +803,28 @@ export class Repository extends RepositoryBase {
&& (rule.tagPrefixList === undefined || rule.tagPrefixList.length === 0)
&& (rule.tagPatternList === undefined || rule.tagPatternList.length === 0)
) {
throw new Error('TagStatus.Tagged requires the specification of a tagPrefixList or a tagPatternList');
throw new ValidationError('TagStatus.Tagged requires the specification of a tagPrefixList or a tagPatternList', this);
}
if (rule.tagStatus !== TagStatus.TAGGED && (rule.tagPrefixList !== undefined || rule.tagPatternList !== undefined)) {
throw new Error('tagPrefixList and tagPatternList can only be specified when tagStatus is set to Tagged');
throw new ValidationError('tagPrefixList and tagPatternList can only be specified when tagStatus is set to Tagged', this);
}
if (rule.tagPrefixList !== undefined && rule.tagPatternList !== undefined) {
throw new Error('Both tagPrefixList and tagPatternList cannot be specified together in a rule');
throw new ValidationError('Both tagPrefixList and tagPatternList cannot be specified together in a rule', this);
}
if (rule.tagPatternList !== undefined) {
rule.tagPatternList.forEach((pattern) => {
const splitPatternLength = pattern.split('*').length;
if (splitPatternLength > 5) {
throw new Error(`A tag pattern cannot contain more than four wildcard characters (*), pattern: ${pattern}, counts: ${splitPatternLength - 1}`);
throw new ValidationError(`A tag pattern cannot contain more than four wildcard characters (*), pattern: ${pattern}, counts: ${splitPatternLength - 1}`, this);
}
});
}
if ((rule.maxImageAge !== undefined) === (rule.maxImageCount !== undefined)) {
throw new Error(`Life cycle rule must contain exactly one of 'maxImageAge' and 'maxImageCount', got: ${JSON.stringify(rule)}`);
throw new ValidationError(`Life cycle rule must contain exactly one of 'maxImageAge' and 'maxImageCount', got: ${JSON.stringify(rule)}`, this);
}

if (rule.tagStatus === TagStatus.ANY && this.lifecycleRules.filter(r => r.tagStatus === TagStatus.ANY).length > 0) {
throw new Error('Life cycle can only have one TagStatus.Any rule');
throw new ValidationError('Life cycle can only have one TagStatus.Any rule', this);
}

this.lifecycleRules.push({ ...rule });
Expand Down Expand Up @@ -862,7 +864,7 @@ export class Repository extends RepositoryBase {
const anyRules = this.lifecycleRules.filter(r => r.tagStatus === TagStatus.ANY);
if (anyRules.length > 0 && anyRules[0].rulePriority !== undefined && autoPrioritizedRules.length > 0) {
// Supporting this is too complex for very little value. We just prohibit it.
throw new Error("Cannot combine prioritized TagStatus.Any rule with unprioritized rules. Remove rulePriority from the 'Any' rule.");
throw new ValidationError("Cannot combine prioritized TagStatus.Any rule with unprioritized rules. Remove rulePriority from the 'Any' rule.", this);
}

const prios = prioritizedRules.map(r => r.rulePriority!);
Expand Down Expand Up @@ -891,7 +893,7 @@ export class Repository extends RepositoryBase {

// if encryption key is set, encryption must be set to KMS.
if (encryptionType !== RepositoryEncryption.KMS && props.encryptionKey) {
throw new Error(`encryptionKey is specified, so 'encryption' must be set to KMS (value: ${encryptionType.value})`);
throw new ValidationError(`encryptionKey is specified, so 'encryption' must be set to KMS (value: ${encryptionType.value})`, this);
}

if (encryptionType === RepositoryEncryption.AES_256) {
Expand All @@ -905,7 +907,7 @@ export class Repository extends RepositoryBase {
};
}

throw new Error(`Unexpected 'encryptionType': ${encryptionType}`);
throw new ValidationError(`Unexpected 'encryptionType': ${encryptionType}`, this);
}

private enableAutoDeleteImages() {
Expand Down Expand Up @@ -958,7 +960,7 @@ function validateAnyRuleLast(rules: LifecycleRule[]) {
if (anyRules.length === 1) {
const maxPrio = Math.max(...rules.map(r => r.rulePriority!));
if (anyRules[0].rulePriority !== maxPrio) {
throw new Error(`TagStatus.Any rule must have highest priority, has ${anyRules[0].rulePriority} which is smaller than ${maxPrio}`);
throw new UnscopedValidationError(`TagStatus.Any rule must have highest priority, has ${anyRules[0].rulePriority} which is smaller than ${maxPrio}`);
}
}
}
Expand Down
Loading