@cleartrip/frontguard 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -7,9 +7,10 @@ import { WriteStream } from 'tty';
|
|
|
7
7
|
import path5, { sep, normalize, delimiter, resolve, dirname } from 'path';
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import { pathToFileURL, fileURLToPath } from 'url';
|
|
10
|
-
import {
|
|
10
|
+
import { tmpdir } from 'os';
|
|
11
|
+
import fs2, { existsSync, statSync, readFileSync } from 'fs';
|
|
12
|
+
import { spawn, execFileSync } from 'child_process';
|
|
11
13
|
import { createRequire } from 'module';
|
|
12
|
-
import fs2 from 'fs';
|
|
13
14
|
import { pipeline } from 'stream/promises';
|
|
14
15
|
import { PassThrough } from 'stream';
|
|
15
16
|
import fg from 'fast-glob';
|
|
@@ -2496,9 +2497,23 @@ async function initFrontGuard(cwd) {
|
|
|
2496
2497
|
await fs.writeFile(tplPr, PR_TEMPLATE, "utf8");
|
|
2497
2498
|
}
|
|
2498
2499
|
}
|
|
2499
|
-
|
|
2500
|
-
// src/ci/bitbucket-pr-snippet.ts
|
|
2500
|
+
var MAX_PNG_BYTES_FOR_EMBED = 22e4;
|
|
2501
2501
|
function checksImageMarkdown() {
|
|
2502
|
+
const embedPath = process.env.FRONTGUARD_EMBED_CHECKS_PNG_PATH?.trim();
|
|
2503
|
+
if (embedPath) {
|
|
2504
|
+
try {
|
|
2505
|
+
if (!existsSync(embedPath)) return null;
|
|
2506
|
+
const st = statSync(embedPath);
|
|
2507
|
+
if (!st.isFile() || st.size > MAX_PNG_BYTES_FOR_EMBED) return null;
|
|
2508
|
+
const buf = readFileSync(embedPath);
|
|
2509
|
+
const b64 = buf.toString("base64");
|
|
2510
|
+
const md = ``;
|
|
2511
|
+
if (md.length > 45e4) return null;
|
|
2512
|
+
return md;
|
|
2513
|
+
} catch {
|
|
2514
|
+
return null;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2502
2517
|
const u4 = process.env.FRONTGUARD_CHECKS_IMAGE_URL?.trim();
|
|
2503
2518
|
if (!u4) return null;
|
|
2504
2519
|
return ``;
|
|
@@ -2524,13 +2539,17 @@ function bitbucketDownloadsPageUrl() {
|
|
|
2524
2539
|
if (ws && slug) return `https://bitbucket.org/${ws}/${slug}/downloads/`;
|
|
2525
2540
|
return null;
|
|
2526
2541
|
}
|
|
2542
|
+
var DETAILED_REPORT_LINE = "For detailed check analysis, please open the full interactive report:";
|
|
2527
2543
|
function formatBitbucketPrSnippet(report) {
|
|
2528
2544
|
const publicReport = process.env.FRONTGUARD_PUBLIC_REPORT_URL?.trim();
|
|
2529
2545
|
const linkOnly = process.env.FRONTGUARD_BITBUCKET_COMMENT_LINK_ONLY === "1";
|
|
2530
2546
|
const imgMd = checksImageMarkdown();
|
|
2531
2547
|
if (linkOnly && publicReport) {
|
|
2532
2548
|
const parts = [];
|
|
2533
|
-
if (imgMd)
|
|
2549
|
+
if (imgMd) {
|
|
2550
|
+
parts.push(imgMd, "");
|
|
2551
|
+
parts.push(DETAILED_REPORT_LINE);
|
|
2552
|
+
}
|
|
2534
2553
|
parts.push(publicReport.endsWith("\n") ? publicReport.slice(0, -1) : publicReport);
|
|
2535
2554
|
return `${parts.join("\n")}
|
|
2536
2555
|
`;
|
|
@@ -2559,15 +2578,13 @@ function formatBitbucketPrSnippet(report) {
|
|
|
2559
2578
|
""
|
|
2560
2579
|
);
|
|
2561
2580
|
if (publicReport) {
|
|
2562
|
-
out.push("Full interactive report (open in browser):");
|
|
2563
|
-
out.push(publicReport);
|
|
2564
|
-
out.push("");
|
|
2565
2581
|
if (imgMd) {
|
|
2566
|
-
out.push(
|
|
2567
|
-
|
|
2568
|
-
);
|
|
2569
|
-
out.push("");
|
|
2582
|
+
out.push(DETAILED_REPORT_LINE);
|
|
2583
|
+
} else {
|
|
2584
|
+
out.push("Full interactive report (open in browser):");
|
|
2570
2585
|
}
|
|
2586
|
+
out.push(publicReport);
|
|
2587
|
+
out.push("");
|
|
2571
2588
|
} else if (downloadsName && downloadsPage) {
|
|
2572
2589
|
out.push("HTML report is in Repository \u2192 Downloads. Open this page while logged in:");
|
|
2573
2590
|
out.push(downloadsPage);
|
|
@@ -5530,6 +5547,30 @@ function applyAiAssistedEscalation(results, pr, config) {
|
|
|
5530
5547
|
}
|
|
5531
5548
|
}
|
|
5532
5549
|
}
|
|
5550
|
+
var PLAYWRIGHT = "playwright@1.49.1";
|
|
5551
|
+
function runCmd(command, args) {
|
|
5552
|
+
return new Promise((resolve, reject) => {
|
|
5553
|
+
const p2 = spawn(command, args, { stdio: "inherit", env: process.env });
|
|
5554
|
+
p2.on("error", reject);
|
|
5555
|
+
p2.on("close", (code) => {
|
|
5556
|
+
if (code === 0) resolve();
|
|
5557
|
+
else reject(new Error(`${command} exited with code ${code}`));
|
|
5558
|
+
});
|
|
5559
|
+
});
|
|
5560
|
+
}
|
|
5561
|
+
async function runChecksHtmlToPng(htmlPath, pngPath) {
|
|
5562
|
+
const fileUrl = pathToFileURL(htmlPath).href;
|
|
5563
|
+
const npx = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
5564
|
+
await runCmd(npx, ["-y", PLAYWRIGHT, "install", "chromium"]);
|
|
5565
|
+
await runCmd(npx, [
|
|
5566
|
+
"-y",
|
|
5567
|
+
PLAYWRIGHT,
|
|
5568
|
+
"screenshot",
|
|
5569
|
+
fileUrl,
|
|
5570
|
+
pngPath,
|
|
5571
|
+
"--viewport-size=920,1000"
|
|
5572
|
+
]);
|
|
5573
|
+
}
|
|
5533
5574
|
|
|
5534
5575
|
// src/report/builder.ts
|
|
5535
5576
|
var import_picocolors = __toESM(require_picocolors());
|
|
@@ -6913,26 +6954,53 @@ async function runFrontGuard(opts) {
|
|
|
6913
6954
|
llmAppendix,
|
|
6914
6955
|
cwd: opts.cwd,
|
|
6915
6956
|
emitHtml: Boolean(opts.htmlOut),
|
|
6916
|
-
emitChecksSnapshot: Boolean(opts.checksSnapshotOut)
|
|
6957
|
+
emitChecksSnapshot: Boolean(opts.checksSnapshotOut || opts.checksPngOut)
|
|
6917
6958
|
});
|
|
6918
6959
|
if (opts.htmlOut && report.html) {
|
|
6919
6960
|
await fs.writeFile(opts.htmlOut, report.html, "utf8");
|
|
6920
6961
|
}
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6962
|
+
let embedPngPath = null;
|
|
6963
|
+
let tmpDir = null;
|
|
6964
|
+
let htmlForPng;
|
|
6965
|
+
if ((opts.checksSnapshotOut || opts.checksPngOut) && report.checksSnapshotHtml) {
|
|
6966
|
+
if (opts.checksSnapshotOut) {
|
|
6967
|
+
const snapPath = path5.isAbsolute(opts.checksSnapshotOut) ? opts.checksSnapshotOut : path5.join(opts.cwd, opts.checksSnapshotOut);
|
|
6968
|
+
await fs.writeFile(snapPath, report.checksSnapshotHtml, "utf8");
|
|
6969
|
+
htmlForPng = snapPath;
|
|
6970
|
+
g.stderr.write(`
|
|
6971
|
+
FrontGuard: wrote checks snapshot HTML to ${snapPath}
|
|
6972
|
+
`);
|
|
6973
|
+
}
|
|
6974
|
+
if (opts.checksPngOut) {
|
|
6975
|
+
if (!htmlForPng) {
|
|
6976
|
+
tmpDir = await fs.mkdtemp(path5.join(tmpdir(), "fg-checks-"));
|
|
6977
|
+
htmlForPng = path5.join(tmpDir, "checks.html");
|
|
6978
|
+
await fs.writeFile(htmlForPng, report.checksSnapshotHtml, "utf8");
|
|
6979
|
+
}
|
|
6980
|
+
const pngAbs = path5.isAbsolute(opts.checksPngOut) ? opts.checksPngOut : path5.join(opts.cwd, opts.checksPngOut);
|
|
6981
|
+
await runChecksHtmlToPng(htmlForPng, pngAbs);
|
|
6982
|
+
embedPngPath = pngAbs;
|
|
6983
|
+
g.stderr.write(`FrontGuard: wrote checks PNG to ${pngAbs} (Playwright via npx).
|
|
6984
|
+
|
|
6985
|
+
`);
|
|
6986
|
+
if (tmpDir) {
|
|
6987
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
6988
|
+
tmpDir = null;
|
|
6989
|
+
}
|
|
6990
|
+
} else if (opts.checksSnapshotOut && htmlForPng) {
|
|
6991
|
+
g.stderr.write(
|
|
6992
|
+
` Tip: add --checksPngOut checks.png to render this HTML to PNG with Playwright (npx).
|
|
6930
6993
|
|
|
6931
6994
|
`
|
|
6932
|
-
|
|
6995
|
+
);
|
|
6996
|
+
}
|
|
6933
6997
|
}
|
|
6934
6998
|
if (opts.prCommentOut) {
|
|
6999
|
+
if (embedPngPath) {
|
|
7000
|
+
g.env.FRONTGUARD_EMBED_CHECKS_PNG_PATH = embedPngPath;
|
|
7001
|
+
}
|
|
6935
7002
|
const snippet = formatBitbucketPrSnippet(report);
|
|
7003
|
+
delete g.env.FRONTGUARD_EMBED_CHECKS_PNG_PATH;
|
|
6936
7004
|
const abs = path5.isAbsolute(opts.prCommentOut) ? opts.prCommentOut : path5.join(opts.cwd, opts.prCommentOut);
|
|
6937
7005
|
await fs.writeFile(abs, snippet, "utf8");
|
|
6938
7006
|
g.stderr.write(
|
|
@@ -6940,7 +7008,7 @@ FrontGuard: wrote checks snapshot HTML to ${snapPath} (screenshot this file for
|
|
|
6940
7008
|
FrontGuard: wrote Bitbucket PR comment text to ${abs} (${snippet.length} bytes).
|
|
6941
7009
|
Use ONLY this file in your POST \u2026/pullrequests/{id}/comments payload (content.raw).
|
|
6942
7010
|
Do not post frontguard-report.md or captured stdout \u2014 that is the long markdown log.
|
|
6943
|
-
|
|
7011
|
+
With --checksPngOut, the PNG is inlined (small files only) or set FRONTGUARD_CHECKS_IMAGE_URL.
|
|
6944
7012
|
|
|
6945
7013
|
`
|
|
6946
7014
|
);
|
|
@@ -6995,7 +7063,11 @@ var run = defineCommand({
|
|
|
6995
7063
|
},
|
|
6996
7064
|
checksSnapshotOut: {
|
|
6997
7065
|
type: "string",
|
|
6998
|
-
description: "Write HTML with only the Checks table (
|
|
7066
|
+
description: "Write HTML with only the Checks table (for screenshots / PR comments)"
|
|
7067
|
+
},
|
|
7068
|
+
checksPngOut: {
|
|
7069
|
+
type: "string",
|
|
7070
|
+
description: "Write PNG of the checks table via Playwright (npx). Pair with --checksSnapshotOut or use alone"
|
|
6999
7071
|
},
|
|
7000
7072
|
prCommentOut: {
|
|
7001
7073
|
type: "string",
|
|
@@ -7010,6 +7082,7 @@ var run = defineCommand({
|
|
|
7010
7082
|
append: typeof args.append === "string" ? args.append : null,
|
|
7011
7083
|
htmlOut: typeof args.htmlOut === "string" ? args.htmlOut : null,
|
|
7012
7084
|
checksSnapshotOut: typeof args.checksSnapshotOut === "string" ? args.checksSnapshotOut : null,
|
|
7085
|
+
checksPngOut: typeof args.checksPngOut === "string" ? args.checksPngOut : null,
|
|
7013
7086
|
prCommentOut: typeof args.prCommentOut === "string" ? args.prCommentOut : null
|
|
7014
7087
|
});
|
|
7015
7088
|
}
|