# Gate every pull request into `main` on the same Rust checks the release runs, # so a formatting slip, a lint regression, or a failing test can't reach the # deployable branch. # # Why this exists: release.yml runs only AFTER merge (on push to `main`) and its # FIRST Rust step is `cargo fmt --check`. Before this workflow, an unformatted # commit merged cleanly and then killed the release job before it could build, # tag, or publish anything — the repo had no pull_request workflow at all. These # gates are deliberately a mirror of release.yml's, in the same order, so a green # PR means the release will get past its gates too. # # Enforcement (one-time, in the Gitea UI): # Repository Settings → Branches → Branch Protection (rule for `main`) # • Enable Status Check # • Status check patterns: PR Checks / * # Note: Gitea only lists a context in its dropdown after it has reported once, # so let this workflow run on one PR first. The `PR Checks / *` glob matches # without needing the dropdown. # # Scope note: this gates PRs into `main` only. Feature work that lands on an # integration branch first (e.g. `edge`) is still caught on the branch's PR into # `main`. To gate that earlier hop too, add the branch to the `branches:` list # below — nothing else needs to change. # # Runner: the same self-hosted `ubuntu-latest` runner release.yml uses. Rust is # not assumed to be preinstalled, so the toolchain step bootstraps it the same # way release.yml does (minus the MinGW cross-compile deps — PRs build for the # host only; the Windows cross-build stays a release-time concern). name: PR Checks on: pull_request: branches: [main] # A newer push to the same PR cancels the in-flight run. concurrency: group: pr-checks-${{ github.ref }} cancel-in-progress: true env: WORKDIR: sidecar jobs: rust-gates: runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 # One job runs all three gates on purpose: installing the toolchain costs # far more than the checks themselves, so splitting fmt/clippy/test into # parallel jobs would pay that cost three times for no wall-clock win. - name: Install Rust toolchain (rustfmt + clippy) run: | set -euo pipefail SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo" $SUDO apt-get update $SUDO apt-get install -y --no-install-recommends \ build-essential curl ca-certificates git if ! command -v cargo >/dev/null 2>&1; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --profile minimal --default-toolchain stable fi echo "${HOME}/.cargo/bin" >> "$GITHUB_PATH" export PATH="${HOME}/.cargo/bin:${PATH}" rustup component add rustfmt clippy cargo --version && cargo fmt --version && cargo clippy --version # Keyed on Cargo.lock: dependency builds are reused until a dep actually # changes. A cache miss only makes the run slower, never wrong. - name: Cache cargo registry and build dir uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git sidecar/target key: ${{ runner.os }}-cargo-${{ hashFiles('sidecar/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo- # Cheapest gate first — parses only, no compile, so a formatting slip # fails in seconds instead of after a full build. - name: cargo fmt --check working-directory: sidecar run: cargo fmt --check # --all-targets covers tests and examples, not just the binary. # -D warnings makes a lint a failure; the crate is clean at this bar today, # so anything new here is a regression introduced by the PR. - name: cargo clippy working-directory: sidecar run: cargo clippy --locked --all-targets -- -D warnings # --locked matches release.yml: it also proves Cargo.lock is in sync with # Cargo.toml, rather than letting the build silently update it. - name: cargo test working-directory: sidecar run: cargo test --locked