8000 ci: add MSRV, public-API semver and dependency policy checks (#395) by adityamukho · Pull Request #418 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Policy

# Release-policy checks (#395):
# - msrv: the crate builds and its unit tests pass on `rust-version`
# - semver-checks: no accidental public-API break against the latest release tag
# - cargo-deny: dependency licenses, duplicate versions and sources (deny.toml)

on:
push:
branches: [ "main" ]
pull_request:
# Major-version branches (e.g. `v3`) run the same checks, but a semver
# break is allowed there — see the semver-checks job.
branches: [ "main", "v[0-9]*" ]

env:
CARGO_TERM_COLOR: always

permissions:
contents: read

jobs:
msrv:
name: MSRV (Rust 1.89)
runs-on: ubuntu-latest
env:
MSRV: "1.89"
# Resolve dependencies to versions that support our rust-version, so a
# new upstream release cannot break the MSRV build on its own.
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Check MSRV matches Cargo.toml
run: |
declared=$(sed -n 's/^rust-version = "\(.*\)"$/\1/p' Cargo.toml)
if [ "$declared" != "$MSRV" ]; then
echo "::error::Cargo.toml rust-version is $declared but this job tests $MSRV; update policy.yml"
exit 1
fi

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: "1.89"

- name: Check (all features)
run: cargo check --all-features

- name: Run unit tests
run: cargo test --lib

semver-checks:
name: Public API semver check
runs-on: ubuntu-latest
# A breaking change is only allowed on a major-version branch (e.g. `v3`).
# There the job still runs, so the break is visible, but it cannot fail
# the PR. On `main` it is a hard gate.
continue-on-error: ${{ github.event_name == 'pull_request' && github.base_ref != 'main' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Find latest release tag
id: baseline
run: |
tag=$(git describe --tags --abbrev=0 --match 'v[0-9]*')
echo "Baseline: $tag"
echo "tag=$tag" >> "$GITHUB_OUTPUT"

- name: Run cargo-semver-checks
uses: obi1kenobi/cargo-semver-checks-action@v2
with:
baseline-rev: ${{ steps.baseline.outputs.tag }}

cargo-deny:
name: Dependency policy (cargo-deny)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run cargo-deny
uses: EmbarkStudios/cargo-deny-action@v2
with:
# Advisories are covered by cargo-audit.yml and osv-scanner.yml.
command: check bans licenses sources
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **A query with `$slot` bind tokens run through `execute()` reported an internal error (#407).** Such a query failed with `[INT-025] internal: unsubstituted :valid-at bind slot reached the executor` when it had a `:valid-at` slot, and with slots in other positions it could run and quietly return nothing. `Minigraf::execute()`, `WriteTransaction::execute()` and the REPL now reject it before execution with the new user error **API-010**, which names the slots and points to `prepare()`. Prepared queries are unchanged.
- **Bound-entity queries could drop rows when one `WriteTransaction` wrote the same attribute in several valid-time windows (#323).** Both facts share a `tx_count`, and the selective lookup path de-duplicated on `(entity, attribute, tx_count, asserted)`, so one window's value was silently lost, while the same query via a full scan returned both. That de-duplication has been removed, and bound-entity queries now always match a full scan.

### CI

- **New `Policy` workflow (#395).** An MSRV job runs `cargo check --all-features` and `cargo test --lib` on Rust 1.89, resolving dependencies to 1.89-compatible versions, and fails if `rust-version` in `Cargo.toml` drifts from the tested toolchain. `cargo-semver-checks` compares the public API with the latest release tag and blocks PRs to `main`; on major-version branches such as `v3` it reports breaks without failing. `cargo-deny` (`deny.toml`) allows only permissive licenses compatible with MIT OR Apache-2.0, rejects duplicate crate versions and wildcard requirements, and requires every crate to come from crates.io.

### Documentation

- **Unsafe WAL recovery advice removed from `docs/ERROR_REFERENCE.md`.** The WAL-001, WAL-002 and STG-011 resolutions said a `.wal` file could be deleted with no data loss, or that a database could be rebuilt from the WAL alone. Both are wrong: transactions committed since the last checkpoint exist only in the WAL, and the WAL holds nothing older than that checkpoint. The resolutions now say to copy both files first, to checkpoint with the version that wrote the WAL, and what is lost if the WAL is deleted.
Expand Down
49 changes: 49 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# cargo-deny policy for Minigraf dependencies (#395).
# Run locally with: cargo deny check bans licenses sources
# Advisories are covered by cargo-audit.yml and osv-scanner.yml.

[graph]
# Check the native targets plus the browser WASM target, so the
# wasm-bindgen / web-sys dependency tree is covered too.
targets = [
"x86_64-unknown-linux-gnu",
"aarch64-apple-darwin",
"x86_64-pc-windows-msvc",
"wasm32-unknown-unknown",
]
all-features = true

[licenses]
# Permissive licenses compatible with Minigraf's MIT OR Apache-2.0.
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Zlib",
"Unicode-3.0",
"Unlicense",
"CC0-1.0",
]
confidence-threshold = 0.9
# Keep the list stable as dependencies come and go.
unused-allowed-license = "allow"

[bans]
# Two versions of the same crate bloat the binary (PHILOSOPHY.md §4).
# If an upstream crate forces a duplicate, list it under `skip` with a
# comment explaining why, e.g.
# skip = [{ crate = "foo@1.2.3", reason = "bar still depends on foo 1.x" }]
multiple-versions = "deny"
skip = []
wildcards = "deny"
allow-wildcard-paths = true

[sources]
# Every crate must come from crates.io.
unknown-registry = "deny"
unknown-git = "deny"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = []
Loading
0