From 94e2cac03b1ece1a52fdf3634ecdd2096de88952 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 1 Aug 2026 22:16:45 -0400 Subject: [PATCH] =?UTF-8?q?ci(go):=20verify=20committed=20sqlc=20output=20?= =?UTF-8?q?matches=20its=20.sql=20sources=20=E2=80=94=20#2380?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit internal/db/dbq is 39 files and ~12k lines of generated Go covering 307 queries, and nothing checked that it still matched internal/db/queries. test-go.yml referenced sqlc.yaml only as a path trigger; sqlc never ran. So a hand-edit, a half-applied regen, or a migration changed without a regen would all pass CI while the typed layer quietly lied about the SQL underneath it — which is the single thing adopting sqlc is supposed to buy. This session's slice-1 change is an instance: its SQL const was verified byte-identical against its own .sql source by script, but never against what sqlc would actually emit. Nothing in the repo could have told the difference. make verify-generate runs ahead of vet/lint/test, because if the typed layer disagrees with its sources then everything downstream is testing a lie. generate-go runs sqlc as a Go tool rather than a container: the ci-go image already has Go, so this avoids docker-in-docker on the runner. It's pinned to the same SQLC_VERSION as the existing containerised `generate`, so both routes emit identical output and there is one version to bump — now annotated for Renovate per rule #44. The diff prints BEFORE the exit-code check on purpose. On failure the log then holds sqlc's exact expected output, so correcting it is a copy rather than a guess. That is also what makes new queries workable without installing anything: this workstation has neither Go nor sqlc. Makefile joins the workflow's paths:. Without it a Makefile-only change — including this one — would not trigger the workflow that now depends on it. Same class as #2204, where CI never ran on plugin/** changes. Landing this on its own, ahead of slice 3, so that if it fails it is unambiguous whether the drift came from slice 1 or from new code. Co-Authored-By: Claude Opus 5 (1M context) --- .gitea/workflows/test-go.yml | 4 ++++ Makefile | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/test-go.yml b/.gitea/workflows/test-go.yml index 0eae539f..b3eb990f 100644 --- a/.gitea/workflows/test-go.yml +++ b/.gitea/workflows/test-go.yml @@ -27,6 +27,7 @@ on: - 'go.mod' - 'go.sum' - 'sqlc.yaml' + - 'Makefile' - 'internal/**' - 'cmd/**' - '.golangci.yml' @@ -53,6 +54,9 @@ jobs: go version golangci-lint --version + - name: Generated code matches queries (sqlc) + run: make verify-generate + - name: go vet run: go vet ./... diff --git a/Makefile b/Makefile index fa1e2e04..69fca217 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,30 @@ -.PHONY: generate test test-short test-integration lint build +.PHONY: generate generate-go verify-generate test test-short test-integration lint build +# renovate: datasource=docker depName=sqlc/sqlc SQLC_VERSION := 1.31.1 +# Local codegen. Containerised so a dev needs no sqlc install. generate: docker run --rm -v "$(CURDIR):/src" -w /src sqlc/sqlc:$(SQLC_VERSION) generate +# Same codegen, run as a Go tool instead of a container. This is the CI path: +# the ci-go image already has Go, so it avoids docker-in-docker. Pinned to the +# SAME version as `generate` above so both routes emit identical output. +generate-go: + go run github.com/sqlc-dev/sqlc/cmd/sqlc@v$(SQLC_VERSION) generate + +# Fail if the committed generated code no longer matches the .sql sources. +# +# Nothing verified this before, so internal/db/dbq could silently drift from +# internal/db/queries — a hand-edit, a half-applied regen, or a schema change +# without a regen would all pass CI while the typed layer lied about the SQL. +# +# The diff is printed BEFORE the exit-code check on purpose: when this fails, +# the log then contains sqlc's exact expected output, which is what you commit. +verify-generate: generate-go + git --no-pager diff -- internal/db/dbq + git diff --quiet -- internal/db/dbq + test: go test -race ./...