tools

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2026 License: Apache-2.0

README

tools

CI Go Reference

Standalone tooling. What it holds today is code-hygiene linters, delivered as golangci-lint module plugins: a consumer compiles them into its own golangci-lint binary and configures them like any other linter, so //nolint, linters.exclusions, output formats, and existing CI wiring apply unchanged.

Linters

Name What it checks Fixes
testlayout Test files follow the repository's test-suite layout conventions.
deadcode Code that nothing can reach, by whole-program call-graph analysis.
zlines Line breaks a declaration or comment should not have, and line breaks it should. --fix

Each linter's package doc — testlayout, deadcode, zlines — is the full reference for its rules; the sections below cover configuration.

testlayout

Sorts every test file into one of two kinds by the package it declares — white-box files declare the package under test, black-box files declare the external <pkg>_test package — and checks which kinds are allowed and what each may be named. Patterns are globs, except that <source> stands for the base name of a source file in the same directory. The defaults allow black-box files only:

linters:
  settings:
    custom:
      testlayout:
        type: module
        settings:
          whitebox:
            allowed: false
          blackbox:
            allowed: true
            patterns: ['<source>_test.go', suite_test.go]
            helper-patterns: [helpers_test.go, fakes_test.go]
          adapter-patterns: [suite_test.go]

Exclude directories with their own layout through linters.exclusions.paths. Don't enable golangci-lint's built-in testpackage alongside this linter — they overlap under the default settings.

zlines

Three rules, all fixable with --fix: signature-wrap (a signature spread over lines that would fit on one), body-collapse (a body written on the line its signature ends on), and comment-wrap (comment paragraphs not filled to the limit). Fixes are only offered when gofmt agrees with the result, so running the formatter afterwards cannot undo them.

linters:
  settings:
    custom:
      zlines:
        type: module
        settings:
          line-length: 160        # default 120, matching lll
          comment-length: 80      # default 80
          signature-wrap: false   # default true
          body-collapse: false    # default true
          comment-wrap: false     # default true
          comment-exempt: ['+kubebuilder']

Set line-length to the limit the repository already enforces; it governs signature-wrap only. comment-exempt lists prefixes marking comment lines meant for a tool rather than a reader — those lines stay where they are.

deadcode

A whole-program analysis. What it loads is governed by its own patterns setting, not the package arguments golangci-lint was invoked with, and it re-runs on every invocation — golangci-lint's cache never spares the work. Plan on a separate CI-only invocation rather than enabling it on save. A repository of sibling modules is analyzed a module at a time; see the deadcode package doc for what that changes.

linters:
  settings:
    custom:
      deadcode:
        type: module
        settings:
          patterns: ['./...']      # absent means ./... from the module root
          build-tags: [integration]
          tests: true              # default; matches run.tests
          api: ['./pkg/...']       # package patterns whose exported surface consumers reach
          api-exempt: [method]     # default when api is set

Two settings that need care:

  • Set issues.uniq-by-line: false — the default true silently discards findings, because deadcode reports more than one verdict per declaration on purpose.
  • To suppress findings in test-support packages, exclude their paths rather than narrowing patterns. Narrowing patterns shrinks what gets loaded, which invents dead code: a package dropped from the analysis stops being a use of anything.

Usage

Module plugins are compiled in, so a consumer builds its own binary. Add .custom-gcl.yml at the repository root:

version: v2.12.2
name: custom-gcl
destination: ./bin
plugins:
  - module: 'github.com/zcayou/tools'
    import: 'github.com/zcayou/tools/golangci'
    version: v0.1.0   # a released tag; see the repository's tags for the current one

Install the matching bootstrap binary and build (requires Go 1.26+):

go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
golangci-lint custom

Enable the linters in .golangci.yml:

version: "2"
linters:
  enable:
    - testlayout
  settings:
    custom:
      testlayout:
        type: module
        description: Checks that test files follow the repository's test-suite layout conventions.
        original-url: github.com/zcayou/tools

Run ./bin/custom-gcl run in place of golangci-lint run. Suppress a finding with //nolint:<linter>, or exclude one rule of a linter by matching the token that opens every message:

linters:
  exclusions:
    rules:
      - linters: [testlayout]
        text: '^spec-less-test-file:'

testlayout and zlines open each message with the rule name; deadcode opens with the verdict (unreachable func:, unused exported func:, and so on).

Clear the cache after every rebuild. Rebuilding the binary does not invalidate golangci-lint's cache, so a stale build replays its previous findings — and under --fix, applies the previous build's edits. Run ./bin/custom-gcl cache clean after golangci-lint custom.

Development

make help      list targets
make test      run the suites
make lint      lint this module, dogfooding its own linters
make verify    build, tidy check, test, lint — the same set CI runs

.custom-gcl.yml's version is the single source of truth for which golangci-lint this module targets; the Makefile reads it to pin the bootstrap binary, so the two cannot drift.

Suites are Ginkgo/Gomega, with analyzer fixtures under golangci/<name>/testdata/ driven by analysistest. Run them from a checkout: the deadcode engine's fixtures are whole modules, and module-zip creation drops directories containing a go.mod, so a copy fetched through a Go proxy is missing them.

License

Copyright 2026 Zachary Cayou. Apache License 2.0.

Directories

Path Synopsis
Package golangci registers every linter in this module with golangci-lint.
Package golangci registers every linter in this module with golangci-lint.
deadcode
Package deadcode exposes the whole-program dead-code engine as a golangci-lint linter.
Package deadcode exposes the whole-program dead-code engine as a golangci-lint linter.
deadcode/engine
Package engine finds code that nothing can reach.
Package engine finds code that nothing can reach.
testlayout
Package testlayout checks that test files follow the repository's test-suite layout conventions.
Package testlayout checks that test files follow the repository's test-suite layout conventions.
zlines
Package zlines reports line breaks a declaration should not have, and line breaks it should.
Package zlines reports line breaks a declaration should not have, and line breaks it should.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL