Repository navigation
feat: add tag exclusions to purge command - #724
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
| } | ||
|
|
||
| // CollectTagExclusions collects tag expressions for already-selected repositories. | ||
| func CollectTagExclusions(tagFilters map[string]string, excludeTags []string, excludeFilters []string, timeout int64) (map[string][]string, error) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
🟢 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-tagsand--exclude-filterflags, 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
| } | ||
|
|
||
| for repoExpression, tagExpressions := range exclusionPatterns { | ||
| repoFilter, err := BuildRegexFilter("^"+repoExpression+"$", timeout) |
There was a problem hiding this comment.
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>
Purpose of the PR
--exclude-tagsto protect exact tag names and--exclude-filterto protect tags matching regex patterns.Fixes #692