Conversation
| const { data: files } = await github.rest.pulls.listFiles({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: prNumber | ||
| }); | ||
| const changedFiles = files.map(f => f.filename); |
There was a problem hiding this comment.
listFiles is not paginated — large PRs will silently miss files
github.rest.pulls.listFiles returns at most 30 results by default (max 100 per page, max 3000 total via pagination). For PRs touching many files, only the first page is fetched, so some changed files will be ignored and their CODEOWNERS reviewers will never be assigned.
Use github.paginate to collect all pages:
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
per_page: 100,
});
const changedFiles = files.map(f => f.filename);| for (const rule of codeowners) { | ||
| const pattern = rule.pattern; | ||
| if (pattern === '*') { | ||
| matchedOwner = rule.owners[0]; | ||
| matchedPattern = pattern; | ||
| } else if (pattern.endsWith('/')) { | ||
| const dir = pattern.replace(/^\//, '').replace(/\/$/, ''); | ||
| if (file.startsWith(dir + '/') || file.startsWith(dir)) { | ||
| matchedOwner = rule.owners[0]; | ||
| matchedPattern = pattern; | ||
| } | ||
| } else if (file === pattern || file === pattern.replace(/^\//, '')) { | ||
| matchedOwner = rule.owners[0]; | ||
| matchedPattern = pattern; | ||
| } |
There was a problem hiding this comment.
CODEOWNERS pattern matching logic uses first-match but CODEOWNERS semantics require last-match
The inner loop iterates all rules and continuously overwrites matchedOwner without ever breaking. Because the CODEOWNERS file is ordered * first then specific directories, this accidentally produces correct "last match wins" behaviour today. But it also means the wildcard * sets feihongxu0824 unconditionally, even if a more specific rule is later matched and overrides it — which relies entirely on rule ordering.
More critically, the parser only handles three pattern shapes:
- Literal
* - Patterns ending with
/(directory prefixes) - Exact file paths
Any future CODEOWNERS rules using standard glob patterns (e.g., *.md, docs/**, /src/*.h) will silently fail to match, causing files to fall through to feihongxu0824 (the * default) rather than their correct owner. Consider using the ignore npm package (already available in actions/github-script) or a dedicated CODEOWNERS parser to match rules correctly.
| * @feihongxu0824 | ||
|
|
||
| # .github directory | ||
| /.github/ @Cuiyus |
There was a problem hiding this comment.
/.github/ CODEOWNERS entry means this PR itself won't auto-assign @Cuiyus
@Cuiyus is listed as the owner of /.github/, but this PR is being submitted by @feihongxu0824 who is almost certainly a MEMBER/OWNER, so the community-pr-handler.yml would skip it anyway. More importantly, for future community PRs that touch .github/ files, the community-pr-handler.yml will correctly assign @Cuiyus — but native GitHub CODEOWNERS review requests are only triggered automatically if the CODEOWNERS file is in the default branch. Until this PR is merged, any in-flight fork PRs touching .github/ files won't automatically request a review from @Cuiyus via native GitHub CODEOWNERS. This is expected behaviour, just worth being aware of.
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Greptile Summary
This PR introduces a CODEOWNERS-based automatic reviewer/assignee system for the repository. It adds three new components: a
CODEOWNERSfile that maps directories to responsible maintainers, anauto-assign.ymlworkflow that self-assigns the PR author as an assignee, and acommunity-pr-handler.ymlworkflow that detects community (non-maintainer) PRs and assigns the relevant CODEOWNERS owners as assignees by parsing theCODEOWNERSfile and matching changed files.Key issues found:
contents: readpermission. GitHub Actions sets any undeclared permission tononewhen apermissionsblock is present. Bothauto-assign.ymlandcommunity-pr-handler.ymlonly declarepull-requests: write, so theactions/checkout@v4steps will fail at runtime.listFilesis not paginated incommunity-pr-handler.yml. The call togithub.rest.pulls.listFilesfetches only the first page (default 30 files). For large PRs this will silently skip changed files, causing their CODEOWNERS owners to never be assigned.*, directory prefixes (ending with/), and exact file path matches. Any future CODEOWNERS rules using standard glob patterns (e.g.,*.md,src/**/*.h) will silently fail to match, falling back to the default*owner instead of the correct one.Confidence Score: 2/5
contents: readpermission will cause both workflow checkout steps to fail, meaning the automation will not work at all.contents: readpermission is a blocking bug that prevents both workflows from running. The pagination gap and limited glob parsing are logic issues that will cause silent failures in common scenarios. These are concrete, reproducible problems rather than theoretical concerns..github/workflows/community-pr-handler.ymland.github/workflows/auto-assign.ymlboth need thecontents: readpermission added.Important Files Changed
contents: readpermission (breaks checkout), no pagination onlistFiles(silently misses files in large PRs), and a limited CODEOWNERS glob parser that only handles*, directory prefixes, and exact paths.kentaro-m/auto-assign-action; missingcontents: readpermission will cause the sparse checkout step to fail./.github/ownership won't be active until after this PR is merged.kentaro-m/auto-assign-action; correctly setsaddAssignees: author, disables reviewer assignment (handled by CODEOWNERS), and skips draft PRs.Sequence Diagram
sequenceDiagram participant Fork as Fork / Community PR participant GH as GitHub Events participant AutoAssign as auto-assign.yml participant CommunityHandler as community-pr-handler.yml participant API as GitHub REST API Fork->>GH: PR opened / reopened / ready_for_review GH->>AutoAssign: pull_request_target trigger AutoAssign->>API: checkout base branch (sparse: auto-assign-config.yml) AutoAssign->>API: kentaro-m/auto-assign-action → add PR author as assignee GH->>CommunityHandler: pull_request_target trigger CommunityHandler->>API: github-script: check author_association alt author is OWNER / MEMBER / COLLABORATOR CommunityHandler-->>CommunityHandler: skip (not community) else community contributor CommunityHandler->>API: checkout base branch (sparse: CODEOWNERS) CommunityHandler->>API: pulls.listFiles (page 1 only ⚠️) CommunityHandler->>CommunityHandler: parse CODEOWNERS (limited globs ⚠️) CommunityHandler->>CommunityHandler: match files → owners CommunityHandler->>API: issues.addAssignees (CODEOWNERS owners) endLast reviewed commit: "fix"