The controller now decides what a pull request's check runs from the mesh's module graph, so the announcement carries the changed directories that hold a module at the head and whether the head has a merge-check.sh. A verdict sets mesh/merge-gate (the gate, with the modules it judged) and mesh/repo-check (the repository's own tests). gitea_branch_protection_get/set let the operator's agent make those statuses required. The catalogue's merge-check.sh leaves the gate to the build seat and keeps its own layer: every manifest through module check, and the touched Go modules' tests.
38 lines
1.8 KiB
TypeScript
38 lines
1.8 KiB
TypeScript
// A branch's protection (novox/hq ADR 0237): what makes a pull request wait for the mesh's merge check —
|
|
// `mesh/merge-gate`, the module graph's gate, and `mesh/repo-check`, the repository's own tests — before it
|
|
// may merge. Pure, so it is tested without a forge; the client does the asking (client.ts).
|
|
|
|
/** A branch protection rule, as the forge keeps it — the fields the mesh reads; the forge sends more. */
|
|
export interface BranchProtection {
|
|
rule_name?: string;
|
|
branch_name?: string;
|
|
enable_push?: boolean;
|
|
enable_status_check?: boolean;
|
|
status_check_contexts?: string[] | null;
|
|
required_approvals?: number;
|
|
block_admin_merge_override?: boolean;
|
|
[field: string]: unknown;
|
|
}
|
|
|
|
/** What a branch's protection is set to. A field not given is left as the rule has it (or the forge's
|
|
* default on a new rule), except pushes, which a new rule refuses unless `push` says otherwise. */
|
|
export interface ProtectionWanted {
|
|
/** The statuses a pull request must have succeeded before it merges, e.g. mesh/merge-gate. Empty: none. */
|
|
statusChecks: string[];
|
|
/** Whether a person may push to the branch directly. */
|
|
push?: boolean;
|
|
/** Whether an administrator is stopped from merging past a status that has not succeeded. */
|
|
blockAdminOverride?: boolean;
|
|
}
|
|
|
|
/** The forge's body for a wanted protection. */
|
|
export function protectionBody(want: ProtectionWanted, creating: boolean): Record<string, unknown> {
|
|
const checks = [...new Set(want.statusChecks.map((c) => c.trim()).filter(Boolean))];
|
|
const body: Record<string, unknown> = { enable_status_check: checks.length > 0, status_check_contexts: checks };
|
|
if (want.push !== undefined) body.enable_push = want.push;
|
|
else if (creating) body.enable_push = false;
|
|
if (want.blockAdminOverride !== undefined) body.block_admin_merge_override = want.blockAdminOverride;
|
|
return body;
|
|
}
|
|
|