chore: optimize CI — path filters, concurrency, skip release builds on PRs #52
Workflow file for this run
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: [master, main] | |
| pull_request: | |
| branches: [master, main] | |
| paths: | |
| - '**/*.rs' | |
| - '**/Cargo.toml' | |
| - '**/Cargo.lock' | |
| - '.github/workflows/**' | |
| - 'Makefile' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| # Gate 1: Compile + Lint (setpoints S1, S2) | |
| check: | |
| name: Check & Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: "1.88" | |
| components: clippy, rustfmt | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo check --workspace | |
| - run: cargo clippy --workspace -- -D warnings | |
| - run: cargo fmt --all -- --check | |
| # Gate 2: All tests pass (setpoint S3) | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: "1.88" | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Run all tests | |
| run: cargo test --workspace | |
| - name: Report test count | |
| run: | | |
| COUNT=$(cargo test --workspace 2>&1 | grep "test result" | awk '{sum += $4} END {print sum}') | |
| echo "### Test Results" >> "$GITHUB_STEP_SUMMARY" | |
| echo "Total passing: **${COUNT}** tests" >> "$GITHUB_STEP_SUMMARY" | |
| # Gate 3: PR title follows conventional commits | |
| pr-lint: | |
| name: PR Lint | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check conventional commit title | |
| run: | | |
| TITLE="${{ github.event.pull_request.title }}" | |
| if echo "$TITLE" | grep -qE '^(feat|fix|docs|chore|refactor|test|perf|ci|style)(\(.+\))?!?:'; then | |
| echo "✅ PR title follows conventional commits: $TITLE" | |
| else | |
| echo "❌ PR title must follow conventional commits format:" | |
| echo " feat: description | fix: description | docs: description | etc." | |
| echo " Got: $TITLE" | |
| exit 1 | |
| fi | |
| # Gate 4: Control metalayer validation | |
| control-audit: | |
| name: Control Audit | |
| needs: [check, test] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Validate setpoint coverage | |
| run: | | |
| # Count setpoints in CONTROL.md | |
| SETPOINTS=$(grep -cE '^\| S[0-9]+ \|' CONTROL.md || echo 0) | |
| echo "Setpoints defined: $SETPOINTS" | |
| # Verify CONTROL.md has the expected structure | |
| if [ "$SETPOINTS" -lt 50 ]; then | |
| echo "❌ CONTROL.md has fewer than 50 setpoints ($SETPOINTS found)" | |
| exit 1 | |
| fi | |
| echo "✅ CONTROL.md has $SETPOINTS setpoints" | |
| # Check that key governance files exist | |
| for f in CLAUDE.md AGENTS.md CONTROL.md PLANS.md EXTENDING.md CONTRIBUTING.md; do | |
| if [ ! -f "$f" ]; then | |
| echo "❌ Missing governance file: $f" | |
| exit 1 | |
| fi | |
| done | |
| echo "✅ All governance files present" | |
| # Check changelog exists | |
| if [ ! -f CHANGELOG.md ]; then | |
| echo "⚠️ CHANGELOG.md missing (generate with: make changelog)" | |
| fi | |
| echo "### Control Audit" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- Setpoints: **${SETPOINTS}**" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- Governance files: ✅" >> "$GITHUB_STEP_SUMMARY" | |
| # Gate 5: Build verification (skip on PRs — release.yml handles tagged builds) | |
| build: | |
| name: Build (${{ matrix.target }}) | |
| if: github.event_name != 'pull_request' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| artifact: symphony-linux-amd64 | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| artifact: symphony-macos-amd64 | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: symphony-macos-arm64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: "1.88" | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| - run: cargo build --release --target ${{ matrix.target }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: target/${{ matrix.target }}/release/symphony | |
| docker: | |
| name: Docker Build | |
| if: github.event_name != 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - run: docker build -t symphony:test . | |
| # Auto-merge: when all gates pass on a PR, enable auto-merge | |
| auto-merge: | |
| name: Auto-Merge | |
| if: github.event_name == 'pull_request' | |
| needs: [check, test, pr-lint, control-audit] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Enable auto-merge | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| PR_NUM=${{ github.event.pull_request.number }} | |
| AUTHOR="${{ github.event.pull_request.user.login }}" | |
| echo "### Auto-Merge Gate" >> "$GITHUB_STEP_SUMMARY" | |
| echo "All control metalayer gates passed." >> "$GITHUB_STEP_SUMMARY" | |
| echo "- Check & Lint: ✅" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- Tests: ✅" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- PR Lint: ✅" >> "$GITHUB_STEP_SUMMARY" | |
| echo "- Control Audit: ✅" >> "$GITHUB_STEP_SUMMARY" | |
| # Enable auto-merge (squash) for the PR | |
| gh pr merge "$PR_NUM" \ | |
| --repo "${{ github.repository }}" \ | |
| --auto \ | |
| --squash \ | |
| --subject "${{ github.event.pull_request.title }}" || true | |
| echo "Auto-merge enabled for PR #${PR_NUM}" >> "$GITHUB_STEP_SUMMARY" |