From 595e4d41280ac3a2e797b39f5c002b9510f1a07f Mon Sep 17 00:00:00 2001 From: Martijn Pieters Date: Mon, 17 Oct 2022 10:41:59 +0100 Subject: [PATCH] Produce test reports for test runs These will help surface flaky tests, and help PR authors see what tests are failing, if any. The workflow uses the really excellent [Publish Test Results][ptr] GitHub action to do all the heavy lifting. [ptr]: https://github.com/marketplace/actions/publish-test-results --- .config/nextest.toml | 7 +++ .github/workflows/coverage.yml | 2 +- .github/workflows/test-report.yml | 71 +++++++++++++++++++++++++++++++ .github/workflows/test.yml | 23 +++++++++- 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/test-report.yml diff --git a/.config/nextest.toml b/.config/nextest.toml index 9b13493..f6299c3 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -6,6 +6,7 @@ # - Call out every test as it finishes, including slow, skipped and flaky tests # - List failures again at the end. # - Run all tests even if some failed. +# - Output test results in JUnit format. [profile.ci] # "retries" defines the number of times a test should be retried. If set to a # non-zero value, tests that succeed on a subsequent attempt will be marked as @@ -32,6 +33,12 @@ failure-output = "immediate-final" # to false. fail-fast = false +[profile.ci.junit] +# Output a JUnit report into the given file inside 'store.dir/'. +# The default value for store.dir is 'target/nextest', so the following file +# is written to the target/nextest/ci/ directory. +path = "junit.xml" + # profile used in GitHub coverage runs # - lower retry count as a compromise between speed and resilience # - no fail-fast to at least keep coverage percentages accurate. diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3e4564d..42b27ef 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,4 +1,4 @@ -name: Test build +name: 'Test Coverage' on: push: diff --git a/.github/workflows/test-report.yml b/.github/workflows/test-report.yml new file mode 100644 index 0000000..e15e535 --- /dev/null +++ b/.github/workflows/test-report.yml @@ -0,0 +1,71 @@ +# This workflow makes it possible to publish test reports without running into +# permission issues when the test workflow was run from a fork or by Dependabot. +# +# The test workflow uploads a junit file per matrix target as an artifact, plus +# the worflow events file, both of which this worfklow buids upon. Note that +# the events file artifact, specifically, is expected to be named 'Event File'. +# +# See the [Publish Test Results action documentation][ptr] for more information. +# +# [ptr]: https://github.com/marketplace/actions/publish-test-results#support-fork-repositories-and-dependabot-branches + +name: 'Test Report' +on: + workflow_run: + workflows: ['Test Build'] + types: + - completed + +permissions: {} + +jobs: + test-results: + name: Test Results + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion != 'skipped' + + permissions: + checks: write + + # permission to comment on PRs + pull-requests: write + + # permission to download artifacts + actions: read + + steps: + - name: Download and extract artifacts + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: | + # Unzip all artifacts created by the triggering workflow into + # directories under an `artifacts/` directory. + # + # This uses `gh api` to output the name and URL for each artifact as + # tab-separated lines, then uses `read` to take each name and URL + # and download those to named zip files, and finally extracting those + # zip files into directories with matching names. + + mkdir -p artifacts && cd artifacts + + # The artifacts URL from the *triggering* test workflow, not *this* + # workflow. + artifacts_url=${{ github.event.workflow_run.artifacts_url }} + + gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact + do + IFS=$'\t' read name url <<< "$artifact" + gh api $url > "$name.zip" + unzip -d "$name" "$name.zip" + done + + # Run the publisher. Note that it is given the 'Event File' artifact + # created by the test workflow so it has the *original* webhook payload + # to base its context on. + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + with: + commit: ${{ github.event.workflow_run.head_sha }} + event_file: artifacts/Event File/event.json + event_name: ${{ github.event.workflow_run.event }} + junit_files: "artifacts/**/*.xml" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fe5382c..9db4dbd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Test build +name: 'Test Build' on: push: @@ -106,3 +106,24 @@ jobs: command: nextest args: run --workspace --target=${{ matrix.target }} use-cross: ${{ matrix.cross }} + + # The test result artifacts are used by the test-report.yaml workflow. + - name: upload test results + uses: actions/upload-artifact@v3 + if: ${{ !matrix.cross }} + with: + name: Test results (${{ matrix.target }}) + path: target/nextest/ci/junit.xml + + # the event file (containing the JSON payload for the webhook triggering this + # workflow) is needed to generate test result reports with the correct + # context. See the test-report.yaml workflow for details. + event_file: + name: "Event File" + runs-on: ubuntu-latest + steps: + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: Event File + path: ${{ github.event_path }}