Merge pull request #1038 from Damola09/feat/snapshot-status-header #1495
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, master] | |
| pull_request: | |
| branches: [main, master] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ============================================ | |
| # Detect which paths changed | |
| # ============================================ | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: read | |
| outputs: | |
| go: ${{ steps.filter.outputs.go }} | |
| rust: ${{ steps.filter.outputs.rust }} | |
| docs: ${{ steps.filter.outputs.docs }} | |
| ci: ${{ steps.filter.outputs.ci }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Path filter | |
| uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| go: | |
| - '**/*.go' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - '.golangci.yml' | |
| rust: | |
| - 'simulator/**' | |
| - '**/Cargo.toml' | |
| - '**/Cargo.lock' | |
| - '**/*.rs' | |
| docs: | |
| - '**/*.md' | |
| ci: | |
| - '.github/workflows/ci.yml' | |
| # ============================================ | |
| # License Header Check | |
| # ============================================ | |
| license-headers: | |
| name: License Headers Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Check license headers (Go, Rust, TypeScript) | |
| run: ./scripts/check-license-headers.sh | |
| - name: Guard against conflict markers and leaked secrets | |
| run: | | |
| set -euo pipefail | |
| echo "Checking for unresolved merge conflict markers..." | |
| if rg -n -e "^(<{7}|={7}|>{7})( .*)?$" . > /tmp/conflict-markers.txt; then | |
| echo "[FAIL] Unresolved merge conflict markers found:" | |
| cat /tmp/conflict-markers.txt | |
| exit 1 | |
| fi | |
| echo "Checking for common secret patterns..." | |
| if rg -n -g "!**/*.md" -g "!**/examples/**" -e "-----BEGIN (RSA|EC|OPENSSH|DSA|PRIVATE KEY)-----|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|xox[baprs]-" . > /tmp/secret-patterns.txt; then | |
| echo "[FAIL] Potential secrets detected in tracked files:" | |
| cat /tmp/secret-patterns.txt | |
| exit 1 | |
| fi | |
| echo " Repository sanity checks passed" | |
| # ============================================ | |
| # Go CLI - Lint, Build & Test | |
| # ============================================ | |
| go: | |
| name: Go CI (${{ matrix.go-version }}, ${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: [license-headers, changes] | |
| if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.event_name == 'push' | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| go-version: ["1.25.0"] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ matrix.go-version }} | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Verify dependencies | |
| run: go mod verify | |
| - name: Check formatting | |
| if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.0' | |
| run: | | |
| if [ -n "$(gofmt -l .)" ]; then | |
| echo "[FAIL] Go files are not formatted. Run 'go fmt ./...' to fix." | |
| gofmt -d . | |
| exit 1 | |
| fi | |
| echo " All Go files are properly formatted" | |
| - name: Run go vet | |
| if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.0' | |
| run: go vet ./... | |
| - name: Install golangci-lint | |
| if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.0' | |
| uses: golangci/golangci-lint-action@v7 | |
| with: | |
| version: latest | |
| args: --config=.golangci.yml --timeout=5m --max-issues-per-linter=0 --max-same-issues=0 | |
| - name: Check for unused variables | |
| if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.0' | |
| run: | | |
| echo "Checking for unused variables and code..." | |
| go vet ./... || { | |
| echo "[FAIL] go vet found issues" | |
| exit 1 | |
| } | |
| echo " No unused variables detected" | |
| - name: Build | |
| run: go build -v ./... | |
| - name: Build erst binary for integration tests | |
| run: go build -o erst ./cmd/erst | |
| - name: Run tests (race) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: go test -v -race ./... | |
| - name: Run tests (compile-only) | |
| if: matrix.os != 'ubuntu-latest' | |
| run: go test -short -run '^$' -v ./... | |
| # ============================================ | |
| # Cross-Platform CLI Binary Integration | |
| # ============================================ | |
| cli-integration: | |
| name: CLI Integration (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: [license-headers, changes] | |
| if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.event_name == 'push' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.25.0" | |
| cache: true | |
| cache-dependency-path: go.sum | |
| - name: Run CLI integration suite via os/exec | |
| run: go test -v ./tests -run TestErstBinaryFullCLISurface -count=1 | |
| # ============================================ | |
| # Docs - Spell Check | |
| # ============================================ | |
| docs-spellcheck: | |
| name: Docs Spellcheck | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| if: needs.changes.outputs.docs == 'true' || needs.changes.outputs.ci == 'true' || github.event_name == 'push' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install misspell | |
| run: | | |
| curl -L https://raw.githubusercontent.com/client9/misspell/master/install-misspell.sh | sh -s -- -b "$HOME/bin" | |
| echo "$HOME/bin" >> $GITHUB_PATH | |
| - name: Run spellcheck | |
| run: | | |
| set -euo pipefail | |
| IGNORE_WORDS=$(paste -sd, .github/spelling/allow.txt) | |
| find . -name '*.md' -print0 | xargs -0 misspell -error -i "$IGNORE_WORDS" | |
| # ============================================ | |
| # Rust Simulator - Lint, Build & Test | |
| # ============================================ | |
| rust: | |
| name: Rust CI (${{ matrix.rust-version }}) | |
| runs-on: ubuntu-latest | |
| needs: [license-headers, changes] | |
| if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.ci == 'true' || github.event_name == 'push' | |
| strategy: | |
| matrix: | |
| rust-version: [stable, "1.87"] | |
| defaults: | |
| run: | |
| working-directory: simulator | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ matrix.rust-version }} | |
| components: rustfmt, clippy | |
| - name: Cache Cargo dependencies and build artifacts | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: simulator -> target | |
| prefix-key: ${{ runner.os }}-rust-${{ matrix.rust-version }} | |
| cache-targets: true | |
| - name: Check formatting | |
| if: matrix.rust-version == 'stable' | |
| run: | | |
| cargo fmt --check || { | |
| echo "[FAIL] Rust files are not formatted. Run 'cargo fmt' to fix." | |
| exit 1 | |
| } | |
| echo " All Rust files are properly formatted" | |
| - name: Run Clippy (strict mode) | |
| if: matrix.rust-version == 'stable' | |
| run: | | |
| echo "Running Clippy with strict warnings..." | |
| cargo clippy --all-targets --all-features -- \ | |
| -D warnings \ | |
| -D clippy::all \ | |
| -D unused-variables \ | |
| -D unused-imports \ | |
| -D unused-mut \ | |
| -D dead-code \ | |
| -D unused-assignments || { | |
| echo "[FAIL] Clippy found issues that must be fixed" | |
| exit 1 | |
| } | |
| echo " Clippy checks passed" | |
| - name: Run tests | |
| run: cargo test --verbose | |
| - name: Build | |
| run: cargo build --verbose | |
| # ============================================ | |
| # Gate - all required jobs must pass for merge | |
| # ============================================ | |
| ci-gate: | |
| name: CI Gate | |
| runs-on: ubuntu-latest | |
| if: always() | |
| needs: [go, rust, cli-integration, docs-spellcheck] | |
| steps: | |
| - name: Check job results | |
| run: | | |
| echo "go: ${{ needs.go.result }}" | |
| echo "rust: ${{ needs.rust.result }}" | |
| echo "cli-integration: ${{ needs.cli-integration.result }}" | |
| echo "docs-spellcheck: ${{ needs.docs-spellcheck.result }}" | |
| for result in \ | |
| "${{ needs.go.result }}" \ | |
| "${{ needs.rust.result }}" \ | |
| "${{ needs.cli-integration.result }}" \ | |
| "${{ needs.docs-spellcheck.result }}"; do | |
| if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then | |
| echo "CI gate failed: a required job did not pass." | |
| exit 1 | |
| fi | |
| done | |
| echo "All CI checks passed or were correctly skipped." |