CODEOWNERS changed-path routing
Resolve each supplied changed path against one selected CODEOWNERS snapshot, retaining the last valid rule, all declared owners and explicit ownership gaps.
- 1Add input
- 2Adjust settings
- 3Get your result
Tool input and files are processed in this browser without being uploaded.
Before you start
Group changed paths by declared reviewer without accessing GitHub. Choose the intended branch snapshot yourself; inspect skipped source lines and distinguish cleared owners from unmatched paths.
How to use this tool
- Choose the intended CODEOWNERS snapshot, then enter repository-relative changed paths, one per line.
- Run routing; inspect skipped rule count, declared owners, explicitly unowned paths and unmatched paths.
- Download full JSON/CSV with source provenance and all owner groups before using the handoff.
Supported inputs and limits
One explicitly selected UTF-8 CODEOWNERS file or paste up to 2 MiB, plus a newline-delimited changed-path list up to 2 MiB. Choose the intended snapshot; .github/root/docs priority and pull-request base branch are not inferred.
Up to 10,000 rule lines, 10,000 paths, 1,024 UTF-16 units per pattern/path and 100 owners per rule. Valid rule count × supplied path count must be at most 2,000,000. Complete JSON and CSV together must fit 32 MiB; combined limits apply.
Case-sensitive GitHub-style *, ?, whole-component **, root paths and directory patterns. Last matching valid source line wins. Owners on the same line stay together; an empty owner list explicitly clears ownership. Duplicate paths remain in order. User, team and email strings are declarations; account existence, access and review requests remain unverified.
GitHub-invalid negation, character ranges and escaped leading # lines are skipped with full original lines, reasons and UTF-8 byte offsets. Legal escaped patterns, including escaped spaces, fail the whole batch as Unsupported. Absolute/backslash/dot-dot/control/ambiguous empty path segments reject; source and path text remain inert.
The complete report includes original sources and hashes, valid/invalid rules, every supplied path and owner grouping. Table previews 200 rows, clipping long cells to 2,000 UTF-16 units. Above 20,000 report characters, copying gives a labelled preview; full downloads retain all rows. Cancellation or an error publishes no partial routing.
Worked example
Example input
# Explicitly selected CODEOWNERS snapshot * @general @org/reviewers *.js @javascript # Same-line owners replace earlier owners /docs/* [email protected] /apps/ @apps /apps/github !legacy @ignored
Example options
{"secondary":"src/app.js\ndocs/readme.md\ndocs/deep/readme.md\napps/github/action.yml\nREADME.md\nsrc/app.js\n","params":{"spreadsheetSafe":true}}Example output
{"format":"GitHub-CODEOWNERS-explicit-snapshot-routing","summary":{"paths":6,"validRules":5,"invalidRules":1,"declaredOwners":4,"matchedPaths":5,"explicitlyUnowned":1,"unmatchedPaths":0,"pairWork":30,"evaluatedPairs":18,"status":"declared-routing-with-skipped-lines"},"source":{"name":"pasted.txt","bytes":202,"sha256":"15e24081c2e8ebf417920dc5806d570ea7e3b0b2289fbbe1f852bd2f27bf3f36","text":"# Explicitly selected CODEOWNERS snapshot\r\n* @general @org/reviewers\r\n*.js @javascript # Same-line owners replace earlier owners\r\n/docs/* [email protected]\r\n/apps/ @apps\r\n/apps/github\r\n!legacy @ignored\r\n"},"changedPaths":{"bytes":90,"sha256":"fdf606604efda531d80a2c4110ec1d168377aa5063c58ae073d8321dbdc2f6a3","text":"src/app.js\ndocs/readme.md\ndocs/deep/readme.md\napps/github/action.yml\nREADME.md\nsrc/app.js\n"},"rules":[{"line":2,"byteOffset":43,"raw":"* @general @org/reviewers","pattern":"*","owners":["@general","@org/reviewers"]},{"line":3,"byteOffset":70,"raw":"*.js @javascript # Same-line owners replace earlier owners","pattern":"*.js","owners":["@javascript"]},{"line":4,"byteOffset":130,"raw":"/docs/* [email protected]","pattern":"/docs/*","owners":["[email protected]"]},{"line":5,"byteOffset":156,"raw":"/apps/ @apps","pattern":"/apps/","owners":["@apps"]},{"line":6,"byteOffset":170,"raw":"/apps/github","pattern":"/apps/github","owners":[]}],"invalidRules":[{"line":7,"byteOffset":184,"raw":"!legacy @ignored","reason":"GitHub-invalid-negation"}],"routing":[{"index":1,"path":"src/app.js","inputLine":1,"line":3,"pattern":"*.js","owners":["@javascript"],"status":"declared-owners","accountPermissions":"not-verified"},{"index":2,"path":"docs/readme.md","inputLine":2,"line":4,"pattern":"/docs/*","owners":["[email protected]"],"status":"declared-owners","accountPermissions":"not-verified"},{"index":3,"path":"docs/deep/readme.md","inputLine":3,"line":2,"pattern":"*","owners":["@general","@org/reviewers"],"status":"declared-owners","accountPermissions":"not-verified"},{"index":4,"path":"apps/github/action.yml","inputLine":4,"line":6,"pattern":"/apps/github","owners":[],"status":"explicitly-unowned","accountPermissions":"not-verified"},{"index":5,"path":"README.md","inputLine":5,"line":2,"pattern":"*","owners":["@general","@org/reviewers"],"status":"declared-owners","accountPermissions":"not-verified"},{"index":6,"path":"src/app.js","inputLine":6,"line":3,"pattern":"*.js","owners":["@javascript"],"status":"declared-owners","accountPermissions":"not-verified"}],"ownerGroups":[{"owner":"@javascript","pathIndexes":[1,6]},{"owner":"[email protected]","pathIndexes":[2]},{"owner":"@general","pathIndexes":[3,5]},{"owner":"@org/reviewers","pathIndexes":[3,5]}],"scope":"Case-sensitive last valid matching line from one user-selected snapshot only. Original source includes every blank/comment/rule line; invalid rules have full original lines and byte offsets. Duplicate supplied paths remain in input order. GitHub existence/write/team visibility and actual review requests are not verified; no repository, filesystem or network access. Valid escaped patterns and unsupported legal grammar fail atomically."}When something does not work
Correct path syntax or select the intended snapshot. Review every skipped rule; re-export or remove unsupported escaped grammar deliberately. Reduce rule/path combinations or full report size when a limit rejects, then rerun; no partial routing is retained.
Frequently asked questions
Does this tell me which reviewers GitHub will request?
It reads declarations in the snapshot you selected. It cannot verify the pull-request base branch, account existence, write permission or team visibility; GitHub may assign no owner when those conditions fail.
Why can a later rule with no owner remove an earlier match?
An empty owner list is an explicit clearing rule. The report distinguishes explicitly-unowned from unmatched and retains the clearing source line.
Does docs/* include docs/deep/readme.md?
No. That pattern covers direct children. /docs/ covers descendants. The matcher is case-sensitive and reports the final source pattern for each supplied path.
Documentation & further reading
Related tools
JSON formatting workspace
Format or minify strict JSON, sort object keys, and encode or decode strings while preserving raw number tokens.
Regex tester
Try a pattern and see what it matches in your text.
Compare text
See what changed, side by side.
HTML formatter
Format HTML indentation so its structure is easier to read.