cli/src/commands/ci-logs.tsblame
View source
69d1a721import { hubRequest } from "../api.js";
69d1a722import { getRepoSlug } from "../config.js";
69d1a723
69d1a724interface LogEntry {
69d1a725 stream: string;
69d1a726 content: string;
69d1a727 created_at: string;
69d1a728}
69d1a729
69d1a7210export async function ciLogs(args: string[]) {
69d1a7211 const slug = await getRepoSlug(args);
69d1a7212
69d1a7213 // Positional args: <run-id> <step-idx>
69d1a7214 const positional = args.filter((a) => !a.startsWith("--") && args[args.indexOf(a) - 1] !== "--repo");
69d1a7215 const runId = positional[0];
69d1a7216 const stepIdx = positional[1];
69d1a7217
69d1a7218 if (!runId || stepIdx === undefined) {
69d1a7219 console.error("Usage: grove ci logs <run-id> <step-index> [--repo <owner/repo>]");
69d1a7220 process.exit(1);
69d1a7221 }
69d1a7222
69d1a7223 const { logs } = await hubRequest<{ logs: LogEntry[] }>(
69d1a7224 `/api/repos/${slug}/canopy/runs/${runId}/logs/${stepIdx}`
69d1a7225 );
69d1a7226
69d1a7227 if (logs.length === 0) {
69d1a7228 console.log("No logs for this step.");
69d1a7229 return;
69d1a7230 }
69d1a7231
69d1a7232 for (const entry of logs) {
69d1a7233 const prefix = entry.stream === "stderr" ? "\x1b[31m" : "";
69d1a7234 const reset = prefix ? "\x1b[0m" : "";
69d1a7235 process.stdout.write(`${prefix}${entry.content}${reset}`);
69d1a7236 }
69d1a7237}