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