From 4a6f3642a0699347dad541418b7460feaef1eb89 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 13 Jun 2026 21:04:36 +0000 Subject: [PATCH 1/2] Wire tommy as conformist (treelint) TOML formatter + codegen linter - treelint.toml: add [formatter.tommy] (tommy fmt over *.toml) and [linter.tommy-codegen] (repair regenerates the *_tommy.go companions via `tommy generate`, so they land in the `conformist --commit` chore). The check command is a no-op `true` so `treelint check` never reports false codegen drift; true staleness stays gated by `just build-go-generate`. - go/default.nix: add a self-gating conformist-tommy-codegen driver (skips when tommy/go are off PATH) plus tommy + go to the treelint-fmt wrapper, so the wrapper resolves the formatter and the codegen repair command. --- go/default.nix | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ treelint.toml | 23 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/go/default.nix b/go/default.nix index 819ac13a9..1b5d9d918 100644 --- a/go/default.nix +++ b/go/default.nix @@ -262,6 +262,47 @@ let # gofumpt/gotools are the same igloo `pkgs` builds the dev-shell carries, # so the Go output matches the dev-loop formatter. null on the non-flake # `import ./go/default.nix` path (treelint absent). + # tommy codegen as a conformist linter driver. Walks the tree for + # `//go:generate tommy generate` directives and runs `tommy generate` per file + # (REPAIR mode; the treelint.toml CHECK command is a no-op `true`). Resolves + # tommy + go from the AMBIENT PATH and skips (exit 0) when either is missing, + # so it is a safe no-op where the toolchain is absent. Regenerates the + # *_tommy.go companions so they land in the `conformist --commit` chore; + # `just build-go-generate` remains the NATO-ordered regen path. + tommyCodegen = pkgs.writeShellApplication { + name = "conformist-tommy-codegen"; + runtimeInputs = [ + pkgs.coreutils + pkgs.findutils + pkgs.gnugrep + ]; + text = '' + mode="repair" + if [ "''${1:-}" = "--check" ]; then + mode="check" + fi + if ! command -v tommy >/dev/null 2>&1; then + echo "tommy-codegen: tommy not on PATH; skipping" >&2 + exit 0 + fi + if ! command -v go >/dev/null 2>&1; then + echo "tommy-codegen: go not on PATH; skipping" >&2 + exit 0 + fi + status=0 + while IFS= read -r f; do + dir=$(dirname "$f") + base=$(basename "$f") + if [ "$mode" = "check" ]; then + ( cd "$dir" || exit 1; GOFILE="$base" tommy generate --check; ) || status=1 + else + ( cd "$dir" || exit 1; GOFILE="$base" tommy generate; ) || status=1 + fi + done < <(grep -rIl --include='*.go' 'go:generate tommy generate' . 2>/dev/null | grep -v '/result' || true) + exit "$status" + ''; + }; + treelint-fmt = if treelint == null then null @@ -275,6 +316,13 @@ let pkgs.nixfmt pkgs.shfmt pkgs.shellcheck + # tommy (TOML formatter, [formatter.tommy]) + go + the codegen driver + # ([linter.tommy-codegen]), so the wrapper resolves the formatter and + # the codegen repair regen. go is needed by `tommy generate`'s + # go/packages analysis in repair mode. + tommy.packages.${system}.default + pkgs.go_1_26 + tommyCodegen ]; text = ''exec conformist "$@"''; }; diff --git a/treelint.toml b/treelint.toml index 218525362..95eaec681 100644 --- a/treelint.toml +++ b/treelint.toml @@ -53,6 +53,13 @@ command = "shfmt" options = ["-w", "-i", "2", "-s", "-ci"] includes = ["*.sh", "*.bash"] +# TOML via tommy's CST-preserving formatter (`tommy fmt`). treelint.toml itself +# is excluded above (intentional layout). +[formatter.tommy] +command = "tommy" +options = ["fmt"] +includes = ["*.toml"] + # Linter: shellcheck runs read-only in `treelint check` (no repair-command, so # it is a no-op in repair mode). Catches shell bugs the formatters miss. [linter.shellcheck] @@ -61,3 +68,19 @@ includes = ["*.sh", "*.bash"] # go/vimdiff.bash is the vendored upstream git-vimdiff mergetool test harness; # it carries ~40 shellcheck findings we don't own. shfmt still formats it. excludes = ["go/vimdiff.bash"] + +# tommy codegen as a REPAIR linter: `treelint` / `conformist --commit` runs +# `tommy generate` for every `//go:generate tommy generate` source file, so the +# regenerated *_tommy.go companions land in the auto-fix chore. The driver +# self-gates on tommy + go (present on the treelint-fmt wrapper PATH), so it is a +# no-op where the toolchain is absent. The CHECK command is a deliberate no-op +# (`true`) so `treelint check` never reports false codegen drift — `tommy +# generate --check` compares against tommy's raw render, which differs from the +# committed file once it is re-run through gofumpt (see `just build-go-generate` +# / `codemod-go-fmt`); true staleness stays gated by that recipe. +# passes-files=false: the driver walks the tree for the directive itself. +[linter.tommy-codegen] +command = "true" +repair-command = "conformist-tommy-codegen" +includes = ["*.go", "**/*.go"] +passes-files = false From a2de3337045232950a55eec38109108e20ba3901 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 13 Jun 2026 21:21:55 +0000 Subject: [PATCH 2/2] Use tommy flake's conformist-tommy-codegen driver Replace the inline codegen driver with tommy.packages.${system}.conformist-tommy-codegen so the pinned tommy flake input resolves which tommy backs the codegen linter. The treelint-fmt wrapper references and treelint.toml are unchanged. --- go/default.nix | 47 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/go/default.nix b/go/default.nix index 1b5d9d918..598b9239e 100644 --- a/go/default.nix +++ b/go/default.nix @@ -262,46 +262,13 @@ let # gofumpt/gotools are the same igloo `pkgs` builds the dev-shell carries, # so the Go output matches the dev-loop formatter. null on the non-flake # `import ./go/default.nix` path (treelint absent). - # tommy codegen as a conformist linter driver. Walks the tree for - # `//go:generate tommy generate` directives and runs `tommy generate` per file - # (REPAIR mode; the treelint.toml CHECK command is a no-op `true`). Resolves - # tommy + go from the AMBIENT PATH and skips (exit 0) when either is missing, - # so it is a safe no-op where the toolchain is absent. Regenerates the - # *_tommy.go companions so they land in the `conformist --commit` chore; - # `just build-go-generate` remains the NATO-ordered regen path. - tommyCodegen = pkgs.writeShellApplication { - name = "conformist-tommy-codegen"; - runtimeInputs = [ - pkgs.coreutils - pkgs.findutils - pkgs.gnugrep - ]; - text = '' - mode="repair" - if [ "''${1:-}" = "--check" ]; then - mode="check" - fi - if ! command -v tommy >/dev/null 2>&1; then - echo "tommy-codegen: tommy not on PATH; skipping" >&2 - exit 0 - fi - if ! command -v go >/dev/null 2>&1; then - echo "tommy-codegen: go not on PATH; skipping" >&2 - exit 0 - fi - status=0 - while IFS= read -r f; do - dir=$(dirname "$f") - base=$(basename "$f") - if [ "$mode" = "check" ]; then - ( cd "$dir" || exit 1; GOFILE="$base" tommy generate --check; ) || status=1 - else - ( cd "$dir" || exit 1; GOFILE="$base" tommy generate; ) || status=1 - fi - done < <(grep -rIl --include='*.go' 'go:generate tommy generate' . 2>/dev/null | grep -v '/result' || true) - exit "$status" - ''; - }; + # tommy's conformist codegen linter driver ([linter.tommy-codegen]), owned by + # the tommy flake so the pinned tommy input resolves which tommy backs it (no + # per-repo driver duplication). It bakes that tommy in and skips when go is + # absent. Regenerates the *_tommy.go companions so they land in the + # `conformist --commit` chore; `just build-go-generate` remains the + # NATO-ordered regen path. + tommyCodegen = tommy.packages.${system}.conformist-tommy-codegen; treelint-fmt = if treelint == null then