@tempo-ai/visual-review 0.0.1 → 0.0.2
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/bin.js +2 -2
- package/dist/{chunk-HMPQK5ZG.js → chunk-4KKBAMNP.js} +14 -7
- package/dist/chunk-4KKBAMNP.js.map +1 -0
- package/dist/{chunk-4QAZFBC3.js → chunk-HTDJZ32L.js} +43 -9
- package/dist/chunk-HTDJZ32L.js.map +1 -0
- package/dist/{cli-3HH2BY7Y.js → cli-X7OOU6H4.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/{report-RCKB2CVS.js → report-RD2OQ5TP.js} +6 -4
- package/package.json +2 -2
- package/dist/chunk-4QAZFBC3.js.map +0 -1
- package/dist/chunk-HMPQK5ZG.js.map +0 -1
- /package/dist/{cli-3HH2BY7Y.js.map → cli-X7OOU6H4.js.map} +0 -0
- /package/dist/{report-RCKB2CVS.js.map → report-RD2OQ5TP.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/report.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\n\nimport { visualReviewPrDeclaration } from \"./github-actions\";\n\nconst STICKY_MARKER = \"<!-- tempo-visual-review -->\";\nconst STATUS_CONTEXT = \"visual-review\";\n\ntype ReportArgs = {\n pollTimeoutS: number;\n bypass: boolean;\n noVisualChange: boolean;\n fallbackFailure: boolean;\n statusUrl?: string;\n pr?: number;\n sha?: string;\n};\n\ntype Gate = {\n satisfied?: boolean;\n required?: number;\n approvalsNeeded?: number;\n rejected?: number;\n blockingErrors?: number;\n};\n\ntype ReportStatus = {\n state?: \"complete\" | \"error\" | string;\n reportUrl?: string;\n trackedTotal?: number;\n counts?: Record<string, number | undefined>;\n gate?: Gate;\n topChanged?: Array<{\n name?: string;\n storyboardId: string;\n diffRatio?: number | null;\n verdict: string;\n error?: string;\n baselineHash?: string;\n candidateHash?: string;\n }>;\n blobUrlTemplate?: string;\n approximateBase?: boolean;\n freshEpoch?: boolean;\n publisherConfigured?: boolean;\n lastPublishError?: { revision: number; error: string };\n lastPublish?: { revision: number };\n statusPublishing?: boolean;\n};\n\nfunction parseArgs(argv: string[]): ReportArgs {\n const args: ReportArgs = {\n pollTimeoutS: 900,\n bypass: false,\n noVisualChange: false,\n fallbackFailure: false,\n };\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index];\n const next = () => {\n const value = argv[++index];\n if (value === undefined) throw new Error(`${flag} needs a value`);\n return value;\n };\n if (flag === \"--status-url\") args.statusUrl = next();\n else if (flag === \"--pr\") args.pr = Number(next());\n else if (flag === \"--sha\") args.sha = next();\n else if (flag === \"--poll-timeout-s\") args.pollTimeoutS = Number(next());\n else if (flag === \"--bypass\") args.bypass = true;\n else if (flag === \"--no-visual-change\") args.noVisualChange = true;\n else if (flag === \"--fallback-failure\") args.fallbackFailure = true;\n else throw new Error(`unknown flag ${flag}`);\n }\n if (!args.sha) throw new Error(\"--sha is required\");\n return args;\n}\n\nfunction gh(...ghArgs: string[]): string {\n return execFileSync(\"gh\", ghArgs, { encoding: \"utf-8\" });\n}\n\nfunction postCommitStatus(\n repo: string,\n sha: string,\n state: \"success\" | \"failure\" | \"pending\",\n description: string,\n targetUrl?: string,\n): void {\n gh(\n \"api\",\n `repos/${repo}/statuses/${sha}`,\n \"-f\",\n `state=${state}`,\n \"-f\",\n `context=${STATUS_CONTEXT}`,\n \"-f\",\n `description=${description.slice(0, 140)}`,\n ...(targetUrl ? [\"-f\", `target_url=${targetUrl}`] : []),\n );\n}\n\nfunction upsertStickyComment(repo: string, pr: number, body: string): void {\n const comments = (\n JSON.parse(\n gh(\"api\", `repos/${repo}/issues/${pr}/comments`, \"--paginate\", \"--slurp\"),\n ) as Array<Array<{ id: number; body?: string }>>\n ).flat();\n const existing = comments.find(\n (comment) =>\n typeof comment.body === \"string\" && comment.body.includes(STICKY_MARKER),\n );\n if (existing) {\n gh(\n \"api\",\n \"--method\",\n \"PATCH\",\n `repos/${repo}/issues/comments/${existing.id}`,\n \"-f\",\n `body=${body}`,\n );\n } else {\n gh(\"api\", `repos/${repo}/issues/${pr}/comments`, \"-f\", `body=${body}`);\n }\n}\n\nfunction describeGate(\n gate: Gate,\n state: ReportStatus[\"state\"],\n): { state: \"success\" | \"failure\" | \"pending\"; description: string } {\n if (state === \"error\") {\n return {\n state: \"failure\",\n description: \"visual review run failed — see report\",\n };\n }\n if (state !== \"complete\") {\n return {\n state: \"pending\",\n description: \"capturing & comparing storyboards…\",\n };\n }\n if (gate.satisfied) {\n return {\n state: \"success\",\n description:\n gate.required === 0\n ? \"no visual changes\"\n : `${gate.required} visual change${gate.required === 1 ? \"\" : \"s\"} approved`,\n };\n }\n const parts: string[] = [];\n if ((gate.approvalsNeeded ?? 0) > 0) {\n parts.push(`${gate.approvalsNeeded} of ${gate.required} need approval`);\n }\n if ((gate.rejected ?? 0) > 0) parts.push(`${gate.rejected} rejected`);\n if ((gate.blockingErrors ?? 0) > 0) {\n parts.push(\n `${gate.blockingErrors} render error${gate.blockingErrors === 1 ? \"\" : \"s\"}`,\n );\n }\n return {\n state: \"failure\",\n description: `visual review: ${parts.join(\", \")} — see report`,\n };\n}\n\nfunction buildCommentBody(status: ReportStatus): string {\n const counts = status.counts ?? {};\n const gateLine = status.gate?.satisfied\n ? \"✅ **Check passing** — every visual change is approved.\"\n : `🔴 **Check failing** — ${status.gate?.approvalsNeeded ?? \"?\"} of ${status.gate?.required ?? \"?\"} storyboards need approval${status.gate?.blockingErrors ? `, ${status.gate.blockingErrors} render error(s)` : \"\"}${status.gate?.rejected ? `, ${status.gate.rejected} rejected` : \"\"}. Approving in the report flips the check instantly — no CI re-run.`;\n const summary = `| tracked | changed | new | removed | render errors | unchanged |\n| --- | --- | --- | --- | --- | --- |\n| ${status.trackedTotal ?? 0} | ${counts.changed ?? 0} | ${counts.added ?? 0} | ${counts.removed ?? 0} | ${counts.errors ?? 0} | ${counts.unchanged ?? 0} |`;\n\n const thumbs = (status.topChanged ?? [])\n .slice(0, 6)\n .map((board) => {\n const title = board.name ?? board.storyboardId;\n const meta =\n board.diffRatio !== undefined && board.diffRatio !== null\n ? ` · ${(board.diffRatio * 100).toFixed(2)}%`\n : \"\";\n if (board.verdict === \"render-error\") {\n return `**${title}** — render error${board.error ? `: \\`${board.error.slice(0, 120)}\\`` : \"\"}`;\n }\n const cell = (hash: string | undefined, label: string) =>\n hash && status.blobUrlTemplate\n ? `<img src=\"${status.blobUrlTemplate}${hash}\" alt=\"${label}\" width=\"360\" />`\n : \"—\";\n return `<details><summary><b>${title}</b> — ${board.verdict}${meta}</summary>\n\n| baseline | candidate |\n| --- | --- |\n| ${cell(board.baselineHash, \"baseline\")} | ${cell(board.candidateHash, \"candidate\")} |\n\n</details>`;\n })\n .join(\"\\n\");\n\n const notes: string[] = [];\n if (status.approximateBase) {\n notes.push(\n \"⚠ exact merge-base had no visual run — compared against the nearest captured ancestor.\",\n );\n }\n if (status.freshEpoch) {\n notes.push(\n \"ℹ fresh baseline epoch (capture environment changed) — everything reports as new.\",\n );\n }\n\n return `${STICKY_MARKER}\n## 👁 Visual review\n\n${gateLine}\n\n${summary}\n\n${notes.length > 0 ? `${notes.join(\"\\n\")}\\n` : \"\"}${thumbs}\n\n📷 **[Open the visual review report](${status.reportUrl})** — side-by-side, onion-skin and diff views; approve, reject, and comment there.`;\n}\n\nfunction buildNoVisualChangeComment(): string {\n return `${STICKY_MARKER}\n## 👁 Visual review\n\n✅ **Not applicable — no storyboard changes expected.** Storyboard capture was skipped from the PR declaration.`;\n}\n\nfunction latestContextState(repo: string, sha: string): string | null {\n const statuses = (\n JSON.parse(\n gh(\n \"api\",\n `repos/${repo}/commits/${sha}/statuses`,\n \"--paginate\",\n \"--slurp\",\n ),\n ) as Array<Array<{ context?: string; state?: string }>>\n ).flat();\n return (\n statuses.find((status) => status.context === STATUS_CONTEXT)?.state ?? null\n );\n}\n\nfunction isPermanentError(error: unknown): boolean {\n return (\n error instanceof Error && \"permanent\" in error && error.permanent === true\n );\n}\n\nexport async function main(argv = process.argv.slice(2)): Promise<number> {\n const args = parseArgs(argv);\n const repo = process.env.GITHUB_REPOSITORY;\n if (!repo) throw new Error(\"GITHUB_REPOSITORY is not set\");\n const sha = args.sha;\n if (!sha) throw new Error(\"--sha is required\");\n const declaration = visualReviewPrDeclaration();\n\n if (args.bypass || declaration.bypass) {\n postCommitStatus(\n repo,\n sha,\n \"success\",\n \"bypassed via visual-review:bypass label\",\n );\n console.log(\"bypass label present — posted success and skipped the report\");\n return 0;\n }\n\n if (args.noVisualChange || declaration.noVisualChange) {\n postCommitStatus(\n repo,\n sha,\n \"success\",\n \"not applicable — no storyboard changes expected\",\n );\n if (args.pr)\n upsertStickyComment(repo, args.pr, buildNoVisualChangeComment());\n console.log(\n \"no-visual-change declaration present — posted success and skipped capture\",\n );\n return 0;\n }\n\n if (args.fallbackFailure) {\n const current = latestContextState(repo, sha);\n if (current === null || current === \"pending\") {\n postCommitStatus(\n repo,\n sha,\n \"failure\",\n \"visual review reporting failed — see workflow logs\",\n );\n console.log(\n `reporting fallback: latest state was ${current ?? \"absent\"} — posted failure`,\n );\n } else {\n console.log(\n `reporting fallback: latest '${STATUS_CONTEXT}' state is '${current}' — leaving it`,\n );\n }\n return 0;\n }\n\n const statusUrl = args.statusUrl;\n if (!statusUrl) throw new Error(\"--status-url is required\");\n const deadline = Date.now() + args.pollTimeoutS * 1_000;\n let status: ReportStatus | undefined;\n for (;;) {\n try {\n const response = await fetch(statusUrl);\n if (response.status === 404) {\n const error = new Error(\"status poll 404 — wrong report key\");\n Object.assign(error, { permanent: true });\n throw error;\n }\n if (!response.ok)\n throw new Error(`status poll failed: ${response.status}`);\n status = (await response.json()) as ReportStatus;\n } catch (error) {\n if (isPermanentError(error)) throw error;\n console.warn(\n `transient status poll failure, retrying: ${error instanceof Error ? error.message : error}`,\n );\n }\n if (status && (status.state === \"complete\" || status.state === \"error\")) {\n break;\n }\n if (Date.now() > deadline) {\n postCommitStatus(\n repo,\n sha,\n \"failure\",\n \"visual review timed out waiting for compare — see report\",\n status?.reportUrl,\n );\n throw new Error(\"timed out waiting for the run to complete\");\n }\n await new Promise((resolve) => setTimeout(resolve, 5_000));\n }\n\n const verdict = describeGate(status.gate ?? {}, status.state);\n const publishError = status.lastPublishError;\n const publishFailing =\n publishError !== undefined &&\n publishError.revision >= (status.lastPublish?.revision ?? 0) &&\n status.statusPublishing === false;\n if (status.publisherConfigured && !publishFailing) {\n console.log(\n `verdict (${verdict.state}) owned by the Convex publisher — skipping CI status write`,\n );\n } else {\n if (publishFailing) {\n console.log(\n `Convex publisher reported a delivery failure (${publishError.error}) — writing the status from CI as a fallback`,\n );\n }\n postCommitStatus(\n repo,\n sha,\n verdict.state,\n verdict.description,\n status.reportUrl,\n );\n console.log(`commit status: ${verdict.state} — ${verdict.description}`);\n }\n\n if (args.pr) {\n upsertStickyComment(repo, args.pr, buildCommentBody(status));\n console.log(`sticky comment upserted on #${args.pr}`);\n }\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|