200 lines · 8.8 KB
import { createServerFn } from "@tanstack/react-start";
import { limitHeavy, limitWrite } from "~/server/limits";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { first } from "~/server/db";
import { loadRepo, repoPermission, requireRepoAccess } from "~/server/repos";
import { branchSha, listRefs, resolveRevision } from "~/server/git/refs";
import { withStore } from "~/server/git/store";
import {
  commitChanges,
  createBranch as pushBranch,
  deleteRef,
  isValidRefName,
  PushRejectedError,
} from "~/server/git/writer";
import type { FileChangeInput } from "~/server/git/writer";
import { signatureNow } from "~/server/git/objects";
import { diffTreesCached } from "~/server/git/diff";
import { compareCommits } from "~/server/git/history";
import { directUpdateViolation, loadProtections, protectionFor } from "~/server/protection";
import { triggerPush } from "~/server/events/push-trigger";
import { badRequest, conflict, forbidden, notFoundError } from "~/server/errors";
import { ZERO_SHA } from "~/server/git/store";
import { repoRef } from "~/lib/validation";
import type { Permission, RepoRow, Viewer } from "~/lib/types";

const MAX_EDIT_BYTES = 5 * 1024 * 1024;
const encoder = new TextEncoder();

async function assertDirectUpdate(repo: RepoRow, permission: Permission, branch: string, deletion: boolean) {
  if (repo.is_archived === 1) throw forbidden("This repository is archived");
  const violation = directUpdateViolation(protectionFor(await loadProtections(repo.id), branch), permission, deletion);
  if (violation) throw forbidden(violation);
}

async function announce(repo: RepoRow, viewer: Viewer, ref: string, before: string, after: string) {
  await triggerPush({
    source: "internal",
    repoId: repo.id,
    artifactsName: repo.artifacts_name,