diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aad0d23..83aef43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,32 @@ on: branches: [master] pull_request: jobs: + # Style linter (https://github.com/Postgres-Extensions/linter, vendored at + # .vendor/linter). Deliberately checked out WITHOUT submodules -- `make + # lint` is the same command a developer runs locally, and lint.mk + # self-initializes the submodule on first use (see its comment). Using the + # exact same entry point here is what actually proves that self-init works, + # rather than papering over it with a submodules: true checkout. The + # linter's own test suite (fixtures + scanner edge cases) is that repo's + # own CI's job, not this one's. No PostgreSQL needed -- sql-lint is a + # standalone Perl script -- so this doesn't use the pgxn-tools container. + lint: + name: 🧹 SQL Lint + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v5 + - name: Lint SQL + run: make lint + test: + # Gated behind lint: the 12-leg PG matrix below is comparatively + # expensive, and every leg would fail anyway on a baseline that's already + # broken by a lint violation. success() is required explicitly once a + # job's `if:` references anything -- GitHub only assumes success() as a + # default when no `if:` is written at all. + needs: [lint] + if: success() strategy: matrix: pg: [17, 16, 15, 14, 13, 12, 11, 10, 9.6, 9.5, 9.4, 9.3] @@ -30,7 +55,7 @@ jobs: # job succeeded or was skipped (e.g. a docs-only push with paths-ignore) and # fails if any failed or were cancelled. all-checks-passed: - needs: [test] + needs: [lint, test] if: always() runs-on: ubuntu-latest steps: diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9236c50 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".vendor/linter"] + path = .vendor/linter + url = https://github.com/Postgres-Extensions/linter diff --git a/.vendor/linter b/.vendor/linter new file mode 160000 index 0000000..b8632c2 --- /dev/null +++ b/.vendor/linter @@ -0,0 +1 @@ +Subproject commit b8632c2a3d93de664a45f4622235871e8f19cf78 diff --git a/Makefile b/Makefile index 033cf30..faf7681 100644 --- a/Makefile +++ b/Makefile @@ -15,3 +15,14 @@ install: deps cat_tools: $(DESTDIR)$(datadir)/extension/cat_tools.control $(DESTDIR)$(datadir)/extension/cat_tools.control: pgxn install 'cat_tools>=0.2.1' --sudo + +# Style linter (see https://github.com/Postgres-Extensions/linter, vendored +# at .vendor/linter -- lint.mk is the thin local hand-off, see its comment). +# Scoped to the actively-maintained source rather than the default +# `sql/ test/`: sql/extension_drop--1.0.0.sql is a frozen, already-released +# version file (RELEASE.md's "Ongoing development" section -- once a version +# is released, its sql/--.sql is never hand-edited again), so +# linting it would produce permanent, unfixable findings and make `make +# lint` unusable as a CI gate. Lint the hand-maintained source instead. +LINT_TARGETS = sql/extension_drop.sql test/ +include lint.mk diff --git a/lint.mk b/lint.mk new file mode 100644 index 0000000..ffcf327 --- /dev/null +++ b/lint.mk @@ -0,0 +1,26 @@ +# lint.mk — thin wrapper; the whole local footprint for consuming +# https://github.com/Postgres-Extensions/linter. Everything else lives in +# the .vendor/linter submodule; see its README for available targets/rules. +# +# 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 a real .git being present (directory for a normal clone, or a +# `gitdir:` file for a worktree/submodule checkout -- $(wildcard .git) matches +# both). A source tarball (git archive output -- PGXN dist packages, `make +# dist`) has no .git at all and never contains submodule content, so without +# this guard GNU Make would still try to satisfy the `include` below via the +# remake rule on every invocation, `git submodule update --init` would fail +# immediately ("fatal: not a git repository"), and that failure would abort +# every `make` target -- not just `make lint` -- in a tarball build. Lint +# simply isn't available/attempted outside a real git checkout, which is +# correct: a tarball build has no reason to lint. +ifneq ($(wildcard .git),) + +.vendor/linter/lint.mk: + git submodule update --init -- .vendor/linter + +include .vendor/linter/lint.mk + +endif