241 lines · 8.2 KB
import { isUnsafeSegment } from "./tree-path";
export { isSafeTreePath } from "./tree-path";
import { basicAuthHeader, forgetRepoToken, repoTokenSecret } from "./artifacts";
import { buildPack, makeBlob, makeCommit, makeTag, makeTree, TREE_MODE } from "./objects";
import type { RawObject, Signature, TreeItem } from "./objects";
import { concatBytes, FLUSH_PKT, packetText, parseAllPackets, pktLine } from "./pktline";
import { invalidateRefs } from "./refs";
import { ZERO_SHA } from "./store";
import type { GitStore } from "./store";
import type { RepoRow } from "~/lib/types";

const FILE_MODE = "100644";
const HTTP_UNAUTHORIZED = 401;
const HTTP_FORBIDDEN = 403;

export type RefUpdate = { ref: string; oldSha: string; newSha: string };

export class PushRejectedError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "PushRejectedError";
  }
}

type PushRepo = Pick<RepoRow, "id" | "artifacts_name" | "artifacts_remote">;

function parseReport(body: Uint8Array): { unpack: string | null; refs: Map<string, string | null> } {
  let unpack: string | null = null;
  const refs = new Map<string, string | null>();
  for (const packet of parseAllPackets(body)) {
    const line = packetText(packet);
    if (line === null) continue;
    if (line.startsWith("unpack ")) unpack = line.slice("unpack ".length);
    else if (line.startsWith("ok ")) refs.set(line.slice(3), null);
    else if (line.startsWith("ng ")) {
      const rest = line.slice(3);
      const space = rest.indexOf(" ");
      refs.set(space === -1 ? rest : rest.slice(0, space), space === -1 ? "rejected" : rest.slice(space + 1));
    }
  }