| 1 | /** |
| 2 | * CODEOWNERS: who owns which paths of a repository, read from the branch a |
| 3 | * pull request merges into. Mirrors `crates/contracts/src/codeowners.rs`, |
| 4 | * which holds the parser and the rules. |
| 5 | */ |
| 6 | |
| 7 | /** Where the file is looked for, first found wins. */ |
| 8 | export const CODEOWNERS_LOCATIONS = [ |
| 9 | ".g1t/CODEOWNERS", |
| 10 | ".github/CODEOWNERS", |
| 11 | "CODEOWNERS", |
| 12 | "docs/CODEOWNERS", |
| 13 | ".gitlab/CODEOWNERS", |
| 14 | ] as const; |
| 15 | |
| 16 | /** Whether `path` is one of the places a CODEOWNERS file is read from. */ |
| 17 | export function isCodeownersPath(path: string): boolean { |
| 18 | return (CODEOWNERS_LOCATIONS as readonly string[]).includes(path); |
| 19 | } |
| 20 | |
| 21 | export type CodeownersErrorKind = |
| 22 | | "too_large" |
| 23 | | "negation" |
| 24 | | "character_range" |
| 25 | | "bad_pattern" |
| 26 | | "bad_owner" |
| 27 | | "bad_section" |
| 28 | | "unknown_user" |
| 29 | | "unknown_team" |
| 30 | | "unknown_email" |
| 31 | | "no_write_access" |
| 32 | | "team_no_access"; |
| 33 | |
| 34 | /** One problem with a CODEOWNERS file, on a line (0 for the whole file). */ |
| 35 | export type CodeownersError = { |
| 36 | line: number; |
| 37 | kind: CodeownersErrorKind; |
| 38 | /** The owner or pattern at fault, as written. */ |
| 39 | token: string | null; |
| 40 | message: string; |
| 41 | }; |
| 42 | |
| 43 | /** A CODEOWNERS file at one branch, checked like a linter. */ |
| 44 | export type CodeownersReport = { |
| 45 | /** Where it was found; null when there is none. */ |
| 46 | path: string | null; |
| 47 | ref: string; |
| 48 | size: number; |
| 49 | rules: number; |
| 50 | sections: string[]; |
| 51 | errors: CodeownersError[]; |
| 52 | }; |
| 53 | |
| 54 | /** Where one rule's review stands on a pull request. */ |
| 55 | export type OwnerReview = { |
| 56 | /** The section's name; null for rules before any section. */ |
| 57 | section: string | null; |
| 58 | line: number; |
| 59 | pattern: string; |
| 60 | /** Owners as written: `@ana`, `@acme/backend`, `ana@example.com`. */ |
| 61 | owners: string[]; |
| 62 | files: string[]; |
| 63 | optional: boolean; |
| 64 | required: number; |
| 65 | approved_by: string[]; |
| 66 | changes_requested_by: string[]; |
| 67 | satisfied: boolean; |
| 68 | }; |
| 69 | |
| 70 | /** Who owns what a pull request changes, and whose approval is still needed. */ |
| 71 | export type PullCodeOwners = { |
| 72 | path: string; |
| 73 | /** Whether branch protection requires code owners' approval. */ |
| 74 | required: boolean; |
| 75 | reviews: OwnerReview[]; |
| 76 | /** What still stands in the way; null when nothing does. */ |
| 77 | missing: string | null; |
| 78 | errors: number; |
| 79 | }; |
| 80 | |
| 81 | /** A short label for an error kind, for the errors view. */ |
| 82 | export const CODEOWNERS_ERROR_LABELS: Record<CodeownersErrorKind, string> = { |
| 83 | too_large: "Too large", |
| 84 | negation: "Negation", |
| 85 | character_range: "Character range", |
| 86 | bad_pattern: "Bad pattern", |
| 87 | bad_owner: "Bad owner", |
| 88 | bad_section: "Bad section", |
| 89 | unknown_user: "Unknown user", |
| 90 | unknown_team: "Unknown team", |
| 91 | unknown_email: "Unknown email", |
| 92 | no_write_access: "No write access", |
| 93 | team_no_access: "Team without access", |
| 94 | }; |