import { badRequest, conflict, forbidden, notFoundError } from "../errors";
import { triggerPush } from "../events/push-trigger";
import { directUpdateViolation, loadProtections, protectionFor } from "../protection";
import { signatureNow } from "./objects";
import { branchSha, listRefs } from "./refs";
import { withStore, ZERO_SHA } from "./store";
import { commitChanges, isValidRefName, PushRejectedError } from "./writer";
import type { FileChangeInput } from "./writer";
import { repoReadOnlyReason } from "../repos";
import type { Permission, RepoRow, Viewer } from "~/lib/types";
export async function assertDirectUpdate(repo: RepoRow, permission: Permission, branch: string, deletion: boolean) {
const readOnly = repoReadOnlyReason(repo);
if (readOnly) throw forbidden(readOnly);
const violation = directUpdateViolation(protectionFor(await loadProtections(repo.id), branch), permission, deletion);
if (violation) throw forbidden(violation);
}
export async function announcePush(repo: RepoRow, viewer: Viewer, ref: string, before: string, after: string) {
await triggerPush({
source: "internal",
repoId: repo.id,
artifactsName: repo.artifacts_name,
ref,
before,
after,
pusherId: viewer.id,
});
}
export function rethrowPush(error: unknown): never {
if (error instanceof PushRejectedError) throw conflict(error.message);
throw error;
}
/**
* Commits a single-file create/edit/rename/delete as the web editor does, optionally onto a new branch.
* Path safety (GIT-7) is enforced by commitChanges; rejections surface as 409 "Invalid path: ...".
*/
export async function commitFileChange(input: {