{"id":18952274,"url":"https://github.com/step-security/publish-unit-test-result-action","last_synced_at":"2026-04-24T20:07:08.263Z","repository":{"id":209994595,"uuid":"725422432","full_name":"step-security/publish-unit-test-result-action","owner":"step-security","description":"GitHub Action to publish unit test results on GitHub","archived":false,"fork":false,"pushed_at":"2025-02-14T05:52:45.000Z","size":1484,"stargazers_count":0,"open_issues_count":22,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-14T06:30:20.719Z","etag":null,"topics":["step-security-maintained-actions"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/step-security.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-30T05:25:26.000Z","updated_at":"2024-11-19T10:46:35.000Z","dependencies_parsed_at":"2024-01-10T21:28:14.851Z","dependency_job_id":"91b9cad6-33e2-47ce-a39e-85331c0cb7da","html_url":"https://github.com/step-security/publish-unit-test-result-action","commit_stats":null,"previous_names":["step-security/publish-unit-test-result-action"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/step-security%2Fpublish-unit-test-result-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/step-security%2Fpublish-unit-test-result-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/step-security%2Fpublish-unit-test-result-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/step-security%2Fpublish-unit-test-result-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/step-security","download_url":"https://codeload.github.com/step-security/publish-unit-test-result-action/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239951621,"owners_count":19723910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["step-security-maintained-actions"],"created_at":"2024-11-08T13:32:29.477Z","updated_at":"2026-04-24T20:07:08.256Z","avatar_url":"https://github.com/step-security.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![StepSecurity Maintained Action](https://raw.githubusercontent.com/step-security/maintained-actions-assets/main/assets/maintained-action-banner.png)](https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions)\n\n# StepSecurity Maintained `publish-unit-test-result-action` Action\n\nForked from [EnricoMi/publish-unit-test-result-action](https://github.com/EnricoMi/publish-unit-test-result-action)\n\nThis [GitHub Action](https://github.com/actions) analyses test result files and\npublishes the results on GitHub. It supports [JSON (Dart, Mocha), TRX (MSTest, VS) and XML (JUnit, NUnit, XUnit) file formats](#generating-test-result-files),\nand runs on Linux, macOS and Windows.\n\nYou can use this action with ![Ubuntu Linux](misc/badge-ubuntu.svg) runners (e.g. `runs-on: ubuntu-latest`)\nor ![ARM Linux](misc/badge-arm.svg) self-hosted runners that support Docker:\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  if: (!cancelled())\n  with:\n    files: |\n      test-results/**/*.xml\n      test-results/**/*.trx\n      test-results/**/*.json\n```\n\nSee the [notes on running this action with absolute paths](#running-with-absolute-paths) if you cannot use relative test result file paths.\n\nUse this for ![macOS](misc/badge-macos.svg) (e.g. `runs-on: macos-latest`) runners (no Docker needed):\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/macos@v2\n  if: (!cancelled())\n  with:\n    files: …\n```\n\n… and ![Windows](misc/badge-windows.svg) (e.g. `runs-on: windows-latest`) runners (no Docker needed):\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/windows@v2\n  if: (!cancelled())\n  with:\n    files: …\n```\n\nFor Windows **without PowerShell** installed, there is the Bash shell variant:\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/windows/bash@v2\n  if: (!cancelled())\n  with:\n    files: …\n```\n\nFor **self-hosted** Linux GitHub Actions runners **without Docker** installed, please use:\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/linux@v2\n  if: (!cancelled())\n  with:\n    files: …\n```\n\nSee the [notes on running this action as a non-Docker action](#running-as-a-non-docker-action).\n\nIf you see the `\"Resource not accessible by integration\"` error, you have to grant additional [permissions](#permissions), or\n[setup the support for pull requests from fork repositories and branches created by Dependabot](#support-fork-repositories-and-dependabot-branches).\n\nThe `if: (!cancelled())` clause guarantees that this action always runs, even if earlier steps (e.g., the test step) in your workflow fail,\nbut not if the workflow was cancelled.\n\nWhen run multiple times in one workflow, the [option](#configuration) `check_name` has to be set to a unique value for each instance.\nOtherwise, the multiple runs overwrite each other's results.\n\n***Note:** By default, this action does not fail if tests failed. This can be [configured](#configuration) via `action_fail`.\nThe action that executed the tests should fail on test failure. The published results however indicate failure if tests fail or errors occur,\nwhich can be [configured](#configuration) via `fail_on`.*\n\nThanks to the provided [typings](action-types.yml), it is possible to use this action in a type-safe way using\n[GitHub Workflows Kt](https://github.com/typesafegithub/github-workflows-kt), which allows writing workflow files using a type-safe Kotlin DSL.\n\n## Permissions\n\nMinimal [workflow job permissions](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs#example-setting-permissions-for-a-specific-job)\nrequired by this action in **public** GitHub repositories are:\n\n```yaml\npermissions:\n  checks: write\n  pull-requests: write\n```\n\nThe following permissions are required in **private** GitHub repos:\n\n```yaml\npermissions:\n  contents: read\n  issues: read\n  checks: write\n  pull-requests: write\n```\n\nWith `comment_mode: off`, the `pull-requests: write` permission is not needed.\n\n## Generating test result files\n\nSupported test result files can be generated by many test environments. Here is a small overview, by far not complete.\nCheck your favorite development and test environment for its JSON, TRX file or JUnit, NUnit, XUnit XML file support.\n\n|Test Environment |Language| JUnit\u003cbr/\u003eXML | NUnit\u003cbr/\u003eXML | XUnit\u003cbr/\u003eXML | TRX\u003cbr/\u003efile | JSON\u003cbr/\u003efile |\n|-----------------|:------:|:---------:|:---------:|:---------:|:---:|:---:|\n|[Dart](https://github.com/dart-lang/test/blob/master/pkgs/test/doc/json_reporter.md)|Dart, Flutter| | | | |:white_check_mark:|\n|[Jest](https://jestjs.io/docs/configuration#default-reporter)|JavaScript|:white_check_mark:| | | | |\n|[Maven](https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html)|Java, Scala, Kotlin|:white_check_mark:| | | | |\n|[Mocha](https://mochajs.org/#xunit)|JavaScript|:white_check_mark:| |[not xunit](https://github.com/mochajs/mocha/issues/4758)| |:white_check_mark:|\n|[MStest / dotnet](https://github.com/Microsoft/vstest-docs/blob/main/docs/report.md#syntax-of-default-loggers)|.Net|[:white_check_mark:](https://github.com/spekt/junit.testlogger#usage)|[:white_check_mark:](https://github.com/spekt/nunit.testlogger#usage)|[:white_check_mark:](https://github.com/spekt/xunit.testlogger#usage)|[:white_check_mark:](https://github.com/Microsoft/vstest-docs/blob/main/docs/report.md#syntax-of-default-loggers)| |\n|[pytest](https://docs.pytest.org/en/latest/how-to/output.html#creating-junitxml-format-files)|Python|:white_check_mark:| | | | |\n|[sbt](https://www.scala-sbt.org/release/docs/Testing.html#Test+Reports)|Scala|:white_check_mark:| | | | |\n|Your favorite\u003cbr/\u003eenvironment|Your favorite\u003cbr/\u003elanguage|probably\u003cbr/\u003e:white_check_mark:| | | | |\n\n## What is new in version 2\n\n\u003cdetails\u003e\n\u003csummary\u003eThese changes have to be considered when moving from version 1 to version 2:\u003c/summary\u003e\n\n### Default value for `check_name` changed\nUnless `check_name` is set in your config, the check name used to publish test results changes from `\"Unit Test Results\"` to `\"Test Results\"`.\n\n**Impact:**\nThe check with the old name will not be updated once moved to version 2.\n\n**Workaround to get version 1 behaviour:**\nAdd `check_name: \"Unit Test Results\"` to your config.\n\n### Default value for `comment_title` changed\nUnless `comment_title` or `check_name` are set in your config, the title used to comment on open pull requests changes from `\"Unit Test Results\"` to `\"Test Results\"`.\n\n**Impact:**\nExisting comments with the old title will not be updated once moved to version 2, but a new comment is created.\n\n**Workaround to get version 1 behaviour:**\nSee workaround for `check_name`.\n\n### Modes `create new` and `update last` removed for option `comment_mode`\nThe action always updates an earlier pull request comment, which is the exact behaviour of mode `update last`.\nThe [configuration](#configuration) options `create new` and `update last` are therefore removed.\n\n**Impact:**\nAn existing pull request comment is always updated.\n\n**Workaround to get version 1 behaviour:**\nNot supported.\n\n### Option `hiding_comments` removed\nThe action always updates an earlier pull request comment, so hiding comments is not required anymore.\n\n### Option `comment_on_pr` removed\nOption `comment_on_pr` has been removed.\n\n**Workaround to get version 1 behaviour:**\nSet `comment_mode` to `always` (the default) or `off`.\n\n\u003c/details\u003e\n\n\n## Publishing test results\n\nTest results are published on GitHub at various ([configurable](#configuration)) places:\n\n- as [a comment](#pull-request-comment) in related pull requests\n- as [a check](#commit-and-pull-request-checks) in the checks section of a commit and related pull requests\n- as [annotations](#commit-and-pull-request-annotations) in the checks section and changed files section of a commit and related pull requests\n- as [a job summary](#github-actions-job-summary) of the GitHub Actions workflow\n- as [a check summary](#github-actions-check-summary-of-a-commit) in the GitHub Actions section of the commit\n\n### Pull request comment\n\nA comment is posted on pull requests related to the commit.\n\n![pull request comment example](misc/github-pull-request-comment.png)\n\nIn presence of failures or errors, the comment links to the respective [check summary](#github-actions-check-summary-of-a-commit) with failure details.\n\nSubsequent runs of the action will update this comment. You can access earlier results in the comment edit history:\n\n![pull request comment history example](misc/github-pull-request-comment-update-history.png)\n\nThe result distinguishes between tests and runs. In some situations, tests run multiple times,\ne.g. in different environments. Displaying the number of runs allows spotting unexpected\nchanges in the number of runs as well.\n\nWhen tests run only a single time, no run information is displayed. Results are then shown differently then:\n\n![pull request comment example without runs](misc/github-pull-request-comment-without-runs.png)\n\nThe change statistics (e.g. 5 tests ±0) might sometimes hide test removal.\nThose are highlighted in pull request comments to easily spot unintended test removal:\n\n![pull request comment example with test changes](misc/github-pull-request-comment-with-test-changes.png)\n\n***Note:** This requires `check_run_annotations` to be set to `all tests, skipped tests`.*\n\nComments can be disabled with `comment_mode: off`.\n\n### Commit and pull request checks\n\nThe checks section of a commit and related pull requests list a short summary (here `1 fail, 1 skipped, …`),\nand a link to the [check summary](#github-actions-check-summary-of-a-commit) in the GitHub Actions section (here `Details`):\n\nCommit checks:\n\n![commit checks example](misc/github-checks-commit.png)\n\nPull request checks:\n\n![pull request checks example](misc/github-pull-request-checks.png)\n\nCheck runs can be disabled with `check_run: false`.\n\n### Commit and pull request annotations\n\nEach failing test produces an annotation with failure details in the checks section of a commit:\n\n![annotations example check](misc/github-checks-annotation.png)\n\nand the changed files section of related pull requests:\n\n![annotations example changed files](misc/github-pull-request-changes-annotation.png)\n\n***Note:** Annotations for test files are only supported when test file paths in test result files are relative to the repository root.\nUse option `test_file_prefix` to add a prefix to, or remove a prefix from these file paths. See [Configuration](#configuration) section for details.*\n\n***Note:** Only the first failure of a test is shown. If you want to see all failures, set `report_individual_runs: \"true\"`.*\n\nCheck run annotations can be disabled with `ignore_runs: true`.\n\n### GitHub Actions job summary\n\nThe results are added to the job summary page of the workflow that runs this action:\n\n![job summary example](misc/github-job-summary-full.png)\n\nIn presence of failures or errors, the job summary links to the respective [check summary](#github-actions-check-summary-of-a-commit) with failure details.\n\n***Note:** Job summary requires [GitHub Actions runner v2.288.0](https://github.com/actions/runner/releases/tag/v2.288.0) or above.*\n\nJob summaries can be disabled with `job_summary: false`.\n\n### GitHub Actions check summary of a commit\n\nTest results are published in the GitHub Actions check summary of the respective commit:\n\n![checks comment example](misc/github-checks-comment.png)\n\nCheck runs can be disabled with `check_run: false`.\n\n## The symbols\n[comment]: \u003c\u003e (This heading is linked to from method get_link_and_tooltip_label_md)\n\nThe symbols have the following meaning:\n\n|Symbol|Meaning|\n|:----:|-------|\n|\u003cimg src=\"https://github.githubassets.com/images/icons/emoji/unicode/2714.png\" height=\"20\"/\u003e  :white_check_mark:|A successful test or run|\n|\u003cimg src=\"https://github.githubassets.com/images/icons/emoji/unicode/1f4a4.png\" height=\"20\"/\u003e|A skipped test or run|\n|\u003cimg src=\"https://github.githubassets.com/images/icons/emoji/unicode/274c.png\" height=\"20\"/\u003e|A failed test or run|\n|\u003cimg src=\"https://github.githubassets.com/images/icons/emoji/unicode/1f525.png\" height=\"20\"/\u003e|An erroneous test or run|\n|\u003cimg src=\"https://github.githubassets.com/images/icons/emoji/unicode/23f1.png\" height=\"20\"/\u003e|The duration of all tests or runs|\n\n***Note:*** For simplicity, \"disabled\" tests count towards \"skipped\" tests.\n\n## Configuration\n\nFiles can be selected via the `files` option. It supports [glob wildcards](https://docs.python.org/3/library/glob.html#glob.glob)\nlike `*`, `**`, `?`, and `[]` character ranges. The `**` wildcard matches all files and directories recursively: `./`, `./*/`, `./*/*/`, etc.\n\nYou can provide multiple file patterns, one pattern per line. Patterns starting with `!` exclude the matching files.\nThere have to be at least one pattern starting without a `!`:\n\n```yaml\nwith:\n  files: |\n    *.xml\n    !config.xml\n```\n\nThe list of most notable options:\n\n|Option|Default Value|Description|\n|:-----|:-----:|:----------|\n|`files`|_no default_|File patterns of test result files. Relative paths are known to work best, while the non-Docker action [also works with absolute paths](#running-with-absolute-paths). Supports `*`, `**`, `?`, and `[]` character ranges. Use multiline string for multiple patterns. Patterns starting with `!` exclude the matching files. There have to be at least one pattern starting without a `!`.|\n|`check_name`|`\"Test Results\"`|An alternative name for the check result. Required to be unique for each instance in one workflow.|\n|`comment_title`|same as `check_name`|An alternative name for the pull request comment.|\n|`comment_mode`|`always`|The action posts comments to pull requests that are associated with the commit. Set to:\u003cbr/\u003e`always` - always comment\u003cbr/\u003e`changes` - comment when changes w.r.t. the target branch exist\u003cbr/\u003e`changes in failures` - when changes in the number of failures and errors exist\u003cbr/\u003e`changes in errors` - when changes in the number of (only) errors exist\u003cbr/\u003e`failures` - when failures or errors exist\u003cbr/\u003e`errors` - when (only) errors exist\u003cbr/\u003e`off` - to not create pull request comments.|\n|`large_files`|`false` unless\u003cbr/\u003e`ignore_runs` is `true`|Support for large files is enabled when set to `true`. Defaults to `false`, unless ignore_runs is `true`.|\n|`ignore_runs`|`false`|Does not collect test run information from the test result files, which is useful for very large files. This disables any check run annotations.|\n\n\u003cdetails\u003e\n\u003csummary\u003eOptions related to Git and GitHub\u003c/summary\u003e\n\n|Option|Default Value|Description|\n|:-----|:-----:|:----------|\n|`commit`|`${{env.GITHUB_SHA}}`|An alternative commit SHA to which test results are published. The `push` and `pull_request`events are handled, but for other [workflow events](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#push) `GITHUB_SHA` may refer to different kinds of commits. See [GitHub Workflow documentation](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) for details.|\n|`github_token`|`${{github.token}}`|An alternative GitHub token, other than the default provided by GitHub Actions runner.|\n|`github_retries`|`10`|Requests to the GitHub API are retried this number of times. The value must be a positive integer or zero.|\n|`ssl_verify`|`true`|Either `true` or `false`, in which case it controls whether to verify the Github server’s TLS certificate, or a string, in which case it must be a path to a CA bundle to use. Default is `true`.|\n|`seconds_between_github_reads`|`0.25`|Sets the number of seconds the action waits between concurrent read requests to the GitHub API.|\n|`seconds_between_github_writes`|`2.0`|Sets the number of seconds the action waits between concurrent write requests to the GitHub API.|\n|`secondary_rate_limit_wait_seconds`|`60.0`|Sets the number of seconds to wait before retrying secondary rate limit errors. If not set, the default defined in the PyGithub library is used (currently 60 seconds).|\n|`pull_request_build`|`\"merge\"`|As part of pull requests, GitHub builds a merge commit, which combines the commit and the target branch. If tests ran on the actual pushed commit, then set this to `\"commit\"`.|\n|`event_file`|`${{env.GITHUB_EVENT_PATH}}`|An alternative event file to use. Useful to replace a `workflow_run` event file with the actual source event file.|\n|`event_name`|`${{env.GITHUB_EVENT_NAME}}`|An alternative event name to use. Useful to replace a `workflow_run` event name with the actual source event name: `${{ github.event.workflow_run.event }}`.|\n|`search_pull_requests`|`false`|Prior to v2.6.0, the action used the `/search/issues` REST API to find pull requests related to a commit. If you need to restore that behaviour, set this to \"true\". Defaults to `false`.|\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOptions related to reporting test results\u003c/summary\u003e\n\n|Option|Default Value|Description|\n|:-----|:-----:|:----------|\n|`time_unit`|`seconds`|Time values in the test result files have this unit. Supports `seconds` and `milliseconds`.|\n|`test_file_prefix`|`none`|Paths in the test result files should be relative to the git repository for annotations to work best. This prefix is added to (if starting with \"+\"), or remove from (if starting with \"-\") test file paths. Examples: \"+src/\" or \"-/opt/actions-runner\".|\n|`check_run`|`true`|Set to `true`, the results are published as a check run, but it may not be associated with the workflow that ran this action.|\n|`job_summary`|`true`|Set to `true`, the results are published as part of the [job summary page](https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/) of the workflow run.|\n|`compare_to_earlier_commit`|`true`|Test results are compared to results of earlier commits to show changes:\u003cbr/\u003e`false` - disable comparison, `true` - compare across commits.'|\n|`test_changes_limit`|`10`|Limits the number of removed or skipped tests reported on pull request comments. This report can be disabled with a value of `0`.|\n|`report_individual_runs`|`false`|Individual runs of the same test may see different failures. Reports all individual failures when set `true`, and the first failure only otherwise.|\n|`report_suite_logs`|`none`|In addition to reporting regular test logs, also report test suite logs. These are logs provided on suite level, not individual test level. Set to `info` for normal output, `error` for error output, `any` for both, or `none` for no suite logs at all. Defaults to `none`.|\n|`deduplicate_classes_by_file_name`|`false`|De-duplicates classes with same name by their file name when set `true`, combines test results for those classes otherwise.|\n|`check_run_annotations`|`all tests, skipped tests`|Adds additional information to the check run. This is a comma-separated list of any of the following values:\u003cbr\u003e`all tests` - list all found tests,\u003cbr\u003e`skipped tests` - list all skipped tests\u003cbr\u003e Set to `none` to add no extra annotations at all.|\n|`check_run_annotations_branch`|`event.repository.default_branch` or `\"main, master\"`|Adds check run annotations only on given branches. If not given, this defaults to the default branch of your repository, e.g. `main` or `master`. Comma separated list of branch names allowed, asterisk `\"*\"` matches all branches. Example: `main, master, branch_one`.|\n|`json_file`|no file|Results are written to this JSON file.|\n|`json_thousands_separator`|`\" \"`|Formatted numbers in JSON use this character to separate groups of thousands. Common values are \",\" or \".\". Defaults to punctuation space (\\u2008).|\n|`json_suite_details`|`false`|Write out all suite details to the JSON file. Setting this to `true` can greatly increase the size of the output. Defaults to `false`.|\n|`json_test_case_results`|`false`|Write out all individual test case results to the JSON file. Setting this to `true` can greatly increase the size of the output. Defaults to `false`.|\n|`fail_on`|`\"test failures\"`|Configures the state of the created test result check run. With `\"test failures\"` it fails if any test fails or test errors occur. It never fails when set to `\"nothing\"`, and fails only on errors when set to `\"errors\"`.|\n|`action_fail`|`false`|When set `true`, the action itself fails when tests have failed (see `fail_on`).|\n|`action_fail_on_inconclusive`|`false`|When set `true`, the action itself fails when tests are inconclusive (no test results).|\n\nPull request comments highlight removal of tests or tests that the pull request moves into skip state.\nThose removed or skipped tests are added as a list, which is limited in length by `test_changes_limit`,\nwhich defaults to `10`. Reporting these tests can be disabled entirely by setting this limit to `0`.\nThis feature requires `check_run_annotations` to contain `all tests` in order to detect test addition\nand removal, and `skipped tests` to detect new skipped and un-skipped tests, as well as\n`check_run_annotations_branch` to contain your default branch.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eOptions related to Docker\u003c/summary\u003e\n\nYou can control the Docker image used for the action as below. For this, you need to run the action as follows:\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/docker@v2\n  if: (!cancelled())\n  with:\n    docker_registry: ghcr.io\n    files: …\n```\n\n| Option            |               Default Value                | Description                                                                                                      |\n|:------------------|:------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------|\n| `docker_registry` |                 `ghcr.io`                  | The docker registry to pull the pre-built action from. Defaults to the Github registry `ghcr.io`.                |\n| `docker_image`    | `step-security/publish-unit-test-result-action` | The docker image name to pull the pre-built action from. Defaults to `step-security/publish-unit-test-result-action`. |\n| `docker_tag`      |      *The same version as in `uses:`*      | The docker tag to pull the pre-built action from. This is usually not needed.                                    |\n| `docker_platform` |                                            | The platform to use when pulling the docker image.                                                               |\n\u003c/details\u003e\n\n## JSON result\n\nThe gathered test information are accessible as JSON via [GitHub Actions steps outputs](https://docs.github.com/en/actions/learn-github-actions/contexts#steps-context) string or JSON file.\n\n\u003cdetails\u003e\n\u003csummary\u003eAccess JSON via step outputs\u003c/summary\u003e\n\nThe `json` output of the action can be accessed through the expression `steps.\u003cid\u003e.outputs.json`.\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  id: test-results\n  if: (!cancelled())\n  with:\n    files: \"test-results/**/*.xml\"\n\n- name: Conclusion\n  run: echo \"Conclusion is ${{ fromJSON( steps.test-results.outputs.json ).conclusion }}\"\n```\n\nHere is an example JSON:\n```json\n{\n  \"title\": \"4 parse errors, 4 errors, 23 fail, 18 skipped, 227 pass in 39m 12s\",\n  \"summary\": \"  24 files  ±0      4 errors  21 suites  ±0   39m 12s [:stopwatch:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"duration of all tests\\\") ±0s\\n272 tests ±0  227 [:white_check_mark:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"passed tests\\\") ±0  18 [:zzz:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"skipped / disabled tests\\\") ±0  23 [:x:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"failed tests\\\") ±0  4 [:fire:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"test errors\\\") ±0 \\n437 runs  ±0  354 [:white_check_mark:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"passed tests\\\") ±0  53 [:zzz:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"skipped / disabled tests\\\") ±0  25 [:x:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"failed tests\\\") ±0  5 [:fire:](https://github.com/step-security/publish-unit-test-result-action/blob/v2.6.1/README.md#the-symbols \\\"test errors\\\") ±0 \\n\\nResults for commit 11c02e56. ± Comparison against earlier commit d8ce4b6c.\\n\",\n  \"conclusion\": \"success\",\n  \"stats\": {\n    \"files\": 24,\n    \"errors\": 4,\n    \"suites\": 21,\n    \"duration\": 2352,\n    \"tests\": 272,\n    \"tests_succ\": 227,\n    \"tests_skip\": 18,\n    \"tests_fail\": 23,\n    \"tests_error\": 4,\n    \"runs\": 437,\n    \"runs_succ\": 354,\n    \"runs_skip\": 53,\n    \"runs_fail\": 25,\n    \"runs_error\": 5,\n    \"commit\": \"11c02e561e0eb51ee90f1c744c0ca7f306f1f5f9\"\n  },\n  \"stats_with_delta\": {\n    \"files\": {\n      \"number\": 24,\n      \"delta\": 0\n    },\n    …,\n    \"commit\": \"11c02e561e0eb51ee90f1c744c0ca7f306f1f5f9\",\n    \"reference_type\": \"earlier\",\n    \"reference_commit\": \"d8ce4b6c62ebfafe1890c55bf7ea30058ebf77f2\"\n  },\n  \"check_url\": \"https://github.com/step-security/publish-unit-test-result-action/runs/5397876970\",\n  \"formatted\": {\n     \"stats\": {\n        \"duration\": \"2 352\",\n        …\n     },\n     \"stats_with_delta\": {\n        \"duration\": {\n           \"number\": \"2 352\",\n           \"delta\": \"+12\"\n        },\n        …\n     }\n  },\n  \"annotations\": 31\n}\n```\n\nThe `formatted` key provides a copy of `stats` and `stats_with_delta`, where numbers are formatted to strings.\nFor example, `\"duration\": 2352` is formatted as `\"duration\": \"2 352\"`. The thousands separator can be configured\nvia `json_thousands_separator`. Formatted numbers are especially useful when those values are used where formatting\nis not easily available, e.g. when [creating a badge from test results](#create-a-badge-from-test-results).\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eAccess JSON via file\u003c/summary\u003e\n\nThe optional `json_file` allows to [configure](#configuration) a file where extended JSON information are to be written.\nCompared to `\"Access JSON via step outputs\"` above, `errors` and `annotations` contain more information\nthan just the number of errors and annotations, respectively.\n\nAdditionally, `json_test_case_results` can be enabled to add the `cases` field to the JSON file, which provides\nall test results of all tests. Enabling this may greatly increase the output size of the JSON file.\n\n```json\n{\n   …,\n   \"stats\": {\n      …,\n      \"errors\": [\n         {\n            \"file\": \"test-files/empty.xml\",\n            \"message\": \"File is empty.\",\n            \"line\": null,\n            \"column\": null\n         }\n      ],\n      …\n   },\n   …,\n   \"annotations\": [\n      {\n         \"path\": \"test/test.py\",\n         \"start_line\": 819,\n         \"end_line\": 819,\n         \"annotation_level\": \"warning\",\n         \"message\": \"test-files/junit.fail.xml\",\n         \"title\": \"1 out of 3 runs failed: test_events (test.Tests)\",\n         \"raw_details\": \"self = \u003ctest.Tests testMethod=test_events\u003e\\n\\n                def test_events(self):\\n                \u003e self.do_test_events(3)\\n\\n                test.py:821:\\n                _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\\n                test.py:836: in do_test_events\\n                self.do_test_rsh(command, 143, events=events)\\n                test.py:852: in do_test_rsh\\n                self.assertEqual(expected_result, res)\\n                E AssertionError: 143 != 0\\n            \"\n      }\n   ],\n   …,\n   \"cases\": [\n      {\n         \"class_name\": \"test.test_spark_keras.SparkKerasTests\",\n         \"test_name\": \"test_batch_generator_fn\",\n         \"states\": {\n            \"success\": [\n               {\n                  \"result_file\": \"test-files/junit-xml/pytest/junit.spark.integration.1.xml\",\n                  \"test_file\": \"test/test_spark_keras.py\",\n                  \"line\": 454,\n                  \"class_name\": \"test.test_spark_keras.SparkKerasTests\",\n                  \"test_name\": \"test_batch_generator_fn\",\n                  \"result\": \"success\",\n                  \"time\": 0.006\n               },\n               {\n                  \"result_file\": \"test-files/junit-xml/pytest/junit.spark.integration.2.xml\",\n                  \"test_file\": \"test/test_spark_keras.py\",\n                  \"line\": 454,\n                  \"class_name\": \"test.test_spark_keras.SparkKerasTests\",\n                  \"test_name\": \"test_batch_generator_fn\",\n                  \"result\": \"success\",\n                  \"time\": 0.006\n               }\n            ]\n         }\n      },\n   …\n   ],\n   …\n}\n```\n\n\u003c/details\u003e\n\nSee [Create a badge from test results](#create-a-badge-from-test-results) for an example on how to create a badge from this JSON.\n\n## Use with matrix strategy\n\nIn a scenario where your tests run multiple times in different environments (e.g. a [strategy matrix](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix)),\nthe action should run only once over all test results. For this, put the action into a separate job\nthat depends on all your test environments. Those need to upload the test results as artifacts, which\nare then all downloaded by your publish job.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample workflow YAML\u003c/summary\u003e\n\n```yaml\nname: CI\n\non: [push]\npermissions: {}\n\njobs:\n  build-and-test:\n    name: Build and Test (Python ${{ matrix.python-version }})\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        python-version: [3.6, 3.7, 3.8]\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n\n      - name: Setup Python ${{ matrix.python-version }}\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - name: PyTest\n        run: python -m pytest test --junit-xml pytest.xml\n\n      - name: Upload Test Results\n        if: (!cancelled())\n        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f  # v6.0.0\n        with:\n          name: Test Results (Python ${{ matrix.python-version }})\n          path: pytest.xml\n\n  publish-test-results:\n    name: \"Publish Tests Results\"\n    needs: build-and-test\n    runs-on: ubuntu-latest\n    permissions:\n      checks: write\n\n      # only needed unless run with comment_mode: off\n      pull-requests: write\n\n      # only needed for private repository\n      contents: read\n\n      # only needed for private repository\n      issues: read\n    if: (!cancelled())\n\n    steps:\n      - name: Download Artifacts\n        uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131  # v7.0.0\n        with:\n          path: artifacts\n\n      - name: Publish Test Results\n        uses: step-security/publish-unit-test-result-action@v2\n        with:\n          files: \"artifacts/**/*.xml\"\n```\n\u003c/details\u003e\n\nPlease consider to [support fork repositories and dependabot branches](#support-fork-repositories-and-dependabot-branches)\ntogether with your matrix strategy.\n\n## Support fork repositories and dependabot branches\n[comment]: \u003c\u003e (This heading is linked to from main method in publish_unit_test_results.py)\n\nGetting test results of pull requests created by contributors from fork repositories or by\n[Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-dependencies-updated-automatically)\nrequires some additional setup. Without this, the action will fail with the\n`\"Resource not accessible by integration\"` error for those situations.\n\nIn this setup, your CI workflow does not need to publish test results anymore as they are **always** published from a separate workflow.\n\n1. Your CI workflow has to upload the GitHub event file and test result files.\n2. Set up an additional workflow on `workflow_run` events, which starts on completion of the CI workflow,\n   downloads the event file and the test result files, and runs this action on them.\n   This workflow publishes the test results for pull requests from fork repositories and dependabot,\n   as well as all \"ordinary\" runs of your CI workflow.\n\n\u003cdetails\u003e\n\u003csummary\u003eStep-by-step instructions\u003c/summary\u003e\n\n1. Add the following job to your CI workflow to upload the event file as an artifact:\n\n```yaml\nevent_file:\n  name: \"Event File\"\n  runs-on: ubuntu-latest\n  steps:\n  - name: Upload\n    uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f  # v6.0.0\n    with:\n      name: Event File\n      path: ${{ github.event_path }}\n```\n\n2. Add the following action step to your CI workflow to upload test results as artifacts.\nAdjust the value of `path` to fit your setup:\n\n```yaml\n- name: Upload Test Results\n  if: (!cancelled())\n  uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f  # v6.0.0\n  with:\n    name: Test Results\n    path: |\n      test-results/*.xml\n```\n\n3. If you run tests in a [strategy matrix](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix),\nmake the artifact name unique for each job, e.g.:\n```yaml\n  with:\n    name: Test Results (${{ matrix.python-version }})\n    path: …\n```\n\n4. Add the following workflow that publishes test results. It downloads and extracts\nall artifacts into `artifacts/ARTIFACT_NAME/`, where `ARTIFACT_NAME` will be `Upload Test Results`\nwhen setup as above, or `Upload Test Results (…)` when run in a strategy matrix.\n\n   It then runs the action on files matching `artifacts/**/*.xml`.\nChange the `files` pattern with the path to your test artifacts if it does not work for you.\nThe publish action uses the event file of the CI workflow.\n\n   Also adjust the value of `workflows` (here `\"CI\"`) to fit your setup:\n\n```yaml\nname: Test Results\n\non:\n  workflow_run:\n    workflows: [\"CI\"]\n    types:\n      - completed\npermissions: {}\n\njobs:\n  test-results:\n    name: Test Results\n    runs-on: ubuntu-latest\n    if: github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'\n\n    permissions:\n      checks: write\n\n      # needed unless run with comment_mode: off\n      pull-requests: write\n\n      # only needed for private repository\n      contents: read\n\n      # only needed for private repository\n      issues: read\n\n      # required by download step to access artifacts API\n      actions: read\n\n    steps:\n      - name: Download and Extract Artifacts\n        uses: dawidd6/action-download-artifact@fe9d59ce33ce92db8a6ac90b2c8be6b6d90417c8  # v15\n        with:\n           run_id: ${{ github.event.workflow_run.id }}\n           path: artifacts\n\n      - name: Publish Test Results\n        uses: step-security/publish-unit-test-result-action@v2\n        with:\n          commit: ${{ github.event.workflow_run.head_sha }}\n          event_file: artifacts/Event File/event.json\n          event_name: ${{ github.event.workflow_run.event }}\n          files: \"artifacts/**/*.xml\"\n```\n\nNote: Running this action on `pull_request_target` events is [dangerous if combined with code checkout and code execution](https://securitylab.github.com/research/github-actions-preventing-pwn-requests).\nThis event is therefore not use here intentionally!\n\u003c/details\u003e\n\n## Running with multiple event types (pull_request, push, schedule, …)\n\nThis action comments on a pull request each time it is executed via any event type.\nWhen run for more than one event type, runs will overwrite earlier pull request comments.\n\nNote that `pull_request` events may produce different test results than any other event type.\nThe `pull_request` event runs the workflow on a merge commit, i.e. the commit merged into the target branch.\nAll other event types run on the commit itself.\n\nIf you want to distinguish between test results from `pull_request` and `push`, or want to distinguish the original test results\nof the `push` to master from subsequent `schedule` events, you may want to add the following to your workflow.\n\n\u003cdetails\u003e\n\u003csummary\u003eThere are two possible ways to avoid the publish action to overwrite results from other event types:\u003c/summary\u003e\n\n### Test results per event type\n\nAdd the event name to `check_name` to avoid different event types overwriting each other's results:\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  if: (!cancelled())\n  with:\n    check_name: \"Test Results (${{ github.event.workflow_run.event || github.event_name }})\"\n    files: \"test-results/**/*.xml\"\n```\n\n### Pull request comments only for pull_request events\n\nDisabling the pull request comment mode (`\"off\"`) for events other than `pull_request` avoids that any other event type overwrites pull request comments:\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  if: (!cancelled())\n  with:\n    # set comment_mode to \"always\" for pull_request event, set to \"off\" for all other event types\n    comment_mode: ${{ (github.event.workflow_run.event == 'pull_request' || github.event_name == 'pull_request') \u0026\u0026 'always' || 'off' }}\n    files: \"test-results/**/*.xml\"\n```\n\u003c/details\u003e\n\n## Create a badge from test results\n\nHere is an example how to use the [JSON](#json-result) output of this action to create a badge like this:\n[![Test Results](https://gist.githubusercontent.com/EnricoMi/612cb538c14731f1a8fefe504f519395/raw/badge.svg)](https://gist.githubusercontent.com/EnricoMi/612cb538c14731f1a8fefe504f519395/raw/badge.svg)\n\n\u003cdetails\u003e\n\u003csummary\u003eExample workflow YAML\u003c/summary\u003e\n\n```yaml\nsteps:\n- …\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  id: test-results\n  if: (!cancelled())\n  with:\n    files: \"test-results/**/*.xml\"\n\n- name: Set badge color\n  shell: bash\n  run: |\n    case ${{ fromJSON( steps.test-results.outputs.json ).conclusion }} in\n      success)\n        echo \"BADGE_COLOR=31c653\" \u003e\u003e $GITHUB_ENV\n        ;;\n      failure)\n        echo \"BADGE_COLOR=800000\" \u003e\u003e $GITHUB_ENV\n        ;;\n      neutral)\n        echo \"BADGE_COLOR=696969\" \u003e\u003e $GITHUB_ENV\n        ;;\n    esac\n\n- name: Create badge\n  uses: emibcn/badge-action@808173dd03e2f30c980d03ee49e181626088eee8  # v2.0.3\n  with:\n    label: Tests\n    status: '${{ fromJSON( steps.test-results.outputs.json ).formatted.stats.tests }} tests, ${{ fromJSON( steps.test-results.outputs.json ).formatted.stats.runs }} runs: ${{ fromJSON( steps.test-results.outputs.json ).conclusion }}'\n    color: ${{ env.BADGE_COLOR }}\n    path: badge.svg\n\n- name: Upload badge to Gist\n  # Upload only for master branch\n  if: \u003e\n    github.event_name == 'workflow_run' \u0026\u0026 github.event.workflow_run.head_branch == 'master' ||\n    github.event_name != 'workflow_run' \u0026\u0026 github.ref == 'refs/heads/master'\n  uses: andymckay/append-gist-action@ab30bf28df67017c7ad696500b218558c7c04db3  # v0.3\n  with:\n    token: ${{ secrets.GIST_TOKEN }}\n    gistURL: https://gist.githubusercontent.com/{user}/{id}\n    file: badge.svg\n```\n\nYou have to create a personal access toke (PAT) with `gist` permission only. Add it to your GitHub Actions secrets, in above example with secret name `GIST_TOKEN`.\n\nSet the `gistURL` to the Gist that you want to write the badge file to, in the form of `https://gist.githubusercontent.com/{user}/{id}`.\n\nYou can then use the badge via this URL: https://gist.githubusercontent.com/{user}/{id}/raw/badge.svg\n\u003c/details\u003e\n\n## Running with absolute paths\n\nIt is known that this action works best with relative paths (e.g. `test-results/**/*.xml`),\nbut most absolute paths (e.g. `/tmp/test-results/**/*.xml`) require to use the non-Docker variant\nof this action:\n\n    uses: step-security/publish-unit-test-result-action/linux@v2\n    uses: step-security/publish-unit-test-result-action/macos@v2\n    uses: step-security/publish-unit-test-result-action/windows@v2\n\nIf you have to use absolute paths with the Docker variant of this action (`uses: step-security/publish-unit-test-result-action@v2`),\nyou have to copy files to a relative path first, and then use the relative path:\n\n```yaml\n- name: Copy Test Results\n  if: (!cancelled())\n  run: |\n    cp -Lpr /tmp/test-results test-results\n  shell: bash\n\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action@v2\n  if: (!cancelled())\n  with:\n     files: |\n        test-results/**/*.xml\n        test-results/**/*.trx\n        test-results/**/*.json\n```\n\nUsing the Docker variant of this action is recommended as it starts up much quicker.\n\n## Running as a non-Docker action\n\nRunning this action as below allows to run it on action runners that do not provide Docker:\n\n    uses: step-security/publish-unit-test-result-action/linux@v2\n    uses: step-security/publish-unit-test-result-action/macos@v2\n    uses: step-security/publish-unit-test-result-action/windows@v2\n\nThese actions, however, require a Python3 environment to be setup on the action runner.\nAll GitHub-hosted runners (Ubuntu, Windows Server and macOS) provide a suitable Python3 environment out-of-the-box.\n\nSelf-hosted runners may require setting up a Python environment first:\n\n```yaml\n- name: Setup Python\n  uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n  with:\n    python-version: 3.8\n```\n\nStart-up of the action is faster with `virtualenv` or `venv` package installed.\n\n## Running as a composite action\n\nRunning this action via:\n\n    uses: step-security/publish-unit-test-result-action/composite@v2\n\nis **deprecated**, please use an action appropriate for your operating system and shell:\n\n- Linux (Bash shell): `uses: step-security/publish-unit-test-result-action/linux@v2`\n- macOS (Bash shell): `uses: step-security/publish-unit-test-result-action/macos@v2`\n- Windows (PowerShell): `uses: step-security/publish-unit-test-result-action/windows@v2`\n- Windows (Bash shell): `uses: step-security/publish-unit-test-result-action/windows/bash@v2`\n\nThese are non-Docker variations of this action. For details, see section [\"Running as a non-Docker action\"](#running-as-a-non-docker-action) above.\n\nThe composite action was able to run on any operating system, as long as Bash shell is installed.\nThe same behaviour can be achieved with multiple steps, each for a specific operating system:\n\n```yaml\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/linux@v2\n  if: runner.os == 'Linux'\n  with:\n    files: test-results/**/*.xml\n\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/macos@v2\n  if: runner.os == 'macOS'\n  with:\n    files: test-results/**/*.xml\n\n- name: Publish Test Results\n  uses: step-security/publish-unit-test-result-action/windows/bash@v2\n  if: runner.os == 'Windows'\n  with:\n    files: test-results/**/*.xml\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstep-security%2Fpublish-unit-test-result-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstep-security%2Fpublish-unit-test-result-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstep-security%2Fpublish-unit-test-result-action/lists"}