trigger.dev
Version:
A Command-Line Interface for Trigger.dev projects
126 lines • 4.69 kB
JavaScript
import { log } from "@clack/prompts";
import { stripVTControlCharacters } from "node:util";
import { DeploymentEventFromString, } from "@trigger.dev/core/v3/schemas";
import chalk from "chalk";
import { z } from "zod";
import { chalkError, chalkGrey, chalkWarning } from "../utilities/cliOutput.js";
import { logger } from "../utilities/logger.js";
import { spinner } from "../utilities/windows.js";
export const BuildLogsMode = z.enum(["compact", "full"]);
export function resolveBuildLogsMode(requested, env) {
// No redrawable spinner in CI, piped output, or the Windows fallback spinner.
if (env.plain || env.ci || !env.tty || env.windows) {
return "full";
}
return requested;
}
function formatBuildLogLine(entry) {
const timestamp = chalkGrey(entry.timestamp.toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
fractionalSecondDigits: 3,
}));
const message = entry.level === "error"
? chalk.bold(chalkError(entry.message))
: entry.level === "warn"
? chalkWarning(entry.message)
: entry.level === "debug"
? chalkGrey(entry.message)
: entry.message;
return `│ ${timestamp} ${message}`;
}
export function createBuildLogRenderer(options) {
const $spinner = options.spinner ?? spinner();
const print = options.print ?? ((line) => console.log(line));
const success = options.success ?? ((message) => log.success(message));
const tailSize = options.tailSize ?? 20;
const tail = [];
let started = false;
$spinner.start("Build queued");
const compactMessage = (message) => {
const columns = options.columns ?? process.stdout.columns ?? 120;
const available = Math.max(columns - options.title.length - 8, 20);
const singleLine = stripVTControlCharacters(message).replace(/\s+/g, " ").trim();
return singleLine.length > available ? `${singleLine.slice(0, available - 1)}…` : singleLine;
};
return {
get started() {
return started;
},
log(entry) {
const line = formatBuildLogLine(entry);
if (options.mode === "full") {
if (!started) {
$spinner.stop("Build started");
print("│");
}
started = true;
print(line);
return;
}
started = true;
tail.push(line);
if (tail.length > tailSize) {
tail.shift();
}
const message = compactMessage(entry.message);
if (message.length > 0 && !/^[-=#*_.\s]+$/.test(message)) {
$spinner.message(`${options.title}: ${message}`);
}
},
finish(message, outcome) {
if (options.mode === "full" && started) {
if (outcome === "success") {
success(message);
}
return;
}
$spinner.stop(message, outcome === "failure" ? 2 : undefined);
if (options.mode === "compact" && outcome === "failure" && tail.length > 0) {
print("│");
print(`│ ${chalkGrey(`Last ${tail.length} ${tail.length === 1 ? "line" : "lines"} of the build log:`)}`);
for (const line of tail) {
print(line);
}
print("│");
}
},
};
}
export async function streamDeploymentEvents(records, renderer, onFinalized) {
let finalEvent;
for await (const record of records) {
const result = DeploymentEventFromString.safeParse(record.body);
if (!result.success) {
logger.debug("Failed to parse deployment event, skipping", {
error: result.error,
record: record.body,
});
continue;
}
const event = result.data;
switch (event.type) {
case "log": {
renderer.log({
timestamp: new Date(record.timestamp),
level: event.data.level,
message: event.data.message,
});
break;
}
case "finalized": {
finalEvent = event.data;
onFinalized();
break;
}
default: {
event;
logger.debug("Unknown deployment event, skipping", { event });
}
}
}
return finalEvent;
}
//# sourceMappingURL=buildLogs.js.map