Files
Josh Siviour 0e08b9d256 feat: ship per-test JUnit results to the Elasticsearch sink (#829)
* feat: ship per-test JUnit results to the Elasticsearch sink

Every e2e workflow already converts its test log to JUnit XML and renders
it into the job summary, then discards it with the artifact. mulga-ci-runs
records which suite failed; nothing records which test failed, so
root-causing a failure means reading raw Actions logs across historical
runs.

The junit-to-es action bulk-indexes one doc per leaf test case into
mulga-ci-test-results: name, subtest, status, duration, failure text, run
id, cell, suite, branch and sha. Parent t.Run wrappers are dropped so a
failing subtest counts once, matching the job summary renderer. The doc id
is deterministic, so a replayed post overwrites rather than
double-counting.

Called from every workflow that produces JUnit XML, and tolerated on
failure: an unreachable sink must not turn a green test run red.

* feat: classify unparsed JUnit cases as unknown, not error

go-junit-report emits <error message="No test result found"> when a
=== RUN line has no matching result line, which means the log it was fed
was truncated or filtered. Recording that as a failure would put 78
phantom failures per green bare-metal run into the pass rate.
2026-08-18 22:54:54 +10:00

44 lines
1.5 KiB
YAML

name: JUnit to Elasticsearch
description: >-
Bulk-index one doc per JUnit test case into the mulga Elasticsearch sink,
so per-test pass rates outlive the 90-day artifact retention. Call it once
per job right after the JUnit XML is produced (with `if: always()`), next to
the junit-report action that renders the same files into the job summary.
inputs:
junit-glob:
description: Shell glob matching the JUnit XML files to ship.
required: true
cell:
description: >-
Cell label stored as labels.ci_cell — the same value the job puts in
ci.cell for its OTel attributes (single, multi, gpu, ddil, 20, ...).
Without it, results from different topologies collapse into one bucket.
required: true
es-sink:
description: host:port of the Elasticsearch sink.
required: false
default: "192.168.1.13:9200"
index:
description: Target index.
required: false
default: mulga-ci-test-results
runs:
using: composite
steps:
- shell: bash
env:
JUNIT_GLOB: ${{ inputs.junit-glob }}
JUNIT_CELL: ${{ inputs.cell }}
MULGA_ES_SINK: ${{ inputs.es-sink }}
ES_INDEX: ${{ inputs.index }}
RUN_ID: ${{ github.run_id }}
RUN_ATTEMPT: ${{ github.run_attempt }}
WORKFLOW: ${{ github.workflow }}
BRANCH: ${{ github.head_ref || github.ref_name }}
SHA: ${{ github.sha }}
ARTIFACT_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
python3 "${{ github.action_path }}/ship.py"