Skip to content

make lint cannot bootstrap golangci-lint, and its brew env var is misspelled by make expansion #1038

Description

@JonJagger

Summary

Makefile:55-56 is the ensure_golangci-lint prerequisite of make lint:

ensure_golangci-lint:
	@$HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade golangci-lint

It has two independent defects. On a machine without golangci-lint,
make lint never reaches the linter:

Error: golangci-lint not installed
make: *** [ensure_golangci-lint] Error 1

Defect 1: $HOMEBREW_NO_AUTO_UPDATE is expanded by make, not the shell

GNU make expands $ followed by a single character as a one-character
variable name, so $HOMEBREW_NO_AUTO_UPDATE is read as the make variable H
followed by the literal text OMEBREW_NO_AUTO_UPDATE. H is undefined here,
so the recipe sets a variable named OMEBREW_NO_AUTO_UPDATE and
HOMEBREW_NO_AUTO_UPDATE is never set.

Reproduced with a probe makefile containing the same line. Undefined H:

$ make -f probe -n demo
echo OMEBREW_NO_AUTO_UPDATE=1 brew upgrade golangci-lint

Adding H := ZZZ to the same probe puts ZZZ exactly where the H was,
confirming which variable is being expanded:

$ make -f probe2 -n demo
echo ZZZOMEBREW_NO_AUTO_UPDATE=1 brew upgrade golangci-lint

Consequence: brew auto-update is not suppressed, so make lint triggers a full
brew update (and, past its 30 day interval, brew cleanup) before doing any
work. That is slow, and it mutates the developer's brew installation as a side
effect of running the project's linter.

Defect 2: brew upgrade cannot install a missing formula

brew upgrade <formula> requires the formula to be installed already. On a
fresh machine, or any machine that never installed golangci-lint, the target
fails with "Error: golangci-lint not installed" and make lint stops before
running golangci-lint run. The developer gets a brew error rather than a
lint result, and no hint about what to install.

Suggested fix

Set the env var so make passes it through to the shell, and make the target
idempotent for install-or-upgrade:

ensure_golangci-lint:
	@HOMEBREW_NO_AUTO_UPDATE=1 brew list golangci-lint >/dev/null 2>&1 \
	  || HOMEBREW_NO_AUTO_UPDATE=1 brew install golangci-lint

Notes for whoever picks this up:

  • HOMEBREW_NO_AUTO_UPDATE=1 with no $ is the simplest correct form.
    $$HOMEBREW_NO_AUTO_UPDATE=1 also reaches the shell intact but reads as a
    reference rather than an assignment, so prefer the plain form.
  • Consider whether the target should upgrade at all. CI does not use brew: the
    lint job in .github/workflows/test.yml:96-102 uses
    golangci-lint-action@v9 with version: latest. A local target that only
    ensures presence keeps local and CI behaviour aligned without surprise
    upgrades.
  • The repo's .golangci.yml declares version: "2", so whatever mechanism is
    chosen must provide golangci-lint v2.
  • Alternative that needs no brew at all, if the team prefers pinning:
    go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@<version> run

Acceptance

  • make lint on a machine without golangci-lint installs it and reports lint
    results, rather than failing with a brew error
  • make lint does not trigger brew update or brew cleanup
  • make lint on a machine that already has golangci-lint still works

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions