issue 1025: the merge check vets and tests every nested Go module (ADR 0420 §5)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// **A repository's merge check runs every module's unit tests, a Go module of its own below the root included**
|
||||
// (novox/hq ADR 0420 §5, issue 1025): `./...` stops at a nested go.mod. This runs the script's own
|
||||
// `nested-modules` mode in a tree with a `go` that only records where it was run and fails for a module named bad.
|
||||
func TestTheMergeCheckVetsAndTestsEveryNestedGoModule(t *testing.T) {
|
||||
script, err := filepath.Abs("../../merge-check.sh")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bin, tree := t.TempDir(), t.TempDir()
|
||||
log := filepath.Join(t.TempDir(), "go.log")
|
||||
fake := "#!/bin/sh\necho \"$(basename \"$PWD\") $1 GOFLAGS=[$GOFLAGS]\" >>\"$LOG\"\n" +
|
||||
"[ \"$(basename \"$PWD\")\" = bad ] && [ \"$1\" = test ] && exit 1\nexit 0\n"
|
||||
if err := os.WriteFile(filepath.Join(bin, "go"), []byte(fake), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
run := func() (string, error) {
|
||||
cmd := exec.Command("sh", script, "nested-modules")
|
||||
cmd.Dir = tree
|
||||
cmd.Env = append(os.Environ(), "PATH="+bin+":"+os.Getenv("PATH"), "LOG="+log, "GOFLAGS=-mod=vendor")
|
||||
out, err := cmd.CombinedOutput()
|
||||
return string(out), err
|
||||
}
|
||||
// No modules directory: a pass, nothing run.
|
||||
if out, err := run(); err != nil {
|
||||
t.Fatalf("a repository with no nested module failed: %v\n%s", err, out)
|
||||
}
|
||||
if _, err := os.Stat(log); err == nil {
|
||||
t.Fatal("go ran with no nested module")
|
||||
}
|
||||
for _, m := range []string{"good", "bad", "other"} {
|
||||
dir := filepath.Join(tree, "modules", m)
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module x\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
// A directory with no go.mod is no Go module of its own.
|
||||
if err := os.MkdirAll(filepath.Join(tree, "modules", "typescript"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out, err := run()
|
||||
if err == nil {
|
||||
t.Fatalf("a nested module whose tests fail passed the check:\n%s", out)
|
||||
}
|
||||
raw, _ := os.ReadFile(log)
|
||||
ran := string(raw)
|
||||
for _, want := range []string{"good vet GOFLAGS=[]", "good test GOFLAGS=[]", "other test GOFLAGS=[]", "bad test GOFLAGS=[]"} {
|
||||
if !strings.Contains(ran, want) {
|
||||
t.Errorf("%q was not run, nor outside the vendor directory:\n%s", want, ran)
|
||||
}
|
||||
}
|
||||
if strings.Contains(ran, "typescript") {
|
||||
t.Errorf("a directory with no go.mod was run:\n%s", ran)
|
||||
}
|
||||
if !strings.Contains(out, "nested module modules/bad FAILED") {
|
||||
t.Errorf("the failing module is not named:\n%s", out)
|
||||
}
|
||||
}
|
||||
+29
-1
@@ -36,6 +36,30 @@ judge_store_tests() {
|
||||
missing=$((missing + 1))
|
||||
fi
|
||||
}
|
||||
# nested_modules vets and tests every Go module of its own below the root, `modules/<name>/go.mod` (novox/hq ADR 0420
|
||||
# §5, issue 1025): `./...` stops at a nested go.mod, so a module that lives whole in this repository would have its
|
||||
# unit tests run by nobody. None is a pass. Each runs in its own directory, outside the vendor directory this
|
||||
# repository's own packages are built from; how its dependencies are found offline is issue 1019's (the move of the
|
||||
# first two modules in), and it is settled there. A failing module fails the check; the others are still run.
|
||||
nested_modules() {
|
||||
nested=0
|
||||
for gomod in modules/*/go.mod; do
|
||||
[ -e "$gomod" ] || continue
|
||||
dir=$(dirname "$gomod")
|
||||
echo "nested module $dir:"
|
||||
if ! (cd "$dir" && GOFLAGS= CGO_ENABLED=0 go vet ./... &&
|
||||
GOFLAGS= CGO_ENABLED="${cgo:-0}" go test ${race:-} -count=1 -timeout 30m ./...); then
|
||||
echo "nested module $dir FAILED"
|
||||
nested=1
|
||||
fi
|
||||
done
|
||||
return $nested
|
||||
}
|
||||
# `sh merge-check.sh nested-modules` runs only that, to try it on a tree.
|
||||
if [ "${1:-}" = nested-modules ]; then
|
||||
nested_modules
|
||||
exit
|
||||
fi
|
||||
# `sh merge-check.sh judge-store-tests <package> <status> <output> <name>…` runs only the judging, to try it on a
|
||||
# recorded `go test -v` output.
|
||||
if [ "${1:-}" = judge-store-tests ]; then
|
||||
@@ -46,7 +70,10 @@ if [ "${1:-}" = judge-store-tests ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
unformatted=$(gofmt -l cmd internal examples)
|
||||
gofmt_dirs="cmd internal examples"
|
||||
[ -d modules ] && gofmt_dirs="$gofmt_dirs modules"
|
||||
# shellcheck disable=SC2086 # the directories are one word each, split on purpose
|
||||
unformatted=$(gofmt -l $gofmt_dirs)
|
||||
if [ -n "$unformatted" ]; then
|
||||
echo "not gofmt'd:"
|
||||
echo "$unformatted"
|
||||
@@ -232,6 +259,7 @@ else
|
||||
cat "$work/rest.out"
|
||||
[ "$(cat "$work/rest.status")" -eq 0 ] || suite_failed=1
|
||||
say_shards || suite_failed=1
|
||||
nested_modules || suite_failed=1
|
||||
fi
|
||||
|
||||
if [ -z "$listed" ]; then
|
||||
|
||||
Reference in New Issue
Block a user