Merge pull request #422 from pikasTech/fix/live-builds-no-reports

fix: 收束 live 构建时间 metadata 来源
This commit is contained in:
Lyon
2026-05-24 12:30:24 +08:00
committed by GitHub
6 changed files with 222 additions and 134 deletions
+56 -4
View File
@@ -1071,7 +1071,7 @@ export async function runDevCloudWorkbenchLayoutSmoke(args = {}) {
const server = useLiveUrl
? null
: await startStaticWebServer({ rootDir: args.build === true ? path.join(webRoot, "dist") : webRoot });
: await startStaticWebServer({ rootDir: args.build === true ? path.join(webRoot, "dist") : webRoot, liveBuildsFixture: true });
const url = useLiveUrl ? args.url : server.url;
let browser;
try {
@@ -3198,7 +3198,7 @@ async function inspectLiveDom(url, options = {}) {
/hwlab-agent-worker/u.test(dom.liveBuildDetailWhenOpen.text) &&
/构建时间不可用/u.test(dom.liveBuildDetailWhenOpen.text) &&
/外部镜像或非 HWLAB 构建产物/u.test(dom.liveBuildDetailWhenOpen.text) &&
/来源 health metadata/u.test(dom.liveBuildDetailWhenOpen.text) &&
/来源 live health/u.test(dom.liveBuildDetailWhenOpen.text) &&
dom.firstViewportForbiddenPresent.length === 0 &&
dom.labelsPresent &&
dom.navLabelsPresent &&
@@ -5394,6 +5394,10 @@ async function startStaticWebServer(options = {}) {
if (options.agentFixture && await handleLocalAgentFixtureApi({ request, response, url, options })) {
return;
}
if (options.liveBuildsFixture && request.method === "GET" && url.pathname === "/v1/live-builds") {
jsonResponse(response, 200, liveBuildsFixturePayload());
return;
}
let pathname = decodeURIComponent(url.pathname);
if (pathname === "/" || pathname === "/workbench" || pathname === "/gate" || pathname === "/diagnostics/gate" || pathname === "/help") {
pathname = "/index.html";
@@ -5783,7 +5787,7 @@ function liveBuildsFixturePayload() {
contractVersion: "live-builds-v1",
observedAt: "2026-05-23T00:30:00.000Z",
source: {
kind: "live-health+artifact-catalog",
kind: "live-health+deploy-artifact-catalog",
route: "/v1/live-builds",
healthPath: "/health/live"
},
@@ -5795,7 +5799,7 @@ function liveBuildsFixturePayload() {
build: {
createdAt: "2026-05-23T00:20:00.000Z",
metadataSource: "runtime-env:HWLAB_BUILD_CREATED_AT",
liveHealthMissingReason: "health payload 缺少 build.createdAt / image.createdAt / buildCreatedAt,已使用 repo-owned artifact metadata"
liveHealthMissingReason: "health payload 缺少 build.createdAt / image.createdAt / buildCreatedAt,已使用与 live tag/revision 匹配的 catalog metadata"
},
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-agent-mgr:f09ad05",
@@ -7494,6 +7498,52 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
return element ? element.scrollWidth <= element.clientWidth + 2 : false;
})()
};
const inspectLiveBuildLayout = async () => {
const details = document.querySelector("#live-build-summary");
const label = document.querySelector("#live-build-latest");
const list = document.querySelector("#live-build-list");
if (!details || !label || !list) {
return { ok: false, exists: false, summaryOverflowX: null, listOverflowX: null, maxRowOverflowX: null, rows: 0 };
}
const wasOpen = details.open;
const summaryOverflowX = Math.max(0, label.scrollWidth - label.clientWidth);
details.open = true;
await new Promise((resolve) => requestAnimationFrame(resolve));
const rows = [...list.querySelectorAll(".live-build-row")];
const rowOverflows = rows.map((row) => Math.max(0, row.scrollWidth - row.clientWidth));
const maxRowOverflowX = Math.max(0, ...rowOverflows);
const listOverflowX = Math.max(0, list.scrollWidth - list.clientWidth);
const scrollContained = list.clientHeight <= Math.ceil(window.innerHeight * 0.42) + 4;
const text = list.textContent?.replace(/\s+/gu, " ").trim() ?? "";
const expectedRows = rows.length >= 4;
const expectedText = /构建时间不可用/u.test(text) && /外部镜像或非 HWLAB 构建产物/u.test(text);
details.open = wasOpen;
await new Promise((resolve) => requestAnimationFrame(resolve));
return {
ok: summaryOverflowX <= 1 && listOverflowX <= 1 && maxRowOverflowX <= 1 && scrollContained && expectedRows && expectedText,
exists: true,
openStateRestored: details.open === wasOpen,
summaryOverflowX,
listOverflowX,
maxRowOverflowX,
rowOverflows,
rows: rows.length,
expectedRows,
expectedText,
scrollContained,
textSample: text.slice(0, 240)
};
};
const liveBuildLayout = await inspectLiveBuildLayout();
if (!liveBuildLayout.ok) {
failures.push({
failureType: "overflow",
selector: "#live-build-summary",
viewport,
summary: "Live build summary/details overflow or cannot be expanded within the viewport.",
liveBuildLayout
});
}
const hardwareTabRows = (() => {
const tabs = [...document.querySelectorAll("[data-hardware-tab]")];
return new Set(tabs.map((tab) => Math.round(tab.getBoundingClientRect().top))).size;
@@ -7816,6 +7866,7 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
rightWidthTarget &&
keyTargetsReachable &&
resourceExplorerRemovalGuard &&
liveBuildLayout.ok &&
sidePanelOverflowUsable;
const passWithWiring =
pass &&
@@ -7842,6 +7893,7 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
overlapChecks,
noHorizontalOverflow,
horizontalOverflowFree: Object.values(noHorizontalOverflow).every(Boolean),
liveBuildLayout,
hardwareTabRows,
rightWidthTarget,
noIncoherentOverlap,