scripts/lint.sh starts gofmt, vet, staticcheck in each module, the shape limits, the tracked-file check, doclint and doccheck together and prints each one's findings whole when it ends. go vet -tags stress sees every file plain vet does, so make lint runs it alone and make check no longer vets twice. File sizes are read with one wc rather than one per file. Given directories, the Go checks look only at them.
- commit
- 159a874b6ebf0f5541cc8382607f0eae2e1b3894
- parent
- bfd41781fe92182fff11732aaabf34bc54e7f1cb
- author
- Dami <dami.etoile@gmail.com>
- kind
- build risk score 1.8 of 3, Jev's estimate
| M | Makefile | 9 | +- |
| M | scripts/ | 159 | +++++++++++++++++++++--------- |
@@ -24,21 +24,18 @@ dist:
2424 test:2525 STRESS_DIR=$(DEPS)/stress go test ./...2626 27-# Everything that must pass before a push: formatting, vet (also with the28-# stress benchmarks), shape limits, unit tests, the speed gate, the27+# Everything that must pass before a push: lint, unit tests, the speed gate, the2928 # excelize oracle and the end-to-end tests in libghostty.3029 check:31- @test -z "$$(gofmt -l cmd internal demos e2e oracle)" || { gofmt -l cmd internal demos e2e oracle; echo "gofmt: files above need formatting"; exit 1; }32- go vet -tags stress ./...3330 $(MAKE) lint3431 STRESS_DIR=$(DEPS)/stress go test ./...3532 $(MAKE) speed3633 $(MAKE) oracle3734 $(MAKE) e2e3835 39-# Code shape limits: cognitive complexity and file length.36+# gofmt, vet (with the stress benchmarks), staticcheck, shape limits and37+# the docs checks, at once.4038 lint:41- go vet ./...4239 scripts/lint.sh4340 4441 # The speed gate: frames and recalculation on mid-sized sheets against@@ -1,11 +1,18 @@
11 2-# Checked by make lint:2+# Checked by make lint, all at once, each check's findings printed whole3+# once it ends:4+# - gofmt, and go vet with -tags stress (every file plain vet sees, and5+# the stress benchmarks; nothing builds only without the tag)36 # - staticcheck, with staticcheck.conf, in every module47 # - no function with cognitive complexity over 25 (gocognit)5-# - no Go file over 500 lines8+# - no Go file over 500 lines, no tracked file over 2 MB or compiled69 # - no docs or comments narrating history (scripts/doclint)710 # - links, anchors, the docs index, media and tapes in step (scripts/doccheck)8-# The tools run with go run at pinned versions, so they never enter go.mod.11+# The tools run with go run at pinned versions, so they never enter go.mod;12+# go run and staticcheck cache their work, so a second run is quick.13+#14+# With directories as arguments (make quick), the Go checks look only at15+# those packages; the tracked-file and docs checks always cover the repo.916 set -eu1017 cd "$(dirname "$0")/.."1118 @@ -13,62 +20,118 @@ GOCOGNIT=github.com/uudashr/gocognit/cmd/gocognit@v1.2.1
1320 STATICCHECK=honnef.co/go/tools/cmd/staticcheck@2026.2.11421 MAX_COGNIT=251522 MAX_LINES=50016-fail=023+: "${PKG_CONFIG_PATH:=$(pwd)/.deps/ghostty/share/pkgconfig}"24+export PKG_CONFIG_PATH25+26+whole=true27+if [ $# -gt 0 ]; then28+ dirs=$* whole=false29+else30+ dirs=$(find cmd internal demos e2e oracle -name '*.go' -exec dirname {} \; | sort -u)31+fi32+33+# pkgs MOD prints the packages to check in module MOD as paths relative34+# to it: ./... for the whole module, else those of the directories given.35+pkgs() {36+ if $whole; then37+ echo ./...38+ return39+ fi40+ for d in $dirs; do41+ case $1 in42+ .) case $d in oracle | oracle/* | e2e | e2e/*) continue ;; esac; echo "./$d" ;;43+ *) case $d in "$1") echo . ;; "$1"/*) echo "./${d#"$1"/}" ;; esac ;;44+ esac45+ done46+}47+48+gofmt_check() {49+ bad=$(gofmt -l $dirs)50+ if [ -n "$bad" ]; then51+ echo "$bad"52+ echo "gofmt: files above need formatting"53+ return 154+ fi55+}56+57+vet() {58+ set -- $(pkgs .)59+ [ $# -eq 0 ] || go vet -tags stress "$@"60+}1761 1862 # Warnings are fixed, or turned off in staticcheck.conf with a reason;1963 # none are left standing.20-for mod in . oracle e2e; do21- if [ "$mod" = e2e ] && [ -z "${PKG_CONFIG_PATH:-}" ]; then22- PKG_CONFIG_PATH="$(pwd)/.deps/ghostty/share/pkgconfig"23- export PKG_CONFIG_PATH24- fi25- if ! (cd "$mod" && go run $STATICCHECK ./...); then64+staticcheck() {65+ mod=$166+ set -- $(pkgs "$mod")67+ [ $# -gt 0 ] || return 068+ if ! (cd "$mod" && go run $STATICCHECK "$@"); then2669 echo "staticcheck: findings in $mod"27- fail=170+ return 12871 fi29-done72+}3073 3174 # Tracked files stay small and textual: no compiled binaries, nothing over3275 # 2 MB (docs/media GIFs have their own 1 MB limit in doccheck).33-big=$(git ls-files | while IFS= read -r f; do34- if [ -f "$f" ] && [ "$(wc -c <"$f")" -gt 2097152 ]; then echo "$f"; fi35-done)36-if [ -n "$big" ]; then37- echo "tracked files over 2 MB:"38- echo "$big"39- fail=140-fi41-bins=$(git ls-files | grep -E '\.(test|exe|o|a|so|dylib)$|^bin/|(^|/)(zz_|tmp_?|scratch|dbg_)[^/]*$' || true)42-if [ -n "$bins" ]; then43- echo "compiled or scratch files tracked by git:"44- echo "$bins"45- fail=146-fi76+tracked() {77+ big=$(git ls-files -z | xargs -0 wc -c 2>/dev/null | awk '$1 > 2097152 && $2 != "total" { sub(/^ *[0-9]+ /, ""); print }')78+ bins=$(git ls-files | grep -E '\.(test|exe|o|a|so|dylib)$|^bin/|(^|/)(zz_|tmp_?|scratch|dbg_)[^/]*$' || true)79+ if [ -n "$big" ]; then80+ echo "tracked files over 2 MB:"81+ echo "$big"82+ fi83+ if [ -n "$bins" ]; then84+ echo "compiled or scratch files tracked by git:"85+ echo "$bins"86+ fi87+ [ -z "$big$bins" ]88+}4789 48-dirs=$(find cmd internal demos e2e oracle -name '*.go' -exec dirname {} \; | sort -u)49-over=$(go run $GOCOGNIT -over $MAX_COGNIT $dirs || true)50-if [ -n "$over" ]; then51- echo "cognitive complexity over $MAX_COGNIT:"52- echo "$over" | sort -rn53- fail=154-fi90+shape() {91+ over=$(go run $GOCOGNIT -over $MAX_COGNIT $dirs || true)92+ long=$(find $dirs -maxdepth 1 -name '*.go' -exec wc -l {} + | awk -v max=$MAX_LINES '$2 != "total" && $1 > max')93+ if [ -n "$over" ]; then94+ echo "cognitive complexity over $MAX_COGNIT:"95+ echo "$over" | sort -rn96+ fi97+ if [ -n "$long" ]; then98+ echo "files over $MAX_LINES lines:"99+ echo "$long" | sort -rn100+ fi101+ [ -z "$over$long" ]102+}55103 56-long=$(find cmd internal demos e2e oracle -name '*.go' -exec wc -l {} + | awk -v max=$MAX_LINES '$2 != "total" && $1 > max')57-if [ -n "$long" ]; then58- echo "files over $MAX_LINES lines:"59- echo "$long" | sort -rn60- fail=161-fi104+# Docs and comments describe the code as it is, not how it got here105+# (doclint); links and anchors resolve, the index lists every doc, and106+# every tape records something a doc shows (doccheck).107+doclint() { go run ./scripts/doclint; }108+doccheck() { go run ./scripts/doccheck; }62109 63-# Docs and comments describe the code as it is, not how it got here.64-if ! go run ./scripts/doclint; then65- fail=166-fi110+out=$(mktemp -d)111+trap 'rm -rf "$out"' EXIT112+names=""113+run() {114+ name=$1115+ shift116+ ("$@") >"$out/$name" 2>&1 &117+ eval "pid_$name=$!"118+ names="$names $name"119+}67120 68-# Links and anchors resolve, the index lists every doc, and every tape69-# records something a doc shows.70-if ! go run ./scripts/doccheck; then71- fail=172-fi121+run gofmt gofmt_check122+run vet vet123+run staticcheck staticcheck .124+run staticcheck_oracle staticcheck oracle125+run staticcheck_e2e staticcheck e2e126+run tracked tracked127+run shape shape128+run doclint doclint129+run doccheck doccheck73130 131+fail=0132+for name in $names; do133+ eval "pid=\$pid_$name"134+ wait "$pid" || fail=1135+ cat "$out/$name"136+done74137 exit $fail