55 lines · 2.7 KB
import { repoDb } from "../scoped-db";
import { badRequest } from "../errors";
import { branchSha, listRefs } from "../git/refs";
import { labelUrl } from "./config";
import { createSiteDeployment, loadSiteForRepo } from "./deploy";
import { previewLabel } from "./naming";
import type { RepoRow } from "~/lib/types";

export { createScratchFromFiles } from "./scratch";
export { createScratchRepo } from "./scratch-git";
export type { ScratchResult } from "./scratch-core";

export type SiteDeployResult = { deploymentId: string; environment: "production" | "preview"; url: string | null };

/**
 * Stable entry point for deploying a repo site from a branch (UI, MCP, API). The site's branch goes to production,
 * any other branch to its preview host. No permission checks: callers must have checked `contents:write`.
 */
export async function deploySiteRef(
  repo: RepoRow,
  input: { ref?: string; actorId: string | null },
): Promise<SiteDeployResult> {
  const site = await loadSiteForRepo(repo.id);
  if (!site) throw badRequest("Sites are not enabled for this repository");
  if (site.disabled_reason) throw badRequest(`This site is disabled: ${site.disabled_reason}`);
  const branch = (input.ref ?? site.branch).replace(/^refs\/heads\//, "");
  const production = branch === site.branch;
  if (!production && site.previews !== 1) throw badRequest("Branch previews are disabled for this site");
  const environment = production ? "production" : "preview";
  const label = production ? site.label : previewLabel(site.label, branch);
  const ref = `refs/heads/${branch}`;
  const base = { site, environment, label, branch, ref, creatorId: input.actorId } as const;
  let deploymentId: string;
  if (site.source !== "workflow") {
    const sha = branchSha(await listRefs(repo), branch);
    if (!sha) throw badRequest(`Branch ${branch} does not exist`);
    deploymentId = (await createSiteDeployment({ ...base, sha, artifactId: null, source: "branch" })).id;
  } else {
    const artifact = await repoDb(repo.id).first<{ id: string; sha: string }>(
      `SELECT a.id, r.sha FROM job_artifacts a JOIN workflow_runs r ON r.id = a.run_id