125 lines · 5.3 KB
import { env } from "cloudflare:workers";
import { repoDb } from "../scoped-db";
import { hasPermission, repoPermission } from "../repos";
import { badRequest, conflict, notFoundError } from "../errors";
import { currentBaseSha, loadPullRepos, requireHeadPush, updateHeadBranch } from "../pull-merge";
import { MergeError } from "../pulls";
import type { PullRow } from "../pulls";
import type { FixPlan } from "./plan";
import { belowThreshold, isStale, selectResolutions } from "./proposal";
import { abandonRequeue } from "./requeue";
import { latestRuns, loadRun, updateRun } from "./store";
import type { RunRow } from "./store";
import type { Viewer } from "~/lib/types";

const STALE_MESSAGE = "The head or base branch moved since this proposal; run the fix again";

export type ApplyOutcome = { runId: string; commitSha: string; requeue: boolean; alreadyApplied: boolean };

function applied(runRow: RunRow, alreadyApplied: boolean): ApplyOutcome {
  return {
    runId: runRow.id,
    commitSha: runRow.commit_sha ?? "",
    requeue: runRow.requeue_status !== null,
    alreadyApplied,
  };
}

async function markStale(runId: string): Promise<never> {
  await updateRun(runId, ["suggested"], { stale: 1, error: STALE_MESSAGE });
  throw conflict(STALE_MESSAGE);
}

/** Hands a claimed proposal back to review without re-sending the "suggested" notification. */
async function releaseClaim(repoId: string, runId: string, error: string | null): Promise<void> {
  await repoDb(repoId).run(
    "UPDATE mergefix_runs SET status = 'suggested', error = ?, applied_by = NULL, applied_files = NULL, updated_at = ? WHERE id = ? AND status = 'applying'",
    error,
    Date.now(),
    runId,
  );