name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
test:
name: Test Suite
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, beta]
exclude:
- os: macos-latest
rust: beta
- os: windows-latest
rust: beta
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy
- name: Cache Rust dependencies
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-${{ matrix.os }}-${{ matrix.rust }}"
cache-all-crates: true
- name: Check formatting
if: matrix.rust == 'stable' && matrix.os == 'ubuntu-latest'
run: cargo fmt -- --check
- name: Check for executor.execute_command antipattern
if: matrix.rust == 'stable' && matrix.os == 'ubuntu-latest'
run: |
# Commands should use self.execute_command(args) not self.executor.execute_command("docker", args)
# The latter causes "docker docker <cmd>" double-command bug (issue #233)
if grep -rE 'executor\.execute_command\("docker"|execute_command\("docker",' src/command.rs src/command/; then
echo "ERROR: Found execute_command(\"docker\", ...) antipattern!"
echo "Use self.execute_command(args) instead to avoid 'docker docker' bug."
echo "For compose commands, pass 'compose' as command name, not 'docker'."
exit 1
fi
- name: Run Clippy
if: matrix.rust == 'stable'
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Build
run: cargo build --all-features
- name: Build examples
run: cargo build --examples --all-features
- name: Check individual template features compile
shell: bash
run: |
for feature in template-redis template-redis-cluster template-redis-enterprise template-postgres template-mysql template-mongodb template-nginx; do
echo "Checking feature: $feature"
cargo check --features "$feature"
done
- name: Run tests
run: cargo test --lib --all-features && cargo test --doc --all-features
docker-tests:
name: Docker Integration Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: stable
- name: Cache Rust dependencies
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-docker"
cache-all-crates: true
- name: Start Docker
run: |
sudo systemctl start docker
docker --version
- name: Pull test images in parallel
run: |
docker pull alpine:latest &
docker pull redis:7.2-alpine &
docker pull redis:7-alpine &
docker pull redis:6-alpine &
docker pull redis/redis-stack:latest &
docker pull nginx:alpine &
docker pull postgres:15-alpine &
docker pull mysql:8 &
docker pull mongo:latest &
wait
- name: Run integration tests
run: cargo test --test '*' --all-features
env:
DOCKER_HOST: unix:///var/run/docker.sock
- name: Build examples
run: cargo build --examples --all-features
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: stable
- name: Cache Rust dependencies
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-security"
cache-all-crates: true
- name: Cache cargo-audit
id: cache-cargo-audit
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cargo-audit
key: cargo-audit-${{ runner.os }}
- name: Install cargo-audit if not cached
if: steps.cache-cargo-audit.outputs.cache-hit != 'true'
run: cargo install cargo-audit --locked
- name: Run security audit
run: cargo audit
msrv:
name: Minimum Supported Rust Version
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust 1.89.0
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: 1.89.0
- name: Cache Rust dependencies
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-msrv"
cache-all-crates: true
- name: Build with MSRV
run: cargo build --all-features
- name: Test with MSRV
run: cargo test --lib --all-features
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: stable
- name: Cache Rust dependencies
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-docs"
cache-all-crates: true
- name: Build documentation
run: cargo doc --all-features --no-deps
env:
RUSTDOCFLAGS: -D warnings
dependency-check:
name: Dependency Management
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
with:
toolchain: stable
- name: Cache Rust dependencies and tools
uses: swatinem/rust-cache@v2
with:
shared-key: "ci-deps"
cache-all-crates: true
cache-directories: |
~/.cargo/bin/
- name: Cache cargo-machete
id: cache-cargo-machete
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cargo-machete
key: cargo-machete-${{ runner.os }}
- name: Install cargo-machete if not cached
if: steps.cache-cargo-machete.outputs.cache-hit != 'true'
run: cargo install cargo-machete --locked
- name: Check for unused dependencies
run: cargo machete
continue-on-error: true
- name: Cache cargo-outdated
id: cache-cargo-outdated
uses: actions/cache@v5
with:
path: ~/.cargo/bin/cargo-outdated
key: cargo-outdated-${{ runner.os }}
- name: Install cargo-outdated if not cached
if: steps.cache-cargo-outdated.outputs.cache-hit != 'true'
run: cargo install cargo-outdated --locked
- name: Check for outdated dependencies
run: cargo outdated --exit-code 1 || true
continue-on-error: true