generated from broadinstitute/golang-project-template
/
create_build.go
137 lines (117 loc) · 4.2 KB
/
create_build.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package cli
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"github.com/broadinstitute/sherlock/internal/controllers/v1controllers"
"github.com/broadinstitute/sherlock/internal/serializers/v1serializers"
"os"
"time"
"github.com/go-resty/resty/v2"
"github.com/spf13/cobra"
"google.golang.org/api/idtoken"
"google.golang.org/api/option"
)
const (
versionStringHelpText string = "unique identifier for this build. should be a full image repository path and tag"
commitShaHelpText string = "git commit sha associated with a particular build"
buildURLHelpText string = "url for the job run that created this build ie a jenkins job or github action log url OPTIONAL"
repoHelpText string = "url for the repo containing code for the service being build OPTIONAL"
)
var (
// ErrInvalidArgs is returned when builds create command receives no or too many arguments
serviceRepo string
versionString string
commitSha string
buildURL string
errInvalidArgs = errors.New("builds create usage: sherlock builds create SERVICE_NAME [flags]")
createBuildCmd = &cobra.Command{
Use: "create",
Short: "create a new build",
Long: `creates a new build of service which will be tracked by sherlock.`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errInvalidArgs
}
return nil
},
RunE: createBuild,
}
)
func init() {
createBuildCmd.Flags().StringVar(&versionString, "version-string", "", versionStringHelpText)
_ = createBuildCmd.MarkFlagRequired("version-string")
createBuildCmd.Flags().StringVar(&commitSha, "commit-sha", "", commitShaHelpText)
_ = createBuildCmd.MarkFlagRequired("commit-sha")
createBuildCmd.Flags().StringVar(&buildURL, "build-url", "", buildURLHelpText)
createBuildCmd.Flags().StringVar(&serviceRepo, "repo-url", "", repoHelpText)
buildCmd.AddCommand(createBuildCmd)
}
func createBuild(cmd *cobra.Command, args []string) error {
serviceName := args[0]
newBuild := v1controllers.CreateBuildRequest{
VersionString: versionString,
CommitSha: commitSha,
ServiceName: serviceName,
BuiltAt: time.Now(),
BuildURL: buildURL,
ServiceRepo: serviceRepo,
}
result, rawResponseBody, err := dispatchCreateBuildRequest(newBuild)
if err != nil {
return fmt.Errorf("ERROR: %v", err)
}
// check for errors returned in response
if result.Error != "" {
return fmt.Errorf("ERROR: %v", result.Error)
}
// pretty print the sherlock api response
var prettyResult bytes.Buffer
if err := json.Indent(&prettyResult, rawResponseBody, "", " "); err != nil {
return fmt.Errorf("error pretty formatting response body: %v", err)
}
fmt.Fprint(cmd.OutOrStdout(), prettyResult.String())
return nil
}
func dispatchCreateBuildRequest(newBuild v1controllers.CreateBuildRequest) (*v1serializers.BuildsResponse, []byte, error) {
var (
req *resty.Request
err error
)
client := resty.New()
req = client.R()
// set authorization headers when running cli via automated workflows
if useServiceAccountAuth {
req, err = setAuthHeader(req)
if err != nil {
return nil, []byte{}, fmt.Errorf("error setting auth header: %v", err)
}
}
resp, err := req.SetHeader("Content-Type", "application/json").
SetBody(newBuild).
Post(fmt.Sprintf("%s/api/v1/builds", sherlockServerURL))
if err != nil {
return nil, []byte{}, fmt.Errorf("ERROR sending post /api/v1/builds request: %v", err)
}
var result v1serializers.BuildsResponse
responseBodyBytes := bytes.NewBuffer(resp.Body())
if err := json.NewDecoder(responseBodyBytes).Decode(&result); err != nil {
return nil, []byte{}, fmt.Errorf("error parsing create build response %v. Status code: %d", err, resp.StatusCode())
}
return &result, resp.Body(), nil
}
func setAuthHeader(req *resty.Request) (*resty.Request, error) {
ctx := context.Background()
audience := os.Getenv("SHERLOCK_OAUTH_AUDIENCE")
tokenGenerator, err := idtoken.NewTokenSource(ctx, audience, option.WithCredentialsFile(clientCredentials))
if err != nil {
return nil, fmt.Errorf("error creating token generator: %v", err)
}
token, err := tokenGenerator.Token()
if err != nil {
return nil, fmt.Errorf("error generating oidc token: %v", err)
}
return req.SetAuthToken(token.AccessToken), nil
}