diff --git a/package.json b/package.json
index b4edd9ed58..eb889d6842 100644
--- a/package.json
+++ b/package.json
@@ -181,6 +181,7 @@
"@emotion/server": "^11.11.0",
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
"@madccc/duplicate-package-checker-webpack-plugin": "^1.0.0",
+ "@microflash/rehype-figure": "^2.1.0",
"@npmcli/run-script": "^7.0.4",
"@octokit/rest": "^20.1.0",
"@qixian.cs/github-contributors-list": "^2.0.1",
@@ -314,13 +315,14 @@
"react-router-dom": "^6.22.3",
"react-sticky-box": "^2.0.5",
"regenerator-runtime": "^0.14.1",
+ "rehype-stringify": "^10.0.0",
"remark": "^15.0.1",
"remark-cli": "^12.0.0",
"remark-gfm": "^4.0.0",
- "remark-html": "^16.0.1",
"remark-lint": "^9.1.2",
"remark-lint-no-undefined-references": "^4.2.1",
"remark-preset-lint-recommended": "^6.1.3",
+ "remark-rehype": "^11.1.0",
"runes2": "^1.1.4",
"semver": "^7.6.0",
"sharp": "^0.33.3",
diff --git a/scripts/visual-regression/build.ts b/scripts/visual-regression/build.ts
index df62573031..5ece812f8c 100644
--- a/scripts/visual-regression/build.ts
+++ b/scripts/visual-regression/build.ts
@@ -6,17 +6,17 @@ import os from 'os';
import path from 'path';
import { Readable } from 'stream';
import { finished } from 'stream/promises';
+import simpleGit from 'simple-git';
import chalk from 'chalk';
import fse from 'fs-extra';
import difference from 'lodash/difference';
import minimist from 'minimist';
import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';
-import { remark } from 'remark';
-import remarkGfm from 'remark-gfm';
-import remarkHtml from 'remark-html';
import sharp from 'sharp';
+import markdown2Html from './convert';
+
const ROOT_DIR = process.cwd();
const ALI_OSS_BUCKET = 'antd-visual-diff';
@@ -119,36 +119,100 @@ async function downloadBaseSnapshots(ref: string, targetDir: string) {
});
}
+interface IImageDesc {
+ src: string;
+ alt: string;
+}
+
+function getMdImageTag(desc: IImageDesc, extraCaption?: boolean) {
+ const { src, alt } = desc;
+ if (!extraCaption || !alt) {
+ // in md2html report, we use `@microflash/rehype-figure` to generate a figure
+ return ``;
+ }
+ // show caption with image in github markdown comment
+ return ` ${alt}`;
+}
+
interface IBadCase {
type: 'removed' | 'changed';
filename: string;
+ /**
+ * compare target file
+ */
+ targetFilename?: string;
/**
* 0 - 1
*/
weight: number;
}
-function md2Html(md: string) {
- return remark().use(remarkGfm).use(remarkHtml).processSync(md).toString();
-}
+const git = simpleGit();
-function parseArgs() {
+async function parseArgs() {
// parse args from -- --pr-id=123 --base_ref=feature
const argv = minimist(process.argv.slice(2));
const prId = argv['pr-id'];
assert(prId, 'Missing --pr-id');
const baseRef = argv['base-ref'];
assert(baseRef, 'Missing --base-ref');
+
+ const { latest } = await git.log();
+
return {
prId,
baseRef,
+ currentRef: latest?.hash.slice(0, 8) || '',
};
}
+function generateLineReport(
+ badCase: IBadCase,
+ publicPath: string,
+ currentRef: string,
+ extraCaption?: boolean,
+) {
+ const { filename, type, targetFilename } = badCase;
+
+ let lineHTMLReport = '';
+ if (type === 'changed') {
+ lineHTMLReport += '| ';
+ lineHTMLReport += [
+ // add ref as query to avoid github cache image object
+ getMdImageTag({
+ src: `${publicPath}/images/base/${filename}?ref=${currentRef}`,
+ alt: targetFilename || '',
+ }, extraCaption),
+ getMdImageTag({
+ src: `${publicPath}/images/current/${filename}?ref=${currentRef}`,
+ alt: filename,
+ }, extraCaption),
+ getMdImageTag({
+ src: `${publicPath}/images/diff/${filename}?ref=${currentRef}`,
+ alt: '',
+ }, extraCaption),
+ ].join(' | ');
+ lineHTMLReport += ' |\n';
+ } else if (type === 'removed') {
+ lineHTMLReport += '| ';
+ lineHTMLReport += [
+ getMdImageTag({
+ src: `${publicPath}/images/base/${filename}?ref=${currentRef}`,
+ alt: targetFilename || '',
+ }, extraCaption),
+ `⛔️⛔️⛔️ Missing ⛔️⛔️⛔️`,
+ `🚨🚨🚨 Removed 🚨🚨🚨`,
+ ].join(' | ');
+ lineHTMLReport += ' |\n';
+ }
+ return lineHTMLReport;
+}
+
function generateReport(
badCases: IBadCase[],
targetBranch: string,
targetRef: string,
+ currentRef: string,
prId: string,
): [string, string] {
const reportDirname = path.basename(REPORT_DIR);
@@ -174,15 +238,15 @@ function generateReport(
'',
].join('\n');
- return [mdStr, md2Html(mdStr)];
+ return [mdStr, markdown2Html(mdStr)];
}
let reportMdStr = `
${commonHeader}
${fullReport}
-| Image name | Expected | Actual | Diff |
-| --- | --- | --- | --- |
+| Expected (Branch ${targetBranch}) | Actual (Current PR) | Diff |
+| --- | --- | --- |
`.trim();
reportMdStr += '\n';
@@ -192,44 +256,33 @@ ${fullReport}
let diffCount = 0;
for (const badCase of badCases) {
- const { filename, type } = badCase;
- let lineReportMdStr = '';
- if (type === 'changed') {
- lineReportMdStr += '| ';
- lineReportMdStr += [
- `\`${badCase.filename}\``,
- ``,
- ``,
- ``,
- ].join(' | ');
- lineReportMdStr += ' |\n';
- } else if (type === 'removed') {
- lineReportMdStr += '| ';
- lineReportMdStr += [
- `\`${badCase.filename}\``,
- ``,
- `⛔️⛔️⛔️ Missing ⛔️⛔️⛔️`,
- `🚨🚨🚨 Removed 🚨🚨🚨`,
- ].join(' | ');
- lineReportMdStr += ' |\n';
- }
-
diffCount += 1;
if (diffCount <= 10) {
- reportMdStr += lineReportMdStr;
+ // 将图片下方增加文件名
+ reportMdStr += generateLineReport(
+ badCase,
+ publicPath,
+ currentRef,
+ true,
+ );
}
- fullVersionMd += lineReportMdStr;
+ fullVersionMd += generateLineReport(
+ badCase,
+ publicPath,
+ currentRef,
+ false,
+ );
}
reportMdStr += addonFullReportDesc;
// convert fullVersionMd to html
- return [reportMdStr, md2Html(fullVersionMd)];
+ return [reportMdStr, markdown2Html(fullVersionMd)];
}
async function boot() {
- const { prId, baseRef: targetBranch = 'master' } = parseArgs();
+ const { prId, baseRef: targetBranch = 'master', currentRef } = await parseArgs();
const baseImgSourceDir = path.resolve(ROOT_DIR, `./imageSnapshots-${targetBranch}`);
@@ -324,6 +377,7 @@ async function boot() {
badCases.push({
type: 'changed',
filename: compareImgName,
+ targetFilename: baseImgName,
weight: mismatchedPxPercent,
});
} else {
@@ -340,6 +394,7 @@ async function boot() {
badCases,
targetBranch,
targetCommitSha,
+ currentRef,
prId,
);
await fse.writeFile(path.join(REPORT_DIR, './report.md'), reportMdStr);
diff --git a/scripts/visual-regression/convert.ts b/scripts/visual-regression/convert.ts
new file mode 100644
index 0000000000..7105767a88
--- /dev/null
+++ b/scripts/visual-regression/convert.ts
@@ -0,0 +1,17 @@
+/* eslint-disable compat/compat */
+/* eslint-disable no-console, no-await-in-loop, import/no-extraneous-dependencies, no-restricted-syntax */
+import { remark } from 'remark';
+import remarkGfm from 'remark-gfm';
+import remarkRehype from 'remark-rehype';
+import rehypeStringify from 'rehype-stringify';
+import rehypeFigure from '@microflash/rehype-figure';
+
+export default function markdown2Html(content: string) {
+ return remark()
+ .use(remarkGfm)
+ .use(remarkRehype)
+ .use(rehypeFigure)
+ .use(rehypeStringify)
+ .processSync(content)
+ .toString();
+}
diff --git a/scripts/visual-regression/report-template.html b/scripts/visual-regression/report-template.html
index 34f36beb7f..a523870703 100644
--- a/scripts/visual-regression/report-template.html
+++ b/scripts/visual-regression/report-template.html
@@ -12,6 +12,16 @@
padding-bottom: 16px;
}
+ /* figcaption */
+ figcaption {
+ color: #a3a3a3;
+ text-align: center;
+ }
+
+ figure {
+ cursor: pointer;
+ }
+
/* Table Styles */
table {
width: 100%;
@@ -33,12 +43,7 @@
th,
td {
- width: 10%;
- }
-
- th+th,
- td+td {
- width: 30%;
+ width: 33%;
}
th {
@@ -89,6 +94,22 @@