arvo 0.9.0

Validated, immutable value objects for common domain types (email, money, identifiers, …)
Documentation
name: CI

on:
  push:
    branches: ["main", "master"]
  pull_request:
    branches: ["main", "master"]
  schedule:
    # Run nightly to catch upstream breakage early
    - cron: "0 3 * * *"

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

env:
  RUSTFLAGS: -Dwarnings
  RUST_BACKTRACE: 1
  # Edition 2024 requires 1.85; bump here and in Cargo.toml [package.rust-version] together
  MSRV: "1.85"

permissions:
  contents: read

jobs:
  # ── Gate ──────────────────────────────────────────────────────────────────
  # All cheap checks must be green before the expensive matrix runs.
  ci:
    name: CI
    if: ${{ always() }}
    needs: [fmt, clippy, docs, msrv, test, test-sql]
    runs-on: ubuntu-latest
    steps:
      - name: Result
        run: |
          results='${{ toJSON(needs) }}'
          if echo "$results" | grep -qv '"result": "success"' | grep -q '"result":'; then
            echo "One or more required jobs failed." && exit 1
          fi
          echo "All required jobs passed."

  # ── Formatting ────────────────────────────────────────────────────────────
  fmt:
    name: fmt
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - name: cargo fmt --check
        run: cargo fmt --all -- --check

  # ── Clippy ────────────────────────────────────────────────────────────────
  clippy:
    name: clippy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - uses: Swatinem/rust-cache@v2
      - name: clippy (no default features)
        run: cargo clippy --no-default-features -- -Dclippy::all
      - name: clippy (all features except sql)
        run: cargo clippy --features full,serde -- -Dclippy::all
      - name: clippy (all features)
        run: cargo clippy --all-features -- -Dclippy::all

  # ── Documentation ─────────────────────────────────────────────────────────
  docs:
    name: docs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@nightly
      - uses: Swatinem/rust-cache@v2
      - name: cargo doc
        run: cargo doc --no-deps --all-features
        env:
          RUSTDOCFLAGS: --cfg docsrs -Dwarnings

  # ── Minimum Supported Rust Version ────────────────────────────────────────
  msrv:
    name: msrv (1.85)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ env.MSRV }}
      - uses: Swatinem/rust-cache@v2
      - name: cargo check (no default features)
        run: cargo check --no-default-features
      - name: cargo check (full + serde)
        run: cargo check --features full,serde

  # ── Tests (no database features) ──────────────────────────────────────────
  test:
    name: test (${{ matrix.os }} / ${{ matrix.rust }})
    needs: [fmt, clippy]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        rust: [stable, beta]
        include:
          # Run nightly only on Ubuntu to keep the matrix lean
          - os: ubuntu-latest
            rust: nightly
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: ${{ matrix.rust }}
      - uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.os }}-${{ matrix.rust }}
      - name: cargo test (no default features)
        run: cargo test --no-default-features
      - name: cargo test (feature contact)
        run: cargo test --features contact
      - name: cargo test (feature serde)
        run: cargo test --features serde
      - name: cargo test (full + serde)
        run: cargo test --features full,serde
      - name: cargo test --doc
        run: cargo test --doc --features full,serde

  # ── Tests (sql feature, requires Postgres) ────────────────────────────────
  test-sql:
    name: test-sql (ubuntu-latest / stable)
    needs: [fmt, clippy]
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: arvo
          POSTGRES_PASSWORD: arvo
          POSTGRES_DB: arvo_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      DATABASE_URL: postgres://arvo:arvo@localhost:5432/arvo_test
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
        with:
          key: sql
      - name: cargo test (sql)
        run: cargo test --features sql
      - name: cargo test (all features)
        run: cargo test --all-features

  # ── Minimal dependency versions ───────────────────────────────────────────
  minimal-versions:
    name: minimal-versions
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@nightly
      - uses: Swatinem/rust-cache@v2
      - name: Install cargo-minimal-versions and cargo-hack
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-hack,cargo-minimal-versions
      - name: cargo minimal-versions check
        run: cargo minimal-versions check --features full,serde

  # ── Semver compatibility ───────────────────────────────────────────────────
#  semver:
#    name: semver
#    runs-on: ubuntu-latest
#    # Only meaningful on pushes to main (not PRs from forks) and when there's
#    # a published baseline version to compare against.
#    if: github.event_name == 'push'
#    steps:
#      - uses: actions/checkout@v4
#      - name: cargo semver-checks
#        uses: obi1kenobi/cargo-semver-checks-action@v2
#        with:
#          rust-toolchain: stable
#          feature-group: only-explicit-features
#          features: full,serde