fix: satisfy backend ruff lint #35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| backend: | |
| name: Backend (Python ${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| - name: Install backend (editable + dev extras) | |
| run: pip install -e "apps/backend[dev]" | |
| - name: Lint (ruff) | |
| working-directory: apps/backend | |
| run: ruff check . | |
| - name: Type-check (mypy) | |
| working-directory: apps/backend | |
| run: mypy zvec_studio | |
| - name: Unit tests | |
| working-directory: apps/backend | |
| run: pytest tests/unit -v --junitxml=../../artifacts/backend-unit-${{ matrix.python-version }}.xml | |
| - name: Integration tests | |
| working-directory: apps/backend | |
| run: pytest tests/integration -v --junitxml=../../artifacts/backend-integration-${{ matrix.python-version }}.xml | |
| - name: Contract tests | |
| working-directory: apps/backend | |
| run: pytest tests/contract -v --junitxml=../../artifacts/backend-contract-${{ matrix.python-version }}.xml | |
| - name: Coverage gate | |
| working-directory: apps/backend | |
| run: pytest --cov=zvec_studio --cov-report=xml:../../artifacts/coverage-${{ matrix.python-version }}.xml --cov-fail-under=60 tests/unit tests/integration | |
| - name: Upload diagnostic artifacts | |
| if: failure() || always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: backend-artifacts-py${{ matrix.python-version }} | |
| path: artifacts/ | |
| if-no-files-found: ignore | |
| backend-platform: | |
| name: Backend (${{ matrix.name }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: macos-latest, name: "macOS ARM64", slug: macos-arm64, python-version: "3.12" } | |
| - { os: ubuntu-24.04-arm, name: "Linux ARM64", slug: linux-arm64, python-version: "3.12" } | |
| - { os: windows-latest, name: "Windows x64", slug: windows-x64, python-version: "3.12" } | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| - name: Install backend (editable + dev extras) | |
| run: pip install -e "apps/backend[dev]" | |
| - name: Lint (ruff) | |
| working-directory: apps/backend | |
| run: ruff check . | |
| - name: Unit tests | |
| working-directory: apps/backend | |
| run: pytest tests/unit -v --junitxml=../../artifacts/backend-unit-${{ matrix.slug }}.xml | |
| - name: Integration tests | |
| working-directory: apps/backend | |
| run: pytest tests/integration -v --junitxml=../../artifacts/backend-integration-${{ matrix.slug }}.xml | |
| - name: Upload diagnostic artifacts | |
| if: failure() || always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: backend-artifacts-${{ matrix.slug }} | |
| path: artifacts/ | |
| if-no-files-found: ignore | |
| desktop: | |
| name: Desktop (${{ matrix.name }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: ubuntu-latest, name: "Linux x64" } | |
| - { os: macos-latest, name: "macOS ARM64" } | |
| - { os: windows-latest, name: "Windows x64" } | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install system dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| - name: Create sidecar stub | |
| shell: bash | |
| run: | | |
| target=$(rustc -vV | awk '/^host:/ { print $2 }') | |
| mkdir -p apps/desktop/src-tauri/binaries | |
| ext="" | |
| if [[ "$target" == *windows* ]]; then ext=".exe"; fi | |
| touch "apps/desktop/src-tauri/binaries/zvec-studio-sidecar-${target}${ext}" | |
| chmod +x "apps/desktop/src-tauri/binaries/zvec-studio-sidecar-${target}${ext}" 2>/dev/null || true | |
| - name: Check formatting | |
| working-directory: apps/desktop/src-tauri | |
| run: cargo fmt --all -- --check | |
| - name: Clippy | |
| working-directory: apps/desktop/src-tauri | |
| run: cargo clippy --all-targets --no-deps -- -D warnings | |
| - name: Tests | |
| working-directory: apps/desktop/src-tauri | |
| run: cargo test --no-fail-fast | |
| frontend: | |
| name: Frontend (Node ${{ matrix.node-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node-version: ['20', '22'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile=false | |
| - name: Lint | |
| run: pnpm --filter frontend lint | |
| - name: Type-check | |
| run: pnpm --filter frontend typecheck | |
| - name: Unit tests | |
| run: pnpm --filter frontend test:unit | |
| - name: Upload diagnostic artifacts | |
| if: failure() || always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: frontend-artifacts-node${{ matrix.node-version }} | |
| path: | | |
| artifacts/ | |
| apps/frontend/playwright-report/ | |
| if-no-files-found: ignore | |
| e2e: | |
| name: E2E (Playwright) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile=false | |
| - name: Install Playwright browsers | |
| run: pnpm --filter frontend exec playwright install --with-deps chromium | |
| - name: Run E2E tests | |
| run: pnpm --filter frontend e2e | |
| - name: Upload Playwright report | |
| if: failure() || always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: artifacts/playwright-report/ | |
| if-no-files-found: ignore | |
| security: | |
| name: Security Audit | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| - name: Audit Python dependencies | |
| run: | | |
| pip install pip-audit | |
| pip install -e "apps/backend[dev]" | |
| pip-audit --desc --fix --dry-run || true | |
| pip-audit --desc 2>&1 | tee /tmp/pip-audit.txt | |
| if grep -qiE '(high|critical)' /tmp/pip-audit.txt; then | |
| echo "::error::High/critical Python vulnerabilities found" | |
| exit 1 | |
| fi | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: pnpm | |
| - name: Audit Node dependencies | |
| run: | | |
| pnpm install --frozen-lockfile=false | |
| pnpm audit --audit-level=high || true | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Audit Rust dependencies | |
| run: | | |
| cargo install cargo-audit --quiet | |
| cd apps/desktop/src-tauri && cargo audit | |
| desktop-build: | |
| name: Desktop Build (Linux x64) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| - name: Install backend (with packaging extras) | |
| run: pip install -e "apps/backend[packaging]" | |
| - uses: pnpm/action-setup@v4 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: pnpm | |
| - name: Install frontend dependencies | |
| run: pnpm install --frozen-lockfile=false | |
| - name: Build frontend | |
| run: pnpm --filter frontend build | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: apps/desktop/src-tauri | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev patchelf | |
| - name: Build sidecar binary | |
| run: python scripts/build_sidecar.py | |
| - name: Build Tauri bundle | |
| working-directory: apps/desktop | |
| run: pnpm tauri build --config src-tauri/tauri.bundle.conf.json | |
| - name: Upload installer artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-linux-x64 | |
| path: | | |
| apps/desktop/src-tauri/target/release/bundle/**/*.deb | |
| apps/desktop/src-tauri/target/release/bundle/**/*.AppImage | |
| if-no-files-found: warn | |
| retention-days: 7 | |
| dco: | |
| name: DCO sign-off check | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Verify commits are signed off | |
| run: | | |
| base="${{ github.event.pull_request.base.sha }}" | |
| head="${{ github.event.pull_request.head.sha }}" | |
| missing=0 | |
| while read -r sha; do | |
| if ! git log -1 --format=%B "$sha" | grep -qE '^Signed-off-by: '; then | |
| echo "::error ::Commit $sha is missing 'Signed-off-by:' line" | |
| missing=1 | |
| fi | |
| done < <(git rev-list "$base..$head") | |
| exit $missing |