-
Notifications
You must be signed in to change notification settings - Fork 9
/
submitresult.go
145 lines (124 loc) · 4.02 KB
/
submitresult.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
138
139
140
141
142
143
144
145
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
"github.com/bitrise-io/bitrise-init/errormapper"
"github.com/bitrise-io/bitrise-init/models"
"github.com/bitrise-io/go-steputils/step"
"github.com/bitrise-io/go-steputils/stepconf"
"github.com/bitrise-io/go-utils/log"
"github.com/bitrise-io/go-utils/retry"
)
type resultClient struct {
URL *url.URL
}
func newResultClient(resultSubmitURL string, resultSubmitAPIToken stepconf.Secret) (*resultClient, error) {
submitURL, err := url.Parse(resultSubmitURL)
if err != nil {
return nil, fmt.Errorf("could not parse submit URL, error: %s", err)
}
q := submitURL.Query()
q.Add("api_token", url.QueryEscape(string(resultSubmitAPIToken)))
submitURL.RawQuery = q.Encode()
return &resultClient{
URL: submitURL,
}, nil
}
func buildErrorScanResultModel(stepID string, err error) models.ScanResultModel {
var errWithRec models.ErrorWithRecommendations
// It's a stepError
if stepError, ok := err.(*step.Error); ok {
rec := stepError.Recommendations
// If it doesn't have recommendations, create one
if rec == nil {
rec = step.Recommendation{}
}
// Check for DetailedError field, if not present, fill it with generic DetailedError
if rec[errormapper.DetailedErrorRecKey] == nil {
rec[errormapper.DetailedErrorRecKey] = errormapper.DetailedError{
Title: stepError.Err.Error(),
Description: "For more information, please see the log.",
}
}
// Create the error with recommendation model
errWithRec = models.ErrorWithRecommendations{
Error: fmt.Sprintf("Error in step %s: %v", stepID, stepError.Err),
Recommendations: rec,
}
} else {
// It's a standard error, fallback to the generic DetailedError
errWithRec = models.ErrorWithRecommendations{
Error: fmt.Sprintf("Error in step %s: %v", stepID, err),
Recommendations: step.Recommendation{
errormapper.DetailedErrorRecKey: errormapper.DetailedError{
Title: err.Error(),
Description: "For more information, please see the log.",
},
},
}
}
return models.ScanResultModel{
ScannerToErrorsWithRecommendations: map[string]models.ErrorsWithRecommendations{
"general": {
errWithRec,
},
},
}
}
func (c *resultClient) uploadErrorResult(stepID string, err error) error {
result := buildErrorScanResultModel(stepID, err)
resultBytes, err := json.MarshalIndent(result, "", "\t")
if err != nil {
failf("failed to marshal results: %v", err)
}
return c.uploadResults(resultBytes)
}
func (c *resultClient) uploadResults(bytes []byte) error {
if err := retry.Times(1).Wait(5 * time.Second).Try(func(attempt uint) error {
if attempt != 0 {
log.TWarnf("%d query attempt failed", attempt)
}
req, err := http.NewRequest(http.MethodPost, c.URL.String(), strings.NewReader(string(bytes)))
if err != nil {
return fmt.Errorf("failed to create request: %v", err)
}
req.Header.Add("Content-Type", "application/json")
reqDump, err := httputil.DumpRequestOut(req, true)
if err != nil {
log.TWarnf("failed to dump request: %v", err)
}
log.TDebugf("Request: %s", reqDump)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.TErrorf("failed to send request: url: %s, request: %s", c.URL.String(), reqDump)
return fmt.Errorf("failed to submit results: %v", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.TErrorf("failed to close response body: %v", err)
}
}()
resp.Header.Del("Set-Cookie") // Removing sensitive info
respDump, err := httputil.DumpResponse(resp, true)
if err != nil {
log.TWarnf("failed to dump response: %s", err)
respDump, err = httputil.DumpResponse(resp, false)
if err != nil {
log.TWarnf("failed to dump response: %s", err)
}
}
if resp.StatusCode != http.StatusOK {
log.TErrorf("Submit failed, url: %s request: %s, response: %s", c.URL.String(), reqDump, respDump)
return fmt.Errorf("failed to submit results, status code: %d", resp.StatusCode)
}
return nil
}); err != nil {
return err
}
return nil
}