clync 0.4.1

Encrypted sync for Claude Code across machines
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  test:
    name: Test
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
      - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
      - run: cargo test --workspace
      - run: cargo clippy --all-targets -- -D warnings -W clippy::too_many_lines

  e2e-storage:
    name: Storage E2E
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
      - uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2

      - name: Run folder storage tests
        run: cargo test --test storage_integration folder_storage

      - name: Start MinIO
        run: |
          docker run -d --name minio \
            -p 9123:9000 \
            -e MINIO_ROOT_USER=minioadmin \
            -e MINIO_ROOT_PASSWORD=minioadmin \
            quay.io/minio/minio:latest server /data
          for i in $(seq 1 30); do
            curl -sf http://localhost:9123/minio/health/live && break
            sleep 1
          done

      - name: Create MinIO bucket
        env:
          AWS_ACCESS_KEY_ID: minioadmin
          AWS_SECRET_ACCESS_KEY: minioadmin
          AWS_DEFAULT_REGION: us-east-1
        run: aws --endpoint-url http://localhost:9123 s3 mb s3://clync-test

      - name: Run S3 storage tests
        run: cargo test --features s3 --test storage_integration s3_storage

  changeset:
    name: Changeset
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
        with:
          fetch-depth: 0
      - name: Check for changeset
        run: |
          files=$(git diff --name-only origin/main...HEAD -- '.changeset/changesets/*.md')
          if [ -z "$files" ]; then
            echo "No changeset found. Add one with:"
            echo "  cargo changeset add -p clync -b patch -c fixed -m \"Description\""
            echo "  cargo changeset add -p clync -b none -c changed -m \"No user-facing changes\""
            exit 1
          fi

  fmt:
    name: Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
      - uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
        with:
          components: rustfmt
      - run: cargo fmt --all -- --check
      - name: Check file length
        run: |
          MAX=600
          violations=""
          while IFS= read -r f; do
            lines=$(wc -l < "$f")
            if [ "$lines" -gt "$MAX" ]; then
              violations="$violations\n  $f: $lines lines"
            fi
          done < <(find src -name '*.rs')
          if [ -n "$violations" ]; then
            printf "Files exceeding %d lines:%b\n" "$MAX" "$violations"
            exit 1
          fi