mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
fix(cli): expose render debug mode
Adds the render --debug CLI flag, forwards it through Docker/local render paths, and captures full producer debug artifacts from pipeline start.
This commit is contained in:
@@ -252,6 +252,21 @@ describe("renderLocal browser GPU config", () => {
|
|||||||
expect(producerState.createdJobs[0]?.videoFrameFormat).toBe("png");
|
expect(producerState.createdJobs[0]?.videoFrameFormat).toBe("png");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("forwards debug mode to createRenderJob", async () => {
|
||||||
|
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
||||||
|
fps: { num: 30, den: 1 },
|
||||||
|
quality: "standard",
|
||||||
|
format: "mp4",
|
||||||
|
gpu: false,
|
||||||
|
browserGpuMode: "software",
|
||||||
|
hdrMode: "auto",
|
||||||
|
quiet: true,
|
||||||
|
debug: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(producerState.createdJobs[0]?.debug).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("omits variables from createRenderJob when not provided", async () => {
|
it("omits variables from createRenderJob when not provided", async () => {
|
||||||
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
await renderLocal("/tmp/project", "/tmp/out.mp4", {
|
||||||
fps: { num: 30, den: 1 },
|
fps: { num: 30, den: 1 },
|
||||||
|
|||||||
@@ -241,6 +241,12 @@ export default defineCommand({
|
|||||||
description: "Suppress verbose output",
|
description: "Suppress verbose output",
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
debug: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"Write full render diagnostics and keep intermediate artifacts under the producer .debug directory.",
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
strict: {
|
strict: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
description: "Fail render on lint errors",
|
description: "Fail render on lint errors",
|
||||||
@@ -548,6 +554,7 @@ export default defineCommand({
|
|||||||
const browserGpuArg = args["browser-gpu"];
|
const browserGpuArg = args["browser-gpu"];
|
||||||
const browserGpuMode = resolveBrowserGpuForCli(useDocker, browserGpuArg);
|
const browserGpuMode = resolveBrowserGpuForCli(useDocker, browserGpuArg);
|
||||||
const quiet = args.quiet ?? false;
|
const quiet = args.quiet ?? false;
|
||||||
|
const debug = args.debug ?? false;
|
||||||
const batchJson = args.json ?? false;
|
const batchJson = args.json ?? false;
|
||||||
const effectiveQuiet = quiet || (batchPath != null && batchJson);
|
const effectiveQuiet = quiet || (batchPath != null && batchJson);
|
||||||
const strictAll = args["strict-all"] ?? false;
|
const strictAll = args["strict-all"] ?? false;
|
||||||
@@ -763,6 +770,7 @@ export default defineCommand({
|
|||||||
pageNavigationTimeoutMs,
|
pageNavigationTimeoutMs,
|
||||||
protocolTimeout,
|
protocolTimeout,
|
||||||
playerReadyTimeout,
|
playerReadyTimeout,
|
||||||
|
debug,
|
||||||
exitAfterComplete: false,
|
exitAfterComplete: false,
|
||||||
throwOnError: true,
|
throwOnError: true,
|
||||||
skipFeedback: true,
|
skipFeedback: true,
|
||||||
@@ -815,6 +823,7 @@ export default defineCommand({
|
|||||||
videoBitrate,
|
videoBitrate,
|
||||||
videoFrameFormat,
|
videoFrameFormat,
|
||||||
quiet,
|
quiet,
|
||||||
|
debug,
|
||||||
variables,
|
variables,
|
||||||
entryFile,
|
entryFile,
|
||||||
outputResolution,
|
outputResolution,
|
||||||
@@ -840,6 +849,7 @@ export default defineCommand({
|
|||||||
videoFrameFormat,
|
videoFrameFormat,
|
||||||
quiet,
|
quiet,
|
||||||
browserPath,
|
browserPath,
|
||||||
|
debug,
|
||||||
variables,
|
variables,
|
||||||
entryFile,
|
entryFile,
|
||||||
outputResolution,
|
outputResolution,
|
||||||
@@ -876,6 +886,7 @@ interface RenderOptions {
|
|||||||
videoBitrate?: string;
|
videoBitrate?: string;
|
||||||
videoFrameFormat?: VideoFrameFormat;
|
videoFrameFormat?: VideoFrameFormat;
|
||||||
quiet: boolean;
|
quiet: boolean;
|
||||||
|
debug?: boolean;
|
||||||
browserPath?: string;
|
browserPath?: string;
|
||||||
variables?: Record<string, unknown>;
|
variables?: Record<string, unknown>;
|
||||||
entryFile?: string;
|
entryFile?: string;
|
||||||
@@ -1124,6 +1135,7 @@ async function renderDocker(
|
|||||||
entryFile: options.entryFile,
|
entryFile: options.entryFile,
|
||||||
outputResolution: options.outputResolution,
|
outputResolution: options.outputResolution,
|
||||||
pageSideCompositing: options.pageSideCompositing,
|
pageSideCompositing: options.pageSideCompositing,
|
||||||
|
debug: options.debug,
|
||||||
pageNavigationTimeoutMs: options.pageNavigationTimeoutMs,
|
pageNavigationTimeoutMs: options.pageNavigationTimeoutMs,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1206,7 +1218,7 @@ export async function renderLocal(
|
|||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const logger = createRenderTelemetryLogger(
|
const logger = createRenderTelemetryLogger(
|
||||||
producer.createConsoleLogger?.("info") ?? createNoopProducerLogger(),
|
producer.createConsoleLogger?.(options.debug ? "debug" : "info") ?? createNoopProducerLogger(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const job = producer.createRenderJob({
|
const job = producer.createRenderJob({
|
||||||
@@ -1233,6 +1245,7 @@ export async function renderLocal(
|
|||||||
variables: options.variables,
|
variables: options.variables,
|
||||||
entryFile: options.entryFile,
|
entryFile: options.entryFile,
|
||||||
outputResolution: options.outputResolution,
|
outputResolution: options.outputResolution,
|
||||||
|
debug: options.debug,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onProgress = options.quiet
|
const onProgress = options.quiet
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ describe("buildDockerRunArgs", () => {
|
|||||||
videoBitrate: undefined,
|
videoBitrate: undefined,
|
||||||
videoFrameFormat: "png",
|
videoFrameFormat: "png",
|
||||||
quiet: true,
|
quiet: true,
|
||||||
|
debug: true,
|
||||||
entryFile: "compositions/intro.html",
|
entryFile: "compositions/intro.html",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -188,6 +189,7 @@ describe("buildDockerRunArgs", () => {
|
|||||||
expect(args).toContain("--video-frame-format");
|
expect(args).toContain("--video-frame-format");
|
||||||
expect(args).toContain("png");
|
expect(args).toContain("png");
|
||||||
expect(args).toContain("--quiet");
|
expect(args).toContain("--quiet");
|
||||||
|
expect(args).toContain("--debug");
|
||||||
expect(args).toContain("--gpu");
|
expect(args).toContain("--gpu");
|
||||||
expect(args).toContain("--no-browser-gpu");
|
expect(args).toContain("--no-browser-gpu");
|
||||||
expect(args).toContain("--hdr");
|
expect(args).toContain("--hdr");
|
||||||
@@ -352,6 +354,18 @@ describe("buildDockerRunArgs", () => {
|
|||||||
expect(args).toContain("--no-page-side-compositing");
|
expect(args).toContain("--no-page-side-compositing");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps Docker debug artifacts under the mounted output directory", () => {
|
||||||
|
const args = buildDockerRunArgs({
|
||||||
|
...FIXED_INPUT,
|
||||||
|
options: { ...BASE, debug: true },
|
||||||
|
});
|
||||||
|
const envIdx = args.indexOf("PRODUCER_RENDERS_DIR=/output/renders");
|
||||||
|
const imageIdx = args.indexOf(FIXED_INPUT.imageTag);
|
||||||
|
expect(envIdx).toBeGreaterThan(-1);
|
||||||
|
expect(envIdx).toBeLessThan(imageIdx);
|
||||||
|
expect(args).toContain("--debug");
|
||||||
|
});
|
||||||
|
|
||||||
it("omits --no-page-side-compositing when pageSideCompositing is not explicitly false", () => {
|
it("omits --no-page-side-compositing when pageSideCompositing is not explicitly false", () => {
|
||||||
const args = buildDockerRunArgs({ ...FIXED_INPUT, options: BASE });
|
const args = buildDockerRunArgs({ ...FIXED_INPUT, options: BASE });
|
||||||
expect(args).not.toContain("--no-page-side-compositing");
|
expect(args).not.toContain("--no-page-side-compositing");
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export interface DockerRenderOptions {
|
|||||||
videoBitrate?: string;
|
videoBitrate?: string;
|
||||||
videoFrameFormat?: "auto" | "jpg" | "png";
|
videoFrameFormat?: "auto" | "jpg" | "png";
|
||||||
quiet: boolean;
|
quiet: boolean;
|
||||||
|
debug?: boolean;
|
||||||
variables?: Record<string, unknown>;
|
variables?: Record<string, unknown>;
|
||||||
entryFile?: string;
|
entryFile?: string;
|
||||||
/** Output resolution preset (e.g. "landscape-4k"). Forwarded as `--resolution`. */
|
/** Output resolution preset (e.g. "landscape-4k"). Forwarded as `--resolution`. */
|
||||||
@@ -109,6 +110,10 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
|
|||||||
`${projectDir}:/project:ro`,
|
`${projectDir}:/project:ro`,
|
||||||
"-v",
|
"-v",
|
||||||
`${outputDir}:/output`,
|
`${outputDir}:/output`,
|
||||||
|
// Keep debug artifacts on the mounted host output path. The producer roots
|
||||||
|
// `.debug` at dirname(PRODUCER_RENDERS_DIR), so `/output/renders` maps to
|
||||||
|
// `/output/.debug/<job id>` instead of a disposable container path.
|
||||||
|
...(options.debug ? ["-e", "PRODUCER_RENDERS_DIR=/output/renders"] : []),
|
||||||
imageTag,
|
imageTag,
|
||||||
"/project",
|
"/project",
|
||||||
"--output",
|
"--output",
|
||||||
@@ -128,6 +133,7 @@ export function buildDockerRunArgs(input: DockerRunArgsInput): string[] {
|
|||||||
? ["--video-frame-format", options.videoFrameFormat]
|
? ["--video-frame-format", options.videoFrameFormat]
|
||||||
: []),
|
: []),
|
||||||
...(options.quiet ? ["--quiet"] : []),
|
...(options.quiet ? ["--quiet"] : []),
|
||||||
|
...(options.debug ? ["--debug"] : []),
|
||||||
...(options.gpu ? ["--gpu"] : []),
|
...(options.gpu ? ["--gpu"] : []),
|
||||||
...(options.browserGpu ? [] : ["--no-browser-gpu"]),
|
...(options.browserGpu ? [] : ["--no-browser-gpu"]),
|
||||||
...(options.hdrMode === "force-hdr" ? ["--hdr"] : []),
|
...(options.hdrMode === "force-hdr" ? ["--hdr"] : []),
|
||||||
|
|||||||
@@ -914,6 +914,14 @@ export async function executeRenderJob(
|
|||||||
assertNotAborted();
|
assertNotAborted();
|
||||||
assertConfiguredFfmpegBinariesExist();
|
assertConfiguredFfmpegBinariesExist();
|
||||||
|
|
||||||
|
if (!existsSync(workDir)) mkdirSync(workDir, { recursive: true });
|
||||||
|
|
||||||
|
if (job.config.debug) {
|
||||||
|
const logPath = join(workDir, "render.log");
|
||||||
|
restoreLogger = installDebugLogger(logPath, log);
|
||||||
|
log.info("[Render] Debug artifacts enabled", { workDir, logPath });
|
||||||
|
}
|
||||||
|
|
||||||
log.info("[Render] Pipeline started", {
|
log.info("[Render] Pipeline started", {
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
arch: process.arch,
|
arch: process.arch,
|
||||||
@@ -939,13 +947,6 @@ export async function executeRenderJob(
|
|||||||
requestedWorkers: job.config.workers ?? "auto",
|
requestedWorkers: job.config.workers ?? "auto",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!existsSync(workDir)) mkdirSync(workDir, { recursive: true });
|
|
||||||
|
|
||||||
if (job.config.debug) {
|
|
||||||
const logPath = join(workDir, "render.log");
|
|
||||||
restoreLogger = installDebugLogger(logPath, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
const entryFile = job.config.entryFile || "index.html";
|
const entryFile = job.config.entryFile || "index.html";
|
||||||
let htmlPath = join(projectDir, entryFile);
|
let htmlPath = join(projectDir, entryFile);
|
||||||
if (!existsSync(htmlPath)) {
|
if (!existsSync(htmlPath)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user