Skip to content

Commit

Permalink
fix: ignore image if it does not match filter-tags
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterStolz committed Apr 2, 2024
1 parent c519556 commit ff7e56a
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 9 deletions.
2 changes: 1 addition & 1 deletion containercrop/github_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async def get_versions(self, image_name: str) -> list[Image]:
async def delete_image(self, image: Image) -> bool:
"Delete an image"
if not image.url:
logging.info("Could not delete image ad it does not have an url: %s", image)
logging.info("Could not delete image as it does not have an url: %s", image)
async with self.session.delete(image.url) as resp: # type: ignore
if resp.status == 204:
return True
Expand Down
13 changes: 9 additions & 4 deletions containercrop/retention.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,26 @@ def matches_retention_policy(image: Image, args: RetentionArgs) -> bool:
):
logging.debug("Image %s(%s) does match skip tags", image.name, image.html_url)
return False

if args.untagged_only and image.tags:
logging.debug(
"Image %s(%s) is tagged and untagged_only is set",
image.name,
image.html_url,
)
return False
if args.cut_off and image.is_before_cut_off_date(args.cut_off):
logging.debug("Image %s(%s) is before cut-off date", image.name, image.html_url)
return True
if args.filter_tags and any(

if args.filter_tags and not any(
any(fnmatch(tag, filter_tag) for filter_tag in args.filter_tags)
for tag in image.tags
):
logging.debug("Image %s(%s) does match filter tags", image.name, image.html_url)
return False

if args.cut_off and image.is_before_cut_off_date(args.cut_off):
logging.debug("Image %s(%s) is before cut-off date", image.name, image.html_url)
return True

logging.debug(
"Image %s(%s) does not match any policy, therefore we keep it",
image.name,
Expand All @@ -117,6 +121,7 @@ def apply_retention_policy(args: RetentionArgs, images: list[Image]) -> list[Ima
"""
Apply the retention policy to the images and return the ones that should be deleted.
"""
images.sort(key=lambda x: x.updated_at, reverse=True) # delete old images first
matches = [image for image in images if matches_retention_policy(image, args)]
return matches[args.keep_at_least :]

Expand Down
108 changes: 104 additions & 4 deletions containercrop/test_retention.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,26 @@ def test_delete_untagged_images_older_than_one_day():


def test_filter_by_specific_tags_for_deletion(generate_images):
images = generate_images(
tags_list=[["v1"], ["v1.0"], ["beta"], ["latest"]],
days_old_list=[30],
names_list=["image1"],
)
policy = RetentionArgs(
image_name="image1",
cut_off="20 days ago UTC",
untagged_only=False,
skip_tags="",
keep_at_least=0,
filter_tags="v1,v1.0",
dry_run=True,
token="dummy_token",
repo_owner="test",
)
assert len(apply_retention_policy(policy, images)) == 2


def test_filter_by_specific_tags_for_deletion_but_not_expired(generate_images):
images = generate_images(
tags_list=[["v1"], ["v1.0"], ["beta"], ["latest"]],
days_old_list=[5, 5, 5, 5],
Expand All @@ -127,6 +147,69 @@ def test_filter_by_specific_tags_for_deletion(generate_images):
token="dummy_token",
repo_owner="test",
)
assert len(apply_retention_policy(policy, images)) == 0


def test_filter_by_specific_tags_for_deletion_when_all_are_expired(generate_images):
images = generate_images(
tags_list=[["v1"], ["v1.0"], ["beta"], ["latest"]],
days_old_list=[30],
names_list=["image1"],
)
policy = RetentionArgs(
image_name="image1",
cut_off="20 days ago UTC",
untagged_only=False,
skip_tags="",
keep_at_least=0,
filter_tags="v1,v1.0",
dry_run=True,
token="dummy_token",
repo_owner="test",
)
assert len(apply_retention_policy(policy, images)) == 2


def test_filter_by_specific_tags_for_deletion_when_there_are_multiple_tags(
generate_images,
):
images = generate_images(
tags_list=[["asdf", "v1"], ["test", "test1", "v1.0"], ["beta"], ["latest"]],
days_old_list=[30],
names_list=["image1"],
)
policy = RetentionArgs(
image_name="image1",
cut_off="20 days ago UTC",
untagged_only=False,
skip_tags="",
keep_at_least=0,
filter_tags="v1,v1.0",
dry_run=True,
token="dummy_token",
repo_owner="test",
)
assert len(apply_retention_policy(policy, images)) == 2


def test_filter_by_wildcard_tags_for_deletion(
generate_images,
):
images = generate_images(
tags_list=[["asdf", "v1"], ["test", "test1", "v1.0"], ["beta"], ["latest"]],
days_old_list=[30],
names_list=["image1"],
)
policy = RetentionArgs(
image_name="image1",
cut_off="20 days ago UTC",
untagged_only=False,
skip_tags="",
keep_at_least=0,
filter_tags="v1*",
token="dummy_token",
repo_owner="test",
)
assert len(apply_retention_policy(policy, images)) == 2


Expand All @@ -143,7 +226,6 @@ def test_skip_specific_tags(generate_images):
skip_tags="beta,latest",
keep_at_least=0,
filter_tags="",
dry_run=True,
token="dummy_token",
repo_owner="test",
)
Expand Down Expand Up @@ -183,7 +265,6 @@ def test_delete_untagged_images_older_than_x_days(generate_images):
cut_off="2 days ago UTC",
untagged_only=True,
skip_tags="",
keep_at_least=0,
filter_tags="",
repo_owner="test",
)
Expand All @@ -205,7 +286,6 @@ def test_delete_tagged_keep_recent_untagged(generate_images):
cut_off="5 days ago UTC",
untagged_only=False,
skip_tags="",
keep_at_least=0,
filter_tags="",
repo_owner="test",
)
Expand Down Expand Up @@ -270,7 +350,6 @@ def test_wildcard_tag_filtering(generate_images):
cut_off="3 days ago UTC",
untagged_only=False,
skip_tags="v1.*", # Skip any version starting with v1.
keep_at_least=0,
filter_tags="*", # Consider all tags
repo_owner="test",
)
Expand All @@ -281,3 +360,24 @@ def test_wildcard_tag_filtering(generate_images):
assert not any(
"v1" in tag for img in retained_images for tag in img.tags
) # No v1.* tags


def test_image_processing_enforces_date_order(generate_images):
images = generate_images(
tags_list=[["v1.1"], ["v1.2"], ["beta"], ["latest"]],
days_old_list=[35, 34, 33, 32],
names_list=["image1"],
)
policy = RetentionArgs(
image_name="image1",
cut_off="30 days ago UTC",
repo_owner="test",
keep_at_least=2,
skip_tags=[],
)
retained_images = apply_retention_policy(policy, images)
assert (
len(retained_images) == 2
) # "beta" and possibly "latest" if not matching skip_tags wildcard
assert retained_images[0].tags == ["v1.2"]
assert retained_images[1].tags == ["v1.1"]

0 comments on commit ff7e56a

Please sign in to comment.