Skip to content

Merge pull request #1038 from Damola09/feat/snapshot-status-header #1495

Merge pull request #1038 from Damola09/feat/snapshot-status-header

Merge pull request #1038 from Damola09/feat/snapshot-status-header #1495

Workflow file for this run

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."