scsh 1.18.2

Scoped Skills Helper — preflight a git repo and run its scoped skills in ephemeral containers.
name: CI

on:
  pull_request:
  push:
    branches: [main]

env:
  RUSTFLAGS: -D warnings

jobs:
  quality:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - uses: Swatinem/rust-cache@v2

      - name: Release-shape gate self-tests
        run: python3 -m unittest discover -s scripts -p 'test_*.py' -v

      # PRs only: on main there is no base to compare against, and with auto-publish a
      # merged bump IS on crates.io moments later. The gate passes untouched-version PRs
      # and enforces the full release shape when the PR bumps; it inspects the PR head
      # explicitly because the pull_request checkout is GitHub's synthetic merge commit,
      # whose subject and empty diff-tree carry no release shape.
      - name: Release shape and version ladder
        if: github.event_name == 'pull_request'
        env:
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
        run: python3 scripts/check-release.py "$BASE_SHA" "$HEAD_SHA"

      - name: Format
        run: cargo fmt --check

      - name: Clippy (debug)
        run: cargo clippy --all-targets -- -D warnings

      - name: Clippy (release)
        run: cargo clippy --release --all-targets -- -D warnings

  tests:
    name: Tests (${{ matrix.suite }}, ${{ matrix.profile }})
    runs-on: ubuntu-latest
    timeout-minutes: 20
    strategy:
      fail-fast: false
      matrix:
        suite: [unit, integration]
        profile: [debug, release]
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: Run ${{ matrix.suite }} tests (${{ matrix.profile }})
        env:
          SUITE: ${{ matrix.suite }}
          PROFILE: ${{ matrix.profile }}
        run: |
          args=""
          if [ "$PROFILE" = release ]; then
            args="$args --release"
          fi
          if [ "$SUITE" = unit ]; then
            cargo build $args
            args="$args --bin scsh"
          else
            args="$args --test cli"
          fi
          cargo test $args