diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9720b01..49a0bf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,25 +2,72 @@ name: CI on: push: - branches: - - main + branches: [main] pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + COVER_MIN: "65" jobs: + lint: + name: Go lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: golangci-lint + uses: golangci/golangci-lint-action@v8 + with: + version: latest + only-new-issues: true + args: --timeout=5m + test: + name: Go tests + coverage runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 + with: + persist-credentials: false - uses: actions/setup-go@v5 with: - go-version: '1.26' + go-version-file: go.mod + cache: true + + - name: Run tests with coverage + env: + GOWORK: off + run: go test $(go list ./pkg/pluginsdk/... | grep -v '/runtimedefault$') -count=1 -covermode=atomic -coverprofile=coverage.out - - name: Run tests - run: go test ./... + - name: Enforce coverage floor + run: ./scripts/check-coverage.sh coverage.out - - name: Build example plugin - run: go build ./examples/hello-scheduled-task + - name: Build examples + run: | + go build ./examples/hello-scheduled-task + go build ./examples/hello-runtime-host - - name: Build hello-runtime-host example - run: go build ./examples/hello-runtime-host + - name: Upload coverage profile + if: always() + uses: actions/upload-artifact@v5 + with: + name: coverage-out + path: coverage.out + if-no-files-found: ignore diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..49619d5 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,29 @@ +version: "2" + +run: + timeout: 5m + +formatters: + enable: + - gofmt + - goimports + + settings: + goimports: + local-prefixes: + - github.com/prairie-server/prairie-plugin-sdk + +linters: + enable: + - errcheck + - govet + - ineffassign + - misspell + - staticcheck + - unused + + exclusions: + rules: + - path: _test\.go + linters: + - errcheck diff --git a/scripts/check-coverage.sh b/scripts/check-coverage.sh new file mode 100755 index 0000000..f83e065 --- /dev/null +++ b/scripts/check-coverage.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Fail if total statement coverage is below COVER_MIN (percent). +set -euo pipefail +COVER_MIN="${COVER_MIN:-70}" +PROFILE="${1:-coverage.out}" +if [[ ! -f "$PROFILE" ]]; then + echo "coverage profile missing: $PROFILE" >&2 + exit 1 +fi +total="$(go tool cover -func="$PROFILE" | awk '/^total:/{gsub(/%/,"",$3); print $3}')" +if [[ -z "$total" ]]; then + echo "could not parse total coverage from $PROFILE" >&2 + exit 1 +fi +awk -v total="$total" -v min="$COVER_MIN" 'BEGIN { + if (total+0 < min+0) { + printf "coverage %.1f%% is below required %.1f%%\n", total, min > "/dev/stderr" + exit 1 + } + printf "coverage %.1f%% (min %.1f%%)\n", total, min +}'