Skip to content

Proposal: Add Minimum and Maximum Retention Policies to Acr Purge #670

Description

What is the problem you're trying to solve

Customers need to combine age-based retention with minimum and maximum count limits.

For example, customers may want either of these behaviors:

  • Delete tags older than 3 days or outside the 10 most recent matching tags.
  • Delete tags older than 3 days only when they are outside the 10 most recent matching tags.

The existing --keep option does not express either policy consistently because it preserves items only from the set already eligible for age-based deletion. Changing its behavior would break existing purge configurations.

Describe the solution you'd like

Add explicit minimum and maximum retention options:

Option Behavior
--min-tags N Protect the newest N matching tags from age-based deletion
--max-tags N Retain no more than N matching tags per repository
--min-untagged-manifests N Protect the newest N dangling manifests from age-based deletion
--max-untagged-manifests N Retain no more than N dangling manifests per repository

Maximum retention: OR behavior

acr purge \
    --registry example \
    --filter "repository:.*" \
    --ago 3d \
    --max-tags 10

A matching tag is deleted when it is older than 3 days or outside the 10 most recent matching tags. This is a hard ceiling; fewer than 10 tags may remain after applying the age policy.

Minimum retention: AND behavior

acr purge \
    --registry example \
    --filter "repository:.*" \
    --ago 3d \
    --min-tags 10

A matching tag is deleted only when it is older than 3 days and outside the 10 most recent matching tags. The newest 10 matching tags are protected from age-based deletion.

The same behavior applies independently to dangling manifests:

acr purge \
    --registry example \
    --untagged-only \
    --ago 3d \
    --min-untagged-manifests 20 \
    --max-untagged-manifests 100

Combining minimum and maximum retention

Minimum and maximum options may be combined:

acr purge \
    --registry example \
    --filter "repository:.*" \
    --ago 3d \
    --min-tags 10 \
    --max-tags 50

This creates three retention zones:

  1. The newest 10 matching tags are protected from age pruning.
  2. Tags 11 through 50 are retained only while newer than 3 days.
  3. Tags beyond 50 are deleted regardless of age.

Equivalent selection logic:

delete :=
    rank > maxTags
    OR
    (olderThanAgo AND rank > minTags)

Compatibility and validation

  • Existing --keep behavior remains unchanged.
  • --keep cannot be combined with the new count policies for the same resource.
  • --min-* requires --ago, because it guards age-based deletion and does not select items independently.
  • --max-* works with or without --ago.
  • When both are supplied, the minimum must not exceed the maximum.
  • Limits apply per repository and effective filter.
  • Tag and dangling-manifest limits are independent.
  • Items are ranked by LastUpdateTime, newest first, with deterministic tie-breaking.
  • When using --untagged, manifest retention is evaluated after tag deletion.
  • Locked items that prevent satisfying a maximum are reported clearly.
  • Dry-run output identifies whether deletion is caused by age, maximum count, or both.

Repository-level conditions that determine whether purge runs at all, such as --purge-if-tags-exceed, are a separate feature and are not part of this retention proposal.

Acceptance criteria

  • Age-only, minimum, maximum, and combined policies work for tags and dangling manifests.
  • Minimum options provide AND behavior and maximum options provide OR behavior.
  • Ranking works across paginated results.
  • Existing filters and --keep behavior remain compatible.
  • Invalid flag combinations produce clear errors.
  • Tests cover pagination, filters, locked items, equal timestamps, and manifests made dangling during the purge.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions