CoolFace
Apppublic

delqhi/sin-github-issues

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
workflows.ts146 linesDownload Raw Back to src
1import { execFile } from 'node:child_process';2import { promisify } from 'node:util';3import { runCommand, runJsonCommand } from './command.js';4 5const execFileAsync = promisify(execFile);6 7type WorkflowRunApi = {8  id: number;9  name?: string;10  display_title?: string;11  event?: string;12  head_branch?: string;13  head_sha?: string;14  status?: string;15  conclusion?: string | null;16  html_url?: string;17  created_at?: string;18  updated_at?: string;19};20 21type WorkflowRunsResponse = {22  workflow_runs?: WorkflowRunApi[];23};24 25type RunnerApi = {26  id: number;27  name: string;28  os: string;29  status: string;30  busy: boolean;31  labels?: Array<{ name: string }>;32};33 34type RunnersResponse = {35  total_count?: number;36  runners?: RunnerApi[];37};38 39const SUITE_COMMANDS: Record<string, string> = {40  'docs-and-architecture': 'npm ci && npm run test:docs:root && npm run test:contracts:active && npm run test:dashboard:boundary && npm run test:guardrails && npm run test:cycles',41  'python-unit-311': "python3.11 -m venv .venv311 && . .venv311/bin/activate && python -m pip install --upgrade pip && python -m pip install -r requirements.txt -r requirements.runtime.txt && python -m pip install -e '.[dev]' && pytest tests/unit -q",42  'dashboard-quality': 'npm --prefix dashboard-enterprise ci && npm --prefix dashboard-enterprise run lint && npm --prefix dashboard-enterprise run type-check && npm run ops:dashboard:build:ci && npm run ops:dashboard:interaction-smoke:ci',43};44 45export async function listWorkflowRuns(input: {46  repo: string;47  branch?: string;48  event?: string;49  status?: string;50  limit?: number;51}) {52  const params = new URLSearchParams();53  params.set('per_page', String(Math.max(1, Math.min(input.limit || 20, 100))));54  if (input.branch) params.set('branch', input.branch);55  if (input.event) params.set('event', input.event);56  if (input.status) params.set('status', input.status);57  const suffix = params.toString() ? `?${params.toString()}` : '';58  const payload = await runJsonCommand<WorkflowRunsResponse>('gh', ['api', `repos/${input.repo}/actions/runs${suffix}`]);59  return {60    ok: true,61    repo: input.repo,62    runs: (payload.workflow_runs || []).map((row) => ({63      id: row.id,64      workflowName: row.name || null,65      title: row.display_title || null,66      event: row.event || null,67      branch: row.head_branch || null,68      sha: row.head_sha || null,69      status: row.status || null,70      conclusion: row.conclusion || null,71      url: row.html_url || null,72      createdAt: row.created_at || null,73      updatedAt: row.updated_at || null,74    })),75  };76}77 78export async function rerunWorkflowRun(repo: string, runId: number) {79  await runCommand('gh', ['run', 'rerun', String(runId), '--repo', repo]);80  return { ok: true, repo, runId };81}82 83export async function cancelWorkflowRun(repo: string, runId: number) {84  await runCommand('gh', ['run', 'cancel', String(runId), '--repo', repo]);85  return { ok: true, repo, runId };86}87 88export async function listRunners(repo: string) {89  const payload = await runJsonCommand<RunnersResponse>('gh', ['api', `repos/${repo}/actions/runners`]);90  return {91    ok: true,92    repo,93    totalCount: payload.total_count || 0,94    runners: (payload.runners || []).map((row) => ({95      id: row.id,96      name: row.name,97      os: row.os,98      status: row.status,99      busy: row.busy,100      labels: (row.labels || []).map((label) => label.name),101    })),102  };103}104 105export async function runLocalSuite(input: {106  repoPath: string;107  suite: 'docs-and-architecture' | 'python-unit-311' | 'dashboard-quality';108  timeoutMs?: number;109}) {110  const command = SUITE_COMMANDS[input.suite];111  if (!command) {112    throw new Error(`unknown_ci_suite:${input.suite}`);113  }114  const startedAt = new Date().toISOString();115  const timeout = Math.max(60_000, Math.min(input.timeoutMs || 900_000, 3_600_000));116  try {117    const result = await execFileAsync('/bin/bash', ['-lc', command], {118      cwd: input.repoPath,119      env: process.env,120      maxBuffer: 1024 * 1024 * 16,121      timeout,122    });123    return {124      ok: true,125      suite: input.suite,126      startedAt,127      finishedAt: new Date().toISOString(),128      stdout: String(result.stdout || '').trim(),129      stderr: String(result.stderr || '').trim(),130    };131  } catch (error) {132    const failure = error as { stdout?: string; stderr?: string; message?: string; signal?: string; code?: number };133    return {134      ok: false,135      suite: input.suite,136      startedAt,137      finishedAt: new Date().toISOString(),138      stdout: String(failure.stdout || '').trim(),139      stderr: String(failure.stderr || '').trim(),140      signal: failure.signal || null,141      code: typeof failure.code === 'number' ? failure.code : null,142      error: String(failure.message || 'local_suite_failed'),143    };144  }145}146