Skip to content

fix(labeler): honor matchCondition: AND and support brace patterns (my pick — matches the commit, scoped, descriptive)#439

Merged
riaankleinhans merged 4 commits into
mainfrom
fix/labeler-honor-match-condition
May 22, 2026
Merged

fix(labeler): honor matchCondition: AND and support brace patterns (my pick — matches the commit, scoped, descriptive)#439
riaankleinhans merged 4 commits into
mainfrom
fix/labeler-honor-match-condition

Conversation

@riaankleinhans
Copy link
Copy Markdown
Contributor

Summary

Fixes two bugs in utilities/labeler that together cause the symptom on cncf/toc#2164: the bot adds needs-triage / needs-kind / needs-group to a fresh PR and immediately removes them in the same run.

  1. matchCondition: AND was ignored. processLabelRule always computed shouldApply := !foundNamespace, so an AND rule behaved identically to its paired NOT rule — exactly inverted from intent. On a fresh PR, both rules fired: one added needs-*, the other removed it. Conversely, when a triage/* label was added via the UI, the AND rule never fired, so needs-triage never auto-cleared.

  2. Brace patterns like {toc,tag/*,sub/*} never matched. filepath.Match doesn't understand brace alternation, so the cncf/toc needs-group rule's pattern only matched a literal label starting with {. Hidden today by bug #1; would surface as needs-group getting permanently applied if #1 were fixed alone.

Fix

  • Honor matchCondition: AND in processLabelRule.
  • Add a small matchAnyPattern / expandBraces helper so {a,b/*,c}-style patterns work.

Tests

go vet and go test ./utilities/labeler/... both pass.

@github-actions github-actions Bot added toc toc specific issue needs-triage Indicates an issue or PR that has not been triaged yet (has a 'triage/foo' label applied) needs-kind Indicates an issue or PR that is missing an issue type or kind (a kind/foo label) and removed needs-triage Indicates an issue or PR that has not been triaged yet (has a 'triage/foo' label applied) labels May 22, 2026
@github-actions github-actions Bot added needs-group Indicates an issue or PR that has not been assigned a group (toc or tag/foo label applied) needs-priority Indicates an issue or PR missing a priority label needs-area Indicates an issue or PR missing an area label needs-status Indicates an issue or PR missing a status label and removed needs-kind Indicates an issue or PR that is missing an issue type or kind (a kind/foo label) needs-group Indicates an issue or PR that has not been assigned a group (toc or tag/foo label applied) needs-priority Indicates an issue or PR missing a priority label needs-area Indicates an issue or PR missing an area label needs-status Indicates an issue or PR missing a status label labels May 22, 2026
processLabelRule previously computed `shouldApply = !foundNamespace`
unconditionally, so a `kind: label` rule with `matchCondition: AND`
behaved identically to a `NOT` rule. Paired NOT/AND rules (e.g. apply
`needs-triage` when no `triage/*` exists, remove it when one does) ended
up firing in exactly the wrong situations: on a fresh PR with no labels
the labeler would add `needs-triage`/`needs-kind`/`needs-group` and
immediately remove them in the same run, and when a `triage/*` label was
later added manually via the UI the paired `needs-*` label would never
be cleared.

Also teach the label-rule `match` parser to understand a single level of
comma-separated brace alternation such as `{toc,tag/*,sub/*}`.
`filepath.Match` on its own does not support braces, so previously such
a pattern only matched a literal label whose name began with `{`.

Adds focused tests for both behaviors, including a regression test that
mirrors the cncf/toc#2164 scenario.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Riaan Kleinhans <riaankleinhans@gmail.com>
@riaankleinhans riaankleinhans force-pushed the fix/labeler-honor-match-condition branch from 14b2827 to 33000fc Compare May 22, 2026 08:57
@riaankleinhans riaankleinhans removed the request for review from mrbobbytables May 22, 2026 08:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes labeler rule evaluation in utilities/labeler to prevent contradictory add/remove label actions in the same run, and adds support for brace-alternation patterns used in .github/labels.yaml.

Changes:

  • Fix processLabelRule to honor matchCondition: AND by firing actions when the matched label namespace is present.
  • Add brace-alternation matching ({a,b/*,c}) for label patterns via matchAnyPattern + expandBraces.
  • Add regression/unit tests covering matchCondition: AND behavior and brace pattern expansion/matching.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
utilities/labeler/labeler.go Fixes AND semantics for label rules and adds brace pattern expansion/matching helper functions.
utilities/labeler/labeler_test.go Adds regression tests for AND behavior and brace pattern matching, plus unit tests for brace expansion.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread utilities/labeler/labeler.go Outdated
Previously `processLabelRule` discarded the error from
`matchAnyPattern` (and from `filepath.Match` before that). A malformed
pattern such as `triage/[` would silently leave `foundNamespace=false`,
causing the rule to fire in the wrong direction.

Return the error (with the rule name and offending pattern) so it is
surfaced by `processRules`, matching the convention already used by
`processFilePathRule`. Add a regression test that exercises a known-bad
pattern.

Addresses Copilot review feedback on PR #439.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Riaan Kleinhans <riaankleinhans@gmail.com>
@riaankleinhans riaankleinhans requested a review from Copilot May 22, 2026 09:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread utilities/labeler/labeler.go Outdated
Comment thread utilities/labeler/labeler.go Outdated
Two follow-ups from Copilot review on PR #439.

1. matchAnyPattern now uses path.Match instead of filepath.Match. Labels
   are not filesystem paths; path.Match treats "/" as the separator on
   every platform so "*" cannot accidentally cross "/" on Windows (where
   filepath.Match uses "\" as the separator). The labeler runs in a
   Linux container so production behavior is unchanged, but tests now
   behave the same regardless of the developer's OS, and the choice
   matches semantic intent.

2. expandBraces now returns an error for patterns it cannot safely
   expand: more than one brace group (e.g. "foo-{a,b}-{c,d}"), nested
   braces (e.g. "{a,{b,c}}"), or unbalanced braces. Previously such
   inputs were silently partially expanded ("foo-a-{c,d}", ...) and
   path.Match treated the leftover "{...}" as literal characters,
   producing confusing non-matches with no diagnostic. The error
   propagates through matchAnyPattern → processLabelRule → processRules,
   so an operator sees the rule name and offending pattern in the log.

Adds table coverage in TestExpandBraces for the new error paths and a
TestLabeler_ProcessLabelRule_UnsupportedBracePattern regression test.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Riaan Kleinhans <riaankleinhans@gmail.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread utilities/labeler/labeler.go Outdated
Comment thread utilities/labeler/labeler_test.go Outdated
Two follow-ups from Copilot review on PR #439.

1. Lift pattern validation out of the existing-labels loop.

   processLabelRule previously called matchAnyPattern inside
   `for _, lbl := range existingLabels`, which meant a malformed
   `spec.match` was only surfaced when the issue already had at least
   one label. On a freshly-opened PR with zero labels the loop never
   ran, validation never happened, and the rule still fired based on
   foundNamespace=false — exactly the silent-mis-fire mode the previous
   fix was meant to close, just down a different path.

   Split the helper into compilePatterns (expand + validate, called once
   per rule) and matchAny (cheap per-label check). This also stops
   re-expanding braces for every label.

2. Fix a stale code-path reference in the InvalidPattern test comment
   that still mentioned filepath.Match; the helper now uses path.Match.

Tests updated to use empty existing-labels slices so they cover the
zero-label regression case directly.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Riaan Kleinhans <riaankleinhans@gmail.com>
@riaankleinhans riaankleinhans merged commit 465f714 into main May 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

toc toc specific issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants