Skip to content

feat: add tag exclusions to purge command - #724

Merged
gildardogmsft merged 3 commits into
Azure:mainfrom
gildardogmsft:gildardog-microsoft-tag-exclusions
Nov 3, 2026
Merged

gildardogmsft merged 3 commits into
Azure:mainfrom
gildardogmsft:gildardog-microsoft-tag-exclusions

Conversation

@gildardogmsft

Copy link
Copy Markdown
Contributor

Purpose of the PR

  • Add --exclude-tags to protect exact tag names and --exclude-filter to protect tags matching regex patterns.
  • Allow multiple exclusions to be combined across one, several, or all selected repositories.
  • Add command-help examples, README documentation, and tests covering validation, repository matching, pagination, and retention.

Fixes #692

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread cmd/acr/purge.go Resolved
Comment thread cmd/acr/purge_test.go Resolved
Comment thread cmd/acr/purge_test.go Resolved
Comment thread cmd/repository/image_functions.go Outdated
}

// CollectTagExclusions collects tag expressions for already-selected repositories.
func CollectTagExclusions(tagFilters map[string]string, excludeTags []string, excludeFilters []string, timeout int64) (map[string][]string, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cleaner model would put both values in one map, for example map[string]struct{ tagFilter string; exclusions []string }. That removes the parallel map and keeps each repository’s related data together. The change would touch the collection and purge call paths, so it’s worthwhile for clarity and structure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a new struct TagFilters to be used instead as a single map versus the parallels maps

- Group per-repository inclusion and exclusion filters in TagFilters and update purge and annotate callers.
- Aggregate exclusion validation errors and clarify error context.
- Consolidate exclusion tests and cover malformed inputs and multiple validation errors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The tag-exclusion change has no active review issues blocking approval.

No open issues 🎉

What changed in this PR

Adds tag exclusions to acr purge, addressing #692 by letting users protect exact tag names or regex matches without complex inclusion filters. Exclusions take precedence over age and count-based retention.

Changes:

  • Adds repeatable --exclude-tags and --exclude-filter flags, validation, and verbose skip messages.
  • Integrates exclusions into shared dry-run and deletion logic before retention counting.
  • Adds documentation and tests for repository matching, pagination, retention, and protected manifests.
File Description
README.md Documents exclusion flags, examples, and retention behavior.
cmd/​repository/​image_functions.go Introduces grouped tag filters and exclusion parsing and validation.
cmd/​repository/​image_functions_test.go Updates expectations for the grouped filter type.
cmd/​acr/​purge.go Adds exclusion flags and applies exclusions before retention.
cmd/​acr/​purge_untagged_only_test.go Adapts filter fixtures and replaces fixed dates with relative timestamps.
cmd/​acr/​purge_test.go Adds exclusion validation, matching, retention, pagination, and manifest-protection tests.
cmd/​acr/​annotate.go Adapts annotation processing to the grouped filter type.

Review effort: Balanced

Comment thread cmd/repository/image_functions.go Outdated
}

for repoExpression, tagExpressions := range exclusionPatterns {
repoFilter, err := BuildRegexFilter("^"+repoExpression+"$", timeout)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we wrap  repoExpression  in a noncapturing group before adding the anchors? Something like "^(?:" + repoExpression + ")$" .

Right now a repo filter like "app|worker"  becomes  ^app|worker$ , which means starts with app OR ends with worker. So we end up protecting tags in repos such as "application" or  "nested/worker"  too. With  ^(?:app|worker)$ , the anchors apply to both alternatives and we only match app or worker.

It seems like the inclusion matcher has the same problem. Can we add a test for this with both exclusion flags?

- Group repository expressions for inclusion and exclusions, validating raw regexes before anchoring.
- Preserve aggregated exclusion errors and add regression coverage for alternation and malformed expressions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@estebanreyl Esteban Rey (estebanreyl) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@gildardogmsft
gildardogmsft merged commit 6a65707 into Azure:main Nov 3, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Tag Exclusions to ACR Purge

3 participants