mikepenz/action-junit-report
Publish JUnit XML results as a check run with PR annotations and a job summary.
What it does
mikepenz/action-junit-report reads JUnit-format XML reports and annotates failing tests directly on the pull request, so failures are visible without digging through logs.
It can also render a job summary, comment on the PR, track flaky (retried) tests, and expose pass/fail counts as outputs.
Usage
workflow (.yml)
permissions:
contents: read
checks: write
steps:
- uses: actions/checkout@v4
- run: ./gradlew test
- uses: mikepenz/action-junit-report@v6
if: ${{ !cancelled() }}
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
fail_on_failure: 'true'Inputs
| Input | Description | Default | Required |
|---|---|---|---|
report_paths | XML report paths in glob format. | **/junit-reports/TEST-*.xml | No |
check_name | Check name for test reports. | JUnit Test Report | No |
fail_on_failure | Fail the build in case a test failure occurred. | false | No |
require_tests | Fail if no tests are found. | false | No |
annotate_only | Only annotate the results on the files; do not create a check run. | false | No |
detailed_summary | Include a table with all test results in the summary. | false | No |
comment | Add a comment to the PR with the summary tables (summary has to be enabled). | false | No |
token | Token used to publish the check. | ${{ github.token }} | No |
Outputs
| Output | Description |
|---|---|
total | The total count of all checks. |
passed | The count of all passed tests. |
skipped | The count of all skipped tests. |
failed | The count of all failed tests. |
report_url | The URL(s) to the test report(s). |
Notes
The action does not fail the build by default, set fail_on_failure: true if the report step should gate the merge, and require_tests: true to catch silently-empty reports.
Run it with if: ${{ !cancelled() }} so reports publish even when the test step fails.
Common errors
Resource not accessible by integrationmeans the token cannot create check runs, addchecks: writetopermissions, or setannotate_only: true/ move to aworkflow_runworkflow for fork PRs.- An empty report usually means the default
report_pathsglob (**/junit-reports/TEST-*.xml) did not match your tool's output directory. Point it at the actual XML location, e.g.**/build/test-results/test/TEST-*.xmlfor Gradle.
Security and pinning
- Grant only
checks: writepluscontents: read; addpull-requests: writeonly if you enable thecommentinput. - Pin the action to a commit SHA, it receives a token that can write checks and PR comments.
Alternatives and related
dorny/test-reporterTurn test result files (JUnit, TRX, JSON) into a GitHub check run with annotations.
codecov/codecov-actionUpload test coverage reports to Codecov from a workflow.
actions/upload-artifactUpload files from a job so other jobs or a person can download them after the run.
Frequently asked questions
Why did my workflow stay green even though tests failed?
The reporter defaults to
fail_on_failure: false, so it only reports. Set fail_on_failure: true (and usually require_tests: true) to make the step fail with the tests.