name: Build & Test
on:
workflow_dispatch:
workflow_call:
inputs:
plan:
required: false
type: string
push:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
nextest:
runs-on: ${{matrix.os}}
strategy:
matrix: &matrix
build: [linux, macos, windows]
include:
- build: linux
os: ubuntu-latest
target: x86_64-unknown-linux-musl
- build: macos
os: macos-latest
target: x86_64-apple-darwin
- build: windows
os: windows-latest
target: x86_64-pc-windows-msvc
permissions:
contents: read
steps:
- &linux-deps
name: "[linux] Install dependencies"
run: |
sudo apt-get install tmux
tmux -V
locale
if: runner.os == 'Linux'
- name: "[macos] Install dependencies"
run: |
brew install tmux
tmux -V
locale
if: runner.os == 'macOS'
env:
HOMEBREW_NO_AUTO_UPDATE: 1
- &checkout
name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 1
- &toolchain
name: Install rust toolchain
run: rustup toolchain install
- &nextest-install
name: Install nextest
uses: taiki-e/install-action@v2
with:
tool: nextest@0.9
- &cache
name: Setup cargo cache
uses: Swatinem/rust-cache@v2
- name: Run doctests
run: cargo test --doc
- name: "Run tests"
run: cargo nextest run --release --profile ci --bins --lib --examples --tests
env:
LC_ALL: en_US.UTF-8
TERM: xterm-256color
- name: Show snapshot diffs on failure
if: failure()
run: |
find tests/snapshots/ -name "*.snap.new" | while read -r new_snap; do
base="${new_snap%.new}"
echo "=== Snapshot diff: $base ==="
echo "new: $new_snap"
cat "$new_snap"
if [ -f "$base" ]; then
echo "old: $base"
cat "$base"
diff "$base" "$new_snap"
fi
done
shell: bash
coverage:
runs-on: ubuntu-latest
permissions:
code-quality: write
steps:
- *linux-deps
- *checkout
- *toolchain
- *nextest-install
- uses: taiki-e/install-action@v2
with:
tool: cargo-llvm-cov@0.8
- *cache
- name: "Run tests with coverage"
run: |
cargo +nightly llvm-cov nextest --release --profile ci --branch --bins --lib --examples --tests --no-report
cargo +nightly llvm-cov report --release --cobertura --output-path coverage.xml
cargo +nightly llvm-cov report --release --html
echo "COVERAGE_PERCENT=$(cargo +nightly llvm-cov report --release | tail -n1 | awk '{ print $13 }')" | tee --append $GITHUB_ENV
env:
LC_ALL: en_US.UTF-8
TERM: xterm-256color
- name: "Upload coverage report"
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
continue-on-error: true
uses: actions/upload-code-coverage@v1
with:
file: coverage.xml
language: Rust
label: ${{ runner.os }}
- name: "Generate coverage badge"
if: &if-master github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
uses: emibcn/badge-action@v2.0.4
with:
label: 'Coverage'
status: ${{ env.COVERAGE_PERCENT }}
color: 'blue'
path: 'target/llvm-cov/html/coverage.svg'
- name: "Upload default branch results to gh pages"
if: *if-master
uses: actions/upload-pages-artifact@v5
with:
path: target/llvm-cov/html
deploy-coverage-page:
if: *if-master
needs: coverage
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: "Deploy gh pages"
id: deployment
uses: actions/deploy-pages@v5
clippy:
runs-on: ${{matrix.os}}
strategy:
matrix: *matrix
steps:
- *checkout
- *toolchain
- *cache
- name: Clippy
run: cargo clippy
rustfmt:
runs-on: ${{matrix.os}}
strategy:
matrix: *matrix
steps:
- *checkout
- *toolchain
- name: Check formatting
run: |
cargo fmt --all -- --check
clippy-no-default-features:
runs-on: ${{matrix.os}}
strategy:
matrix: *matrix
steps:
- *checkout
- *toolchain
- *cache
- name: Run clippy with specific features
run: |
cargo clippy --no-default-features -- -Dwarnings
cargo clippy --no-default-features --features cli -- -Dwarnings
cargo clippy --no-default-features --features image -- -Dwarnings
cargo clippy --no-default-features --features listen -- -Dwarnings
cargo clippy --no-default-features --features frizbee -- -Dwarnings
msrv:
runs-on: ubuntu-latest
steps:
- *checkout
- *toolchain
- uses: taiki-e/install-action@v2
with:
tool: cargo-msrv@0.19
- name: MSRV Verify
run: cargo msrv verify
fuzz:
permissions:
contents: read
runs-on: ${{matrix.os}}
strategy:
matrix: *matrix
steps:
- *checkout
- *toolchain
- *cache
- name: Set up MSVC dev environment
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
- uses: taiki-e/install-action@v2
with:
tool: cargo-fuzz@0.13
- name: Run fuzz targets
shell: bash
run: |
host_target="$(rustc +nightly -vV | sed -n 's/^host: //p')"
if [ "$RUNNER_OS" = "Windows" ]; then
# Git Bash's own coreutils `link` (for hardlinks) sits ahead of
# the MSVC one on PATH within this shell, so cargo/rustc would
# otherwise invoke the wrong `link.exe`. Point at the real MSVC
# linker explicitly, using the dev env ilammy/msvc-dev-cmd set up.
export CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="${VCToolsInstallDir}bin\\HostX64\\x64\\link.exe"
fi
for target in ansi_strip field_extract fuzzy_match query_match keymap_parse; do
cargo +nightly fuzz run "$target" --target "$host_target" -- -max_total_time=60
done
- name: Upload crash artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-crashes-${{ matrix.build }}
path: fuzz/artifacts/
if-no-files-found: ignore
ci-success:
name: CI Success
if: always()
needs:
- nextest
- coverage
- deploy-coverage-page
- clippy
- rustfmt
- clippy-no-default-features
- msrv
- fuzz
runs-on: ubuntu-latest
steps:
- name: Check all required jobs succeeded
run: |
echo "${{ toJson(needs) }}"
if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" || "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then
echo "One or more required jobs failed or were cancelled."
exit 1
fi
echo "All required jobs passed (deploy-coverage-page is expected to skip off master)."