Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Builds wicked-sqlc for every supported platform, runs each binary on its own
# platform, and attaches the archives, checksums.txt and build provenance to the
# GitHub release of the tag. Install with scripts/install.sh.
#
# A tag push builds that tag. To add binaries to an existing release, run the
# workflow by hand with the tag (the tag's source is built, with this file's
# steps).
name: release

on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: "Existing tag to build, e.g. v2.4.0"
required: true

permissions:
contents: read

concurrency:
group: release-${{ inputs.tag || github.ref_name }}
cancel-in-progress: false

env:
TAG: ${{ inputs.tag || github.ref_name }}
# Go release used for the binaries: the newest patch of go.mod's version.
GO_VERSION: "1.26"

jobs:
build:
name: build ${{ matrix.goos }}/${{ matrix.goarch }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: true
matrix:
include:
# Linux: CGO (native PostgreSQL parser) linked statically against
# musl in Alpine, so the binary runs on any distribution. The amd64
# job also cross-builds Windows without CGO (WebAssembly parser).
- { goos: linux, goarch: amd64, runner: ubuntu-24.04 }
- { goos: linux, goarch: arm64, runner: ubuntu-24.04-arm }
# macOS: CGO, native runners, runs on macOS 12 and later.
- { goos: darwin, goarch: amd64, runner: macos-15-intel }
- { goos: darwin, goarch: arm64, runner: macos-15 }
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ env.TAG }}
persist-credentials: false

- name: Version
run: |
echo "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$' || { echo "not a release tag: $TAG" >&2; exit 1; }
echo "VERSION=${TAG#v}" >> "$GITHUB_ENV"
# Same version string as `make build` from the tag.
echo "LDFLAGS=-s -w -X github.com/sqlc-dev/sqlc/internal/info.Version=${TAG}-wicked-fork" >> "$GITHUB_ENV"

- name: Build (Linux, Alpine)
if: matrix.goos == 'linux'
run: |
docker run --rm -v "$PWD:/src" -w /src \
-e LDFLAGS -e GOFLAGS=-buildvcs=false -e WINDOWS="${{ matrix.goarch == 'amd64' }}" \
"golang:${GO_VERSION}-alpine" sh -euc '
apk add --no-cache build-base >/dev/null
CGO_ENABLED=1 go build -trimpath \
-ldflags="$LDFLAGS -linkmode external -extldflags -static" -o dist/sqlc ./cmd/sqlc
if [ "$WINDOWS" = true ]; then
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath \
-ldflags="$LDFLAGS" -o dist/windows/sqlc.exe ./cmd/sqlc
fi
chown -R "$(stat -c %u:%g /src)" dist'
file dist/sqlc | grep -q 'statically linked'

- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
if: matrix.goos == 'darwin'
with:
go-version: ${{ env.GO_VERSION }}
cache: false

- name: Build (macOS)
if: matrix.goos == 'darwin'
env:
CGO_ENABLED: "1"
MACOSX_DEPLOYMENT_TARGET: "12.0"
run: go build -trimpath -ldflags="$LDFLAGS" -o dist/sqlc ./cmd/sqlc

- name: Smoke test
run: |
got="$(dist/sqlc version)"
test "$got" = "${TAG}-wicked-fork" || { echo "sqlc version = $got" >&2; exit 1; }
cp -R internal/endtoend/testdata/wicked_compat "$RUNNER_TEMP/smoke"
(cd "$RUNNER_TEMP/smoke" && "$GITHUB_WORKSPACE/dist/sqlc" compile && "$GITHUB_WORKSPACE/dist/sqlc" generate)

- name: Package
run: |
mkdir -p out
name="sqlc_${VERSION}_${{ matrix.goos }}_${{ matrix.goarch }}"
cp LICENSE dist/
tar -C dist -czf "out/${name}.tar.gz" sqlc LICENSE
if [ -f dist/windows/sqlc.exe ]; then
cp LICENSE dist/windows/
(cd dist/windows && zip -q "../../out/sqlc_${VERSION}_windows_amd64.zip" sqlc.exe LICENSE)
fi
ls -l out

- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sqlc-${{ matrix.goos }}-${{ matrix.goarch }}
path: out/*
if-no-files-found: error
retention-days: 7

windows:
name: test windows/amd64
needs: build
runs-on: windows-2025
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ env.TAG }}
persist-credentials: false
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: sqlc-linux-amd64
path: out
- name: Smoke test
shell: bash
run: |
unzip -q out/sqlc_*_windows_amd64.zip -d "$RUNNER_TEMP/bin"
sqlc="$RUNNER_TEMP/bin/sqlc.exe"
got="$("$sqlc" version | tr -d '\r')"
test "$got" = "${TAG}-wicked-fork" || { echo "sqlc version = $got" >&2; exit 1; }
cp -R internal/endtoend/testdata/wicked_compat "$RUNNER_TEMP/smoke"
(cd "$RUNNER_TEMP/smoke" && "$sqlc" compile && "$sqlc" generate)

publish:
needs: [build, windows]
runs-on: ubuntu-24.04
permissions:
contents: write # upload to the release
id-token: write # build provenance
attestations: write
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: sqlc-*
path: out
merge-multiple: true

- name: Checksums
working-directory: out
run: |
sha256sum sqlc_* > checksums.txt
cat checksums.txt

- uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: out/sqlc_*

- name: Upload to the release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
if ! gh release view "$TAG" >/dev/null 2>&1; then
gh release create "$TAG" --verify-tag --title "$TAG" --generate-notes
fi
gh release upload "$TAG" out/* --clobber

install:
name: install on ${{ matrix.runner }}
needs: publish
runs-on: ${{ matrix.runner }}
strategy:
matrix:
runner: [ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15]
steps:
# scripts/install.sh from this workflow's commit (an older tag may not have it).
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install the release with scripts/install.sh
env:
INSTALL_DIR: ${{ runner.temp }}/bin
run: |
sh scripts/install.sh "$TAG"
got="$("$INSTALL_DIR/sqlc" version)"
test "$got" = "${TAG}-wicked-fork" || { echo "sqlc version = $got" >&2; exit 1; }
23 changes: 23 additions & 0 deletions GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ your customers are disappointed, or (2) before the product is launched, writing

## Install

Releases from v2.4.1 on ship binaries for Linux (amd64, arm64; static, any
distribution), macOS (amd64, arm64; 12 or later) and Windows (amd64), with a
`checksums.txt` and build provenance. `scripts/install.sh` downloads one,
checks its SHA-256 and installs it into `$(go env GOPATH)/bin` (or
`INSTALL_DIR`):

```bash
curl -fsSL https://raw.githubusercontent.com/Stumble/sqlc/main/scripts/install.sh | sh -s -- v2.4.1
sqlc version # v2.4.1-wicked-fork
```

Set `SQLC_SHA256` to the archive's checksum to accept only that archive (a
project that pins sqlc should do this). `gh attestation verify <archive> -R
Stumble/sqlc` checks that an archive was built by this repository's release
workflow. On Windows, download `sqlc_<version>_windows_amd64.zip` from the
release.

The Linux and macOS binaries use the native PostgreSQL parser (CGO). The
Windows binary, and builds with `CGO_ENABLED=0`, use its WebAssembly build:
same output, about two seconds slower per run.

### Build from source

Build this fork from source using the Go version required by [go.mod](go.mod).
The default build uses CGO and requires a C compiler. Ensure Go's installation
directory (`GOBIN`, or `GOPATH/bin` when unset) is on your `PATH`.
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,22 @@ the wicked backend.

## Use it

Build the current `main` branch with the Go version specified in [go.mod](go.mod):
Install a release binary (Linux, macOS; the SHA-256 is checked):

```sh
curl -fsSL https://raw.githubusercontent.com/Stumble/sqlc/main/scripts/install.sh | sh -s -- v2.4.1
```

Or build the current `main` branch with the Go version specified in [go.mod](go.mod):

```sh
git clone https://github.com/Stumble/sqlc.git
cd sqlc
make install
```

See [GUIDE.md](GUIDE.md#install) for platforms, checksums and Windows.

Select the backend in `sqlc.yaml`:

```yaml
Expand Down
88 changes: 88 additions & 0 deletions docs/changelogs/2026-11-04-release-binaries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Release binaries with checksums and an install script

Tracking: alva-ai/mono-meta#1115. Yumin, 2026-11-04: developers should not
have to clone this repository and run `make` to get the right sqlc; publish
binaries for several platforms with an install script that checks the SHA-256.

## 1. Current State

- Releases carry no binaries. The only way to get a binary that reports its
version is `make build` / `make install` in a clone: `internal/info.Version`
is `v1.31.1` in the source, and the Makefile sets `<tag>-wicked-fork`
through `-ldflags`.
- Builds without the Makefile (`go install ./cmd/sqlc`, as ggsrc/ggsrv-layout's
CI did) write `sqlc v1.31.1` into generated headers.
- The PostgreSQL engine uses pg_query_go with CGO and its WebAssembly build
(wasilibs/go-pgquery) without CGO. Measured on v2.4.0: identical output on
`wicked_compat`, ggsrv-layout's repositories and Stumble/bookstore; ~60–80 ms
with CGO, ~2.2 s without (WebAssembly start-up).

## 2. Intended Behavior

- B1 A tag push (or a manual run with an existing tag) builds `sqlc` for
linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 and windows/amd64 and
attaches `sqlc_<version>_<os>_<arch>.tar.gz` (`.zip` on Windows), each with
`sqlc` and `LICENSE`, plus `checksums.txt` (SHA-256) to the tag's release.
- B2 Each binary reports `<tag>-wicked-fork`, like `make build` from the tag.
- B3 Every binary runs `sqlc version`, `sqlc compile` and `sqlc generate` on its
own platform before anything is published; after publishing,
`scripts/install.sh` installs the release on Linux and macOS runners.
- B4 Linux binaries are static (CGO, musl) and run on any distribution; macOS
binaries use CGO and run on macOS 12 or later; the Windows binary has no CGO.
- B5 `scripts/install.sh [version]` picks the platform, downloads the archive,
checks it against `SQLC_SHA256` or the release's `checksums.txt`, and installs
it into `INSTALL_DIR` (default `$(go env GOPATH)/bin`, else `~/.local/bin`).
- B6 Build provenance is attested (`gh attestation verify`).
- F1 A wrong checksum, a missing archive or a tag that is not `vX.Y.Z[-pre]`
stops without installing or publishing.

## 3. Decisions and Risks

- D1 CGO where it is available (Linux via a static musl build in Alpine, macOS
on native runners): 30× faster runs than the WebAssembly parser, same output.
- D2 Native runners for every platform, so each binary is executed where it
will run. Windows is cross-built on Linux and run on a Windows runner.
- D3 The build steps live in the workflow, not the Makefile, so a manual run
can build tags older than this change (v2.4.0); the version flag matches the
Makefile's.
- D4 Go: newest patch of 1.26 (go.mod's version).
- R1 GitHub runner labels (`macos-15-intel`, `ubuntu-24.04-arm`) are checked
only when the workflow first runs.

## 4. Changes

- `.github/workflows/release.yml` (new): B1–B4, B6.
- `scripts/install.sh` (new): B5, F1.
- `GUIDE.md`, `README.md`: install from a release.

## 5. Verification

Local, v2.4.0 source, with the workflow's Linux build command:

- `golang:1.26-alpine`, CGO, `-extldflags -static`: `statically linked`;
`sqlc version` = `v2.4.0-wicked-fork`; `compile` and `generate` on
`wicked_compat` pass. The binary runs on Debian 11, Ubuntu 20.04 and Alpine
3.20 and generates ggsrv-layout's repositories identically to a CGO
`make build` (except the version header, which the old build got wrong).
- Cross builds with `CGO_ENABLED=0` succeed for all five platforms.
- `scripts/install.sh` against a local copy of the release layout, on Ubuntu
20.04 (dash) and Alpine 3.20 (busybox): latest-release lookup, explicit
version, pinned `SQLC_SHA256`, wrong checksum (refused), unknown version
(404, nothing installed).
- ShellCheck (`install.sh`) and actionlint (`release.yml`): clean.

## 6. Human Decisions

- Yumin, 2026-11-04 (request above).
- Yumin, 2026-11-04: govulncheck failed on `main`; fix the dependencies first
(#22) and publish the first binaries as v2.4.1 rather than attaching
binaries built from v2.4.0's vulnerable dependencies.

## 7. Outcome

- [ ] Merged.
- [ ] v2.4.1 released by a tag push, with binaries.

## 8. Remaining Work

- None.
33 changes: 33 additions & 0 deletions docs/releases/v2.4.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# wicked-sqlc v2.4.1

This patch release publishes prebuilt binaries for the first time and updates
Go and dependencies flagged by govulncheck. Generated code is the same as v2.4.0
apart from the version comment.

## Changes

- Binaries for Linux (amd64, arm64; static, any distribution), macOS (amd64,
arm64; 12 or later) and Windows (amd64), with `checksums.txt` and build
provenance.
- `scripts/install.sh` installs a release after checking its SHA-256.
- Go 1.26.10 (was 1.26.8), golang.org/x/net v0.60.0, golang.org/x/text v0.42.0
and google.golang.org/grpc v1.83.1 fix 14 vulnerabilities govulncheck reports
as reachable in v2.4.0.

## Upgrade

```sh
curl -fsSL https://raw.githubusercontent.com/Stumble/sqlc/main/scripts/install.sh | sh -s -- v2.4.1
sqlc version
# v2.4.1-wicked-fork
```

Set `SQLC_SHA256` to the archive's value in `checksums.txt` to accept only that
archive. `gh attestation verify <archive> -R Stumble/sqlc` checks that an
archive was built by this repository's release workflow. On Windows, download
`sqlc_2.4.1_windows_amd64.zip` from the release. Building from source with
`make install` now requires Go 1.26.10.

Regenerate with `sqlc generate`; only the version comments change.

See the [guide](https://github.com/Stumble/sqlc/blob/main/GUIDE.md#install).
Loading
Loading