Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ecr): tag pattern list for lifecycle policy #28432

Merged
merged 11 commits into from
Dec 20, 2023
18 changes: 17 additions & 1 deletion packages/aws-cdk-lib/aws-ecr/lib/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,33 @@ export interface LifecycleRule {
* Only one rule is allowed to select untagged images, and it must
* have the highest rulePriority.
*
* @default TagStatus.Tagged if tagPrefixList is given, TagStatus.Any otherwise
* @default TagStatus.Tagged if tagPrefixList or tagPatternList is
* given, TagStatus.Any otherwise
*/
readonly tagStatus?: TagStatus;

/**
* Select images that have ALL the given prefixes in their tag.
*
* Both tagPrefixList and tagPatternList cannot be specified together.
*
* Only if tagStatus == TagStatus.Tagged
*/
readonly tagPrefixList?: string[];

/**
* Select images that have ALL the given patterns in their tag.
*
* There is a maximum limit of four wildcards (*) per string.
* For example, ["*test*1*2*3", "test*1*2*3*"] is valid but
* ["test*1*2*3*4*5*6"] is invalid.
*
* Both tagPrefixList and tagPatternList cannot be specified together.
*
* Only if tagStatus == TagStatus.Tagged
*/
readonly tagPatternList?: string[];

/**
* The maximum number of images to retain
*
Expand Down
34 changes: 26 additions & 8 deletions packages/aws-cdk-lib/aws-ecr/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,14 +758,31 @@ export class Repository extends RepositoryBase {
public addLifecycleRule(rule: LifecycleRule) {
// Validate rule here so users get errors at the expected location
if (rule.tagStatus === undefined) {
rule = { ...rule, tagStatus: rule.tagPrefixList === undefined ? TagStatus.ANY : TagStatus.TAGGED };
}

if (rule.tagStatus === TagStatus.TAGGED && (rule.tagPrefixList === undefined || rule.tagPrefixList.length === 0)) {
throw new Error('TagStatus.Tagged requires the specification of a tagPrefixList');
}
if (rule.tagStatus !== TagStatus.TAGGED && rule.tagPrefixList !== undefined) {
throw new Error('tagPrefixList can only be specified when tagStatus is set to Tagged');
rule = { ...rule, tagStatus: rule.tagPrefixList === undefined && rule.tagPatternList === undefined ? TagStatus.ANY : TagStatus.TAGGED };
}

if (rule.tagStatus === TagStatus.TAGGED
&& (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');
}
if (
(rule.tagStatus !== TagStatus.TAGGED && rule.tagPrefixList !== undefined)
|| (rule.tagStatus !== TagStatus.TAGGED && rule.tagPatternList !== undefined)
) {
throw new Error('tagPrefixList and tagPatternList can only be specified when tagStatus is set to Tagged');
}
if (rule.tagPrefixList !== undefined && rule.tagPatternList !== undefined) {
throw new Error('Both tagPrefixList and tagPatternList cannot be specified together');
}
if (rule.tagPatternList !== undefined) {
rule.tagPatternList.forEach((pattern) => {
const splittedPatternLength = pattern.split('*').length;
if (splittedPatternLength > 5) {
throw new Error(`A tag pattern cannot contain more than four wildcard characters (*), tagPattern: ${pattern}, counts: ${splittedPatternLength - 1}`);
}
});
}
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)}`);
Expand Down Expand Up @@ -924,6 +941,7 @@ function renderLifecycleRule(rule: LifecycleRule) {
selection: {
tagStatus: rule.tagStatus || TagStatus.ANY,
tagPrefixList: rule.tagPrefixList,
tagPatternList: rule.tagPatternList,
countType: rule.maxImageAge !== undefined ? CountType.SINCE_IMAGE_PUSHED : CountType.IMAGE_COUNT_MORE_THAN,
countNumber: rule.maxImageAge?.toDays() ?? rule.maxImageCount,
countUnit: rule.maxImageAge !== undefined ? 'days' : undefined,
Expand Down
Loading