Keep main's rule right at every start and copy a covering glob's checks (issue 948, review round 1)
This commit is contained in:
+19
-14
@@ -6,7 +6,7 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { ConfiguredToken, MintedToken, type TokenSource } from "./token.js";
|
||||
import { MAIN_BRANCH, mainRuleBody, protectionBody, type BranchProtection, type ProtectionWanted } from "./protection.js";
|
||||
import { Refused, checkSentPath, pathSegment, pathSegments } from "./guard.js";
|
||||
import { Refused, checkSentPath, ruleCovers, pathSegment, pathSegments } from "./guard.js";
|
||||
import { isCommit } from "./checks.js";
|
||||
import { TOOLS_ACCOUNT } from "./tools-account.js";
|
||||
|
||||
@@ -1005,21 +1005,26 @@ export class GiteaAdmin {
|
||||
if (list.length < 50) break;
|
||||
}
|
||||
for (const repo of repos) {
|
||||
const rules = await this.branchProtections(org, repo);
|
||||
const own = rules.find((r) => (r.rule_name ?? r.branch_name) === MAIN_BRANCH);
|
||||
const rule = `${repoPath(org, repo)}/branch_protections/${MAIN_BRANCH}`;
|
||||
const patch = await this.request(rule, { method: "PATCH", body: JSON.stringify(mainRuleBody()) });
|
||||
if (patch.status === 200) continue;
|
||||
if (patch.status !== 404) GiteaAdmin.fail(rule, patch);
|
||||
const made = await this.request(`${repoPath(org, repo)}/branch_protections`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ rule_name: MAIN_BRANCH, enable_status_check: false, status_check_contexts: [], ...mainRuleBody() }),
|
||||
});
|
||||
if (made.status === 201) continue;
|
||||
if (made.status === 403 || made.status === 409 || made.status === 422) {
|
||||
// A rule made between the two calls: edit it.
|
||||
const again = await this.request(rule, { method: "PATCH", body: JSON.stringify(mainRuleBody()) });
|
||||
if (again.status === 200) continue;
|
||||
if (own) {
|
||||
const patch = await this.request(rule, { method: "PATCH", body: JSON.stringify(mainRuleBody()) });
|
||||
if (patch.status !== 200) GiteaAdmin.fail(rule, patch);
|
||||
continue;
|
||||
}
|
||||
GiteaAdmin.fail(`${repoPath(org, repo)}/branch_protections`, made);
|
||||
// A rule named exactly main is matched before any glob rule, so it would hide the statuses, approvals and
|
||||
// administrator limit a glob rule covering main asks: they are copied into it (issue 948, review round 1).
|
||||
const covering = rules.filter((r) => ruleCovers(String(r.rule_name ?? r.branch_name ?? ""), MAIN_BRANCH));
|
||||
const checks = [...new Set(covering.filter((r) => r.enable_status_check).flatMap((r) => (r.status_check_contexts ?? []).filter(Boolean)))];
|
||||
const copied: Record<string, unknown> = { enable_status_check: checks.length > 0, status_check_contexts: checks };
|
||||
const approvals = Math.max(0, ...covering.map((r) => Number(r.required_approvals ?? 0)));
|
||||
if (approvals > 0) copied.required_approvals = approvals;
|
||||
if (covering.some((r) => r.block_admin_merge_override === true)) copied.block_admin_merge_override = true;
|
||||
const made = await this.request(`${repoPath(org, repo)}/branch_protections`, {
|
||||
method: "POST", body: JSON.stringify({ rule_name: MAIN_BRANCH, ...copied, ...mainRuleBody() }),
|
||||
});
|
||||
if (made.status !== 201) GiteaAdmin.fail(`${repoPath(org, repo)}/branch_protections`, made);
|
||||
}
|
||||
return repos;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user