From e7e020a5507b83c6de8d9d0c0a6ed71f2f804b34 Mon Sep 17 00:00:00 2001 From: Sundram Gupta Date: Wed, 10 Jun 2026 16:39:56 +0530 Subject: [PATCH 1/2] docs: restructure README, add all-inputs example, pin to @v0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh the README for the demo and current published state. Structure: - Reordered sections: Usage → Customize (Inputs/Outputs/Behavior) → Versioning → Examples → Troubleshooting → Resources → License. - Top-level TOC matches the new order so readers can land on any section directly. - Dropped the introductory line that compared this action's design to other vendors' actions; the structure itself now communicates the pattern. Inputs section: - Added a worked example that uses all three inputs (command, bru-version, working-directory) so users see a realistic invocation alongside the table. Version pins: - Every `uses: usebruno/bruno-cli-action@v1` updated to `@v0`, matching the floating major tag actually published to the Marketplace. - Versioning table now shows `@v0` / `@v0.0.0` rather than the pre-publish `@v1` / `@v1.2.3` placeholders. Supersedes #4 and #5. --- README.md | 168 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 93159e0..c62e322 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,46 @@ # Bruno CLI GitHub Action -Official GitHub Action for running [Bruno](https://www.usebruno.com) CLI commands in CI. +Official GitHub Action for running [Bruno](https://www.usebruno.com) CLI commands in CI/CD workflows. -Installs `@usebruno/cli`, runs an arbitrary `bru` command, parses the emitted JUnit XML, and exposes machine-readable counts (`exit-code`, `passed`, `failed`, `total`, `duration-ms`) for downstream steps. UI rendering, artifact upload, PR comments, and soft-fail semantics are delegated to the GitHub Actions ecosystem (`EnricoMi/publish-unit-test-result-action`, `dorny/test-reporter`, `actions/upload-artifact`, `continue-on-error`). See [Pairing with downstream actions](#pairing-with-downstream-actions) for canonical recipes. +Installs `@usebruno/cli`, runs an arbitrary `bru` command, parses the emitted JUnit XML, and exposes machine-readable counts (`exit-code`, `passed`, `failed`, `total`, `duration-ms`) for downstream steps. -Design pattern follows [`postmanlabs/postman-cli-action`](https://github.com/postmanlabs/postman-cli-action) and [`kong/setup-inso`](https://github.com/kong/setup-inso): minimal-input pass-through, no flag mirroring. +- [Usage](#usage) +- [Customize](#customize) + - [Inputs](#inputs) + - [Outputs](#outputs) + - [Behavior](#behavior) +- [Versioning](#versioning) +- [Examples](#examples) +- [Troubleshooting](#troubleshooting) +- [Resources](#resources) -## Quickstart +## Usage + +The following shows the minimum setup to configure the GitHub Action with a command and return counts as outputs. Learn about the [supported inputs](#inputs) you can use to customize the GitHub Action. ```yaml -# Minimal — installs the CLI, runs the collection, returns counts as outputs. -# Step fails (red) on assertion failure, succeeds (green) on success. -# No UI surfaces, no artifact upload by default. -# See "Pairing with downstream actions" for PR comments, annotations, -# Step Summary, artifact upload, soft-fail, and more. -- uses: usebruno/bruno-cli-action@v1 - with: - working-directory: tests/payments - command: 'run --env prod' +name: API Tests + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Run Bruno Collection + uses: usebruno/bruno-cli-action@v0 + with: + working-directory: tests/payments + command: 'run --env prod' ``` -**What you'll see:** the workflow step turns red on assertion failure (green on success). No PR comments, no annotations, no Step Summary, no uploaded artifact. Outputs are populated for downstream conditional steps. +**What you'll see:** the workflow step turns red on assertion failure (green on success). Outputs are populated for downstream conditional steps. + +UI rendering, artifact upload, PR comments, and soft-fail semantics are delegated to the GitHub Actions ecosystem (`EnricoMi/publish-unit-test-result-action`, `dorny/test-reporter`, `actions/upload-artifact`, `continue-on-error`). See [Examples](#examples) for canonical recipes. -## Inputs +## Customize + +### Inputs | Input | Required | Default | Description | |---|---|---|---| @@ -32,7 +50,18 @@ Design pattern follows [`postmanlabs/postman-cli-action`](https://github.com/pos No typed inputs for `--env`, `--env-var`, `--tags`, `--bail`, `--sandbox`, `--reporter-*`, etc. They all go in `command`. Every CLI flag works the day it ships in the CLI, with zero coordination cost. -## Outputs +**Example using all inputs:** + +```yaml +- name: Run Bruno collection + uses: usebruno/bruno-cli-action@v0 + with: + command: 'run --env prod --reporter-junit results.xml' + bru-version: '3.4.2' + working-directory: tests/payments +``` + +### Outputs Available as `${{ steps..outputs. }}` in subsequent steps: @@ -46,23 +75,44 @@ Available as `${{ steps..outputs. }}` in subsequent steps: Report file paths are intentionally **not** outputs. Users who chain to downstream actions pass an explicit `--reporter-junit ` in `command` and reference that path directly in the next step. -## Behavior - -### JUnit auto-injection (always-on) +### Behavior -If the user's `command` does not contain `--reporter-junit`, the action appends `--reporter-junit "$RUNNER_TEMP/bruno-junit.xml"` before invoking `bru`. JUnit is required for output extraction; auto-injection means a minimal `command: 'run'` produces count outputs without the user having to remember reporter flags. The file lives in the runner's temp dir and is auto-cleaned post-job. +**JUnit auto-injection (always-on).** If the user's `command` does not contain `--reporter-junit`, the action appends `--reporter-junit "$RUNNER_TEMP/bruno-junit.xml"` before invoking `bru`. JUnit is required for output extraction; auto-injection means a minimal `command: 'run'` produces count outputs without the user having to remember reporter flags. The file lives in the runner's temp dir and is auto-cleaned post-job. If the user explicitly passes `--reporter-junit some/path.xml`, the action honors that path and parses from there. -### Exit code propagation +**Exit code propagation.** The action propagates `bru`'s exit code naturally. The workflow step succeeds on exit 0 and fails on non-zero. Users who want the workflow to continue past failures use GitHub Actions' built-in `continue-on-error: true` (see [Soft-fail recipe](#soft-fail-recipe)). + +## Versioning + +| Tag | Behaviour | +|---|---| +| `@v0` | Floating major. Receives every backwards-compatible release. | +| `@v0.0.0` | Immutable. Pinned to a specific release. | + +The `v` tag is retagged automatically on every published release. -The action propagates `bru`'s exit code naturally. The workflow step succeeds on exit 0 and fails on non-zero. Users who want the workflow to continue past failures use GitHub Actions' built-in `continue-on-error: true` (see recipe #12). +## Examples -## Pairing with downstream actions +The following examples cover every reporting and artifact use case. The action emits clean JUnit XML; downstream actions render it for the user-visible surface needed or upload it as a workflow artifact. -This section covers every reporting and artifact use case. The action emits clean JUnit XML; downstream actions render it for the user-visible surface needed or upload it as a workflow artifact. +- [PR comment on every run (sticky)](#pr-comment-on-every-run-sticky) +- [PR comment only on failures](#pr-comment-only-on-failures) +- [Step Summary without PR comment](#step-summary-without-pr-comment) +- [Workflow-level annotations on PR Checks](#workflow-level-annotations-on-pr-checks) +- [Checks tab UI via dorny/test-reporter](#checks-tab-ui-via-dornytest-reporter) +- [EnricoMi + dorny together](#enricomi--dorny-together) +- [Artifact upload with header sanitization](#artifact-upload-with-header-sanitization) +- [Multiple report formats (JUnit + HTML + JSON)](#multiple-report-formats-junit--html--json) +- [Slack notification on failure](#slack-notification-on-failure) +- [Simple non-sticky PR comment via gh CLI](#simple-non-sticky-pr-comment-via-gh-cli) +- [Matrix across environments](#matrix-across-environments) +- [Soft-fail recipe](#soft-fail-recipe) +- [Forked-PR caveat](#forked-pr-caveat) +- [Enterprise patterns (mTLS, custom CA)](#enterprise-patterns-mtls-custom-ca) +- [Other CI platforms](#other-ci-platforms) -### 1. PR comment on every run (sticky, updated in place) +### PR comment on every run (sticky) The most common ask. `EnricoMi/publish-unit-test-result-action` posts a single comment per PR with structured results, updated on re-runs. Adds a check run with rich annotations as a side benefit. @@ -80,7 +130,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: usebruno/bruno-cli-action@v1 + - uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml' @@ -95,7 +145,7 @@ jobs: **What you'll see:** a single Bruno-themed comment in the PR Conversation tab that updates in place on every re-run, plus a check run with structured per-test results in the PR Checks tab. **Why `if: always()`:** EnricoMi must run even when the Bruno step fails the build, otherwise users do not see the comment on failure. -### 2. PR comment only when there are failures +### PR comment only on failures For teams who do not want a green-passes-everywhere comment polluting the conversation: @@ -110,7 +160,7 @@ For teams who do not want a green-passes-everywhere comment polluting the conver **What you'll see:** PR comment appears only when at least one assertion failed. Successful runs leave no comment behind. **Other `comment_mode` values:** `always` (default), `failures`, `errors`, `off`. -### 3. Step Summary on the workflow run page (without PR comment) +### Step Summary without PR comment EnricoMi writes a Step Summary by default. If you want the workflow-page digest but no PR comment noise: @@ -125,7 +175,7 @@ EnricoMi writes a Step Summary by default. If you want the workflow-page digest **What you'll see:** a markdown summary on the workflow run page (visible by clicking into the run from the Actions tab). No PR Conversation comment, no Checks-tab check run annotations. -### 4. Workflow-level annotations (errors visible on the PR Checks card) +### Workflow-level annotations on PR Checks EnricoMi posts annotations via the Check Runs API. These appear in the PR Checks tab attached to EnricoMi's check run: @@ -140,12 +190,12 @@ EnricoMi posts annotations via the Check Runs API. These appear in the PR Checks **What you'll see:** the PR Checks tab shows the EnricoMi check run with one annotation per failed assertion, expandable for failure details. **Note:** line-anchored annotations on `.bru` source lines would require the CLI to emit `file=` and `line=` in JUnit. Not currently planned. -### 5. Checks tab UI via dorny/test-reporter +### Checks tab UI via dorny/test-reporter If you have a polyglot test stack (Jest, Pytest, Bruno) and want all results in the same Checks tab UI, dorny is the better tool than EnricoMi: ```yaml -- uses: usebruno/bruno-cli-action@v1 +- uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml' @@ -160,12 +210,12 @@ If you have a polyglot test stack (Jest, Pytest, Bruno) and want all results in **What you'll see:** a separate check run in the PR Checks tab labeled "Bruno API tests" with structured per-test results and expandable failure details. Visually consistent with check runs from your other JUnit-emitting test suites. -### 6. EnricoMi + dorny together (PR comment + rich Checks tab) +### EnricoMi + dorny together When you want both: a PR Conversation comment from EnricoMi and a polished Checks tab UI from dorny: ```yaml -- uses: usebruno/bruno-cli-action@v1 +- uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml' @@ -186,12 +236,12 @@ When you want both: a PR Conversation comment from EnricoMi and a polished Check **What you'll see:** PR Conversation gets the EnricoMi sticky comment; PR Checks tab shows two check runs (one from each downstream action) plus the EnricoMi annotations. -### 7. Artifact upload with header sanitization +### Artifact upload with header sanitization Bruno's CLI handles sensitive-header redaction; pass the flag in `command`. Chain `actions/upload-artifact@v7` to persist the report: ```yaml -- uses: usebruno/bruno-cli-action@v1 +- uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml --reporter-skip-headers "Authorization Cookie X-Tenant-Token"' @@ -207,12 +257,12 @@ Bruno's CLI handles sensitive-header redaction; pass the flag in `command`. Chai To customize retention or use compression options, see `actions/upload-artifact@v7`'s own inputs (`retention-days`, `compression-level`, `if-no-files-found`). -### 8. Multiple report formats (JUnit + HTML + JSON) +### Multiple report formats (JUnit + HTML + JSON) Pass multiple reporter flags in `command`. Chain `actions/upload-artifact@v7` with a path list: ```yaml -- uses: usebruno/bruno-cli-action@v1 +- uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml --reporter-html report.html --reporter-json report.json' @@ -229,13 +279,13 @@ Pass multiple reporter flags in `command`. Chain `actions/upload-artifact@v7` wi **What you'll see:** an artifact containing all three report files. Download to a browser to view the rich HTML report; JSON is consumable by custom dashboards or aggregators. -### 9. Slack notification on failure +### Slack notification on failure Use the JUnit-derived `failed` output as a conditional. Use `continue-on-error: true` so the notification step still runs: ```yaml - id: bruno - uses: usebruno/bruno-cli-action@v1 + uses: usebruno/bruno-cli-action@v0 continue-on-error: true with: working-directory: tests/payments @@ -262,13 +312,13 @@ Use the JUnit-derived `failed` output as a conditional. Use `continue-on-error: **Prerequisites:** `SLACK_WEBHOOK_URL` secret configured in the repository. **What you'll see:** the Bruno step shows red on failure (honest signal) but the workflow continues; a Slack message lands in the channel mapped to the webhook with counts, branch, duration, and a link to the workflow run. -### 10. Simple non-sticky PR comment via gh CLI (lightweight alternative to EnricoMi) +### Simple non-sticky PR comment via gh CLI For users who do not want EnricoMi's full setup and only need a quick "post a comment with the counts" pattern (no stickiness, each run adds a new comment): ```yaml - id: bruno - uses: usebruno/bruno-cli-action@v1 + uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod' @@ -289,9 +339,9 @@ For users who do not want EnricoMi's full setup and only need a quick "post a co ``` **Prerequisites:** `pull-requests: write` permission and the workflow triggered on `pull_request`. -**What you'll see:** a new comment posted to the PR on every workflow run. Each re-run adds another comment (no in-place update). Use EnricoMi (recipe #1) if you want stickiness. +**What you'll see:** a new comment posted to the PR on every workflow run. Each re-run adds another comment (no in-place update). Use EnricoMi (above) if you want stickiness. -### 11. Matrix across environments +### Matrix across environments Use distinct JUnit paths and artifact names per matrix leg. Chain EnricoMi and `actions/upload-artifact@v7` per leg: @@ -311,7 +361,7 @@ jobs: env: [staging, prod] steps: - uses: actions/checkout@v6 - - uses: usebruno/bruno-cli-action@v1 + - uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env ${{ matrix.env }} --reporter-junit results-${{ matrix.env }}.xml' @@ -333,13 +383,13 @@ jobs: **What you'll see:** two matrix legs running in parallel against staging and prod. Each leg produces its own artifact (`bruno-report-staging`, `bruno-report-prod`), its own check run (`Bruno (staging)` / `Bruno (prod)`) in the PR Checks tab, and a PR comment only when that leg fails. **Note:** include the matrix key in both `--reporter-junit` and the artifact `name` to avoid `actions/upload-artifact@v7`'s duplicate-name error across matrix legs. -### 12. Soft-fail recipe +### Soft-fail recipe Record results without failing the build, then notify selectively. Use GitHub Actions' built-in `continue-on-error: true`: ```yaml - id: bruno - uses: usebruno/bruno-cli-action@v1 + uses: usebruno/bruno-cli-action@v0 continue-on-error: true with: working-directory: tests/payments @@ -351,11 +401,11 @@ Record results without failing the build, then notify selectively. Use GitHub Ac **What you'll see:** the Bruno step appears red in the workflow run UI when assertions fail (honest signal that something went wrong), but downstream steps still run because `continue-on-error` lets the workflow proceed. Outputs are populated for the conditional notification step. -### 13. Forked-PR caveat +### Forked-PR caveat GitHub restricts `GITHUB_TOKEN` to read-only for workflows triggered by `pull_request` events from forked repositories, regardless of the `permissions` block in the workflow file. EnricoMi and any PR comment poster need write permission, which means workflows running on community contributions must use `pull_request_target` (with care: it runs with the base branch's permissions and secrets). See the [GitHub docs](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) and [EnricoMi's fork PR docs](https://github.com/EnricoMi/publish-unit-test-result-action#support-fork-repositories-and-dependabot-branches) for the trade-offs. -## Enterprise patterns (mTLS, custom CA) +### Enterprise patterns (mTLS, custom CA) Marshall secrets via shell, pass paths to bru: @@ -368,7 +418,7 @@ Marshall secrets via shell, pass paths to bru: CA_CERT: ${{ secrets.API_CA_CERT }} CLIENT_CERT_CONFIG: ${{ secrets.API_CLIENT_CERT_CONFIG }} -- uses: usebruno/bruno-cli-action@v1 +- uses: usebruno/bruno-cli-action@v0 with: working-directory: tests/payments command: 'run --env prod --cacert /tmp/certs/ca.pem --client-cert-config /tmp/certs/client.json' @@ -377,19 +427,10 @@ Marshall secrets via shell, pass paths to bru: **Prerequisites:** `API_CA_CERT` and `API_CLIENT_CERT_CONFIG` secrets configured. **What you'll see:** Bruno runs against an internal mTLS-protected API. Secrets never appear in logs (GitHub auto-masks); cert files are written to a temp dir and cleaned up when the runner is destroyed. -## Other CI platforms +### Other CI platforms Bruno's CLI works on Jenkins, Azure DevOps, GitLab CI, and Bitbucket Pipelines via direct CLI invocation. The [Bruno CLI Docker image](https://hub.docker.com/r/usebruno/cli) is the recommended primitive there. See the [Bruno CLI docs](https://docs.usebruno.com/bru-cli/overview) for platform-specific examples. -## Versioning - -| Tag | Behaviour | -|---|---| -| `@v1` | Floating major. Receives every backwards-compatible release. | -| `@v1.2.3` | Immutable. Pinned to a specific release. | - -The `v` tag is retagged automatically on every published release. - ## Troubleshooting **Sandbox migration (Bruno CLI v3+).** v3 changed the default sandbox. If your tests rely on Node built-ins (`require`, `Buffer`, etc.), add `--sandbox developer` to `command`: @@ -444,6 +485,15 @@ All of these surface npm exit `1`. The useful signal is the stderr text, not the **Network timeouts.** Bruno honours `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`. Set them via `env:` on the step. +## Resources + +- [Bruno CLI documentation](https://docs.usebruno.com/bru-cli/overview) +- [Bruno CLI command options](https://docs.usebruno.com/bru-cli/commandOptions) +- [`@usebruno/cli` on npm](https://www.npmjs.com/package/@usebruno/cli) +- [`usebruno/bruno` (main Bruno repo)](https://github.com/usebruno/bruno) +- [GitHub Actions documentation](https://docs.github.com/en/actions) +- [Recommended downstream actions](#examples) for PR comments, Checks tab UI, and artifact upload + ## License MIT From a06375114b77f942cc3f95b88c8726c06eac6464 Mon Sep 17 00:00:00 2001 From: Sundram Gupta Date: Wed, 10 Jun 2026 18:58:09 +0530 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20trim=20README=20+=20Postman-style?= =?UTF-8?q?=20Inputs=20table=20+=20sweep=20@v0=20=E2=86=92=20@v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tighten the README ahead of the v1 announcement. Structure: - Trimmed Examples down to the six most-asked recipes: PR sticky comment, dorny Checks tab, artifact upload with sanitization, multi-format reports, Slack on failure, gh CLI PR comment. - Removed the Behavior subsection and the Troubleshooting block (including the long exit-code reference) since users hitting issues land on the Bruno CLI docs first anyway. - Promoted "Other CI platforms" out of Examples into its own top-level section. - Updated the TOC to match. Inputs table: - Reshaped to a 3-column layout (Name | Type | Description) to match the pattern that mature first-party CLI actions use. Required/Default metadata moves into the Description column (Required. ... / (Default: X)). Version pins: - Every `usebruno/bruno-cli-action@v0` updated to `@v1`, matching the public release tag that ships with the announcement. - Versioning table updated to `@v1` / `@v1.0.0`. --- README.md | 298 ++++++------------------------------------------------ 1 file changed, 30 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index c62e322..f8cf15c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Bruno CLI GitHub Action -Official GitHub Action for running [Bruno](https://www.usebruno.com) CLI commands in CI/CD workflows. - -Installs `@usebruno/cli`, runs an arbitrary `bru` command, parses the emitted JUnit XML, and exposes machine-readable counts (`exit-code`, `passed`, `failed`, `total`, `duration-ms`) for downstream steps. +Official GitHub Action for running [Bruno CLI](https://docs.usebruno.com/bru-cli/overview) commands in CI/CD workflows with full support for collection runs and exposes machine-readable counts (`exit-code`, `passed`, `failed`, `total`, `duration-ms`) for downstream steps. - [Usage](#usage) - [Customize](#customize) @@ -11,7 +9,7 @@ Installs `@usebruno/cli`, runs an arbitrary `bru` command, parses the emitted JU - [Behavior](#behavior) - [Versioning](#versioning) - [Examples](#examples) -- [Troubleshooting](#troubleshooting) +- [Other CI Platforms](#other-ci-platforms) - [Resources](#resources) ## Usage @@ -28,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Run Bruno Collection - uses: usebruno/bruno-cli-action@v0 + uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod' @@ -40,24 +38,24 @@ UI rendering, artifact upload, PR comments, and soft-fail semantics are delegate ## Customize -### Inputs +Customize the Bruno CLI GitHub Action to suit your API project's CI/CD workflow. -| Input | Required | Default | Description | -|---|---|---|---| -| `command` | yes | — | The `bru` subcommand and flags (e.g. `run --env prod`). The action prepends `bru`. Reporter flags are optional; `--reporter-junit` is auto-injected if absent. | -| `bru-version` | no | `latest` | Version of `@usebruno/cli` to install. | -| `working-directory` | no | `.` | Shell working directory. Typically the Bruno collection root. | +### Inputs -No typed inputs for `--env`, `--env-var`, `--tags`, `--bail`, `--sandbox`, `--reporter-*`, etc. They all go in `command`. Every CLI flag works the day it ships in the CLI, with zero coordination cost. +| Name | Type | Description | +|---|---|---| +| `command` | String | **Required.** The Bruno CLI command to run and its options (e.g. `run --env prod`). The action prepends `bru`. | +| `bru-version` | String | Version of `@usebruno/cli` to install. (Default: `latest`) | +| `working-directory` | String | Path of the Bruno collection directory. (Default: `.`) | **Example using all inputs:** ```yaml - name: Run Bruno collection - uses: usebruno/bruno-cli-action@v0 + uses: usebruno/bruno-cli-action@v1 with: command: 'run --env prod --reporter-junit results.xml' - bru-version: '3.4.2' + bru-version: '3.5.0' working-directory: tests/payments ``` @@ -65,52 +63,33 @@ No typed inputs for `--env`, `--env-var`, `--tags`, `--bail`, `--sandbox`, `--re Available as `${{ steps..outputs. }}` in subsequent steps: -| Output | Description | +| Name | Description | |---|---| -| `exit-code` | The `bru` process exit code. | +| `exit-code` | Exit code from the Bruno CLI command. 0 indicates success, non-zero indicates failure. | | `passed` | Number of passed requests. | | `failed` | Number of failed requests (assertion failures or runtime errors). | -| `total` | Total requests run. | +| `total` | Total number of requests run. | | `duration-ms` | Total run duration in milliseconds. | -Report file paths are intentionally **not** outputs. Users who chain to downstream actions pass an explicit `--reporter-junit ` in `command` and reference that path directly in the next step. - -### Behavior - -**JUnit auto-injection (always-on).** If the user's `command` does not contain `--reporter-junit`, the action appends `--reporter-junit "$RUNNER_TEMP/bruno-junit.xml"` before invoking `bru`. JUnit is required for output extraction; auto-injection means a minimal `command: 'run'` produces count outputs without the user having to remember reporter flags. The file lives in the runner's temp dir and is auto-cleaned post-job. - -If the user explicitly passes `--reporter-junit some/path.xml`, the action honors that path and parses from there. - -**Exit code propagation.** The action propagates `bru`'s exit code naturally. The workflow step succeeds on exit 0 and fails on non-zero. Users who want the workflow to continue past failures use GitHub Actions' built-in `continue-on-error: true` (see [Soft-fail recipe](#soft-fail-recipe)). - ## Versioning | Tag | Behaviour | |---|---| -| `@v0` | Floating major. Receives every backwards-compatible release. | -| `@v0.0.0` | Immutable. Pinned to a specific release. | +| `@v1` | Floating major. Receives every backwards-compatible release. | +| `@v1.0.0` | Immutable. Pinned to a specific release. | The `v` tag is retagged automatically on every published release. ## Examples -The following examples cover every reporting and artifact use case. The action emits clean JUnit XML; downstream actions render it for the user-visible surface needed or upload it as a workflow artifact. +The following examples cover some of the reporting and artifact use case. Use `--reporter-junit` flag to emit clean JUnit XML; downstream actions render it for the user-visible surface needed or upload it as a workflow artifact. - [PR comment on every run (sticky)](#pr-comment-on-every-run-sticky) -- [PR comment only on failures](#pr-comment-only-on-failures) -- [Step Summary without PR comment](#step-summary-without-pr-comment) -- [Workflow-level annotations on PR Checks](#workflow-level-annotations-on-pr-checks) - [Checks tab UI via dorny/test-reporter](#checks-tab-ui-via-dornytest-reporter) -- [EnricoMi + dorny together](#enricomi--dorny-together) - [Artifact upload with header sanitization](#artifact-upload-with-header-sanitization) - [Multiple report formats (JUnit + HTML + JSON)](#multiple-report-formats-junit--html--json) - [Slack notification on failure](#slack-notification-on-failure) - [Simple non-sticky PR comment via gh CLI](#simple-non-sticky-pr-comment-via-gh-cli) -- [Matrix across environments](#matrix-across-environments) -- [Soft-fail recipe](#soft-fail-recipe) -- [Forked-PR caveat](#forked-pr-caveat) -- [Enterprise patterns (mTLS, custom CA)](#enterprise-patterns-mtls-custom-ca) -- [Other CI platforms](#other-ci-platforms) ### PR comment on every run (sticky) @@ -130,7 +109,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: usebruno/bruno-cli-action@v0 + - uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml' @@ -141,61 +120,14 @@ jobs: files: tests/payments/results.xml ``` -**Prerequisites:** `pull-requests: write` and `checks: write` permissions in the workflow file. **What you'll see:** a single Bruno-themed comment in the PR Conversation tab that updates in place on every re-run, plus a check run with structured per-test results in the PR Checks tab. -**Why `if: always()`:** EnricoMi must run even when the Bruno step fails the build, otherwise users do not see the comment on failure. - -### PR comment only on failures - -For teams who do not want a green-passes-everywhere comment polluting the conversation: - -```yaml -- uses: EnricoMi/publish-unit-test-result-action@v2 - if: always() - with: - files: tests/payments/results.xml - comment_mode: failures # post a comment only when something failed -``` - -**What you'll see:** PR comment appears only when at least one assertion failed. Successful runs leave no comment behind. -**Other `comment_mode` values:** `always` (default), `failures`, `errors`, `off`. - -### Step Summary without PR comment - -EnricoMi writes a Step Summary by default. If you want the workflow-page digest but no PR comment noise: - -```yaml -- uses: EnricoMi/publish-unit-test-result-action@v2 - if: always() - with: - files: tests/payments/results.xml - comment_mode: off # disable PR comment - job_summary: true # default true; shown for clarity -``` - -**What you'll see:** a markdown summary on the workflow run page (visible by clicking into the run from the Actions tab). No PR Conversation comment, no Checks-tab check run annotations. - -### Workflow-level annotations on PR Checks - -EnricoMi posts annotations via the Check Runs API. These appear in the PR Checks tab attached to EnricoMi's check run: - -```yaml -- uses: EnricoMi/publish-unit-test-result-action@v2 - if: always() - with: - files: tests/payments/results.xml - report_individual_runs: true # one annotation per failed test -``` - -**What you'll see:** the PR Checks tab shows the EnricoMi check run with one annotation per failed assertion, expandable for failure details. -**Note:** line-anchored annotations on `.bru` source lines would require the CLI to emit `file=` and `line=` in JUnit. Not currently planned. ### Checks tab UI via dorny/test-reporter If you have a polyglot test stack (Jest, Pytest, Bruno) and want all results in the same Checks tab UI, dorny is the better tool than EnricoMi: ```yaml -- uses: usebruno/bruno-cli-action@v0 +- uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml' @@ -210,38 +142,12 @@ If you have a polyglot test stack (Jest, Pytest, Bruno) and want all results in **What you'll see:** a separate check run in the PR Checks tab labeled "Bruno API tests" with structured per-test results and expandable failure details. Visually consistent with check runs from your other JUnit-emitting test suites. -### EnricoMi + dorny together - -When you want both: a PR Conversation comment from EnricoMi and a polished Checks tab UI from dorny: - -```yaml -- uses: usebruno/bruno-cli-action@v0 - with: - working-directory: tests/payments - command: 'run --env prod --reporter-junit results.xml' - -- uses: EnricoMi/publish-unit-test-result-action@v2 - if: always() - with: - files: tests/payments/results.xml - comment_mode: always - -- uses: dorny/test-reporter@v1 - if: always() - with: - name: Bruno API tests - path: tests/payments/results.xml - reporter: java-junit -``` - -**What you'll see:** PR Conversation gets the EnricoMi sticky comment; PR Checks tab shows two check runs (one from each downstream action) plus the EnricoMi annotations. - ### Artifact upload with header sanitization Bruno's CLI handles sensitive-header redaction; pass the flag in `command`. Chain `actions/upload-artifact@v7` to persist the report: ```yaml -- uses: usebruno/bruno-cli-action@v0 +- uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml --reporter-skip-headers "Authorization Cookie X-Tenant-Token"' @@ -253,16 +159,14 @@ Bruno's CLI handles sensitive-header redaction; pass the flag in `command`. Chai path: tests/payments/results.xml ``` -**What you'll see:** an artifact named `bruno-report--` on the workflow run page, downloadable for 90 days (GitHub default retention). `Authorization`, `Cookie`, and `X-Tenant-Token` headers are redacted in the JUnit XML before upload. - -To customize retention or use compression options, see `actions/upload-artifact@v7`'s own inputs (`retention-days`, `compression-level`, `if-no-files-found`). +**What you'll see:** an artifact named `bruno-report--` on the workflow run page, downloadable for 90 days (GitHub default retention). ### Multiple report formats (JUnit + HTML + JSON) Pass multiple reporter flags in `command`. Chain `actions/upload-artifact@v7` with a path list: ```yaml -- uses: usebruno/bruno-cli-action@v0 +- uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod --reporter-junit results.xml --reporter-html report.html --reporter-json report.json' @@ -281,11 +185,11 @@ Pass multiple reporter flags in `command`. Chain `actions/upload-artifact@v7` wi ### Slack notification on failure -Use the JUnit-derived `failed` output as a conditional. Use `continue-on-error: true` so the notification step still runs: +Use the action's `failed` output as a conditional. Use `continue-on-error: true` so the notification step still runs: ```yaml - id: bruno - uses: usebruno/bruno-cli-action@v0 + uses: usebruno/bruno-cli-action@v1 continue-on-error: true with: working-directory: tests/payments @@ -318,7 +222,7 @@ For users who do not want EnricoMi's full setup and only need a quick "post a co ```yaml - id: bruno - uses: usebruno/bruno-cli-action@v0 + uses: usebruno/bruno-cli-action@v1 with: working-directory: tests/payments command: 'run --env prod' @@ -341,158 +245,16 @@ For users who do not want EnricoMi's full setup and only need a quick "post a co **Prerequisites:** `pull-requests: write` permission and the workflow triggered on `pull_request`. **What you'll see:** a new comment posted to the PR on every workflow run. Each re-run adds another comment (no in-place update). Use EnricoMi (above) if you want stickiness. -### Matrix across environments - -Use distinct JUnit paths and artifact names per matrix leg. Chain EnricoMi and `actions/upload-artifact@v7` per leg: - -```yaml -on: [pull_request] - -permissions: - pull-requests: write - checks: write - contents: read - -jobs: - bruno: - runs-on: ubuntu-latest - strategy: - matrix: - env: [staging, prod] - steps: - - uses: actions/checkout@v6 - - uses: usebruno/bruno-cli-action@v0 - with: - working-directory: tests/payments - command: 'run --env ${{ matrix.env }} --reporter-junit results-${{ matrix.env }}.xml' - - - uses: actions/upload-artifact@v7 - if: always() - with: - name: bruno-report-${{ matrix.env }} - path: tests/payments/results-${{ matrix.env }}.xml - - - uses: EnricoMi/publish-unit-test-result-action@v2 - if: always() - with: - check_name: Bruno (${{ matrix.env }}) - files: tests/payments/results-${{ matrix.env }}.xml - comment_mode: failures -``` - -**What you'll see:** two matrix legs running in parallel against staging and prod. Each leg produces its own artifact (`bruno-report-staging`, `bruno-report-prod`), its own check run (`Bruno (staging)` / `Bruno (prod)`) in the PR Checks tab, and a PR comment only when that leg fails. -**Note:** include the matrix key in both `--reporter-junit` and the artifact `name` to avoid `actions/upload-artifact@v7`'s duplicate-name error across matrix legs. - -### Soft-fail recipe - -Record results without failing the build, then notify selectively. Use GitHub Actions' built-in `continue-on-error: true`: - -```yaml -- id: bruno - uses: usebruno/bruno-cli-action@v0 - continue-on-error: true - with: - working-directory: tests/payments - command: 'run --env prod' - -- if: steps.bruno.outputs.failed != '0' - run: ./notify-slack.sh ${{ steps.bruno.outputs.failed }} -``` - -**What you'll see:** the Bruno step appears red in the workflow run UI when assertions fail (honest signal that something went wrong), but downstream steps still run because `continue-on-error` lets the workflow proceed. Outputs are populated for the conditional notification step. - -### Forked-PR caveat - -GitHub restricts `GITHUB_TOKEN` to read-only for workflows triggered by `pull_request` events from forked repositories, regardless of the `permissions` block in the workflow file. EnricoMi and any PR comment poster need write permission, which means workflows running on community contributions must use `pull_request_target` (with care: it runs with the base branch's permissions and secrets). See the [GitHub docs](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) and [EnricoMi's fork PR docs](https://github.com/EnricoMi/publish-unit-test-result-action#support-fork-repositories-and-dependabot-branches) for the trade-offs. - -### Enterprise patterns (mTLS, custom CA) - -Marshall secrets via shell, pass paths to bru: - -```yaml -- run: | - mkdir -p /tmp/certs && chmod 700 /tmp/certs - echo "$CA_CERT" > /tmp/certs/ca.pem - echo "$CLIENT_CERT_CONFIG" > /tmp/certs/client.json - env: - CA_CERT: ${{ secrets.API_CA_CERT }} - CLIENT_CERT_CONFIG: ${{ secrets.API_CLIENT_CERT_CONFIG }} - -- uses: usebruno/bruno-cli-action@v0 - with: - working-directory: tests/payments - command: 'run --env prod --cacert /tmp/certs/ca.pem --client-cert-config /tmp/certs/client.json' -``` - -**Prerequisites:** `API_CA_CERT` and `API_CLIENT_CERT_CONFIG` secrets configured. -**What you'll see:** Bruno runs against an internal mTLS-protected API. Secrets never appear in logs (GitHub auto-masks); cert files are written to a temp dir and cleaned up when the runner is destroyed. - -### Other CI platforms - -Bruno's CLI works on Jenkins, Azure DevOps, GitLab CI, and Bitbucket Pipelines via direct CLI invocation. The [Bruno CLI Docker image](https://hub.docker.com/r/usebruno/cli) is the recommended primitive there. See the [Bruno CLI docs](https://docs.usebruno.com/bru-cli/overview) for platform-specific examples. - -## Troubleshooting - -**Sandbox migration (Bruno CLI v3+).** v3 changed the default sandbox. If your tests rely on Node built-ins (`require`, `Buffer`, etc.), add `--sandbox developer` to `command`: - -```yaml -command: 'run --env ci --sandbox developer' -``` - -**`exit-code` is non-zero but `failed` is `0`.** The `bru` process crashed before writing JUnit, or wrote an empty report. Treat as a runtime error — check the step log for stderr. See the exit-code reference below. - -**Verifying which flags `bru` was invoked with.** The action prints the full `bru` invocation inside a `::group::` block in the run log, including any flags it auto-injected (`--reporter-junit "$RUNNER_TEMP/bruno-junit.xml"`). Expand the group to confirm what ran. - -### Exit-code reference - -`bru` exits with one of the following codes, available as `steps..outputs.exit-code`: - -| Code | Meaning | Common cause | -|------|---------|--------------| -| 0 | All requests, tests, and assertions passed | — | -| 1 | One or more requests, tests, or assertions failed | inspect the JUnit XML; fix the failing tests | -| 2 | Reporter output directory does not exist | create the dir or change `--reporter-junit` path | -| 3 | Request chain caused an infinite loop | break the loop in your collection | -| 4 | `bru` was invoked outside a collection root | set `working-directory` to the collection dir | -| 5 | A file referenced by `command` was not found | typo'd path in `command` | -| 6 | Environment file not found | check `environments/.bru` exists | -| 7 | `--env-var` value not parsable as `name=value` | fix the quoting in `command` | -| 8 | `--env-var` format incorrect | same — see Bruno CLI docs | -| 9 | Invalid reporter format | only `json` / `junit` / `html` accepted | -| 10 | Failed to parse a `.bru` / env / config file | syntax error in the file | -| 11 | Workspace not found (when `--workspace-path` used) | check the path | -| 12 | `--global-env` used without `--workspace-path` | add `--workspace-path` | -| 13 | Global environment file not found | check the global env name | -| 137 | OS killed the process (`SIGKILL`, usually OOM) | bigger runner or split the collection | -| 130 | Job was cancelled (`SIGINT`) | check `timeout-minutes`; nothing to fix in `command` | -| 255 | Unhandled CLI crash (`ERROR_GENERIC`) | open an issue in `usebruno/bruno` with the stderr | - -(Source: `packages/bruno-cli/src/constants.js` in the Bruno repo. Codes may shift across major CLI versions; the nightly workflow catches changes.) - -### Job failed before bru could run - -If the run log shows a red **Install Bruno CLI** step (not **Run bru**), the failure is in `npm install -g @usebruno/cli`, not in your collection. `outputs.exit-code` will be empty because `bru` never ran. Expand that step and look for one of: - -| stderr substring | Likely cause | Fix | -|---|---|---| -| `E404` / `404 Not Found` | `bru-version` doesn't exist on npm | pick a real version (or `latest`) | -| `ENOTFOUND` / `ETIMEDOUT` | runner can't reach `registry.npmjs.org` | check corp proxy / network policy | -| `EACCES` | self-hosted runner missing install permission | adjust npm prefix or run with sudo | -| `ENOSPC` | self-hosted runner disk full | clear space | -| `EINTEGRITY` | corrupted npm cache | `npm cache clean --force` then re-run | - -All of these surface npm exit `1`. The useful signal is the stderr text, not the exit number. +## Other CI platforms -**Network timeouts.** Bruno honours `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`. Set them via `env:` on the step. +Bruno's CLI works on Jenkins, Azure DevOps, GitLab CI, and Bitbucket Pipelines via direct CLI invocation. The [Bruno CLI Docker image](https://hub.docker.com/r/usebruno/cli) is the recommended primitive there. See the [Bruno CLI Docker docs](https://docs.usebruno.com/bru-cli/docker) for platform-specific examples. ## Resources - [Bruno CLI documentation](https://docs.usebruno.com/bru-cli/overview) - [Bruno CLI command options](https://docs.usebruno.com/bru-cli/commandOptions) -- [`@usebruno/cli` on npm](https://www.npmjs.com/package/@usebruno/cli) -- [`usebruno/bruno` (main Bruno repo)](https://github.com/usebruno/bruno) -- [GitHub Actions documentation](https://docs.github.com/en/actions) -- [Recommended downstream actions](#examples) for PR comments, Checks tab UI, and artifact upload +- [Bruno NPM package](https://www.npmjs.com/package/@usebruno/cli) +- [Main Bruno repo](https://github.com/usebruno/bruno) ## License