From 49c1a12d6824b302da8c88162be86e394ae483dc Mon Sep 17 00:00:00 2001 From: Zack Maril Date: Sat, 29 Aug 2026 19:44:52 -0400 Subject: [PATCH] Add scripts/dev.sh and scope the CI jobs to what changed `scripts` had nothing to point a fresh checkout at. scripts/dev.sh sets core.hooksPath, which no clone can inherit, then runs the gate CI runs. Doctests get their own step because --all-targets does not run them, and they are what holds the README to the crate. `ci-scoped` flagged test and msrv as running on every pull request with nothing deciding whether they need to. A changes job now answers that once and the four cargo jobs depend on it. On a push there is no base to diff against, so everything counts as changed and main is gated exactly as before. The filter names what cannot affect a build -- DESIGN.md, CHANGELOG.md, images/ -- rather than what can, so an unfamiliar file is treated as code until someone decides otherwise. README.md is deliberately not on that list: its Rust snippets are doctests and `cargo package` ships it, so a README-only change really does have to run the suite. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0144PU3MssnfbM5tZiqXW7d3 --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++++++++++ README.md | 11 ++++++++++ scripts/dev.sh | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100755 scripts/dev.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6665b37..fade14e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,45 @@ env: CARGO_TERM_COLOR: always jobs: + # What a pull request touched decides what the rest of this file runs. On a + # push there is no base to compare against, so everything counts as changed + # and main is gated on the whole file exactly as before. + changes: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + code: ${{ steps.filter.outputs.code }} + steps: + - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + with: + fetch-depth: 0 + - id: filter + env: + BASE: ${{ github.event.pull_request.base.sha }} + run: | + if [ -z "$BASE" ]; then + echo "code=true" >> "$GITHUB_OUTPUT" + echo "not a pull request; everything runs" + exit 0 + fi + # Named as what cannot affect a build rather than what can, so a new + # kind of file is treated as code until someone says otherwise. That + # matters more here than the saved minutes: README.md is absent from + # this list because every Rust snippet in it is a doctest, and + # `cargo package` ships it. + if git diff --name-only "$BASE"...HEAD \ + | grep -qvE '^(DESIGN|CHANGELOG)\.md$|^images/'; then + echo "code=true" >> "$GITHUB_OUTPUT" + else + echo "code=false" >> "$GITHUB_OUTPUT" + echo "only prose and images changed; the cargo jobs are skipped" + fi + test: runs-on: ubuntu-latest timeout-minutes: 30 + needs: changes + if: needs.changes.outputs.code == 'true' steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable @@ -31,6 +67,8 @@ jobs: examples: runs-on: ubuntu-latest timeout-minutes: 30 + needs: changes + if: needs.changes.outputs.code == 'true' steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable @@ -47,6 +85,8 @@ jobs: msrv: runs-on: ubuntu-latest timeout-minutes: 30 + needs: changes + if: needs.changes.outputs.code == 'true' steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 - uses: dtolnay/rust-toolchain@e09e0d4c1f9d84cdd46855833435a743d2e6b596 # 1.70.0 @@ -59,6 +99,8 @@ jobs: packaging: runs-on: ubuntu-latest timeout-minutes: 60 + needs: changes + if: needs.changes.outputs.code == 'true' steps: - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable diff --git a/README.md b/README.md index d6c91e7..11138c9 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,17 @@ cargo run --example validate # early cancellation, and the lowering report cargo run --example sse # the realistic shape: JSON inside a data: stream ``` +## Development + +`scripts/dev.sh` points git at the committed hooks and then runs the gate CI +runs: build, fmt, clippy, the tests, and the doctests. The doctests are a +separate step because `--all-targets` does not run them, and they are what keeps +the snippets above honest. + +```sh +scripts/dev.sh +``` + ## Framing jawohl parses JSON, not the envelope around it. Provider streams wrap fragments diff --git a/scripts/dev.sh b/scripts/dev.sh new file mode 100755 index 0000000..3d316de --- /dev/null +++ b/scripts/dev.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Stand up a fresh jawohl checkout: hooks, then the gate CI runs. Safe to +# re-run; every step is idempotent. +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +# A clone runs no hooks until it is pointed at them: core.hooksPath is per-clone +# configuration, so nothing a checkout carries can set it for you. +git config core.hooksPath .githooks +if [ ! -d .githooks ]; then + echo "note: .githooks is fleet-managed and not synced here yet; git will" + echo " start using it the moment ordnung writes it." +fi + +if ! command -v cargo >/dev/null; then + echo "error: cargo is not on PATH; install Rust from https://rustup.rs" >&2 + exit 1 +fi + +echo "== build" +cargo build --all-targets + +echo "== fmt" +cargo fmt --all -- --check + +echo "== clippy" +cargo clippy --all-targets -- -D warnings + +echo "== test" +cargo test --all-targets + +# Every Rust snippet in the README is a doctest, so this is what stops the front +# page from drifting away from the crate. It is a separate cargo invocation +# because --all-targets does not run doctests. +echo "== doctests" +cargo test --doc + +echo +echo "ready. the examples double as documentation:" +echo " cargo run --example complete # finish truncated documents" +echo " cargo run --example streaming # chunk by chunk" +echo " cargo run --example validate # early cancellation" +echo " cargo run --example sse # JSON inside a data: stream"