x/exp/cmd/gorelease: diagnostic about proposed prerelease

Adds diagnostics about:

- Prereleases with suffixes that sort lower than pseudo-versions.
- Prereleases with plus signs.

Fixes golang/go#37565

Change-Id: I210df3a0c37912963e750c632d1dc4a556e94e88
Reviewed-on: https://go-review.googlesource.com/c/exp/+/257077
Trust: Jean de Klerk <deklerk@google.com>
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jean de Klerk <deklerk@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
diff --git a/cmd/gorelease/gorelease.go b/cmd/gorelease/gorelease.go
index 380e25a..e024710 100644
--- a/cmd/gorelease/gorelease.go
+++ b/cmd/gorelease/gorelease.go
@@ -53,6 +53,10 @@
 //
 // For more information on semantic versioning, see https://semver.org.
 //
+// Note: gorelease does not accept build metadata in releases (like
+// v1.0.0+debug). Although it is valid semver, the Go tool and other tools in
+// the ecosystem do not support it, so its use is not recommended.
+//
 // gorelease accepts the following flags:
 //
 // -base=version: The version that the current version of the module will be
@@ -167,6 +171,9 @@
 		return false, usageErrorf("no arguments allowed")
 	}
 	if releaseVersion != "" {
+		if semver.Build(releaseVersion) != "" {
+			return false, usageErrorf("release version %q is not a canonical semantic version: build metadata is not supported", releaseVersion)
+		}
 		if c := semver.Canonical(releaseVersion); c != releaseVersion {
 			return false, usageErrorf("release version %q is not a canonical semantic version", releaseVersion)
 		}
@@ -250,6 +257,11 @@
 		version:   version,
 		goModPath: filepath.Join(modRoot, "go.mod"),
 	}
+
+	if version != "" && semver.Compare(version, "v0.0.0-99999999999999-zzzzzzzzzzzz") < 0 {
+		m.diagnostics = append(m.diagnostics, fmt.Sprintf("Version %s is lower than most pseudo-versions. Consider releasing v0.1.0-0 instead.", version))
+	}
+
 	m.goModData, err = ioutil.ReadFile(m.goModPath)
 	if err != nil {
 		return moduleInfo{}, err
diff --git a/cmd/gorelease/report.go b/cmd/gorelease/report.go
index 32311c4..cea58a4 100644
--- a/cmd/gorelease/report.go
+++ b/cmd/gorelease/report.go
@@ -86,6 +86,11 @@
 	} else {
 		if r.release.tagPrefix == "" {
 			fmt.Fprintf(buf, "%s is a valid semantic version for this release.\n", r.release.version)
+
+			if semver.Compare(r.release.version, "v0.0.0-99999999999999-zzzzzzzzzzzz") < 0 {
+				fmt.Fprintf(buf, `Note: %s sorts lower in MVS than pseudo-versions, which may be
+unexpected for users. So, it may be better to choose a different suffix.`, r.release.version)
+			}
 		} else {
 			fmt.Fprintf(buf, "%[1]s (with tag %[2]s%[1]s) is a valid semantic version for this release\n", r.release.version, r.release.tagPrefix)
 		}
diff --git a/cmd/gorelease/testdata/mod/example.com_prerelease_v0.0.0-20300101000000-000000000000.txt b/cmd/gorelease/testdata/mod/example.com_prerelease_v0.0.0-20300101000000-000000000000.txt
new file mode 100644
index 0000000..e165690
--- /dev/null
+++ b/cmd/gorelease/testdata/mod/example.com_prerelease_v0.0.0-20300101000000-000000000000.txt
@@ -0,0 +1,4 @@
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
diff --git a/cmd/gorelease/testdata/prerelease/README.txt b/cmd/gorelease/testdata/prerelease/README.txt
new file mode 100644
index 0000000..64a4c96
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/README.txt
@@ -0,0 +1 @@
+This directory contains tests for pre-release versions.
\ No newline at end of file
diff --git a/cmd/gorelease/testdata/prerelease/prerelease_2.test b/cmd/gorelease/testdata/prerelease/prerelease_2.test
new file mode 100644
index 0000000..b3e83db
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/prerelease_2.test
@@ -0,0 +1,10 @@
+mod=example.com/prerelease
+release=v0.0.0-2
+success=false
+-- want --
+Inferred base version: none
+Version v0.0.0-2 is lower than most pseudo-versions. Consider releasing v0.1.0-0 instead.
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
\ No newline at end of file
diff --git a/cmd/gorelease/testdata/prerelease/prerelease_3.test b/cmd/gorelease/testdata/prerelease/prerelease_3.test
new file mode 100644
index 0000000..e155209
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/prerelease_3.test
@@ -0,0 +1,10 @@
+mod=example.com/prerelease
+release=v0.0.0-3
+success=false
+-- want --
+Inferred base version: none
+Version v0.0.0-3 is lower than most pseudo-versions. Consider releasing v0.1.0-0 instead.
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
\ No newline at end of file
diff --git a/cmd/gorelease/testdata/prerelease/prerelease_beta2.test b/cmd/gorelease/testdata/prerelease/prerelease_beta2.test
new file mode 100644
index 0000000..766abfc
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/prerelease_beta2.test
@@ -0,0 +1,9 @@
+mod=example.com/prerelease
+release=v0.0.0-beta2
+-- want --
+Inferred base version: none
+v0.0.0-beta2 is a valid semantic version for this release.
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
\ No newline at end of file
diff --git a/cmd/gorelease/testdata/prerelease/prerelease_build_metadata.test b/cmd/gorelease/testdata/prerelease/prerelease_build_metadata.test
new file mode 100644
index 0000000..4d3be83
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/prerelease_build_metadata.test
@@ -0,0 +1,11 @@
+mod=example.com/prerelease
+release=v1.0.0-alpha+001
+error=true
+-- want --
+usage: gorelease [-base=version] [-version=version]
+release version "v1.0.0-alpha+001" is not a canonical semantic version: build metadata is not supported
+For more information, run go doc golang.org/x/exp/cmd/gorelease
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
\ No newline at end of file
diff --git a/cmd/gorelease/testdata/prerelease/prerelease_wordsonly.test b/cmd/gorelease/testdata/prerelease/prerelease_wordsonly.test
new file mode 100644
index 0000000..b24b76b
--- /dev/null
+++ b/cmd/gorelease/testdata/prerelease/prerelease_wordsonly.test
@@ -0,0 +1,9 @@
+mod=example.com/prerelease
+release=v0.0.0-some-words-only-suffix
+-- want --
+Inferred base version: none
+v0.0.0-some-words-only-suffix is a valid semantic version for this release.
+-- go.mod --
+module example.com/prerelease
+
+go 1.12
\ No newline at end of file