Template
fix(test): grade golangci-lint on its exit code, not on grepping its output
Found by an adversarial review of the same harness in template-go-web (template-go-web#13). This copy had the identical defect. The harness matched golangci-lint's human-readable summary to decide pass or fail. Any failure that is not "found issues" -- bad config, unwritable TMPDIR, OOM, or simply a future change to the output format -- produces non-matching text and was scored as a pass. That is the exact defect class this harness exists to end. It is the only gate covering cmd/__PROJECT_NAME__, so a linter that dies leaves the entrypoint unchecked with CI green. golangci-lint exits 0 clean / 1 issues found / >1 the linter itself failed. Now graded on that, with the >1 case reported as UNCHECKED rather than clean. Also: a missing tool now fails instead of `exit 0` with zero assertions, which was indistinguishable from a real pass to anything reading the exit code. And Dockerfile joins the substituted file set -- it references the entrypoint path, which is the one thing a rename has historically broken here. Verified with a shimmed linter exiting 3: 3 passed, 1 failed. Normal run 4/4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,9 +48,12 @@ bad() { printf ' FAIL %s\n %s\n' "$1" "${2:-}"; fail=$((fail+1)); }
|
||||
|
||||
echo "generated-child tests"
|
||||
|
||||
# A missing tool is a FAILURE, not a skip. An `exit 0` with zero assertions is
|
||||
# indistinguishable from a real pass to anything reading the exit code -- which
|
||||
# is the whole failure mode this harness exists to close.
|
||||
if ! command -v golangci-lint >/dev/null 2>&1; then
|
||||
echo " SKIP golangci-lint not installed — cannot gate the generated child" >&2
|
||||
exit 0
|
||||
bad "golangci-lint is available" "not on PATH — the generated child cannot be gated"
|
||||
echo; echo "$pass passed, $fail failed"; exit 1
|
||||
fi
|
||||
|
||||
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
|
||||
@@ -73,7 +76,7 @@ if [ ! -d "$tmp/cmd/__PROJECT_NAME__" ]; then
|
||||
echo; echo "$pass passed, $fail failed"; exit 1
|
||||
fi
|
||||
mv "$tmp/cmd/__PROJECT_NAME__" "$tmp/cmd/childproj"
|
||||
find "$tmp" -type f \( -name '*.go' -o -name '*.mod' -o -name '*.yml' -o -name '*.md' \) \
|
||||
find "$tmp" -type f \( -name '*.go' -o -name '*.mod' -o -name '*.yml' -o -name '*.md' -o -name 'Dockerfile' \) \
|
||||
-exec sed -i \
|
||||
-e 's|__MODULE_PATH__|git.d-ma.be/mathias/childproj|g' \
|
||||
-e 's|__PROJECT_NAME__|childproj|g' {} +
|
||||
@@ -97,12 +100,21 @@ out="$(cd "$tmp" && go vet ./... 2>&1)"
|
||||
|
||||
# The one that caught #1/#2: errcheck on the deferred shutdown, in a package the
|
||||
# template's own `golangci-lint run ./...` never analysed.
|
||||
out="$(cd "$tmp" && golangci-lint run ./... 2>&1)"
|
||||
if printf '%s' "$out" | grep -qE '^[0-9]+ issues:|issues:$'; then
|
||||
bad "the generated child passes golangci-lint" "$(printf '%s' "$out" | grep -E '\.go:[0-9]+' | head -3)"
|
||||
else
|
||||
ok "the generated child passes golangci-lint"
|
||||
fi
|
||||
# Graded on the EXIT CODE, never on grepping the output. golangci-lint exits
|
||||
# 0 clean / 1 issues found / >1 the linter itself failed. Matching its
|
||||
# human-readable summary instead scores a CRASHED linter as a pass -- bad
|
||||
# config, unwritable TMPDIR, OOM, or a future change to its output format all
|
||||
# produce non-matching text. Since this harness is the only gate covering the
|
||||
# entrypoint, that would leave it unchecked with CI green, which is precisely
|
||||
# the defect class this file exists to end.
|
||||
out="$(cd "$tmp" && golangci-lint run ./... 2>&1)"; rc=$?
|
||||
case "$rc" in
|
||||
0) ok "the generated child passes golangci-lint" ;;
|
||||
1) bad "the generated child passes golangci-lint" \
|
||||
"$(printf '%s' "$out" | grep -E '\.go:[0-9]+' | head -3)" ;;
|
||||
*) bad "golangci-lint ran successfully" \
|
||||
"linter exited $rc — the child is UNCHECKED, not clean: $(printf '%s' "$out" | tail -2)" ;;
|
||||
esac
|
||||
|
||||
echo
|
||||
echo "$pass passed, $fail failed"
|
||||
|
||||
Reference in New Issue
Block a user