From e1a0c7af0636f488401c6d2fbee4091d24f99156 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 17:08:59 -0500 Subject: [PATCH 1/2] Guard the vendored linter include so tarball builds don't break The top-level Makefile's `include lint.mk` is unconditional, so Make tries to satisfy every include this file pulls in before running any target at all, for any target. lint.mk auto-initializes the .vendor/linter submodule via a rule for .vendor/linter/lint.mk, then includes it. git archive (what `make dist` uses, and what PGXN ships to real consumers) never includes submodule content and strips .git entirely, so in a tarball extracted from a release archive, `git submodule update --init` fails immediately (not a git repository), aborting the include and the entire Makefile parse -- breaking `make`, `make install`, everything, not just `make lint`. Wrap the auto-init rule and the vendored include in `ifneq ($(wildcard .git),)`, so a tarball build (no .git at all) never even asks Make to look for .vendor/linter/lint.mk, and the auto-remake rule never fires. $(wildcard .git) matches both a real .git directory (plain clone) and the .git file pointer used inside a git worktree, so normal checkouts are unaffected and `make lint` keeps working exactly as before. `make lint` becoming unavailable in a tarball build is expected -- PGXN consumers don't need the linter. --- lint.mk | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lint.mk b/lint.mk index 0d18abf..83cd9e2 100644 --- a/lint.mk +++ b/lint.mk @@ -5,7 +5,20 @@ # Self-initializing (via the rule below) so `make lint` works right after a # plain `git clone`, with no --recurse-submodules needed, and so CI can rely # on the exact same entry point a developer would use locally. +# +# Guarded on $(wildcard .git): the top-level Makefile's `include lint.mk` is +# unconditional, so Make tries to satisfy this file's own includes before +# running ANY target. `git archive` (what `make dist`/PGXN ship) drops +# submodules and .git entirely, so on a released tarball the rule below would +# run `git submodule update` outside a git repo, fail, and abort the whole +# Makefile parse -- breaking even plain `make`/`make install` for every +# consumer, not just `make lint`. Skipping the include there is fine: PGXN +# consumers don't need the linter. $(wildcard .git) matches both a real +# .git directory (plain clone) and the .git file pointer used inside a git +# worktree, and is empty only when neither exists (a tarball extraction). +ifneq ($(wildcard .git),) .vendor/linter/lint.mk: git submodule update --init -- .vendor/linter include .vendor/linter/lint.mk +endif From 9382144522d101ffa273f6e6a7a7ea47d95a58a1 Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Tue, 4 Aug 2026 17:22:27 -0500 Subject: [PATCH 2/2] ci.yml: document why the lint job must call `make lint` directly lint.mk's vendored include is now guarded on $(wildcard .git) so a source tarball with no .git can still build. If that guard ever went false in CI (checkout somehow left no .git), `lint` wouldn't exist as a make target, and `make lint` fails loudly rather than silently skipping -- but only if CI actually invokes that exact command with nothing swallowing its exit code. Document that constraint at the call site so it isn't accidentally routed through a wrapper or a different entry point later. --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f70d35..970f69b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -395,6 +395,14 @@ jobs: - name: Check out the repo uses: actions/checkout@v6 - name: Lint SQL + # CRITICAL: call `make lint` directly, not some other path (a script, a + # different target, etc). lint.mk's vendored include is guarded on + # `$(wildcard .git)` so a source tarball (no .git) can still build/install + # -- if that guard ever went false here (checkout somehow left no .git), + # `lint` wouldn't exist as a target at all, and `make lint` fails loudly + # ("No rule to make target 'lint'") rather than silently skipping. Any + # wrapper that swallows that exit code or calls a different entry point + # would defeat this safety net. run: make lint # cancel-on-close.yml cancels in-flight CI/claude-review runs on PR close by