diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4cbbc90 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,70 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + schedule: + # Mondays 06:00 UTC. A new Rust release lands on its own schedule, so + # without this the advisory `stable` job below only runs when someone + # happens to push, and breakage can sit unnoticed for weeks. + - cron: '0 6 * * 1' + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + # Nothing it covers can change on a timer: the toolchain is pinned and + # the dependencies are locked. The weekly run is for `stable` only. + if: github.event_name != 'schedule' + steps: + - uses: actions/checkout@v4 + # Pinned, and kept in step with `devVersion` in flake.nix (which in + # turn tracks invoiceninja-sdk's own `devVersion`), so CI and the dev + # shell agree and a new stable release cannot turn a lint failure + # into an unrelated red build. + - uses: dtolnay/rust-toolchain@1.99.1 + with: + components: rustfmt, clippy + - run: cargo build --all-targets + - run: cargo test + - run: cargo fmt --check + - run: cargo clippy --all-targets -- -D warnings + + msrv: + name: Build on the declared MSRV + runs-on: ubuntu-latest + if: github.event_name != 'schedule' + steps: + - uses: actions/checkout@v4 + # Must match `rust-version` in Cargo.toml, which in turn is pinned to + # invoiceninja-sdk's own MSRV (see the comment there). Build only — + # lint and format output varies by release, and pinning those to the + # oldest supported toolchain is not useful. + - uses: dtolnay/rust-toolchain@1.88.0 + - run: cargo test + + stable: + name: Latest stable (advisory) + runs-on: ubuntu-latest + # Deliberately NOT `continue-on-error`: a failure here should render as + # a real red X, not a green check with an annotation nobody reads. + # + # This job is advisory all the same — it tracks a moving toolchain, so a + # new clippy lint can break it through no fault of the change under + # test. **Keep it out of the required status checks** in branch + # protection; that, rather than a flag in this file, is what stops it + # blocking merges. Expect it red sometimes, and fix it when bumping + # `devVersion`. + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - run: cargo test + - run: cargo clippy --all-targets -- -D warnings diff --git a/CLAUDE.md b/CLAUDE.md index cc45948..6c7ab13 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -71,6 +71,43 @@ matching package named `invoiceninja-sdk` found" or an unresolved `../invoiceninjars-sdk/Cargo.toml`'s `[package] name`, if you have a checkout) first. +### Rust version and CI + +| | Version | Declared in | +| --- | --- | --- | +| Dev toolchain | 1.99.1 | `devVersion` in `flake.nix`, `test` job in `.github/workflows/ci.yml` | +| MSRV | 1.88 | `rust-version` in `Cargo.toml` (inherited from the SDK's own floor — see the comment there), `msrv` job in `ci.yml` | + +Unlike `invoiceninjars-sdk`'s `flake.nix`, this crate's has no separate +`msrvVersion`/toolchain — the `msrv` CI job is the only place 1.88 actually +gets built against, not a Nix devShell. If that ever earns its keep, mirror +the SDK's `msrvToolchain`/`shellFor` pattern rather than inventing a new one. + +CI runs on GitHub Actions, against the GitHub push mirror (Gitea is +canonical — see `.gitea`/remote config — but Actions run on GitHub, the +same arrangement as `invoiceninjars-sdk`'s own CI). Three jobs, mirroring +the SDK's `ci.yml` job-for-job: + +- **`test`** — the pinned dev toolchain; `cargo build --all-targets`, + `cargo test`, `cargo fmt --check`, `cargo clippy --all-targets -- -D + warnings`. +- **`msrv`** — build and test only, on the declared 1.88 floor. No lint or + format check: those vary by release, and pinning them to the oldest + supported toolchain isn't useful. +- **`stable`** (advisory) — latest stable `rustc`, runs on push/PR and + weekly via `schedule` (Mondays 06:00 UTC) so a new Rust release that + breaks the build or fires a new clippy lint doesn't sit unnoticed for + weeks between pushes. Deliberately **not** `continue-on-error` — a real + red X, not a silent annotation — so if branch protection ever requires + status checks, keep `stable` **out** of the required list; that setting, + not anything in `ci.yml`, is what should stop it blocking merges. Expect + it red occasionally through no fault of the change under test, and fix it + when bumping `devVersion`. + +The `test` and `msrv` jobs skip scheduled runs (`if: github.event_name != +'schedule'`) — a pinned toolchain against a locked dependency graph can't +change on a timer, so the weekly run is for `stable` only. + ## Common commands ```sh diff --git a/GOALS.md b/GOALS.md index 934bc16..f919be0 100644 --- a/GOALS.md +++ b/GOALS.md @@ -67,6 +67,16 @@ the SDK doesn't already consider safe. If the SDK decides `POST` isn't replayed on a 5xx because it might double-create an invoice, that reasoning applies here unchanged — the CLI is not a place to relax it for convenience. +### 6. CI mirrors the SDK's, job for job + +`.github/workflows/ci.yml` has the same three jobs as `invoiceninjars-sdk`'s +own — pinned-toolchain `test`, build-only `msrv` on the declared floor, and +an advisory `stable` that reports red but stays out of required status +checks — rather than inventing a different shape for this crate. See +`CLAUDE.md`'s "Rust version and CI" for the per-job reasoning; a deviation +from this shape should be written down there the same way `update`'s +exception is written down in goal 1. + ## Non-goals - **No Cargo workspace with the SDK.** Explained in `CLAUDE.md`: the SDK is @@ -111,12 +121,6 @@ These are genuinely undecided; deciding one is a change to this file. `--param key=value` for the rest. A per-resource convenience filter (e.g. a `--unpaid` shorthand for `client_status=unpaid`) would read nicer but means hand-picking which filters earn a dedicated flag per resource. -- **Whether this crate gets its own CI.** No longer blocked on needing a - sibling checkout — the SDK dependency switched from a path to a crates.io - version requirement (`invoiceninja-sdk = "0.2.0"`) once 0.2.0 was published - on 2026-10-25. A workflow here can now just `cargo build` against the - registry like any other Rust project; it doesn't need to check out - `invoiceninjars-sdk` at all. - **Whether the Nix packaging goes further than this repo's own flake.** `flake.nix` now has `packages.default`/`devShells.default` (built with a pinned `rust-overlay` toolchain, for parity between `nix build` and