CI workflow (hyperium/hyper)
The CI workflow from hyperium/hyper, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the CI workflow from the hyperium/hyper repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: CI
on:
pull_request:
push:
branches:
- master
env:
RUST_BACKTRACE: 1
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
ci-pass:
name: CI is green
runs-on: ubuntu-latest
needs:
- style
- lint
- test
- msrv
- miri
- features
- ffi
- ffi-header
- ffi-cargo-c
- doc
- check-external-types
- udeps
- minimal-versions
- semver
steps:
- run: exit 0
style:
name: Check Style
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: cargo fmt --check
run: |
if ! rustfmt --check --edition 2021 $(git ls-files '*.rs'); then
printf "Please run \`rustfmt --edition 2021 \$(git ls-files '*.rs')\` to fix rustfmt errors.\nSee docs/CODE_STYLE.md for more details.\n" >&2
exit 1
fi
lint:
name: Linter
#needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
# not --all-targets, lints can't seem to tell integrations tests are tests
- name: Clippy
run: cargo clippy --features full -- -D warnings
test:
name: Test ${{ matrix.rust }} on ${{ matrix.os }}
needs: [style]
strategy:
matrix:
rust:
- stable
- beta
- nightly
os:
- ubuntu-latest
- windows-latest
- macOS-latest
include:
- rust: stable
features: "--features full"
- rust: beta
features: "--features full"
- rust: nightly
features: "--features full,nightly"
benches: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust (${{ matrix.rust }})
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2
- name: Test
run: cargo test ${{ matrix.features }}
- name: Test all benches
if: matrix.benches
run: cargo test --benches ${{ matrix.features }}
msrv:
name: Check MSRV
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: Resolve MSRV aware dependencies
run: cargo update
env:
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
- name: Get MSRV from package metadata
id: msrv
run: echo "version=$(yq '.package.rust-version' Cargo.toml)" >> $GITHUB_OUTPUT
- name: Install Rust (${{ steps.msrv.outputs.version }})
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.msrv.outputs.version }}
- uses: Swatinem/rust-cache@v2
- name: Check
run: cargo check --features full
miri:
name: Test with Miri
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
with:
components: miri
- uses: Swatinem/rust-cache@v2
- name: Test
# Can't enable tcp feature since Miri does not support the tokio runtime
run: MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --features http1,http2,client,server,nightly
features:
name: features
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
- uses: Swatinem/rust-cache@v2
- name: check --feature-powerset
run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --skip ffi,tracing
env:
RUSTFLAGS: "-D dead_code -D unused_imports"
- name: check --feature-powerset with tracing feature
run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --features tracing --skip ffi
env:
RUSTFLAGS: "--cfg hyper_unstable_tracing -D dead_code -D unused_imports"
ffi:
name: Test C API (FFI)
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build FFI
env:
RUSTFLAGS: --cfg hyper_unstable_ffi
run: cargo rustc --features client,http1,http2,ffi --crate-type cdylib
- name: Make Examples
run: cd capi/examples && make client
- name: Run FFI unit tests
env:
RUSTFLAGS: --cfg hyper_unstable_ffi
run: cargo test --features client,http1,http2,ffi --lib
ffi-header:
name: Verify hyper.h is up to date
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cbindgen
uses: taiki-e/cache-cargo-install-action@v2
with:
tool: cbindgen
- name: Install cargo-expand
uses: taiki-e/cache-cargo-install-action@v2
with:
tool: cargo-expand
- uses: Swatinem/rust-cache@v2
- name: Build FFI
env:
RUSTFLAGS: --cfg hyper_unstable_ffi
run: cargo build --features client,http1,http2,ffi
- name: Ensure that hyper.h is up to date
run: ./capi/gen_header.sh --verify
ffi-cargo-c:
name: Test cargo-c support (FFI)
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-c
env:
LINK: https://github.com/lu-zero/cargo-c/releases/latest/download
CARGO_C_FILE: cargo-c-x86_64-unknown-linux-musl.tar.gz
run: |
curl -L $LINK/$CARGO_C_FILE | tar xz -C ~/.cargo/bin
- name: Build with cargo-c
env:
RUSTFLAGS: --cfg hyper_unstable_ffi
run: cargo cbuild --features client,http1,http2,ffi
doc:
name: Build docs
needs: [style, test]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- name: cargo doc
run: cargo rustdoc --features full,ffi -- --cfg docsrs --cfg hyper_unstable_ffi -D rustdoc::broken-intra-doc-links
check-external-types:
name: Check exposed types
needs: [style, test]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2025-10-18 # Compatible version for cargo-check-external-types
- name: Install cargo-check-external-types
uses: taiki-e/cache-cargo-install-action@v2
with:
tool: cargo-check-external-types@0.4.0
- uses: Swatinem/rust-cache@v2
- name: check-external-types
run: cargo check-external-types --config .github/workflows/external-types.toml
udeps:
needs: [style]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
- name: Install cargo-udeps
uses: taiki-e/install-action@cargo-udeps
- uses: Swatinem/rust-cache@v2
- name: Check unused dependencies on default features
run: cargo udeps
- name: Check unused dependencies on full features
run: cargo udeps --features full
minimal-versions:
runs-on: ubuntu-latest
needs: [style]
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@cargo-hack
- uses: taiki-e/install-action@cargo-minimal-versions
- uses: Swatinem/rust-cache@v2
- run: cargo minimal-versions check
- run: cargo minimal-versions check --features full
semver:
name: semver
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
feature-group: only-explicit-features
features: full
release-type: minor
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: CI on: pull_request: push: branches: - master env: RUST_BACKTRACE: 1 permissions: contents: read # to fetch code (actions/checkout) concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: ci-pass: timeout-minutes: 30 name: CI is green runs-on: latchkey-small needs: - style - lint - test - msrv - miri - features - ffi - ffi-header - ffi-cargo-c - doc - check-external-types - udeps - minimal-versions - semver steps: - run: exit 0 style: timeout-minutes: 30 name: Check Style runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: components: rustfmt - name: cargo fmt --check run: | if ! rustfmt --check --edition 2021 $(git ls-files '*.rs'); then printf "Please run \`rustfmt --edition 2021 \$(git ls-files '*.rs')\` to fix rustfmt errors.\nSee docs/CODE_STYLE.md for more details.\n" >&2 exit 1 fi lint: timeout-minutes: 30 name: Linter #needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 # not --all-targets, lints can't seem to tell integrations tests are tests - name: Clippy run: cargo clippy --features full -- -D warnings test: timeout-minutes: 30 name: Test ${{ matrix.rust }} on ${{ matrix.os }} needs: [style] strategy: matrix: rust: - stable - beta - nightly os: - ubuntu-latest - windows-latest - macOS-latest include: - rust: stable features: "--features full" - rust: beta features: "--features full" - rust: nightly features: "--features full,nightly" benches: true runs-on: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust (${{ matrix.rust }}) uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test ${{ matrix.features }} - name: Test all benches if: matrix.benches run: cargo test --benches ${{ matrix.features }} msrv: timeout-minutes: 30 name: Check MSRV needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@stable - name: Resolve MSRV aware dependencies run: cargo update env: CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback - name: Get MSRV from package metadata id: msrv run: echo "version=$(yq '.package.rust-version' Cargo.toml)" >> $GITHUB_OUTPUT - name: Install Rust (${{ steps.msrv.outputs.version }}) uses: dtolnay/rust-toolchain@master with: toolchain: ${{ steps.msrv.outputs.version }} - uses: Swatinem/rust-cache@v2 - name: Check run: cargo check --features full miri: timeout-minutes: 30 name: Test with Miri needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@nightly with: components: miri - uses: Swatinem/rust-cache@v2 - name: Test # Can't enable tcp feature since Miri does not support the tokio runtime run: MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --features http1,http2,client,server,nightly features: timeout-minutes: 30 name: features needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Install cargo-hack uses: taiki-e/install-action@cargo-hack - uses: Swatinem/rust-cache@v2 - name: check --feature-powerset run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --skip ffi,tracing env: RUSTFLAGS: "-D dead_code -D unused_imports" - name: check --feature-powerset with tracing feature run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --features tracing --skip ffi env: RUSTFLAGS: "--cfg hyper_unstable_tracing -D dead_code -D unused_imports" ffi: timeout-minutes: 30 name: Test C API (FFI) needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Build FFI env: RUSTFLAGS: --cfg hyper_unstable_ffi run: cargo rustc --features client,http1,http2,ffi --crate-type cdylib - name: Make Examples run: cd capi/examples && make client - name: Run FFI unit tests env: RUSTFLAGS: --cfg hyper_unstable_ffi run: cargo test --features client,http1,http2,ffi --lib ffi-header: timeout-minutes: 30 name: Verify hyper.h is up to date runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Install cbindgen uses: taiki-e/cache-cargo-install-action@v2 with: tool: cbindgen - name: Install cargo-expand uses: taiki-e/cache-cargo-install-action@v2 with: tool: cargo-expand - uses: Swatinem/rust-cache@v2 - name: Build FFI env: RUSTFLAGS: --cfg hyper_unstable_ffi run: cargo build --features client,http1,http2,ffi - name: Ensure that hyper.h is up to date run: ./capi/gen_header.sh --verify ffi-cargo-c: timeout-minutes: 30 name: Test cargo-c support (FFI) needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Install cargo-c env: LINK: https://github.com/lu-zero/cargo-c/releases/latest/download CARGO_C_FILE: cargo-c-x86_64-unknown-linux-musl.tar.gz run: | curl -L $LINK/$CARGO_C_FILE | tar xz -C ~/.cargo/bin - name: Build with cargo-c env: RUSTFLAGS: --cfg hyper_unstable_ffi run: cargo cbuild --features client,http1,http2,ffi doc: timeout-minutes: 30 name: Build docs needs: [style, test] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@nightly - uses: Swatinem/rust-cache@v2 - name: cargo doc run: cargo rustdoc --features full,ffi -- --cfg docsrs --cfg hyper_unstable_ffi -D rustdoc::broken-intra-doc-links check-external-types: timeout-minutes: 30 name: Check exposed types needs: [style, test] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2025-10-18 # Compatible version for cargo-check-external-types - name: Install cargo-check-external-types uses: taiki-e/cache-cargo-install-action@v2 with: tool: cargo-check-external-types@0.4.0 - uses: Swatinem/rust-cache@v2 - name: check-external-types run: cargo check-external-types --config .github/workflows/external-types.toml udeps: timeout-minutes: 30 needs: [style] runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v6 - name: Install Rust uses: dtolnay/rust-toolchain@nightly - name: Install cargo-udeps uses: taiki-e/install-action@cargo-udeps - uses: Swatinem/rust-cache@v2 - name: Check unused dependencies on default features run: cargo udeps - name: Check unused dependencies on full features run: cargo udeps --features full minimal-versions: timeout-minutes: 30 runs-on: latchkey-small needs: [style] steps: - uses: actions/checkout@v6 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-hack - uses: taiki-e/install-action@cargo-minimal-versions - uses: Swatinem/rust-cache@v2 - run: cargo minimal-versions check - run: cargo minimal-versions check --features full semver: timeout-minutes: 30 name: semver runs-on: latchkey-small steps: - uses: actions/checkout@v6 - name: Check semver uses: obi1kenobi/cargo-semver-checks-action@v2 with: feature-group: only-explicit-features features: full release-type: minor
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
5 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
- Network fetches
This workflow runs 15 jobs (23 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.