// Package gofmt refuses a Go file of the catalogue that gofmt would change (the second of a kind in one milestone: // buildstep's generated.go and claude-code's config_test.go reached a join unformatted). A check here holds every // module to it, where a module's own tests hold only themselves. package gofmt import ( "bytes" "go/format" "io/fs" "os" "path/filepath" "sort" "strings" ) // Files are the Go files under root, relative to it: every .go file but those in .git, node_modules and a testdata // directory (a test's fixture may be anything). func Files(root string) ([]string, error) { var out []string err := filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() { switch d.Name() { case ".git", "node_modules", "testdata": return filepath.SkipDir } return nil } if strings.HasSuffix(d.Name(), ".go") && d.Type().IsRegular() { rel, _ := filepath.Rel(root, p) out = append(out, filepath.ToSlash(rel)) } return nil }) sort.Strings(out) return out, err } // Unformatted are the files gofmt would change, and why for one that does not parse. func Unformatted(root string, files []string) (map[string]string, error) { out := map[string]string{} for _, f := range files { src, err := os.ReadFile(filepath.Join(root, f)) if err != nil { return nil, err } got, err := format.Source(src) switch { case err != nil: out[f] = "it does not parse: " + err.Error() case !bytes.Equal(got, src): out[f] = "gofmt changes it: run gofmt -w " + f } } return out, nil }