x/exp/cmd/gorelease: specify which incomplete requirements were missing

Fixes golang/go#38164

Change-Id: I71a3edeb4445c568ae7a94f7c30da68682104f02
Reviewed-on: https://go-review.googlesource.com/c/exp/+/253039
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Trust: Jay Conrod <jayconrod@google.com>
Trust: Jean de Klerk <deklerk@google.com>
diff --git a/cmd/gorelease/gorelease.go b/cmd/gorelease/gorelease.go
index fba7fc0..b369332 100644
--- a/cmd/gorelease/gorelease.go
+++ b/cmd/gorelease/gorelease.go
@@ -957,17 +957,17 @@
 
 	// Report new requirements in go.mod.
 	goModPath := filepath.Join(loadDir, "go.mod")
-	loadReqs := func(data []byte) (string, error) {
+	loadReqs := func(data []byte) ([]string, error) {
 		modFile, err := modfile.ParseLax(goModPath, data, nil)
 		if err != nil {
-			return "", err
+			return nil, err
 		}
 		lines := make([]string, len(modFile.Require))
 		for i, req := range modFile.Require {
 			lines[i] = req.Mod.String()
 		}
 		sort.Strings(lines)
-		return strings.Join(lines, "\n"), nil
+		return lines, nil
 	}
 
 	oldReqs, err := loadReqs(goModData)
@@ -983,19 +983,28 @@
 		return nil, nil, err
 	}
 
-	goModChanged := oldReqs != newReqs
-	if goModChanged {
-		diagnostics = append(diagnostics, "go.mod: requirements are incomplete.\nRun 'go mod tidy' to add missing requirements.")
+	oldMap := make(map[string]bool)
+	for _, req := range oldReqs {
+		oldMap[req] = true
+	}
+	var missing []string
+	for _, req := range newReqs {
+		if !oldMap[req] {
+			missing = append(missing, req)
+		}
 	}
 
-	if !goModChanged {
-		newGoSumData, err := ioutil.ReadFile(filepath.Join(loadDir, "go.sum"))
-		if err != nil && !os.IsNotExist(err) {
-			return nil, nil, err
-		}
-		if !bytes.Equal(goSumData, newGoSumData) {
-			diagnostics = append(diagnostics, "go.sum: one or more sums are missing.\nRun 'go mod tidy' to add missing sums.")
-		}
+	if len(missing) > 0 {
+		diagnostics = append(diagnostics, fmt.Sprintf("go.mod: the following requirements are needed\n\t%s\nRun 'go mod tidy' to add missing requirements.", strings.Join(missing, "\n\t")))
+		return pkgs, diagnostics, nil
+	}
+
+	newGoSumData, err := ioutil.ReadFile(filepath.Join(loadDir, "go.sum"))
+	if err != nil && !os.IsNotExist(err) {
+		return nil, nil, err
+	}
+	if !bytes.Equal(goSumData, newGoSumData) {
+		diagnostics = append(diagnostics, "go.sum: one or more sums are missing.\nRun 'go mod tidy' to add missing sums.")
 	}
 
 	return pkgs, diagnostics, nil
diff --git a/cmd/gorelease/testdata/tidy/misleading_req.test b/cmd/gorelease/testdata/tidy/misleading_req.test
index ee970a9..de0d745 100644
--- a/cmd/gorelease/testdata/tidy/misleading_req.test
+++ b/cmd/gorelease/testdata/tidy/misleading_req.test
@@ -22,5 +22,6 @@
 import _ "example.com/tidy/a"
 import _ "example.com/tidy/b"
 -- want --
-go.mod: requirements are incomplete.
+go.mod: the following requirements are needed
+	example.com/tidy/b@v0.2.0
 Run 'go mod tidy' to add missing requirements.
diff --git a/cmd/gorelease/testdata/tidy/missing_req.test b/cmd/gorelease/testdata/tidy/missing_req.test
index 3e43e76..9290804 100644
--- a/cmd/gorelease/testdata/tidy/missing_req.test
+++ b/cmd/gorelease/testdata/tidy/missing_req.test
@@ -2,7 +2,8 @@
 base=v0.0.1
 success=false
 -- want --
-go.mod: requirements are incomplete.
+go.mod: the following requirements are needed
+	example.com/basic@v1.1.2
 Run 'go mod tidy' to add missing requirements.
 -- go.mod --
 module example.com/tidy