name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions: {}
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings
NEXTEST_VERSION: "0.9.140"
CARGO_FUZZ_VERSION: "0.13.2"
LLVM_COV_VERSION: "0.8.7"
CARGO_DENY_VERSION: "0.20.2"
FUZZ_MAX_TOTAL_TIME: "60"
COVERAGE_FAIL_UNDER: "70"
jobs:
features:
name: Features (${{ matrix.name }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: none
args: --no-default-features
- name: cookie-jar
args: --no-default-features --features cookie-jar
- name: gzip
args: --no-default-features --features gzip
- name: zstd
args: --no-default-features --features zstd
- name: all
args: --all-features
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: nextest@${{ env.NEXTEST_VERSION }}
- name: Cache
uses: Swatinem/rust-cache@v2
with:
key: features-${{ matrix.name }}
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Check
run: cargo check --locked ${{ matrix.args }}
- name: Clippy
if: ${{ !cancelled() }}
run: cargo clippy --locked --all-targets ${{ matrix.args }} -- -D warnings
- name: Test
if: ${{ !cancelled() }}
run: cargo nextest run --profile ci --locked ${{ matrix.args }}
embedded:
name: Embedded
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: thumbv7em-none-eabi
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Check
run: |
cargo check --locked --target thumbv7em-none-eabi --no-default-features
cargo check --locked --target thumbv7em-none-eabi --features gzip
miri:
name: Miri
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install nightly + miri
uses: dtolnay/rust-toolchain@nightly
with:
components: miri
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Miri (sync + focused)
env:
MIRIFLAGS: -Zmiri-strict-provenance
run: |
cargo miri setup
cargo miri test --lib sync::
cargo miri test --lib --features gzip gzip::
cargo miri test --lib --features cookie-jar cookie_jar::
fuzz:
name: Fuzz
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install nightly
uses: dtolnay/rust-toolchain@nightly
- name: Install clang
run: sudo apt-get update && sudo apt-get install -y clang
- name: Install cargo-fuzz
uses: taiki-e/install-action@v2
with:
tool: cargo-fuzz@${{ env.CARGO_FUZZ_VERSION }}
- name: Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: fuzz -> target
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Cache fuzz corpora
uses: actions/cache@v5
with:
path: |
fuzz/corpus
fuzz/artifacts
key: fuzz-corpus-${{ runner.os }}-${{ hashFiles('fuzz/fuzz_targets/**', 'fuzz/Cargo.toml') }}
restore-keys: |
fuzz-corpus-${{ runner.os }}-
- name: Fuzz targets
run: |
mkdir -p fuzz/corpus fuzz/artifacts
T="${{ env.FUZZ_MAX_TOTAL_TIME }}"
cargo +nightly fuzz run --target x86_64-unknown-linux-gnu parse_response -- \
-max_total_time="$T" -dict=fuzz/dictionaries/http.dict
cargo +nightly fuzz run --target x86_64-unknown-linux-gnu parse_response_structured -- \
-max_total_time="$T" -dict=fuzz/dictionaries/http.dict
cargo +nightly fuzz run --target x86_64-unknown-linux-gnu parse_uri -- \
-max_total_time="$T" -dict=fuzz/dictionaries/uri.dict
cargo +nightly fuzz run --target x86_64-unknown-linux-gnu inflate_gzip -- \
-max_total_time="$T" -dict=fuzz/dictionaries/gzip.dict
deny:
name: cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
tool: cargo-deny@${{ env.CARGO_DENY_VERSION }}
- name: cargo deny check
run: cargo deny check advisories licenses bans
coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: nextest@${{ env.NEXTEST_VERSION }}
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2
with:
tool: cargo-llvm-cov@${{ env.LLVM_COV_VERSION }}
- name: Cache
uses: Swatinem/rust-cache@v2
with:
key: coverage
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Coverage (LCOV + Cobertura + HTML)
run: bash scripts/coverage.sh
- name: Upload coverage artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v6
with:
name: coverage-${{ github.sha }}
path: |
target/llvm-cov/lcov.info
target/llvm-cov/cobertura.xml
target/llvm-cov/html
if-no-files-found: error
ui:
name: API compile tests (trybuild)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache
uses: Swatinem/rust-cache@v2
with:
key: ui
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: trybuild / UI tests
run: cargo test --locked --test ui
stable:
name: Stable checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Format
run: cargo fmt --all -- --check
- name: Docs
if: ${{ !cancelled() }}
env:
RUSTDOCFLAGS: -D warnings
run: cargo doc --locked --no-deps --all-features
- name: Examples
if: ${{ !cancelled() }}
run: cargo build --locked --examples --all-features
- name: Lockfile
if: ${{ !cancelled() }}
run: cargo metadata --format-version 1 --locked >/dev/null
- name: Available dependency updates
if: ${{ !cancelled() }}
run: cargo update --dry-run
- name: Dependency tree
if: ${{ !cancelled() }}
run: cargo tree -e features --all-features
benches:
name: Benches
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Valgrind
run: sudo apt-get update && sudo apt-get install -y valgrind
- name: Install gungraun-runner
uses: taiki-e/install-action@v2
with:
tool: gungraun-runner@0.19.4
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Cache Gungraun baselines
uses: actions/cache@v5
with:
path: |
target/gungraun
.gungraun
key: gungraun-${{ runner.os }}-${{ hashFiles('benches/**', 'src/**', 'Cargo.lock') }}
restore-keys: |
gungraun-${{ runner.os }}-
- name: Compile all benches
run: cargo bench --locked --no-run --all-features
- name: Callgrind regression (soft limits)
run: cargo bench --locked --bench gungraun_callgrind --all-features
- name: Criterion smoke (compile + short run)
run: |
cargo bench --locked --bench criterion_hot_paths --all-features -- \
--warm-up-time 0.2 --measurement-time 0.5 --sample-size 10
cargo bench --locked --bench criterion_e2e --all-features -- \
--warm-up-time 0.2 --measurement-time 0.5 --sample-size 10
- name: dhat allocation smoke
env:
BAREHTTP_DHAT_ITERS: "5"
run: |
cargo bench --locked --bench dhat_parser --all-features
cargo bench --locked --bench dhat_gzip --features gzip
cargo bench --locked --bench dhat_e2e --all-features
msrv:
name: MSRV (1.90)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust 1.90
uses: dtolnay/rust-toolchain@1.90
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: nextest@${{ env.NEXTEST_VERSION }}
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Check (all features)
run: cargo check --locked --all-features
- name: Nextest (all features)
run: cargo nextest run --profile ci --locked --all-features
os-matrix:
name: OS (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-nextest
uses: taiki-e/install-action@v2
with:
tool: nextest@${{ env.NEXTEST_VERSION }}
- name: Cache
uses: Swatinem/rust-cache@v2
- name: Quiet rust-cache trybuild ENOENT
if: always()
shell: bash
run: mkdir -p target/tests/target target/tests/trybuild
- name: Nextest (default / none)
run: cargo nextest run --profile ci --locked --no-default-features
- name: Nextest (all features)
run: cargo nextest run --profile ci --locked --all-features