Per-path approval and per-group reviewer suggestions#4918
Merged
simonfaltum merged 9 commits intomainfrom Apr 8, 2026
Merged
Conversation
Replace the author-based isExempted check with per-path ownership group approval. Each OWNERS pattern group now needs at least one approval from its owners (or a team member for org/team refs). - Add getOwnershipGroups to owners.js (groups files by last-match-wins OWNERS pattern) - Add checkPerPathApproval to maintainer-approval.js with team membership resolution via GitHub Teams API - Wildcard-only files require a maintainer - Failure messages list uncovered groups with their owners - PR author is excluded from approver list (self-approval defense) Co-authored-by: Isaac
When a PR touches files across multiple ownership areas (as defined in OWNERS), suggest-reviewers.js now shows a structured "Reviewers by ownership area" comment with per-group sections instead of a flat list. Each section shows the matched files, team refs, and individual owners ranked by git history score. Single-domain PRs keep the existing flat format. Co-authored-by: Isaac
Use createCommitStatus instead of core.setFailed so that PRs waiting for approval show a yellow pending dot, not a red failure X. The workflow itself always succeeds; the commit status context "maintainer-approval" is what branch rulesets check. Co-authored-by: Isaac
…ad args - isTeamMember now distinguishes 404 (not a member) from permission errors (403/other), logging a core.warning when team resolution fails due to insufficient token scope - Wildcard reviewer suggestions now filter to maintainers only, since non-maintainers cannot approve wildcard files - checkPerPathApproval accepts rulesWithTeams directly instead of re-parsing OWNERS internally; removed unused findOwners import and dead rules parameter - Added YAML comment about org:read token requirement for team membership Co-authored-by: Isaac
If the PR author is a maintainer, any single approval (from anyone) is sufficient. Maintainers already have the trust to approve anything, so the review gate only serves as a "second pair of eyes" check. Co-authored-by: Isaac
Tests for owners.js (24 cases) covering ownersMatch, parseOwnersFile, findOwners, getMaintainers, and getOwnershipGroups. Tests for maintainer-approval.js (12 cases) covering maintainer approval, maintainer-authored PRs, per-path approval, team membership, wildcard files, self-approval exclusion, and missing OWNERS rules. Uses node:test runner with zero external dependencies. Co-authored-by: Isaac
mihaimitrea-db
approved these changes
Apr 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Cross-domain PRs aren't handled correctly by the current maintainer-approval workflow. If a PR touches
/cmd/pipelines/and/cmd/apps/, a single approval from either team covers the whole PR. Each domain team should approve their own area independently.The
suggest-reviewerscomment also doesn't surface which ownership areas need review. It just shows a flat list.On top of that, the workflow uses
core.setFailed()to block PRs missing approval. This shows a red X, which is misleading: "waiting for approval" isn't an error, it's a normal pending state.Changes
Before: One exemption check (
isExempted) that only worked when the PR author owned all changed files. Cross-domain PRs fell through to requiring a maintainer.suggest-reviewersshowed a flat list. Missing approval = red X.Now: Per-path approval where each ownership group needs at least one approval from its owners.
suggest-reviewersshows per-group sections for cross-domain PRs. Missing approval = yellow pending dot via Commit Status API.owners.jsAdded
getOwnershipGroups(filenames, rules)that groups files by their last-match-wins OWNERS pattern. ReturnsMap<pattern, { owners, files }>. This is the shared building block used by both the approval check and reviewer suggestions.maintainer-approval.jsReplaced
isExemptedwithcheckPerPathApproval. The new flow:success(unchanged)success(new, any second pair of eyes suffices)*? ->pending(needs maintainer)success. Some uncovered ->pending(lists which groups need approval)Team refs (
@org/team) are resolved viagetMembershipForUserInOrg. The resolution distinguishes 404 (not a member) from permission errors (logs a warning, falls back to requiring maintainer).Switched from
core.setFailed()tocreateCommitStatus()withpending/successstates, so "waiting for approval" is a yellow dot instead of a red X. The ruleset should require themaintainer-approvalcommit status context.suggest-reviewers.jsWhen a PR crosses 2+ ownership groups, shows "Reviewers by ownership area" with per-group sections. Each section lists the matched files, team refs, and individually ranked owners (by git history score). Single-domain PRs keep the existing flat format. The wildcard section (
*files) only suggests maintainers, since only they can approve those files.OWNERS/bundle/,/acceptance/bundle/, and/acceptance/labs/rules mirroring their source counterpartsmaintainer-approval.ymlstatuses: writepermission (needed forcreateCommitStatus)Test plan
node:testrunner (zero dependencies)owners.js:ownersMatch,parseOwnersFile,findOwners,getMaintainers,getOwnershipGroupsmaintainer-approval.jswith mocked GitHub API: maintainer approval, maintainer-authored PR self-approval, single domain, cross-domain (both covered and partially covered), wildcard files, team member approval, non-team-member rejection,CHANGES_REQUESTEDexclusion, self-approval exclusion, missing*rule errornode --test .github/scripts/owners.test.js .github/workflows/maintainer-approval.test.js/cmd/pipelines/files): pending until pipelines owner approves/cmd/pipelines/+/cmd/apps/): pending until both groups approved*files: pending, message says "needs maintainer"maintainer-approvalcommit status contextEdge case coverage (from unit tests)
*files*filesCHANGES_REQUESTEDreview