mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat(cli): add Docker image with alpine and debian variants (#8001)
This commit is contained in:
271
packages/bruno-cli/docker/README.md
Normal file
271
packages/bruno-cli/docker/README.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# Bruno CLI Docker Images
|
||||
|
||||
Official Docker images for [Bruno CLI](https://www.usebruno.com), enabling container-native API collection runs in CI/CD pipelines and local environments without requiring Node.js or npm on the host.
|
||||
|
||||
## Image structure
|
||||
|
||||
```text
|
||||
docker/
|
||||
├── README.md ← you are here
|
||||
└── images/
|
||||
├── alpine/
|
||||
│ ├── Dockerfile ← Alpine Linux variant (smallest, ~141MB)
|
||||
│ └── README.md
|
||||
└── debian/
|
||||
├── Dockerfile ← Debian slim variant (~200MB+, glibc support)
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Registries
|
||||
|
||||
```bash
|
||||
docker pull usebruno/cli:latest
|
||||
docker pull ghcr.io/usebruno/cli:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variants
|
||||
|
||||
| Variant | Base image | Details |
|
||||
|---------|-----------|---------|
|
||||
| **Alpine** (default) | `node:22-alpine` | [→ Alpine README](./images/alpine/README.md) |
|
||||
| **Debian** | `node:22-slim` | [→ Debian README](./images/debian/README.md) |
|
||||
|
||||
### Quick choice
|
||||
|
||||
- **Use Alpine** unless you have a specific reason not to (90% of users)
|
||||
- **Use Debian** if you hit SSL/glibc compatibility issues
|
||||
|
||||
---
|
||||
|
||||
## Tags
|
||||
|
||||
| Tag | Example | Variant |
|
||||
|-----|---------|---------|
|
||||
| `latest` | `usebruno/cli:latest` | alpine |
|
||||
| `<version>` | `usebruno/cli:3.3.0` | alpine |
|
||||
| `<major.minor>` | `usebruno/cli:3.3` | alpine |
|
||||
| `<major>` | `usebruno/cli:3` | alpine |
|
||||
| `<version>-alpine` | `usebruno/cli:3.3.0-alpine` | alpine |
|
||||
| `<version>-debian` | `usebruno/cli:3.3.0-debian` | debian |
|
||||
| `debian` | `usebruno/cli:debian` | debian |
|
||||
|
||||
---
|
||||
|
||||
## Step-by-step guide
|
||||
|
||||
### Step 1 — Pull the image
|
||||
|
||||
```bash
|
||||
# latest (alpine by default — smallest, fastest to pull)
|
||||
docker pull usebruno/cli:latest
|
||||
|
||||
# specific version (recommended for production CI)
|
||||
docker pull usebruno/cli:3.3.0
|
||||
|
||||
# major.minor — gets patch updates automatically
|
||||
docker pull usebruno/cli:3.3
|
||||
|
||||
# debian variant
|
||||
docker pull usebruno/cli:debian
|
||||
docker pull usebruno/cli:3.3.0-debian
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 2 — Check it works
|
||||
|
||||
```bash
|
||||
docker run --rm usebruno/cli --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 3 — Run your collection
|
||||
|
||||
> Mount your collection directory to `/bruno` and pass `bru` arguments directly after the image name.
|
||||
|
||||
> **Cross-platform note:** the examples below use `$(pwd)` which works in Bash / Zsh / Git Bash / WSL.
|
||||
> On Windows native shells, substitute `$(pwd)` with:
|
||||
> - PowerShell: `${PWD}`
|
||||
> - CMD: `%cd%`
|
||||
|
||||
```bash
|
||||
# collection at your current directory
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run --env staging
|
||||
|
||||
# collection in a subfolder
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run ./api-tests --env staging
|
||||
|
||||
# single request file
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run ./api-tests/login.bru --env staging
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4 — Choose your environment
|
||||
|
||||
```bash
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run --env local
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run --env staging
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run --env production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — Pass variables at runtime
|
||||
|
||||
```bash
|
||||
# override a single variable
|
||||
docker run --rm \
|
||||
-v $(pwd):/bruno \
|
||||
usebruno/cli run --env staging --env-var API_KEY=your_key
|
||||
|
||||
# override multiple variables
|
||||
docker run --rm \
|
||||
-v $(pwd):/bruno \
|
||||
usebruno/cli run --env staging \
|
||||
--env-var BASE_URL=https://api.example.com \
|
||||
--env-var API_KEY=secret123
|
||||
|
||||
# load variables from a file
|
||||
docker run --rm \
|
||||
-v $(pwd):/bruno \
|
||||
--env-file .env \
|
||||
usebruno/cli run --env staging
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 6 — Save test results
|
||||
|
||||
```bash
|
||||
# JSON report
|
||||
docker run --rm \
|
||||
-v $(pwd):/bruno \
|
||||
usebruno/cli run --env staging --output results.json --format json
|
||||
|
||||
# JUnit XML report (for CI test reporters)
|
||||
docker run --rm \
|
||||
-v $(pwd):/bruno \
|
||||
usebruno/cli run --env staging --output results.xml --format junit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 7 — Stop on first failure
|
||||
|
||||
```bash
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli run --env staging --bail
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 8 — Pin the right version
|
||||
|
||||
```bash
|
||||
# exact version — safest for production, no surprise updates
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3.0 run --env staging
|
||||
|
||||
# major.minor — gets patch fixes automatically
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3 run --env staging
|
||||
|
||||
# latest — always newest, not recommended for production CI
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:latest run --env staging
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 9 — Choose alpine or debian
|
||||
|
||||
```bash
|
||||
# alpine (default) — use this for most cases
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3.0 run --env staging
|
||||
|
||||
# debian — use if you hit SSL, glibc, or native module issues
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3.0-debian run --env staging
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage by variant
|
||||
|
||||
### Alpine variant
|
||||
|
||||
See [Alpine README](./images/alpine/README.md) for:
|
||||
- Building the Alpine image
|
||||
- When to use Alpine
|
||||
- Variant-specific options
|
||||
|
||||
### Debian variant
|
||||
|
||||
See [Debian README](./images/debian/README.md) for:
|
||||
- Building the Debian image
|
||||
- When to use Debian
|
||||
- Compatibility notes
|
||||
|
||||
---
|
||||
|
||||
## CI/CD integration
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
api-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run Bruno collection
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}:/bruno \
|
||||
usebruno/cli:3.3 run --env staging --output results.xml --format junit
|
||||
|
||||
- name: Publish Test Report
|
||||
uses: dorny/test-reporter@v3
|
||||
if: always()
|
||||
with:
|
||||
name: Bruno Test Results
|
||||
path: results.xml
|
||||
reporter: java-junit
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
||||
```yaml
|
||||
api-tests:
|
||||
image: usebruno/cli:3.3
|
||||
script:
|
||||
- bru run --env staging --output results.xml --format junit
|
||||
artifacts:
|
||||
reports:
|
||||
junit: results.xml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Image details
|
||||
|
||||
All variants include:
|
||||
|
||||
- **Entrypoint:** `bru`
|
||||
- **Working directory:** `/bruno`
|
||||
- **User:** `node` (UID 1000, non-root)
|
||||
- **Architectures:** `linux/amd64`, `linux/arm64`
|
||||
|
||||
---
|
||||
|
||||
## All version × variant combinations
|
||||
|
||||
| | Alpine | Debian |
|
||||
|---|---|---|
|
||||
| `latest` | `usebruno/cli:latest` | `usebruno/cli:debian` |
|
||||
| `3` | `usebruno/cli:3` | `usebruno/cli:3-debian` |
|
||||
| `3.3` | `usebruno/cli:3.3` | `usebruno/cli:3.3-debian` |
|
||||
| `3.3.0` | `usebruno/cli:3.3.0` | `usebruno/cli:3.3.0-debian` |
|
||||
| `3.2.0` | `usebruno/cli:3.2.0` | `usebruno/cli:3.2.0-debian` |
|
||||
34
packages/bruno-cli/docker/images/alpine/Dockerfile
Normal file
34
packages/bruno-cli/docker/images/alpine/Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
LABEL maintainer="Bruno <engineering@usebruno.com>"
|
||||
|
||||
ARG BRUNO_VERSION
|
||||
ENV BRUNO_VERSION=${BRUNO_VERSION}
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/usebruno/bruno"
|
||||
LABEL org.opencontainers.image.description="Bruno CLI - Open source IDE for exploring and testing APIs"
|
||||
LABEL org.opencontainers.image.licenses="MIT"
|
||||
LABEL org.opencontainers.image.title="Bruno CLI"
|
||||
LABEL org.opencontainers.image.version="${BRUNO_VERSION}"
|
||||
LABEL org.opencontainers.image.url="https://www.usebruno.com"
|
||||
LABEL org.opencontainers.image.documentation="https://docs.usebruno.com/bru-cli/overview"
|
||||
|
||||
ENV LC_ALL="en_US.UTF-8" \
|
||||
LANG="en_US.UTF-8" \
|
||||
LANGUAGE="en_US.UTF-8"
|
||||
|
||||
# If BRUNO_VERSION is provided, validate it is a valid semver before installing
|
||||
RUN if [ -n "$BRUNO_VERSION" ]; then \
|
||||
if ! echo "$BRUNO_VERSION" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+$"; then \
|
||||
echo "\033[0;31mA valid semver Bruno version is required in the BRUNO_VERSION build-arg (e.g. 1.16.0)\033[0m"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi && \
|
||||
npm install -g @usebruno/cli${BRUNO_VERSION:+@${BRUNO_VERSION}}
|
||||
|
||||
WORKDIR /bruno
|
||||
|
||||
USER node
|
||||
|
||||
ENTRYPOINT ["bru"]
|
||||
CMD []
|
||||
27
packages/bruno-cli/docker/images/alpine/README.md
Normal file
27
packages/bruno-cli/docker/images/alpine/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Bruno CLI — Alpine
|
||||
|
||||
Alpine Linux variant of the Bruno CLI Docker image.
|
||||
|
||||
**Base image:** `node:22-alpine`
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
docker build -t usebruno/cli:alpine ./images/alpine
|
||||
|
||||
# with specific Bruno CLI version
|
||||
docker build \
|
||||
--build-arg BRUNO_VERSION=3.3.0 \
|
||||
-t usebruno/cli:3.3.0-alpine \
|
||||
./images/alpine
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Run a collection
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:alpine run --env staging
|
||||
|
||||
# with pinned version
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3.0-alpine run --env staging
|
||||
```
|
||||
34
packages/bruno-cli/docker/images/debian/Dockerfile
Normal file
34
packages/bruno-cli/docker/images/debian/Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
||||
FROM node:22-slim
|
||||
|
||||
LABEL maintainer="Bruno <engineering@usebruno.com>"
|
||||
|
||||
ARG BRUNO_VERSION
|
||||
ENV BRUNO_VERSION=${BRUNO_VERSION}
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/usebruno/bruno"
|
||||
LABEL org.opencontainers.image.description="Bruno CLI - Open source IDE for exploring and testing APIs"
|
||||
LABEL org.opencontainers.image.licenses="MIT"
|
||||
LABEL org.opencontainers.image.title="Bruno CLI"
|
||||
LABEL org.opencontainers.image.version="${BRUNO_VERSION}"
|
||||
LABEL org.opencontainers.image.url="https://www.usebruno.com"
|
||||
LABEL org.opencontainers.image.documentation="https://docs.usebruno.com/bru-cli/overview"
|
||||
|
||||
ENV LC_ALL="en_US.UTF-8" \
|
||||
LANG="en_US.UTF-8" \
|
||||
LANGUAGE="en_US.UTF-8"
|
||||
|
||||
# If BRUNO_VERSION is provided, validate it is a valid semver before installing
|
||||
RUN if [ -n "$BRUNO_VERSION" ]; then \
|
||||
if ! echo "$BRUNO_VERSION" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+$"; then \
|
||||
echo "\033[0;31mA valid semver Bruno version is required in the BRUNO_VERSION build-arg (e.g. 1.16.0)\033[0m"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi && \
|
||||
npm install -g @usebruno/cli${BRUNO_VERSION:+@${BRUNO_VERSION}}
|
||||
|
||||
WORKDIR /bruno
|
||||
|
||||
USER node
|
||||
|
||||
ENTRYPOINT ["bru"]
|
||||
CMD []
|
||||
27
packages/bruno-cli/docker/images/debian/README.md
Normal file
27
packages/bruno-cli/docker/images/debian/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Bruno CLI — Debian
|
||||
|
||||
Debian slim variant of the Bruno CLI Docker image.
|
||||
|
||||
**Base image:** `node:22-slim`
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
docker build -t usebruno/cli:debian ./images/debian
|
||||
|
||||
# with specific Bruno CLI version
|
||||
docker build \
|
||||
--build-arg BRUNO_VERSION=3.3.0 \
|
||||
-t usebruno/cli:3.3.0-debian \
|
||||
./images/debian
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Run a collection
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:debian run --env staging
|
||||
|
||||
# with pinned version
|
||||
docker run --rm -v $(pwd):/bruno usebruno/cli:3.3.0-debian run --env staging
|
||||
```
|
||||
135
packages/bruno-cli/docker/smoke-test.sh
Executable file
135
packages/bruno-cli/docker/smoke-test.sh
Executable file
@@ -0,0 +1,135 @@
|
||||
#!/bin/sh
|
||||
# Smoke tests for Bruno CLI Docker image
|
||||
# Usage: ./smoke-test.sh <image> [collection-abs-path] [run-target] [env-name]
|
||||
# Examples:
|
||||
# ./smoke-test.sh usebruno/cli:alpine
|
||||
# ./smoke-test.sh usebruno/cli:alpine /abs/path/to/collection echo Prod
|
||||
|
||||
set -e
|
||||
|
||||
IMAGE=$1
|
||||
COLLECTION_PATH=$2
|
||||
RUN_TARGET=${3:-.}
|
||||
COLLECTION_ENV=$4
|
||||
|
||||
if [ -z "$IMAGE" ]; then
|
||||
echo "Usage: $0 <image> [collection-abs-path] [run-target] [env-name]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running smoke tests for image: $IMAGE"
|
||||
echo "---"
|
||||
|
||||
# Test 1 - bru is installed and returns a version
|
||||
echo "Test 1: bru --version"
|
||||
VERSION=$(docker run --rm "$IMAGE" --version)
|
||||
echo " → $VERSION"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo " FAIL: no version output"
|
||||
exit 1
|
||||
fi
|
||||
echo " PASS"
|
||||
|
||||
# Test 2 - container runs as non-root user "node"
|
||||
echo "Test 2: non-root user"
|
||||
USER=$(docker run --rm --entrypoint whoami "$IMAGE")
|
||||
echo " → $USER"
|
||||
if [ "$USER" != "node" ]; then
|
||||
echo " FAIL: expected 'node', got '$USER'"
|
||||
exit 1
|
||||
fi
|
||||
echo " PASS"
|
||||
|
||||
# Test 3 - working directory is /bruno
|
||||
echo "Test 3: working directory"
|
||||
DIR=$(docker run --rm --entrypoint pwd "$IMAGE")
|
||||
echo " → $DIR"
|
||||
if [ "$DIR" != "/bruno" ]; then
|
||||
echo " FAIL: expected '/bruno', got '$DIR'"
|
||||
exit 1
|
||||
fi
|
||||
echo " PASS"
|
||||
|
||||
# Test 4 - bru help works
|
||||
echo "Test 4: bru --help"
|
||||
docker run --rm "$IMAGE" --help > /dev/null
|
||||
echo " PASS"
|
||||
|
||||
# Test 5 (optional) - run an actual Bruno collection
|
||||
#
|
||||
# Engine-vs-content semantics:
|
||||
# This test validates that bru can execute a collection end-to-end
|
||||
# (parser, request layer, JS sandbox, assertion engine, summary output).
|
||||
# It does NOT require every test/assertion in the collection to pass.
|
||||
#
|
||||
# Success: bru reaches the run summary AND at least 1 request passed.
|
||||
# Failure: bru did not emit a summary (engine broken) OR every request failed
|
||||
# (suggests image-level breakage rather than incidental test flakes).
|
||||
#
|
||||
# Any individual test/request failures are surfaced as warnings (full bru
|
||||
# output kept above for trace) so the team can investigate without blocking
|
||||
# the publish.
|
||||
if [ -n "$COLLECTION_PATH" ]; then
|
||||
if [ ! -d "$COLLECTION_PATH" ]; then
|
||||
echo "Test 5: FAIL - collection path not found: $COLLECTION_PATH"
|
||||
exit 1
|
||||
fi
|
||||
# Build the optional --env argument as positional params so it remains
|
||||
# properly quoted when passed to docker run (avoids word-splitting issues
|
||||
# if COLLECTION_ENV ever contains spaces or special characters).
|
||||
set --
|
||||
if [ -n "$COLLECTION_ENV" ]; then
|
||||
set -- --env "$COLLECTION_ENV"
|
||||
fi
|
||||
echo "Test 5: bru run $RUN_TARGET${COLLECTION_ENV:+ --env $COLLECTION_ENV}"
|
||||
echo "----- bru run output -----"
|
||||
|
||||
set +e
|
||||
# Use --mount instead of -v so Windows-style paths (e.g. C:\repo\collection)
|
||||
# don't collide with -v's host:container colon separator.
|
||||
OUTPUT=$(docker run --rm \
|
||||
--mount "type=bind,source=$COLLECTION_PATH,target=/bruno" \
|
||||
"$IMAGE" \
|
||||
run "$RUN_TARGET" "$@" 2>&1)
|
||||
EXIT=$?
|
||||
set -e
|
||||
|
||||
echo "$OUTPUT"
|
||||
echo "----- bru run output end (exit=$EXIT) -----"
|
||||
|
||||
# Locate bru's end-of-run summary, supporting both output formats:
|
||||
# New (table): "Requests | 14 (12 Passed, 2 Failed)"
|
||||
# Legacy (line): "Requests: 14, Passed: 12, Failed: 2"
|
||||
# Reject ANSI/box-drawing chars by grep'ing for the request-count pattern.
|
||||
SUMMARY_REQ=$(echo "$OUTPUT" | grep -E "[0-9]+[[:space:]]+Passed,[[:space:]]+[0-9]+[[:space:]]+Failed" | head -1)
|
||||
if [ -z "$SUMMARY_REQ" ]; then
|
||||
# Fall back to legacy "Requests: N, Passed: N, Failed: N" form
|
||||
SUMMARY_REQ=$(echo "$OUTPUT" | grep -E "Requests:[[:space:]]+[0-9]+,[[:space:]]+Passed:[[:space:]]+[0-9]+,[[:space:]]+Failed:[[:space:]]+[0-9]+" | head -1)
|
||||
fi
|
||||
if [ -z "$SUMMARY_REQ" ]; then
|
||||
echo " FAIL: bru did not emit a run summary - engine likely crashed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PASSED=$(echo "$SUMMARY_REQ" | grep -oE "([0-9]+[[:space:]]+Passed|Passed:[[:space:]]+[0-9]+)" | head -1 | grep -oE "[0-9]+")
|
||||
FAILED=$(echo "$SUMMARY_REQ" | grep -oE "([0-9]+[[:space:]]+Failed|Failed:[[:space:]]+[0-9]+)" | head -1 | grep -oE "[0-9]+")
|
||||
PASSED=${PASSED:-0}
|
||||
FAILED=${FAILED:-0}
|
||||
echo " Summary: $SUMMARY_REQ"
|
||||
|
||||
if [ "$PASSED" -ge 1 ]; then
|
||||
if [ "$FAILED" -gt 0 ]; then
|
||||
echo " PASS (with warnings: $FAILED request(s) failed - see output above for details)"
|
||||
# Surface as a GitHub Actions warning annotation when run in CI
|
||||
echo "::warning::Smoke Test 5 ($IMAGE): $FAILED request(s) failed in collection '$RUN_TARGET' env=$COLLECTION_ENV. $PASSED passed. Image marked OK. Review bru output in this job's log."
|
||||
else
|
||||
echo " PASS (all $PASSED request(s) passed)"
|
||||
fi
|
||||
else
|
||||
echo " FAIL: 0 requests passed (Passed=$PASSED, Failed=$FAILED) - check image and network"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
echo "All smoke tests passed for $IMAGE"
|
||||
Reference in New Issue
Block a user