Twice in the registry milestone a module's program, built in its folder, was committed with git add -A and stayed in the branch's history. The ignore list was kept by hand and covered 56 of 229 programs. checks/gitignored now lists every main package's program (in its directory and at its Go module's root) and fails on one no ignore file names; the root .gitignore names each, anchored to its path. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
159 lines
5.9 KiB
Go
159 lines
5.9 KiB
Go
package gitignored
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The kind of catalogue review F1: a bare pattern hides the command directory it shares a name with; an anchored one
|
|
// hides the binary alone; a glob that ignores source is refused too; a negation keeps a path.
|
|
func TestFindNamesEachPatternThatHidesSource(t *testing.T) {
|
|
for name, c := range map[string]struct {
|
|
ignore string
|
|
hidden []string
|
|
}{
|
|
"a bare name hides cmd/<name>": {"nfs-server\n", []string{"modules/m/cmd/nfs-server/", "modules/m/cmd/nfs-server/" + Probe, "modules/m/cmd/nfs-server/main.go"}},
|
|
"anchored to the binary": {"/nfs-server\n/cmd/nfs-server/nfs-server\n", nil},
|
|
"a glob ignoring Go source": {"*.go\n!main.go\n", []string{"modules/m/cmd/" + Probe, "modules/m/cmd/nfs-server/" + Probe,
|
|
"modules/m/internal/" + Probe, "modules/m/internal/x/" + Probe, "modules/m/internal/x/x.go"}},
|
|
"a pattern over internal/": {"internal/\n", []string{"modules/m/internal/", "modules/m/internal/" + Probe, "modules/m/internal/x/",
|
|
"modules/m/internal/x/" + Probe, "modules/m/internal/x/x.go"}},
|
|
"nothing but generated JavaScript": {"*.js\n", nil},
|
|
} {
|
|
root := t.TempDir()
|
|
for f, b := range map[string]string{
|
|
"modules/m/.gitignore": c.ignore,
|
|
"modules/m/cmd/nfs-server/main.go": "package main\n",
|
|
"modules/m/cmd/nfs-server/run.js": "",
|
|
"modules/m/internal/x/x.go": "package x\n",
|
|
"modules/m/node_modules/y/index.go": "",
|
|
"modules/other/cmd/other/other.go": "package main\n",
|
|
} {
|
|
p := filepath.Join(root, f)
|
|
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(p, []byte(b), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
dirs, err := Sources(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := Find(root, dirs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var paths []string
|
|
for _, h := range got {
|
|
paths = append(paths, h.Path)
|
|
if !strings.HasPrefix(h.Pattern, "modules/m/.gitignore:") {
|
|
t.Errorf("%s: %s is named hidden by %q, want the module's .gitignore", name, h.Path, h.Pattern)
|
|
}
|
|
}
|
|
if strings.Join(paths, ",") != strings.Join(c.hidden, ",") {
|
|
t.Errorf("%s: hidden %v, want %v", name, paths, c.hidden)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The catalogue's own tree: no ignore pattern hides a path under a module's cmd/ or internal/.
|
|
func TestNoIgnorePatternHidesAModulesSource(t *testing.T) {
|
|
root := filepath.Join("..", "..")
|
|
dirs, err := Sources(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(dirs) == 0 {
|
|
t.Fatal("no module source directory found: the check reads nothing")
|
|
}
|
|
hidden, err := Find(root, dirs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, h := range hidden {
|
|
t.Errorf("%s is hidden by %s: a module's source is never ignored; anchor the pattern to the binary (/<name>, /cmd/<name>/<name>)", h.Path, h.Pattern)
|
|
}
|
|
}
|
|
|
|
// The kind of issue 1577, met twice in one milestone: a module's program `go build` left in its folder was committed.
|
|
// Every program a main package builds, in its own directory and at its module's root, is found, and one no ignore file
|
|
// names is open; a directory of the same name is no program's place.
|
|
func TestEveryProgramABuildLeavesIsIgnored(t *testing.T) {
|
|
files := map[string]string{
|
|
"modules/m/go.mod": "module example.com/m/v2\n",
|
|
"modules/m/main.go": "// a program\npackage main\n",
|
|
"modules/m/cmd/m-tools/main.go": "package main\n",
|
|
"modules/m/cmd/m-tools/main_test.go": "package main\n",
|
|
"modules/m/internal/x/x.go": "package x\n",
|
|
"modules/m/internal/x/x_test.go": "package main\n",
|
|
"modules/m/node_modules/y/y.go": "package main\n",
|
|
"modules/m/tool/go.mod": "module tool\n",
|
|
"modules/m/tool/cmd/tool/main.go": "package main\n",
|
|
"modules/m/tool/tool/source.go": "package tool\n",
|
|
"checks/c/go.mod": "module example.com/checks/c\n",
|
|
"checks/c/main.go": "package main\n",
|
|
}
|
|
for name, c := range map[string]struct {
|
|
ignore string
|
|
open []string
|
|
}{
|
|
"nothing ignored": {"", []string{"checks/c/c", "modules/m/cmd/m-tools/m-tools", "modules/m/m", "modules/m/m-tools",
|
|
"modules/m/tool/cmd/tool/tool"}},
|
|
"each anchored": {"/checks/c/c\n/modules/m/cmd/m-tools/m-tools\n/modules/m/m\n/modules/m/m-tools\n/modules/m/tool/cmd/tool/tool\n", nil},
|
|
"one kept by a negation": {"/checks/c/c\n/modules/m/*\n!/modules/m/m\n/modules/m/cmd/m-tools/m-tools\n/modules/m/tool/cmd/tool/tool\n",
|
|
[]string{"modules/m/m"}},
|
|
} {
|
|
root := t.TempDir()
|
|
for f, b := range files {
|
|
p := filepath.Join(root, f)
|
|
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(p, []byte(b), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, ".gitignore"), []byte(c.ignore), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
programs, err := Programs(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := "checks/c/c,modules/m/cmd/m-tools/m-tools,modules/m/m,modules/m/m-tools,modules/m/tool/cmd/tool/tool"
|
|
if got := strings.Join(programs, ","); got != want {
|
|
t.Fatalf("%s: programs %s, want %s", name, got, want)
|
|
}
|
|
open, err := Unignored(root, programs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Join(open, ",") != strings.Join(c.open, ",") {
|
|
t.Errorf("%s: open %v, want %v", name, open, c.open)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The catalogue's own tree: every program a local build leaves is ignored, so `git add -A` never takes one.
|
|
func TestNoProgramABuildLeavesIsCommitted(t *testing.T) {
|
|
root := filepath.Join("..", "..")
|
|
programs, err := Programs(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(programs) == 0 {
|
|
t.Fatal("no main package found: the check reads nothing")
|
|
}
|
|
open, err := Unignored(root, programs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range open {
|
|
t.Errorf("%s is the program a local go build leaves, and no ignore file names it: add /%s to the catalogue's .gitignore", p, p)
|
|
}
|
|
}
|