Artifact a79f6fe9ea685d8779820ff00e2675211565c508b5f96ccbfc71d28833df4ac6:
- File
.github/workflows/test.yml
— part of check-in
[10abca922c]
at
2026-07-27 23:37:46
on branch trunk
— ci: gate the js/wasm build on every PR (#201) (#205)
test.yml had zero references to wasm or GOOS=js, so the WebAssembly build was never compiled on any leg. Browser support is the reason the ncruces driver is in the tree, and a break there would have shipped undetected -- including in db/config_wasm.go, whose js-tagged wasmPragmaOverrides() no job compiled at all.
Adds a build-only job covering 31 of the main module's 33 js-resolvable packages plus the ncruces driver submodule. The package set comes from go list rather than a hand-written list so new packages are gated by default. Two main packages are excluded, both for the same structural reason: cmd/libfossil and examples/embed-repo-api import the modernc driver directly in their own main.go, and modernc.org/libc has no js/wasm build. internal/stash and internal/undo declare //go:build !js in source and are dropped by go list itself. Building under -tags test_ncruces keeps internal/testdriver in the gate by pointing it at the driver that can actually target WASM.
Running tests under WASM needs a browser harness (wasmbrowsertest) and is deliberately out of scope; compilation catches the realistic failure mode. (user: [email protected], size: 11617) [annotate] [blame] [check-ins using]
name: Tests on: push: branches: [main] pull_request: env: # The canonical fossil the real-fossil-gated tests compare against. Local # development validates against this exact version, so CI must too -- # otherwise the two are checking our output against different reference # implementations. Bump deliberately, here, in one place. # # The distro package is unusable for this: it is unpinned, currently lags # several releases behind, and tracks different upstream check-ins over time # under the same version string, so two runs at nominally the same version # can behave differently. The official upstream release tarball is a fixed # build, and FOSSIL_SHA256 pins it to that exact artifact -- a re-upload # upstream then fails the checksum loudly instead of silently changing what # we test against. FOSSIL_VERSION: "2.28" FOSSIL_SHA256: "c9d2bf9d150dff1076eae1b0b822ed3cde892e1273f78b040c4f8ace1b59dd40" jobs: test: name: Test (modernc) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Install pinned Fossil run: | curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \ -o /tmp/fossil.tar.gz \ "https://fossil-scm.org/home/uv/fossil-linux-x64-${FOSSIL_VERSION}.tar.gz" echo "${FOSSIL_SHA256} /tmp/fossil.tar.gz" | sha256sum -c - sudo tar -xzf /tmp/fossil.tar.gz -C /usr/local/bin fossil rm -f /tmp/fossil.tar.gz - name: Verify Fossil version # A silent upstream change has to surface as an explicit failure here, # not as mysterious behavioural drift in the real-fossil-gated tests. run: | reported=$(fossil version | sed -n 's/.*fossil version \([0-9][0-9.]*\).*/\1/p') if [ "$reported" != "${FOSSIL_VERSION}" ]; then echo "expected fossil ${FOSSIL_VERSION}, got: $(fossil version)" >&2 exit 1 fi fossil version - name: Warm Fossil global config # Fossil keeps a per-user global config database outside any repository # and creates it lazily on first use. `go test` runs packages # concurrently, several of them shell out to fossil, and nothing sets # HOME, so on a fresh runner two test processes can race to create it: # one wins and the others die with "table global_config already exists". # Creating it once here, single-threaded, means no test process is ever # the one to create it. `fossil version` does not open that database, so # the step above does not incidentally cover this; `fossil all list` # does, and prints nothing. # # The first call's exit status is ignored deliberately -- it exists to # create the database, not to assert anything, so an unrelated non-zero # must not red the job. The second call is what carries the weight: it # must succeed on its own, which proves the database is both present and # usable. Checking that a file exists would not -- a truncated or # partially-written database passes an existence check while concurrent # invocations still die on the missing schema, which is exactly the # "looks like protection while the race stays live" failure this guards # against. Re-running the command also keeps the check independent of # where fossil resolved the database to (~/.fossil, ~/.config/fossil.db, # $XDG_CONFIG_HOME, or $FOSSIL_HOME). run: | fossil all list >/dev/null 2>&1 || true fossil all list >/dev/null - name: Build all packages # Build every package, not just the cmd/libfossil dependency closure. # The `go test $(go list ./...)` step below silently drops any package # that fails to compile (go list omits it from stdout instead of # failing), so a broken import can vanish from the test run undetected. # Building `./...` first makes that a loud, fail-fast build error. run: GOWORK=off go build ./... - name: Unit tests # REQUIRE_FOSSIL_BIN turns "fossil is missing" into a failure rather # than an invisible skip. Verifying a real fossil reads what we write # is the one thing our own tests cannot substitute for. env: REQUIRE_FOSSIL_BIN: "1" run: GOWORK=off go test $(GOWORK=off go list ./... | grep -v '/dst') -count=1 -timeout=120s - name: DST run: GOWORK=off go test ./dst/... -count=1 -timeout=300s - name: Driver tests (modernc) run: cd db/driver/modernc && GOWORK=off go test ./... -count=1 - name: Vet run: GOWORK=off go vet ./... test-ncruces: name: Test (ncruces) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Install pinned Fossil run: | curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \ -o /tmp/fossil.tar.gz \ "https://fossil-scm.org/home/uv/fossil-linux-x64-${FOSSIL_VERSION}.tar.gz" echo "${FOSSIL_SHA256} /tmp/fossil.tar.gz" | sha256sum -c - sudo tar -xzf /tmp/fossil.tar.gz -C /usr/local/bin fossil rm -f /tmp/fossil.tar.gz - name: Verify Fossil version # A silent upstream change has to surface as an explicit failure here, # not as mysterious behavioural drift in the real-fossil-gated tests. run: | reported=$(fossil version | sed -n 's/.*fossil version \([0-9][0-9.]*\).*/\1/p') if [ "$reported" != "${FOSSIL_VERSION}" ]; then echo "expected fossil ${FOSSIL_VERSION}, got: $(fossil version)" >&2 exit 1 fi fossil version - name: Warm Fossil global config # Same single-threaded warm-up as the modernc leg -- see the comment # there for why `fossil version` does not cover this, and why the first # call's exit status is ignored but the second call's is not. run: | fossil all list >/dev/null 2>&1 || true fossil all list >/dev/null - name: Build all packages (ncruces) # Same fail-fast guard as the modernc leg, under the test_ncruces tag so # the ncruces driver's compile surface is covered too. run: GOWORK=off go build -tags test_ncruces ./... - name: Unit tests (ncruces) env: REQUIRE_FOSSIL_BIN: "1" run: GOWORK=off go test -tags test_ncruces $(GOWORK=off go list ./... | grep -v '/dst' | grep -v 'cmd/libfossil') -count=1 -timeout=120s - name: DST (ncruces) run: GOWORK=off go test -tags test_ncruces ./dst/... -count=1 -timeout=300s - name: Driver tests (ncruces) run: cd db/driver/ncruces && GOWORK=off go test ./... -count=1 build-wasm: name: Build (js/wasm) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Build main module for js/wasm # Browser support is the reason the ncruces driver is in this repo at # all, but until this job nothing was ever compiled for js/wasm. # # What a build gate catches is a dependency with no js/wasm build at # all -- most realistically the wrong SQLite driver reaching a shared # package, since modernc.org/libc is linux/darwin-only and would fail # here while both linux legs above stay green. It does not catch every # WASM problem: much of the stdlib (os/exec included) compiles for js # behind stubs and only fails when called, so runtime-behaviour gaps # need tests under a browser harness, which is a separate question. # # test_ncruces is the same tag the ncruces leg builds under, and it is # the correct one here: it only switches internal/testdriver's blank # driver import from modernc to ncruces, which is the driver that can # actually target WASM. Without the tag internal/testdriver would have # to be excluded too, for no reason other than the default it picks. # # The package set comes from `go list`, not a hand-written list, so a # newly added package is inside the gate by default rather than # silently outside it. `-e` stops go list from aborting on the two # packages excluded below -- without it their unresolvable imports # discard the entire list. Packages that already declare `//go:build # !js` in source (internal/stash, internal/undo) are dropped by go list # itself under GOOS=js; that exclusion lives in the code, not here. # # The two greps are the only exclusions this job adds and both have the # same single cause: each of these main packages imports the modernc # driver directly in its own main.go, and modernc.org/libc ships no # js/wasm build, so neither can target WASM by construction. Both stay # fully covered by the linux legs above. env: GOWORK: "off" GOOS: js GOARCH: wasm run: | set -o pipefail pkgs=$(go list -e -tags test_ncruces ./... \ | grep -v -e '/cmd/libfossil$' -e '/examples/embed-repo-api$') echo "building $(echo "$pkgs" | wc -l) packages for js/wasm:" echo "$pkgs" echo "$pkgs" | xargs go build -tags test_ncruces - name: Build ncruces driver for js/wasm # A separate module, so the step above never reaches it -- and it is # the driver the browser build actually runs on. Its js-only source # (ncruces_js.go) is compiled by no other job in this workflow. env: GOWORK: "off" GOOS: js GOARCH: wasm run: cd db/driver/ncruces && go build ./... test-otel: name: Test (observer/otel) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: OTel sub-module tests run: cd observer/otel && GOWORK=off go test ./... -count=1 test-docs: name: Test (docs/site) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod - name: Install Hugo (extended) # docs/site pulls the hextra theme via Hugo Modules, which need both the # Go toolchain (setup-go above) and the Hugo binary. Pin the version so a # future Hugo release can't silently change build behaviour under us. env: HUGO_VERSION: "0.162.1" run: | curl -fsSL "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \ | sudo tar -xz -C /usr/local/bin hugo - name: Build docs site # docs/site is the one module with no Go source of its own: its go.mod # exists only to import the hextra theme as a Hugo Module, so `go build # ./...` there matches no packages and gates nothing. A real Hugo build # is the equivalent compile gate — it resolves the module import, # compiles templates, and renders content, failing loud on a broken # import or template the way the Go build steps do for the other modules. run: cd docs/site && GOWORK=off hugo --gc --minify