From c48876cd22c39fac909ab97a3458f6e486a54df4 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Tue, 21 Jul 2026 19:18:16 +0700 Subject: [PATCH] ci(e2e): flag an advisory visual diff as a warning, not a mock-tier failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sticky PR comment took its header from the whole-workflow conclusion, so a visual-snapshot diff — advisory, never a required check — rendered a red ❌ over a "62 passed, 0 failed" mock-tier stats line, reading as a gate failure it isn't. Track the header on the mock gate instead (✅ pass / ❌ real failure) and surface a differing visual job as a separate ⚠️ line pointing at the diff artifact. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/e2e-report.yml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e-report.yml b/.github/workflows/e2e-report.yml index 3b8c8f34..23c3973a 100644 --- a/.github/workflows/e2e-report.yml +++ b/.github/workflows/e2e-report.yml @@ -59,22 +59,44 @@ jobs: } let statsLine = 'The run produced no results file (it likely failed before the tests started).'; + let mockPassed = false; try { const report = JSON.parse(fs.readFileSync('results/results.json', 'utf8')); const n = (value) => Number(value) || 0; const { expected, unexpected, flaky, skipped } = report.stats ?? {}; statsLine = `**${n(expected)} passed**, ${n(unexpected)} failed, ${n(flaky)} flaky, ${n(skipped)} skipped.`; + mockPassed = n(unexpected) === 0; } catch (error) { core.info(`results.json unavailable: ${error}`); } - const conclusion = run.conclusion === 'success' ? '✅' : '❌'; + // The visual job is advisory (never a required check), so the header must + // track the mock gate, not the whole-run conclusion — otherwise a visual-only + // diff reads as a mock failure over a "0 failed" stats line. + let visualDiffers = false; + try { + const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: run.id, + per_page: 100, + }); + visualDiffers = jobs.jobs.some((job) => /visual/.test(job.name) && job.conclusion === 'failure'); + } catch (error) { + core.info(`run jobs unavailable: ${error}`); + } + + const conclusion = !mockPassed ? '❌' : visualDiffers ? '⚠️' : '✅'; const marker = ''; + const advisoryLine = visualDiffers + ? '⚠️ **Visual snapshots differ** — advisory only, does not block merge. Download the `e2e-visual-diffs` artifact to compare expected / actual / diff.' + : null; const body = [ marker, `### ${conclusion} E2E (mock tier)`, '', statsLine, + ...(advisoryLine ? ['', advisoryLine] : []), '', `[Run + report/trace artifacts](${run.html_url}) · commit ${run.head_sha.slice(0, 7)}`, '',