name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
PROPTEST_CASES: "4096"
jobs:
fmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
with: { components: rustfmt }
- run: cargo fmt --all --check
clippy:
name: clippy
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
features:
- "--no-default-features"
- "" - "--features serde"
- "--features cli"
- "--features serde,cli,strict,optimized-str,optimized-lowercase"
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
with: { components: clippy }
- uses: Swatinem/rust-cache@v2
with:
key: clippy-${{ matrix.features }}
- run: cargo clippy --all-targets ${{ matrix.features }} -- -D warnings
test:
name: test (lib + doc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --lib --features serde,cli,strict,optimized-str,optimized-lowercase
- run: cargo test --doc --features serde
doc:
name: doc
runs-on: ubuntu-latest
env:
RUSTDOCFLAGS: "-D warnings"
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo doc --no-deps --all-features
msrv:
name: msrv (1.94.1)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@1.94.1
- uses: Swatinem/rust-cache@v2
- run: cargo check --all-features
coverage:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
with: { components: llvm-tools-preview }
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-llvm-cov
- name: Collect coverage (pure-Rust lib tests)
run: cargo llvm-cov --lib --features serde,cli,strict,optimized-str,optimized-lowercase --lcov --output-path lcov.info
- uses: codecov/codecov-action@v4
with:
files: lcov.info
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
package:
name: cargo package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo package --no-verify
semver:
name: semver (all features)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- uses: obi1kenobi/cargo-semver-checks-action@v2
with:
feature-group: all-features
changelog:
name: changelog entry
if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]' && !contains(github.event.pull_request.labels.*.name, 'skip-changelog')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0, lfs: false }
- name: Require a CHANGELOG.md update
run: |
git fetch --no-tags origin "$GITHUB_BASE_REF"
if git diff --name-only "origin/$GITHUB_BASE_REF...HEAD" | grep -qx 'CHANGELOG.md'; then
echo "CHANGELOG.md updated."
else
echo "::error::Add an entry under [Unreleased] in CHANGELOG.md, or apply the 'skip-changelog' label for changes that don't warrant one (CI, docs, refactors)."
exit 1
fi
parity-deterministic:
name: parity vs Python (deterministic)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- name: Fetch representative dump subset (LFS)
run: git lfs pull --include="dev-data/reference-dumps/dewiktionary-20240901-ci-subset.xml.zst"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- name: Set up reference WikiWho venv
run: |
python -m venv .venv
./.venv/bin/pip install --upgrade pip
./.venv/bin/pip install -r requirements.txt
# "Activate" the venv for later steps so pyo3's auto-initialized interpreter
# finds the installed WikiWho module (VIRTUAL_ENV is what site.py keys on).
echo "VIRTUAL_ENV=$PWD/.venv" >> "$GITHUB_ENV"
echo "PYO3_PYTHON=$PWD/.venv/bin/python" >> "$GITHUB_ENV"
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
- name: Deterministic parity (synthetic fixtures + real subset pages)
run: |
SUBSET="$PWD/dev-data/reference-dumps/dewiktionary-20240901-ci-subset.xml.zst"
if [ -f "$SUBSET" ]; then
export WIKIWHO_TEST_DUMP="$SUBSET"
echo "Using representative subset: $SUBSET"
else
echo "::warning::subset not available; real-page parity tests will self-skip"
fi
cargo test --features python-diff,serde --test algorithm_exact_tests -- \
known_bad_example_anontalkpagetext \
known_bad_example_familia \
known_bad_example_hallo \
random_pages_100 \
test_case_
- name: Deep parity on full dump (push to main only)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if python3 tools/fetch_test_data.py --which full --dest dev-data/reference-dumps; then
export WIKIWHO_TEST_DUMP="$PWD/dev-data/reference-dumps/dewiktionary-20240901-pages-meta-history.xml.zst"
cargo test --features python-diff,serde --test algorithm_exact_tests -- \
known_bad_example_familia known_bad_example_hallo random_pages_100
else
echo "::warning::full dump unavailable from wikiwho-data; skipping deep parity"
fi
gold-standard:
name: gold standard accuracy (pure Rust)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- name: Fetch gold-standard article cache (LFS)
run: git lfs pull --include="dev-data/article-cache/*.json.zst"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Cache gold-standard CSV
id: gold-csv
uses: actions/cache@v4
with:
path: dev-data/gold_standard.partial.newnames.csv
key: gold-standard-csv-${{ hashFiles('tools/fetch_gold_standard.py') }}
- name: Fetch the archived gold-standard CSV
if: steps.gold-csv.outputs.cache-hit != 'true'
run: python3 tools/fetch_gold_standard.py - name: Precision vs. paper gold standard (imara-diff / pure Rust)
run: |
cargo test --features serde --test algorithm_statistic_tests -- \
--ignored --nocapture gold_standard_precision_rust
gold-standard-parity:
name: gold standard vs Python (push to main)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { lfs: false }
- name: Fetch gold-standard article cache (LFS)
run: git lfs pull --include="dev-data/article-cache/*.json.zst"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- name: Set up reference WikiWho venv
run: |
python -m venv .venv
./.venv/bin/pip install --upgrade pip
./.venv/bin/pip install -r requirements.txt
# "Activate" the venv for later steps so pyo3's auto-initialized interpreter
# finds the installed WikiWho module (VIRTUAL_ENV is what site.py keys on).
echo "VIRTUAL_ENV=$PWD/.venv" >> "$GITHUB_ENV"
echo "PYO3_PYTHON=$PWD/.venv/bin/python" >> "$GITHUB_ENV"
echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
- name: Cache gold-standard CSV
id: gold-csv
uses: actions/cache@v4
with:
path: dev-data/gold_standard.partial.newnames.csv
key: gold-standard-csv-${{ hashFiles('tools/fetch_gold_standard.py') }}
- name: Fetch the archived gold-standard CSV
if: steps.gold-csv.outputs.cache-hit != 'true'
run: python3 tools/fetch_gold_standard.py
- name: Python-diff precision + Rust/Python divergence
run: |
cargo test --features python-diff,serde --test algorithm_statistic_tests -- \
--ignored --nocapture \
gold_standard_precision_python_diff \
divergence_rate_gold_standard_articles