name: CI on: pull_request: push: branches: - main concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} permissions: contents: read jobs: quality: name: Code Quality & Lint runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.2.2 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.3.0 with: go-version-file: go.mod cache: true - name: Check formatting run: make fmt-check - name: Vet run: go vet ./... - name: deadcode (advisory) continue-on-error: true run: make deadcode - name: golangci-lint (advisory) continue-on-error: true run: make lint-static test: name: Unit Tests & Coverage runs-on: ubuntu-latest timeout-minutes: 15 permissions: contents: read steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.2.2 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.3.0 with: go-version-file: go.mod cache: true - name: Test with coverage run: | go test -count=1 -coverprofile=coverage.out -covermode=atomic ./... - name: Publish coverage summary if: always() shell: bash run: | if [ -f coverage.out ]; then go tool cover -func=coverage.out | awk ' BEGIN { total = "unknown" rows = "" } $1 == "total:" { total = $3 next } { rows = rows sprintf("| `%s` | `%s` | **%s** |\n", $1, $2, $3) } END { print "### 📊 Test Coverage Summary: **" total "**" print "
Coverage per function\n" print "| File | Function | Coverage |" print "| :--- | :--- | :--- |" printf "%s", rows print "
" }' >> "$GITHUB_STEP_SUMMARY" fi - name: Upload coverage artifact if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: zero-coverage-report path: coverage.out if-no-files-found: warn smoke: name: Smoke (${{ matrix.os }}) runs-on: ${{ matrix.os }} timeout-minutes: 15 strategy: fail-fast: false matrix: os: - ubuntu-latest - macos-latest - windows-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.2.2 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.3.0 with: go-version-file: go.mod cache: true - name: Test (Fast Non-Race) run: go test ./... - name: Build binary run: go run ./cmd/zero-release build - name: Smoke binary run: go run ./cmd/zero-release smoke race: name: Race Detector runs-on: ubuntu-latest permissions: contents: read # A race the detector newly reports can present as a deadlock rather than a # failure, and the default job timeout is six hours. This job is expected to # be the longest in the workflow, so the ceiling is generous but finite. timeout-minutes: 30 steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff with: go-version-file: go.mod cache: true # Invoke the Makefile target rather than repeating its flags. `make test` # is already `go test ./... -race -count=1`, so running it here is what # stops the project's declared test command and what CI actually runs # from drifting apart again. The race detector needs cgo, which the # hosted ubuntu runner supplies without an extra setup step. - name: Test with the race detector run: make test performance: name: Performance Smoke runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.2.2 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.3.0 with: go-version-file: go.mod cache: true - name: Build binary run: go run ./cmd/zero-release build - name: Performance smoke run: | mkdir -p dist/perf go run ./cmd/zero-perf-bench --output dist/perf/perf-bench.json --ci - name: Upload performance report if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: zero-performance-smoke path: dist/perf/perf-bench.json if-no-files-found: warn security: name: Security & Code Health runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read steps: - name: Checkout uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.2.2 with: persist-credentials: false - name: Setup Go uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.3.0 with: go-version-file: go.mod cache: true - name: govulncheck (linux) run: make vulncheck - name: govulncheck (windows) run: make vulncheck-windows