exec.go: Support reading exit codes by returning a wrapped exec.ExitError instead of an error string.

This is now possible thanks to the following Go 1.13 features:

  - https://golang.org/doc/go1.13#error_wrapping
  - https://golang.org/pkg/errors/#As

Change-Id: Icdb6eaaac9a6224786b50c7d19f10d1c8192b8fb
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/245167
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
diff --git a/go/exec/exec.go b/go/exec/exec.go
index fd82886..3755e6b 100644
--- a/go/exec/exec.go
+++ b/go/exec/exec.go
@@ -245,7 +245,7 @@
 		return fmt.Errorf("%s %f secs", TIMEOUT_ERROR_PREFIX, command.Timeout.Seconds())
 	case err := <-done:
 		if err != nil {
-			return fmt.Errorf("Command exited with %s: %s", err, DebugString(command))
+			return fmt.Errorf("Command exited with %w: %s", err, DebugString(command))
 		}
 		return nil
 	}
diff --git a/go/exec/exec_test.go b/go/exec/exec_test.go
index 91c133c..19e57d6 100644
--- a/go/exec/exec_test.go
+++ b/go/exec/exec_test.go
@@ -3,6 +3,7 @@
 import (
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -234,12 +235,15 @@
 		Args: []string{"-u", "-c", `
 import sys
 sys.stderr.write('Error in subprocess!')
-sys.exit(1)
+sys.exit(123)
 `},
 		Stderr: &output,
 	})
 	expect.Error(t, err)
-	expect.Contains(t, err.Error(), "exit status 1")
+	expect.Contains(t, err.Error(), "exit status 123")
+	var exitError *exec.ExitError
+	require.True(t, errors.As(err, &exitError))
+	require.Equal(t, 123, exitError.ExitCode())
 	expect.Contains(t, string(output.Bytes()), "Error in subprocess!")
 }