From c15632a3771c587bcfc2a3927defc9593b6c23ea Mon Sep 17 00:00:00 2001 From: thc1006 <84045975+thc1006@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:26:42 +0800 Subject: [PATCH] Coverage that cannot report a green it did not earn Two parts of the coverage path report success while doing nothing. Both are in the logs of any recent run. The six matrix legs all uploaded an artifact named `coverage` with `overwrite: true`, which deletes the previous artifact rather than merging into it. Run 30461091931 shows `Artifact 'coverage' (ID: 8727950028) deleted` and then finalized again by a later leg, so five of the six reports were thrown away and the surviving one was whichever leg happened to finish last. Each leg now writes and uploads a report named after itself, and the upload job downloads all of them. The headline number was not far off, since all six legs land on 80%, but which platform's report reached Codecov was decided by a race, and code that only runs on one platform was counted or not depending on it. `files:` was a YAML block literal, so the name arrived as "coverage.xml\n" and was not found. The upload only worked because the uploader falls back to searching. That fallback is now unnecessary: the reports are in one directory, and the directory is what is passed. `fail_ci_if_error` is tied to whether a token was there to use. A pull request from a fork gets no secrets, and a contributor should not see red for that. What this does not fix: `CODECOV_TOKEN` resolves to empty on this repository, so the upload is still rejected with "Token required - not valid tokenless upload", and with no token the run stays green. Setting that secret is the last step and it needs repository admin. Once it is set, this workflow fails when an upload fails, without another change. Upstream RocketPy carries both of these unchanged. Happy to send the same patch there so it comes back through the usual sync. Verified: actionlint clean, `--cov-report=xml:` writes the named file, and `pattern` / `merge-multiple` / `directory` / `fail_ci_if_error` all exist as inputs on the pinned actions. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --- .github/workflows/test_pytest.yaml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test_pytest.yaml b/.github/workflows/test_pytest.yaml index 51c6febcf..2e7692cd9 100644 --- a/.github/workflows/test_pytest.yaml +++ b/.github/workflows/test_pytest.yaml @@ -61,14 +61,16 @@ jobs: run: pytest tests/integration --cov=rocketpy --cov-append - name: Run Acceptance Tests - run: pytest tests/acceptance --cov=rocketpy --cov-append --cov-report=xml + run: pytest tests/acceptance --cov=rocketpy --cov-append --cov-report=xml:coverage-${{ matrix.os }}-${{ matrix.python-version }}.xml - name: Upload coverage to artifacts uses: actions/upload-artifact@main with: - name: coverage - path: coverage.xml - overwrite: true + # One name per leg. Six legs sharing a name with overwrite deleted each + # other's artifact rather than merging, so five reports were discarded + # and the surviving one was whichever leg happened to finish last. + name: coverage-${{ matrix.os }}-${{ matrix.python-version }} + path: coverage-${{ matrix.os }}-${{ matrix.python-version }}.xml if-no-files-found: error CodecovUpload: @@ -76,11 +78,24 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@main - - name: Download latest coverage report + - name: Download every coverage report uses: actions/download-artifact@main + with: + pattern: coverage-* + merge-multiple: true + path: coverage-reports + - name: Refuse to upload nothing + # `ls` exits non-zero on no match. Without this the upload has nothing to + # send and still reports success, which is the failure being fixed here. + run: ls coverage-reports/*.xml - name: Upload to Codecov uses: codecov/codecov-action@main with: token: ${{ secrets.CODECOV_TOKEN }} - files: | - coverage.xml + # A directory rather than a filename: there is one report per matrix + # leg now. The previous block literal passed "coverage.xml\n", which was + # not found, and only the fallback search made the upload work at all. + directory: coverage-reports + # Only fail when a token was there to use. Pull requests from forks get + # no secrets, and a contributor should not see red for that. + fail_ci_if_error: ${{ secrets.CODECOV_TOKEN != '' }}