release.bash: add support for building release binaries

Updates golang/protobuf#738

Change-Id: I6dd85ff0129bfcfb67b12b06549c568eebfd68e3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189342
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/.gitignore b/.gitignore
index 578b3d1..fd09e45 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,11 @@
-.cache
-.gocache
-vendor
-cmd/protoc-gen-go/protoc-gen-go
-cmd/protoc-gen-go/testdata/go.sum
-cmd/protoc-gen-go-grpc/protoc-gen-go-grpc
-cmd/protoc-gen-go-grpc/testdata/go.sum
+/.cache
+/.gocache
+/bin
+/cmd/protoc-gen-go/protoc-gen-go
+/cmd/protoc-gen-go/testdata/go.sum
+/cmd/protoc-gen-go-grpc/protoc-gen-go-grpc
+/cmd/protoc-gen-go-grpc/testdata/go.sum
+/vendor
 
 # This file includes artifacts of the system test that should not be checked in.
 # For files created by specific development environment (e.g. editor),
diff --git a/integration_test.go b/integration_test.go
index cbda497..c91b227 100644
--- a/integration_test.go
+++ b/integration_test.go
@@ -25,10 +25,13 @@
 	"sync"
 	"testing"
 	"time"
+
+	"google.golang.org/protobuf/runtime/protoimpl"
 )
 
 var (
-	regenerate = flag.Bool("regenerate", false, "regenerate files")
+	regenerate   = flag.Bool("regenerate", false, "regenerate files")
+	buildRelease = flag.Bool("buildRelease", false, "build release binaries")
 
 	protobufVersion = "3.9.1"
 	golangVersions  = []string{"1.9.7", "1.10.8", "1.11.13", "1.12.9"}
@@ -45,16 +48,7 @@
 
 func Test(t *testing.T) {
 	mustInitDeps(t)
-
-	if *regenerate {
-		t.Run("Generate", func(t *testing.T) {
-			fmt.Print(mustRunCommand(t, "go", "run", "-tags", "protolegacy", "./internal/cmd/generate-types", "-execute"))
-			fmt.Print(mustRunCommand(t, "go", "run", "-tags", "protolegacy", "./internal/cmd/generate-protos", "-execute"))
-			files := strings.Split(strings.TrimSpace(mustRunCommand(t, "git", "ls-files", "*.go")), "\n")
-			mustRunCommand(t, append([]string{"gofmt", "-w"}, files...)...)
-		})
-		t.SkipNow()
-	}
+	mustHandleFlags(t)
 
 	var wg sync.WaitGroup
 	sema := make(chan bool, (runtime.NumCPU()+1)/2)
@@ -382,6 +376,55 @@
 	}
 }
 
+func mustHandleFlags(t *testing.T) {
+	if *regenerate {
+		t.Run("Generate", func(t *testing.T) {
+			fmt.Print(mustRunCommand(t, "go", "run", "-tags", "protolegacy", "./internal/cmd/generate-types", "-execute"))
+			fmt.Print(mustRunCommand(t, "go", "run", "-tags", "protolegacy", "./internal/cmd/generate-protos", "-execute"))
+			files := strings.Split(strings.TrimSpace(mustRunCommand(t, "git", "ls-files", "*.go")), "\n")
+			mustRunCommand(t, append([]string{"gofmt", "-w"}, files...)...)
+		})
+	}
+	if *buildRelease {
+		t.Run("BuildRelease", func(t *testing.T) {
+			v := protoimpl.VersionString()
+			for _, goos := range []string{"linux", "darwin", "windows"} {
+				for _, goarch := range []string{"386", "amd64"} {
+					binPath := filepath.Join("bin", fmt.Sprintf("protoc-gen-go.%v.%v.%v", v, goos, goarch))
+
+					// Build the binary.
+					cmd := command{Env: append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)}
+					cmd.mustRun(t, "go", "build", "-trimpath", "-ldflags", "-s -w", "-o", binPath, "./cmd/protoc-gen-go")
+
+					// Archive and compress the binary.
+					in, err := ioutil.ReadFile(binPath)
+					if err != nil {
+						t.Fatal(err)
+					}
+					out := new(bytes.Buffer)
+					gz, _ := gzip.NewWriterLevel(out, gzip.BestCompression)
+					gz.Comment = fmt.Sprintf("protoc-gen-go VERSION=%v GOOS=%v GOARCH=%v", v, goos, goarch)
+					tw := tar.NewWriter(gz)
+					tw.WriteHeader(&tar.Header{
+						Name: "protoc-gen-go",
+						Mode: int64(0775),
+						Size: int64(len(in)),
+					})
+					tw.Write(in)
+					tw.Close()
+					gz.Close()
+					if err := ioutil.WriteFile(binPath+".tar.gz", out.Bytes(), 0664); err != nil {
+						t.Fatal(err)
+					}
+				}
+			}
+		})
+	}
+	if *regenerate || *buildRelease {
+		t.SkipNow()
+	}
+}
+
 type command struct {
 	Dir string
 	Env []string
diff --git a/release.bash b/release.bash
index 3326136..cc3d886 100755
--- a/release.bash
+++ b/release.bash
@@ -74,8 +74,8 @@
 fi
 git commit -a -m "all: release $(version_string)"
 
-# TODO: Build release binaries.
-# go test -mod=vendor -timeout=60m -count=1 integration_test.go "$@" -buildRelease
+# Build release binaries.
+go test -mod=vendor -timeout=60m -count=1 integration_test.go "$@" -buildRelease
 
 # Create commit to start development after release.
 VERSION_PRERELEASE="${VERSION_PRERELEASE}.devel" # append ".devel"