206 lines · 7.3 KB
import { env } from "cloudflare:workers";
import { z } from "zod";
import { placeholders } from "../../db";
import { repoDb } from "../../scoped-db";
import { badRequest, notFoundError } from "../../errors";
import { runnerStub } from "../../ci/jobs";
import type { WorkflowJobRow, WorkflowRunRow } from "../../ci/jobs";
import type { LogRow } from "../../ci/runner-meta";
import { runUrl, scheduleWorkflows } from "../../ci/scheduler";
import { WORKFLOW_DIR } from "../../ci/spec";
import { limitHeavy, limitWrite } from "../../limits";
import { defineTool, repoArgs, scopedRepo } from "./base";
import { resolveRef } from "./content";

const LIST_LIMIT = 25;
const MAX_LISTED_RUNS = 20;
const MAX_LOG_ROWS = 2000;
const MAX_LOG_CHARS = 64 * 1024;
const MAX_FOLLOW_SECONDS = 25;
const POLL_MS = 2000;

const runCiTool = defineTool({
  name: "run_ci",
  title: "Run CI",
  description: `Dispatch a workflow (a file under ${WORKFLOW_DIR} with workflow_dispatch) at a ref.`,
  input: z.object({
    ...repoArgs,
    workflow: z.string().min(1).max(500).describe(`Workflow path, e.g. ${WORKFLOW_DIR}/ci.yml`),
    ref: z.string().max(250).optional(),
    inputs: z.record(z.string(), z.string().max(1000)).default({}),
  }),
  write: true,
  async run({ caller }, args) {
    await limitWrite(caller.viewer);
    const { repo } = await scopedRepo(caller, args.owner, args.repo, "actions", "write");
    const revision = await resolveRef(repo, args.ref);
    const ids = await scheduleWorkflows(repo, {
      event: "workflow_dispatch",
      action: null,
      ref: revision.kind === "tag" ? `refs/tags/${revision.name}` : `refs/heads/${revision.name}`,