CI #711
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 | |
| # Simplified CI workflow with clear separation of concerns: | |
| # - PR: Fast checks (fmt, clippy, basic tests) - must pass | |
| # - Main: Full test suite across platforms | |
| # - Schedule: Security & dependency audits | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| branches: [main, master] | |
| schedule: | |
| # Daily security audit at 10:00 UTC (3:00 AM LA time) | |
| - cron: '0 10 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| skip_tests: | |
| description: 'Skip tests (for debugging)' | |
| required: false | |
| type: boolean | |
| default: false | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| # ============================================================================ | |
| # PR & Push Checks - Fast feedback (<5 minutes) | |
| # ============================================================================ | |
| format: | |
| name: Format Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - name: Check formatting | |
| run: cargo fmt --all -- --check | |
| clippy: | |
| name: Clippy Lints | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Build frontend | |
| run: | | |
| cd front-end | |
| npm ci | |
| npm run build | |
| - name: Run clippy | |
| run: cargo clippy --all-targets --all-features -- -D warnings | |
| test-quick: | |
| name: Quick Tests (Ubuntu/stable) | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' || github.event_name == 'push' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Build frontend | |
| run: | | |
| cd front-end | |
| npm ci | |
| npm run build | |
| - name: Build | |
| run: cargo build --verbose | |
| - name: Run unit and CLI tests | |
| if: ${{ !inputs.skip_tests }} | |
| run: cargo test --lib --bins --verbose | |
| - name: Run integration tests (parallel safe) | |
| if: ${{ !inputs.skip_tests }} | |
| run: | | |
| cargo test --test integration_tests --verbose | |
| cargo test --test interface_spec_test --verbose | |
| - name: Clean up test database before doctor command | |
| run: rm -rf ~/.intent-engine | |
| - name: Test doctor command | |
| run: cargo run --bin ie -- doctor | |
| # ============================================================================ | |
| # Main Branch - Full Test Suite | |
| # ============================================================================ | |
| test-full: | |
| name: Full Tests (${{ matrix.os }} / ${{ matrix.rust }}) | |
| if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event_name == 'workflow_dispatch' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux | |
| - os: ubuntu-latest | |
| rust: stable | |
| - os: ubuntu-latest | |
| rust: beta | |
| # macOS | |
| - os: macos-latest | |
| rust: stable | |
| # Windows | |
| - os: windows-latest | |
| rust: stable | |
| # Nightly (experimental) | |
| - os: ubuntu-latest | |
| rust: nightly | |
| experimental: true | |
| continue-on-error: ${{ matrix.experimental || false }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ matrix.rust }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| shared-key: ${{ matrix.rust }}-${{ matrix.os }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Build frontend | |
| run: | | |
| cd front-end | |
| npm ci | |
| npm run build | |
| - name: Build | |
| run: cargo build --verbose | |
| - name: Run unit and CLI tests | |
| if: ${{ !inputs.skip_tests }} | |
| run: cargo test --lib --bins --verbose | |
| - name: Run integration tests (parallel safe) | |
| if: ${{ !inputs.skip_tests }} | |
| run: | | |
| cargo test --test integration_tests --verbose | |
| cargo test --test interface_spec_test --verbose | |
| - name: Build release | |
| run: cargo build --release --verbose | |
| - name: Upload artifacts on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: test-logs-${{ matrix.os }}-${{ matrix.rust }} | |
| path: target/*/deps/*.log | |
| retention-days: 7 | |
| # ============================================================================ | |
| # Documentation & Package | |
| # ============================================================================ | |
| docs: | |
| name: Documentation | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Check documentation | |
| run: cargo doc --no-deps --all-features --document-private-items | |
| env: | |
| RUSTDOCFLAGS: -D warnings | |
| - name: Test doc examples | |
| run: cargo test --doc --all-features | |
| package: | |
| name: Package Check | |
| runs-on: ubuntu-latest | |
| if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Build frontend | |
| run: | | |
| cd front-end | |
| npm ci | |
| npm run build | |
| - name: Verify package | |
| run: | | |
| cargo package --allow-dirty | |
| PKG_FILE=$(find target/package -name "intent-engine-*.crate" -type f | head -n 1) | |
| echo "Found package: $PKG_FILE" | |
| # Extract and test | |
| tar -xzf "$PKG_FILE" -C target/package/ | |
| PKG_DIR=$(find target/package -maxdepth 1 -name "intent-engine-*" -type d | head -n 1) | |
| cd "$PKG_DIR" | |
| cargo build --release --verbose | |
| # Run tests | |
| cargo test --lib --bins --verbose | |
| cargo test --test integration_tests --verbose | |
| cargo test --test interface_spec_test --verbose | |
| # ============================================================================ | |
| # Security & Dependencies (Daily Schedule) | |
| # ============================================================================ | |
| security: | |
| name: Security Audit | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit | |
| - name: Run security audit | |
| run: cargo audit | |
| - name: Install cargo-deny | |
| run: cargo install cargo-deny | |
| - name: Check licenses and advisories | |
| run: cargo deny check | |
| outdated: | |
| name: Outdated Dependencies | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'schedule' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - name: Install cargo-outdated | |
| run: cargo install cargo-outdated | |
| - name: Check outdated dependencies | |
| run: cargo outdated --exit-code 1 | |
| continue-on-error: true | |
| # ============================================================================ | |
| # PR Dependency Review | |
| # ============================================================================ | |
| dependency-review: | |
| name: Dependency Review | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/dependency-review-action@v4 | |
| continue-on-error: true | |
| # ============================================================================ | |
| # Status Checks | |
| # ============================================================================ | |
| ci-success: | |
| name: CI Success | |
| runs-on: ubuntu-latest | |
| needs: [format, clippy, test-quick, docs] | |
| if: always() && (github.event_name == 'pull_request' || github.event_name == 'push') | |
| steps: | |
| - name: Check all jobs | |
| run: | | |
| if [ "${{ needs.format.result }}" != "success" ]; then | |
| echo "❌ Format check failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.clippy.result }}" != "success" ]; then | |
| echo "❌ Clippy check failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.test-quick.result }}" != "success" ]; then | |
| echo "❌ Quick tests failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.docs.result }}" != "success" ]; then | |
| echo "❌ Documentation check failed" | |
| exit 1 | |
| fi | |
| echo "✅ All CI checks passed!" | |
| # ============================================================================ | |
| # Issue Creation on Failure (Schedule Only) | |
| # ============================================================================ | |
| create-issue: | |
| name: Create Issue on Failure | |
| runs-on: ubuntu-latest | |
| needs: [security, outdated] | |
| if: always() && github.event_name == 'schedule' && (needs.security.result == 'failure' || needs.outdated.result == 'failure') | |
| steps: | |
| - uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const date = new Date().toISOString().split('T')[0]; | |
| const failures = []; | |
| if ('${{ needs.security.result }}' === 'failure') { | |
| failures.push('🔒 Security Audit'); | |
| } | |
| if ('${{ needs.outdated.result }}' === 'failure') { | |
| failures.push('📦 Outdated Dependencies'); | |
| } | |
| const body = `## 🚨 Scheduled CI Failed - ${date}\n\n` + | |
| `The following checks failed:\n\n` + | |
| failures.map(f => `- ❌ ${f}`).join('\n') + '\n\n' + | |
| `[View workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n` + | |
| `---\n` + | |
| `<sub>Auto-created by scheduled CI</sub>`; | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: `🚨 CI Failure - ${date}`, | |
| body: body, | |
| labels: ['ci', 'automated', 'security'] | |
| }); |