Skip to content

feat(labeler): add except to skip a label conditionally - #45

Merged
ReneWerner87 merged 1 commit into
mainfrom
feat/except-matcher
Jul 28, 2026
Merged

feat(labeler): add except to skip a label conditionally#45
ReneWerner87 merged 1 commit into
mainfrom
feat/except-matcher

Conversation

@ReneWerner87

@ReneWerner87 ReneWerner87 commented Jul 28, 2026

Copy link
Copy Markdown
Member

What this PR does / why we need it:

Matchers within a label are OR-ed, so there was no way to express "label this, but not when ...".
except adds that:

labels:
  - label: 'v3'
    except:
      labels: ['v2']
      baseBranch: '/^v2$/'
      title: '/wip/i'
    matcher:
      baseBranch: '/^main$/'
      body: '/(v3)/i'
  • Takes the same 8 matchers as matcher, plus labels for labels matched by another entry. Any hit drops the label.
  • Shorthand for the labels-only case: except: ['v2'].
  • No duplicated matching logic, the matchers run a second time against a config view where except
    takes the place of matcher. files/commits only cost an extra API call when used inside an except.
  • except.labels is evaluated against the matched set, so two labels excluding each other cancel out.
    Keep those one directional.
  • Optional field, existing configs are unaffected.

Motivation: in gofiber/fiber, PRs against main picked up the v2 label from Go module paths like
github.com/gofiber/utils/v2 in the title, and PRs against v2 picked up v3 from the body.
Replaying the last 400 fiber PRs through this build with a base-branch-driven config gives 0 mismatches.

162 tests green, 4 new ones covering except by title, branch and label.

Which issue(s) does this PR fixes?:

n/a

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for excluding labels when specified conditions match.
    • Exclusions can be based on existing labels, pull request titles, branches, or base branches.
    • Added configuration examples for defining label exclusions.
  • Bug Fixes

    • Improved label application to remove only labels affected by matching exclusion rules.
  • Documentation

    • Updated configuration documentation with the new except option and usage examples.

Matchers within a label are OR-ed and there was no way to say "not this
one". except takes the same 8 matchers plus a list of labels, any hit
drops the label. Reuses the existing matchers by running them against a
config view where except takes the place of matcher.

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.

Pull request overview

Adds an except clause to label rules so a label can be applied by normal matchers but suppressed when additional “negative” conditions match (including other matched labels). This fits the labeler’s existing model (per-label OR over matchers) by reusing the same matcher execution pipeline via an “except-as-matcher” config view.

Changes:

  • Extend config schema to support except as either string[] (labels-only shorthand) or a matcher-shaped object + optional labels.
  • Implement exclusion flow in the label computation by running matchers twice (normal + except-view) and filtering matched labels accordingly.
  • Document except in README and add fixtures/tests for valid/invalid configs and exclusion behavior.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/labeler.ts Adds excludeLabels, builds an exceptConfig view, and computes final labels as mergeLabels(excludeLabels(...), config).
src/config.ts Adds Except io-ts type and Label.except union to validate new config shape.
README.md Documents except semantics and provides usage example including shorthand form.
dist/index.js Updates built output to include new config types and exclusion logic.
tests/labeler.test.ts Adds behavioral tests covering exclusion by label, title, and branch.
tests/fixtures/invalid/except-invalid.yml Adds invalid fixture to ensure schema rejects non-array/non-object except.
tests/fixtures/except.yml Adds valid fixture demonstrating shorthand and matcher-based except.
tests/config.test.ts Adds parse tests for the new valid/invalid fixtures.

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

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb160052-010d-4a01-926c-81fa95269348

📥 Commits

Reviewing files that changed from the base of the PR and between 383a973 and b1dfb56.

⛔ Files ignored due to path filters (4)
  • __tests__/fixtures/except.yml is excluded by !**/*.yml
  • __tests__/fixtures/invalid/except-invalid.yml is excluded by !**/*.yml
  • dist/index.js is excluded by !**/dist/**, !dist/**
  • dist/index.js.map is excluded by !**/dist/**, !**/*.map, !dist/**, !**/*.map
📒 Files selected for processing (5)
  • README.md
  • __tests__/config.test.ts
  • __tests__/labeler.test.ts
  • src/config.ts
  • src/labeler.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: copilot-pull-request-reviewer
🔇 Additional comments (5)
src/config.ts (1)

36-50: LGTM!

Also applies to: 87-87

__tests__/config.test.ts (1)

26-28: LGTM!

Also applies to: 66-68

src/labeler.ts (1)

2-4: LGTM!

Also applies to: 35-101

__tests__/labeler.test.ts (1)

157-237: LGTM!

README.md (1)

12-12: LGTM!

Also applies to: 83-88


📝 Walkthrough

Walkthrough

Adds an except configuration option for conditionally skipping labels. The config schema, label evaluation flow, tests, and README examples now support string-based and structured exclusion matchers.

Changes

Except label matching

Layer / File(s) Summary
Except configuration contract
src/config.ts, __tests__/config.test.ts
Adds the exported Except type and permits string-list or structured except matchers, with valid and invalid parsing coverage.
Except matching flow
src/labeler.ts
Evaluates normal and transformed except matchers, removes overlapping labels, and merges the remaining results.
Behavior validation and documentation
__tests__/labeler.test.ts, README.md
Tests exclusions by title, branch, base label, and other conditions, and documents the new configuration syntax.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant labels
  participant match
  participant exceptConfig
  participant excludeLabels
  labels->>match: evaluate original config
  labels->>exceptConfig: transform except definitions
  exceptConfig-->>labels: return transformed config
  labels->>match: evaluate transformed config
  match-->>excludeLabels: provide matched and excepted labels
  excludeLabels-->>labels: return filtered labels
Loading

Suggested reviewers: copilot

Poem

A bunny hops through labels bright,
Then skips the ones that rules alight.
Branches, titles, labels too,
Say “not this time” when matches do.
The final tags emerge just right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding conditional except handling to the labeler.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/except-matcher

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ReneWerner87
ReneWerner87 merged commit 86e6d5a into main Jul 28, 2026
18 checks passed
@ReneWerner87
ReneWerner87 deleted the feat/except-matcher branch July 28, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants