fix(ci): make the template guard survive its own substitution
CD / Detect unsubstituted template (pull_request) Successful in 1s
CD / Lint / Test / Vet (pull_request) Skipped
CD / Build & Import (pull_request) Skipped
CD / Deploy via GitOps (pull_request) Skipped
CD / Detect unsubstituted template (push) Successful in 1s
CD / Lint / Test / Vet (push) Skipped
CD / Build & Import (push) Skipped
CD / Deploy via GitOps (push) Skipped

Closes #9. Closes #10.

Every child repo born from this template has had fake-green CI: cd.yml's
guard grepped a literal placeholder, and both scaffolders substitute every
file in the tree -- including the guard. In a generated repo the check
became `grep -q 'git.d-ma.be/mathias/<name>' go.mod` against a go.mod whose
first line is `module git.d-ma.be/mathias/<name>`, so it matched forever,
check/build/deploy all skipped, and the run reported success having built
nothing. Confirmed in cad-atlas (#9) and openbanking-api (#10).

The second occurrence landed directly underneath a comment warning against
exactly this. That is the tell: an inline shell block in a workflow cannot
be tested, so a fix for it can only be reviewed by reading, and reading is
what missed it twice.

So the detection moves to scripts/is-template.sh and gets a test.

It greps the SHAPE of a placeholder rather than any literal token, which
also catches leftovers the scaffolders know nothing about, and a missing
target now exits non-zero instead of answering "false" -- failing open
there would skip CI on a repo that is not a template at all, which is the
same fake-green failure by another road.

scripts/tests/is-template_test.sh runs a scaffolder-style substitution over
a copy of the guard and asserts it still answers correctly. Both shipped
bugs fail that test.

The test assembles placeholder tokens at runtime rather than writing them
whole, for the same reason the guard does: a fixture containing a literal
token is substituted before the test runs, and the suite would then fail in
every generated repo while passing here. The first draft of the guard was
itself caught by this -- its explanatory comment named a token literally.

Verified by simulating a generated child (whole tree substituted):

    child  go.mod module git.d-ma.be/mathias/childproj
    guard  child    -> false   (CI runs)
    guard  template -> true    (template still skips its own build)
    suite  in child -> 8 passed, 0 failed
    suite  in template -> 8 passed, 0 failed

Wired into `task check`, so the guard that decides whether CI runs at all
in every child is covered by the same gate as the Go tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit was merged in pull request #11.
This commit is contained in:
2026-09-17 16:29:29 +02:00
co-authored by Claude Opus 5
parent 7c70489efe
commit b9bbbae3bb
4 changed files with 166 additions and 9 deletions
+11 -9
View File
@@ -19,16 +19,18 @@ jobs:
steps:
- uses: actions/checkout@v4
- id: detect
# The detection lives in scripts/is-template.sh so it can be TESTED.
# It was inline here twice and wrong both times (#9, #10): the grep
# named a placeholder literally, and the scaffolder substitutes every
# file including this one, so in a generated repo the guard matched
# forever and check/build/deploy all skipped while the run went green.
#
# An inline shell block in a workflow cannot be run by a test, which is
# why the second fix repeated the first bug under a comment warning
# about it. scripts/tests/is-template_test.sh now substitutes the guard
# and asserts it still answers correctly.
run: |
# Grep the PLACEHOLDER, never the value substitution writes. A guard
# that greps its own substituted module path matches forever and
# skips every job below it -- see harg-bygglov-go#8, where that cost
# five weeks of empty green runs on a repo that never compiled.
if grep -q '__MODULE_PATH__' go.mod; then
echo "is_template=true" >> "$GITHUB_OUTPUT"
else
echo "is_template=false" >> "$GITHUB_OUTPUT"
fi
echo "is_template=$(bash scripts/is-template.sh go.mod)" >> "$GITHUB_OUTPUT"
check:
name: Lint / Test / Vet