import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { pullInput, requirePullMutation } from "~/server/pull-access";
import { limitWrite } from "~/server/limits";
import { requireHeadPush } from "~/server/pull-merge";
import { MergeError } from "~/server/pulls";
import { kickBranch } from "~/server/merge-automation";
import { enableStackMerge, restackTree, stackParent, StackError } from "~/server/stacks";
import { badRequest, conflict } from "~/server/errors";
/** Replays a stacked pull request's own commits onto its parent's current head, cascading up the stack. */
export const restackPullRequest = createServerFn({ method: "POST" })
.middleware([viewerMiddleware])
.validator(pullInput.extend({ expectedHead: z.string().length(40) }))
.handler(async ({ data, context }) => {
const viewer = requireViewer(context.viewer);
await limitWrite(viewer);
const { pull, headRepo } = await requirePullMutation(data.owner, data.repo, data.number, viewer, "read");
if (pull.state !== "open") throw badRequest("Pull request is not open");
if (pull.head_sha !== data.expectedHead) throw conflict("The head branch changed; reload and try again");
if (headRepo.id !== pull.repo_id) throw badRequest("Only same-repository branches can be restacked here");
await requireHeadPush(headRepo, pull.head_ref, viewer);
const parent = await stackParent(pull);
if (!parent) throw badRequest("This pull request is not stacked on another one");
const outcome = await restackTree(pull, parent.head_sha, [pull.restack_upstream_sha, pull.base_sha], {
actorId: viewer.id,
committer: { name: viewer.displayName ?? viewer.name, email: viewer.email },
parentNumber: parent.number,
ontoRef: parent.head_ref,
});
if (outcome === "conflict") throw conflict("The commits conflict with the parent; restack locally and force-push");
if (outcome === "unsupported") throw conflict("This history can't be restacked on the server; restack locally");
if (outcome === "moved") throw conflict("The head branch moved; reload and try again");
return { outcome };
});
/** Merges every pull request from the bottom of the stack up to this one, each as its checks pass. */
export const mergeStack = createServerFn({ method: "POST" })
.middleware([viewerMiddleware])