From adc6469b91f36892288a61ff9e46bf483ce486bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Mon, 24 Aug 2026 16:31:21 -0400 Subject: [PATCH] Published the coverage report instead of everything the run produced (#655) The download step in deploy_code_coverage asked for the artifact named ${{ steps.artifact.outputs.coverage_report }}. That output is set by the "Coverage Report name" step of run_tests, which is a different job, and the steps context does not cross jobs. So the expression evaluated to the empty string and the action took its documented path for an unspecified name: No input name, artifact-ids or pattern filtered specified, downloading all artifacts Total of 4 artifact(s) downloaded The four are the two coverage reports and the two test_reports bundles of JUnit XML, each extracted into a directory named after the artifact. The next step uploads the lot to Pages, so the published site has carried the test reports alongside the coverage, one directory deeper than intended, under a path containing a run timestamp that changed on every publish. Any link to a coverage report broke the next time one was published. Selecting by pattern with merge-multiple fixes both halves: the pattern excludes the test_reports bundles, and merging puts the contents of the two coverage artifacts directly into coverage_report rather than under a directory named for each. Each artifact holds one directory named for its suite, renamed from default_build_coverage by "Prepare Coverage GitHub Pages", so the result is the two suite directories the deploy expects and the timestamped artifact name no longer appears in the published path. Verified on a runner rather than reasoned about, with an isolated workflow that uploads artifacts shaped like the real ones and downloads them both ways: OLD coverage_report/coverage_report--ThreadX/ThreadX/index.html coverage_report/coverage_report--ThreadX/default_build_coverage.xml coverage_report/coverage_report--SMP/SMP/index.html coverage_report/coverage_report--SMP/default_build_coverage.xml coverage_report/test_reports SMP/results.xml coverage_report/test_reports ThreadX/results.xml NEW coverage_report/ThreadX/index.html coverage_report/SMP/index.html coverage_report/default_build_coverage.xml Both artifacts carry a default_build_coverage.xml and the merge means one overwrites the other, which the run above also shows. That file is consumed by CodeCoverageSummary back in run_tests and is not read here, so it is untidy rather than wrong, and it is called out in a comment. The delete step is fixed in the same place and for a related reason. The artifacts are named coverage_report-, useGlob defaults to true in this action, and as a glob "coverage_report" matches only the literal string. It has been deleting nothing, without failing, and retention-days: 1 on the upload is what has actually been clearing these up. Assisted-by: Claude Opus 5 --- .github/workflows/regression_template.yml | 37 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/.github/workflows/regression_template.yml b/.github/workflows/regression_template.yml index 4f73cdd0..7f9f496f 100644 --- a/.github/workflows/regression_template.yml +++ b/.github/workflows/regression_template.yml @@ -178,10 +178,37 @@ jobs: id-token: write steps: + # Selects the coverage artifacts by pattern rather than by name. + # + # This used to ask for ${{ steps.artifact.outputs.coverage_report }}, + # which is set by the "Coverage Report name" step of run_tests -- a + # different job. The steps context does not cross jobs, so that + # expression evaluated to the empty string and the action fell back to + # its documented behaviour for an unspecified name: "No input name, + # artifact-ids or pattern filtered specified, downloading all + # artifacts". It pulled down four, the two coverage reports and the two + # test_reports bundles of JUnit XML, each into a directory named after + # the artifact -- so the published site carried the test reports as well + # as the coverage, under paths containing a run timestamp that changed + # on every publish. + # + # merge-multiple puts the contents of both coverage artifacts directly + # into coverage_report rather than under a directory named for each + # artifact. Each one holds a single directory named for its suite, + # ThreadX or SMP, renamed from default_build_coverage by the "Prepare + # Coverage GitHub Pages" step, so the merge yields exactly the two + # suite directories the deploy expects, and the artifact name -- with + # its timestamp -- stops appearing in the published path at all. + # + # The two artifacts also each carry a default_build_coverage.xml, and + # the merge means one overwrites the other. That file is consumed by + # CodeCoverageSummary back in run_tests and is not read here, so this is + # untidy rather than wrong. - uses: actions/download-artifact@v4.3.0 if: ${{ inputs.skip_test }} with: - name: ${{ steps.artifact.outputs.coverage_report }} + pattern: coverage_report-* + merge-multiple: true path: ${{ inputs.cmake_path }}/coverage_report - name: Upload Code Coverage Pages @@ -190,10 +217,16 @@ jobs: with: path: . + # The artifacts are named coverage_report- by run_tests, so the + # bare name matched nothing: useGlob defaults to true in this action, and + # as a glob "coverage_report" matches only the literal string. The step + # has therefore been deleting nothing. It does not fail on a miss, which + # is why that went unnoticed; retention-days: 1 on the upload is what has + # actually been clearing these up. - name: Delete Duplicate Code Coverage Artifact uses: geekyeggo/delete-artifact@v5.1.0 with: - name: coverage_report + name: coverage_report-* - name: Deploy GitHub Pages site id: deployment