mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-01 14:34:42 +01:00
* feat(flaky): gstack-flaky run reruns a failed JUnit test once and ledgers the flake (GSTA-158) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(flaky): stream output, keep unreported runner failures red, fail-closed duplicates and nonzero reruns Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes gstack-flaky never greens an incomplete run: a targeted rerun needs the runner's summary proving the first run complete, otherwise (and always for generic runners) the rerun repeats the whole command. A rerun clears a test only when it exits 0 and the test passes once on its first attempt. Killed runners exit 3 (FLAKY_COMMAND_KILLED) and signals are forwarded. The first report is restored at --junit with reruns kept beside it; ids are redacted at every output; the ledger gets its own GSTACK_FLAKE_LEDGER_JUNIT; fixtures are registered in FREE_FIXTURES. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: latch cancellation and check whole-command rerun reports A cancel forwarded to a runner that traps the signal now counts as killed for every later attempt, so a cancelled job is never rerun or greened. A whole-command rerun clears nothing when its report has a failed test, misses a first-run test, or its runner counted failures outside the report. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: whole-command rerun when coverage or runner-flaky tests can fail the run A coverage threshold or a fail-on-flaky policy fails a run for a reason a narrowed rerun cannot reproduce, so either forces a whole-command rerun. --junit refuses an existing file that is not a JUnit report instead of deleting it. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * feat(flaky): rerun the whole command by default; targeted rerun is opt-in A rerun counts only on the runner's own full green verdict: exit 0, no failed or missing test, nothing counted outside the report. That covers every way a run can fail, which a narrowed rerun cannot (a coverage threshold with an lcov reporter, a fail-on-flaky policy, a test never reached). --rerun-scope test reruns the failed test alone, with its preconditions documented and the complete-run checks kept as a safety net. An unreadable existing --junit file is a usage error, not a crash. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: gstack-flaky CHANGELOG entry and standalone-binaries row (GSTA-158) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
138 lines
6.3 KiB
XML
138 lines
6.3 KiB
XML
<testsuites id="" name="" tests="10" failures="4" skipped="2" errors="0" time="3.23467">
|
||
<testsuite name="a.spec.ts" timestamp="2026-10-29T16:02:06.214Z" hostname="alpha" tests="5" failures="2" skipped="1" time="0.03" errors="0">
|
||
<testcase name="group one › passes" classname="a.spec.ts" time="0.011">
|
||
</testcase>
|
||
<testcase name="group one › fails always" classname="a.spec.ts" time="0.004">
|
||
<system-out>
|
||
<![CDATA[
|
||
[[ATTACHMENT|pw/test-results/a-group-one-fails-always-alpha/error-context.md]]
|
||
]]>
|
||
</system-out>
|
||
<failure message="expect(received).toBe(expected) // Object.is equality" type="expect.toBe">
|
||
<![CDATA[ [alpha] › a.spec.ts:5:7 › group one › fails always ───────────────────────────────────────────────
|
||
|
||
Error: expect(received).toBe(expected) // Object.is equality
|
||
|
||
Expected: 2
|
||
Received: 1
|
||
|
||
3 | test.describe('group one', () => {
|
||
4 | test('passes', () => { expect(1).toBe(1); });
|
||
> 5 | test('fails always', () => { expect(1).toBe(2); });
|
||
| ^
|
||
6 | test('flaky once', ({}, info) => { const f = '/tmp/pwflake-' + info.project.name; if (!fs.existsSync(f)) { fs.writeFileSync(f, '1'); expect('first').toBe('second'); } });
|
||
7 | test.skip('skipped', () => {});
|
||
8 | test('title with $(rm -rf) [x] (y)? *', () => { expect(1).toBe(1); });
|
||
at /repo/tests/a.spec.ts:5:42
|
||
|
||
Error Context: ../test-results/a-group-one-fails-always-alpha/error-context.md
|
||
]]>
|
||
</failure>
|
||
</testcase>
|
||
<testcase name="group one › flaky once" classname="a.spec.ts" time="0.009">
|
||
<system-out>
|
||
<![CDATA[
|
||
[[ATTACHMENT|pw/test-results/a-group-one-flaky-once-alpha/error-context.md]]
|
||
]]>
|
||
</system-out>
|
||
<failure message="expect(received).toBe(expected) // Object.is equality" type="expect.toBe">
|
||
<![CDATA[ [alpha] › a.spec.ts:6:7 › group one › flaky once ─────────────────────────────────────────────────
|
||
|
||
Error: expect(received).toBe(expected) // Object.is equality
|
||
|
||
Expected: "second"
|
||
Received: "first"
|
||
|
||
4 | test('passes', () => { expect(1).toBe(1); });
|
||
5 | test('fails always', () => { expect(1).toBe(2); });
|
||
> 6 | test('flaky once', ({}, info) => { const f = '/tmp/pwflake-' + info.project.name; if (!fs.existsSync(f)) { fs.writeFileSync(f, '1'); expect('first').toBe('second'); } });
|
||
| ^
|
||
7 | test.skip('skipped', () => {});
|
||
8 | test('title with $(rm -rf) [x] (y)? *', () => { expect(1).toBe(1); });
|
||
9 | });
|
||
at /repo/tests/a.spec.ts:6:152
|
||
|
||
Error Context: ../test-results/a-group-one-flaky-once-alpha/error-context.md
|
||
]]>
|
||
</failure>
|
||
</testcase>
|
||
<testcase name="group one › skipped" classname="a.spec.ts">
|
||
<properties>
|
||
<property name="skip" value="">
|
||
</property>
|
||
</properties>
|
||
<skipped>
|
||
</skipped>
|
||
</testcase>
|
||
<testcase name="group one › title with $(rm -rf) [x] (y)? *" classname="a.spec.ts" time="0.006">
|
||
</testcase>
|
||
</testsuite>
|
||
<testsuite name="a.spec.ts" timestamp="2026-10-29T16:02:06.214Z" hostname="beta" tests="5" failures="2" skipped="1" time="0.027" errors="0">
|
||
<testcase name="group one › passes" classname="a.spec.ts" time="0.005">
|
||
</testcase>
|
||
<testcase name="group one › fails always" classname="a.spec.ts" time="0.002">
|
||
<system-out>
|
||
<![CDATA[
|
||
[[ATTACHMENT|pw/test-results/a-group-one-fails-always-beta/error-context.md]]
|
||
]]>
|
||
</system-out>
|
||
<failure message="expect(received).toBe(expected) // Object.is equality" type="expect.toBe">
|
||
<![CDATA[ [beta] › a.spec.ts:5:7 › group one › fails always ────────────────────────────────────────────────
|
||
|
||
Error: expect(received).toBe(expected) // Object.is equality
|
||
|
||
Expected: 2
|
||
Received: 1
|
||
|
||
3 | test.describe('group one', () => {
|
||
4 | test('passes', () => { expect(1).toBe(1); });
|
||
> 5 | test('fails always', () => { expect(1).toBe(2); });
|
||
| ^
|
||
6 | test('flaky once', ({}, info) => { const f = '/tmp/pwflake-' + info.project.name; if (!fs.existsSync(f)) { fs.writeFileSync(f, '1'); expect('first').toBe('second'); } });
|
||
7 | test.skip('skipped', () => {});
|
||
8 | test('title with $(rm -rf) [x] (y)? *', () => { expect(1).toBe(1); });
|
||
at /repo/tests/a.spec.ts:5:42
|
||
|
||
Error Context: ../test-results/a-group-one-fails-always-beta/error-context.md
|
||
]]>
|
||
</failure>
|
||
</testcase>
|
||
<testcase name="group one › flaky once" classname="a.spec.ts" time="0.013">
|
||
<system-out>
|
||
<![CDATA[
|
||
[[ATTACHMENT|pw/test-results/a-group-one-flaky-once-beta/error-context.md]]
|
||
]]>
|
||
</system-out>
|
||
<failure message="expect(received).toBe(expected) // Object.is equality" type="expect.toBe">
|
||
<![CDATA[ [beta] › a.spec.ts:6:7 › group one › flaky once ──────────────────────────────────────────────────
|
||
|
||
Error: expect(received).toBe(expected) // Object.is equality
|
||
|
||
Expected: "second"
|
||
Received: "first"
|
||
|
||
4 | test('passes', () => { expect(1).toBe(1); });
|
||
5 | test('fails always', () => { expect(1).toBe(2); });
|
||
> 6 | test('flaky once', ({}, info) => { const f = '/tmp/pwflake-' + info.project.name; if (!fs.existsSync(f)) { fs.writeFileSync(f, '1'); expect('first').toBe('second'); } });
|
||
| ^
|
||
7 | test.skip('skipped', () => {});
|
||
8 | test('title with $(rm -rf) [x] (y)? *', () => { expect(1).toBe(1); });
|
||
9 | });
|
||
at /repo/tests/a.spec.ts:6:152
|
||
|
||
Error Context: ../test-results/a-group-one-flaky-once-beta/error-context.md
|
||
]]>
|
||
</failure>
|
||
</testcase>
|
||
<testcase name="group one › skipped" classname="a.spec.ts">
|
||
<properties>
|
||
<property name="skip" value="">
|
||
</property>
|
||
</properties>
|
||
<skipped>
|
||
</skipped>
|
||
</testcase>
|
||
<testcase name="group one › title with $(rm -rf) [x] (y)? *" classname="a.spec.ts" time="0.007">
|
||
</testcase>
|
||
</testsuite>
|
||
</testsuites> |