chore: release 1.3.0 #723
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: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| # Detect the scope of the diff so the heavy jobs can short-circuit on | |
| # docs/site-only changes. Gating is by *changed paths*: any .go / go.mod / | |
| # go.sum / Makefile / .github / scripts touch flips `code` true and the full | |
| # pipeline runs. See docs/CI_CD.md § "Path-based job gating". | |
| changes: | |
| name: Detect change scope | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| code: ${{ steps.filter.outputs.code }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 | |
| id: filter | |
| with: | |
| # `code` = anything that can change the built binary or the CI/build | |
| # machinery itself. Mirrors the docs-only definition in CLAUDE.md: a | |
| # PR touching none of these is docs/site-only and skips build+fuzz. | |
| # | |
| # The Go source directories are matched wholesale rather than by | |
| # `*.go` extension, because the binary embeds non-Go files too | |
| # (`internal/schemaindex/schema_index.json`, | |
| # `internal/compliance/datasafety/reference.csv`). Gating on the | |
| # extension let those through as "docs-only", skipping the very tests | |
| # that guard them. Directory-level globs keep any future `go:embed` | |
| # covered by default; there are no docs under these paths, so nothing | |
| # is over-triggered. | |
| filters: | | |
| code: | |
| - 'cmd/**' | |
| - 'commands/**' | |
| - 'internal/**' | |
| - '**/*.go' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - 'Makefile' | |
| - '.github/**' | |
| - 'scripts/**' | |
| - 'install.sh' | |
| # Inputs to `make schema-index-update`: they live under docs/ but | |
| # a change here can desynchronise the embedded Schema index. | |
| - 'docs/discovery/**' | |
| build: | |
| name: Build, lint, test | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| # NOTE: no job-level `if`. "Build, lint, test" is a required check on main, | |
| # and a *skipped* required job blocks merge (GitHub treats skipped as | |
| # unsatisfied). So the job always runs and reports success; the expensive | |
| # steps self-select on `changes.outputs.code`. On a docs-only PR every step | |
| # below is skipped and the job goes green in seconds — merge stays unblocked. | |
| steps: | |
| - if: needs.changes.outputs.code == 'true' | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - if: needs.changes.outputs.code == 'true' | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| - name: gofmt | |
| if: needs.changes.outputs.code == 'true' | |
| run: | | |
| diff <(gofmt -d .) <(echo -n) || (echo '::error::run "make format" to fix formatting'; exit 1) | |
| - name: go vet | |
| if: needs.changes.outputs.code == 'true' | |
| run: go vet ./... | |
| - name: golangci-lint | |
| if: needs.changes.outputs.code == 'true' | |
| uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 | |
| with: | |
| version: v2.12.2 | |
| - name: test | |
| if: needs.changes.outputs.code == 'true' | |
| run: go test -race ./... | |
| - name: build | |
| if: needs.changes.outputs.code == 'true' | |
| run: go build ./cmd/gplay | |
| fuzz: | |
| name: Fuzz smoke (untrusted-input parsers) | |
| runs-on: ubuntu-latest | |
| needs: changes | |
| # Fuzz smoke is NOT a required check, so it can be skipped outright at the | |
| # job level on docs-only PRs — no green-stub gymnastics needed. | |
| if: needs.changes.outputs.code == 'true' | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| # Short bounded fuzzing of the parsers that consume untrusted bytes (API | |
| # error envelope, JWT scope claim, reply-batch TSV). The seed corpora run | |
| # as ordinary cases in the `test` job; this surfaces crashers from | |
| # generated input without materially slowing it. -fuzztime is small on | |
| # purpose — this is a smoke, not an exhaustive campaign. | |
| - name: Fuzz parsers | |
| run: | | |
| set -euo pipefail | |
| # Go persists generated fuzz inputs in $GOCACHE/fuzz, which setup-go's | |
| # build cache restores across runs. That corpus grows unboundedly and | |
| # eventually pushes the time-boxed run past the coordinator's shutdown | |
| # deadline ("context deadline exceeded") on slow runners — seen on the | |
| # v0.17.0 release PR (#383). Reset it so each smoke starts from the | |
| # in-code f.Add seeds only; regression cases still run in `test`. | |
| rm -rf "$(go env GOCACHE)/fuzz" | |
| go test -run='^$' -fuzz='^FuzzParseErrorEnvelope$' -fuzztime=30s ./internal/play/api/ | |
| go test -run='^$' -fuzz='^FuzzScopesFromAssertion$' -fuzztime=30s ./internal/transport/ | |
| go test -run='^$' -fuzz='^FuzzParse$' -fuzztime=30s ./internal/reviews/batch/ | |
| docs: | |
| name: Docs sanity | |
| runs-on: ubuntu-latest | |
| # Always runs: it's a required check, and its steps (verb gate, dash gate, | |
| # shellcheck, required-files) are cheap and relevant to every PR regardless | |
| # of scope. | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Verb vocabulary gate (ADR-0019) | |
| run: bash scripts/verb-gate.sh | |
| - name: Em dash gate (help text and error messages reach users) | |
| run: bash scripts/dash-gate.sh | |
| - name: shellcheck install.sh | |
| run: shellcheck install.sh scripts/install-test.sh | |
| # Offline: a stub curl serves a fixture release, so this asserts the | |
| # fail-closed sha256 gate without touching the network. | |
| - name: Install script fail-closed checksum gate | |
| run: bash scripts/install-test.sh | |
| - name: Verify required files exist | |
| run: | | |
| set -euo pipefail | |
| missing=0 | |
| for f in \ | |
| CLAUDE.md \ | |
| CONTEXT.md \ | |
| CONTRIBUTING.md \ | |
| CODE_OF_CONDUCT.md \ | |
| LICENSE \ | |
| README.md \ | |
| SUPPORT.md \ | |
| docs/DESIGN.md \ | |
| docs/BACKLOG.md \ | |
| docs/CI_CD.md \ | |
| docs/adr/0001-credential-storage.md \ | |
| docs/adr/0002-safe-production-defaults.md \ | |
| docs/adr/0003-json-passthrough.md | |
| do | |
| if [ ! -f "$f" ]; then | |
| echo "::error file=$f::missing required file" | |
| missing=$((missing+1)) | |
| fi | |
| done | |
| exit $missing |