From 147b20ba22a02be72fb77284c4cc993f46e19e8a Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Thu, 25 Jun 2026 18:46:09 +0000 Subject: [PATCH 1/3] ci: test-job-summary: drop stale re-run jobs from test summary When a failed LAVA job is re-run, GitHub keeps the original failed job's "-test-job-" artifact and adds a new artifact for the re-submitted job, which LAVA assigns a fresh, higher id. The summary step downloads every matching artifact, so the stale failed job was counted again and the PR comment reported phantom failures (e.g. "Fail: 1") even after a fully green re-run. Because multiple boot jobs for one device were merged in non-deterministic find(1) order, the reported count was unstable too. De-duplicate to the newest LAVA job (highest id) per (requested_device_type, description) before counting. That pair is stable across re-runs of the same job and is read directly from the saved job-detail JSON, so no extra LAVA API calls are needed. The same de-duplicated list now drives both the pass/fail table and the "All jobs summary" table so they always agree. The EnricoMi "Test Results" check is unaffected: it parses the deterministically named result artifacts, which are overwritten on re-run, so it already reflected the latest result. This change brings the comment into agreement with it. Signed-off-by: Ricardo Salveti --- .github/actions/test-job-summary/action.yml | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/actions/test-job-summary/action.yml b/.github/actions/test-job-summary/action.yml index cd30f1851..732fb7af4 100644 --- a/.github/actions/test-job-summary/action.yml +++ b/.github/actions/test-job-summary/action.yml @@ -45,7 +45,28 @@ runs: INPUTS_SUMMARY_TITLE: ${{ inputs.summary_title }} run: | set -x - INPUT=$(for TESTJOB in $(find "${GITHUB_WORKSPACE}" -name "${INPUTS_PREFIX}.json") + # When a failed LAVA job is re-run, GitHub keeps the original failed + # job's "-test-job-" artifact AND adds a new artifact for the + # re-submitted job (LAVA assigns a fresh, higher id). Both get downloaded + # here, so without de-duplication the stale failed job is counted again + # and the summary reports phantom failures even after a green re-run. + # Keep only the newest LAVA job (highest id) per device + test, keyed by + # (requested_device_type, description) which is stable across re-runs of + # the same job. The fields are read from the saved job-detail JSON. + declare -A KEEP_FILE + declare -A KEEP_ID + for TESTJOB in $(find "${GITHUB_WORKSPACE}" -name "${INPUTS_PREFIX}.json") + do + KEY=$(jq -r '"\(.requested_device_type)@@\(.description)"' "${TESTJOB}") + JOB_ID=$(jq -r '.id' "${TESTJOB}") + if [ -z "${KEEP_ID[$KEY]:-}" ] || [ "${JOB_ID}" -gt "${KEEP_ID[$KEY]}" ]; then + KEEP_ID["$KEY"]="${JOB_ID}" + KEEP_FILE["$KEY"]="${TESTJOB}" + fi + done + TESTJOBS=$(printf '%s\n' "${KEEP_FILE[@]}") + + INPUT=$(for TESTJOB in ${TESTJOBS} do JOB_ID=$(cat "$TESTJOB" | jq ".id") JOB_URL="https://lava.infra.foundries.io/results/$JOB_ID" @@ -148,7 +169,7 @@ runs: echo "" >> "${INPUTS_SUMMARY_FILE_NAME}" echo "| Job ID | Device | State | Health |" >> "${INPUTS_SUMMARY_FILE_NAME}" echo "| ---- | ---- | ---- | ---- |" >> "${INPUTS_SUMMARY_FILE_NAME}" - for TESTJOB in $(find "${GITHUB_WORKSPACE}" -name "${INPUTS_PREFIX}.json") + for TESTJOB in ${TESTJOBS} do JOB_ID=$(cat "${TESTJOB}" | jq ".id") JOB_URL="https://lava.infra.foundries.io/results/$JOB_ID" From 99ba458dbf54e1caf6212e792dda7c0881411c8b Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Thu, 25 Jun 2026 18:46:09 +0000 Subject: [PATCH 2/3] ci: test-pr: report only the current PR head on re-runs Test reporting is decoupled from the build via workflow_run and the LAVA jobs run for hours, so when a PR is updated or force-pushed the in-flight test run keeps publishing the "Test Results" check and a PR comment for an orphaned commit. The result is a red check and stale comments on the PR head while a separate, green run exists for a commit that is no longer part of the branch. Add a concurrency group keyed on the PR head (head repository and branch) with cancel-in-progress, so a newer build supersedes the older test run instead of both reporting in parallel. Re-running failed jobs on an existing run keeps the same run id and is therefore not cancelled. Tag the bot comment with comment-tag so a single comment is updated in place per PR rather than a new one being posted on every run, which previously accumulated multiple comments for different commits. The "## Test jobs for commit " header is kept so the comment always shows which commit it reflects. Signed-off-by: Ricardo Salveti --- .github/workflows/test-pr.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index 68e601966..d82d183ee 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -8,6 +8,15 @@ on: types: - completed +# Cancel an in-flight test run for a PR when a newer commit (re)triggers the +# build. This stops an orphaned commit's run from continuing to publish the +# "Test Results" check and PR comment after the PR head has moved on, so the +# only surviving results belong to the current head. Re-running failed jobs on +# an existing run keeps the same run id and is therefore not cancelled. +concurrency: + group: test-pr-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: true + permissions: checks: write pull-requests: write @@ -93,6 +102,10 @@ jobs: with: file-path: pr-comment.txt pr-number: ${{ steps.pr_comment_prep.outputs.pr_number }} + # Update a single tagged comment per PR instead of posting a new one on + # every run, so the PR shows one current result instead of accumulating + # stale comments (one per run / per superseded commit). + comment-tag: test-results publish-test-results: uses: ./.github/workflows/publish-results.yml From b648deb7d139f029d4603b46b26ef859dc3ce13f Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Tue, 7 Jul 2026 19:33:38 +0000 Subject: [PATCH 3/3] ci: test-job-summary: report test results from Incomplete jobs LAVA test jobs that finish with health Incomplete (e.g. the device crashed or timed out partway through the run) still carry valid test results for everything that ran before the failure, but the summary only fetched suite results for jobs that were both Finished and Complete, discarding Incomplete test jobs entirely. This is worse now that stale re-run artifacts are de-duplicated to the newest LAVA job per device and test: if that newest job ends up Incomplete, the device would show no results at all and its failures would silently disappear from the summary. Require only the Finished state for test jobs so their partial results are reported; boot jobs keep the Complete requirement as their health is the result. Suggested-by: Milosz Wasilewski Signed-off-by: Ricardo Salveti --- .github/actions/test-job-summary/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/test-job-summary/action.yml b/.github/actions/test-job-summary/action.yml index 732fb7af4..ae191d516 100644 --- a/.github/actions/test-job-summary/action.yml +++ b/.github/actions/test-job-summary/action.yml @@ -84,7 +84,7 @@ runs: TEST_RESULTS=$(for SUITE in $(echo "$JOB_SUITES" | jq -r -c ".results[]") do if [ "${JOB_TYPE}" = "test" ]; then - if [ "${JOB_STATE}" = "Finished" ] && [ ${JOB_HEALTH} = "Complete" ]; then + if [ "${JOB_STATE}" = "Finished" ]; then SUITE_NAME=$(echo "$SUITE" | jq -r ".name") SUITE_ID=$(echo "$SUITE" | jq -r ".id") SUITE_TESTS=$(curl -s "https://lava.infra.foundries.io/api/v0.2/jobs/$JOB_ID/suites/$SUITE_ID/tests/")