diff --git a/README.md b/README.md index ac9e7ad..122bde1 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,11 @@ logs.) * `version`: Application version. Included in the `details.log.gz` file. +* `label`: Label to attach to the github issue, and include in the details file. + + If using the JSON upload encoding, this should be encoded as a `labels` field, + whose value should be a list of strings. + * `log`: a log file, with lines separated by newline characters. Multiple log files can be included by including several `log` parts. diff --git a/src/github.com/matrix-org/rageshake/submit.go b/src/github.com/matrix-org/rageshake/submit.go index 62f4441..820e2ab 100644 --- a/src/github.com/matrix-org/rageshake/submit.go +++ b/src/github.com/matrix-org/rageshake/submit.go @@ -58,6 +58,7 @@ type payload struct { UserAgent string `json:"user_agent"` Logs []logEntry `json:"logs"` Data map[string]string `json:"data"` + Labels []string `json:"labels"` Files []string } @@ -257,6 +258,22 @@ func parseFormPart(part *multipart.Part, p *payload, reportDir string) error { } data := string(b) + if field == "log" || field == "compressed-log" { + // todo: we could save the log directly rather than pointlessly + // unzipping and re-zipping. + p.Logs = append(p.Logs, logEntry{ + ID: part.FileName(), + Lines: data, + }) + } else { + formPartToPayload(field, data, p) + } + return nil +} + +// formPartToPayload updates the relevant part of *p from a name/value pair +// read from the form data. +func formPartToPayload(field, data string, p *payload) { if field == "text" { p.Text = data } else if field == "app" { @@ -265,17 +282,11 @@ func parseFormPart(part *multipart.Part, p *payload, reportDir string) error { p.Version = data } else if field == "user_agent" { p.UserAgent = data - } else if field == "log" || field == "compressed-log" { - // todo: we could save the log directly rather than pointlessly - // unzipping and re-zipping. - p.Logs = append(p.Logs, logEntry{ - ID: part.FileName(), - Lines: data, - }) + } else if field == "label" { + p.Labels = append(p.Labels, data) } else { p.Data[field] = data } - return nil } // we use a quite restrictive regexp for the filenames; in particular: @@ -326,6 +337,7 @@ func (s *submitServer) saveReport(ctx context.Context, p payload, reportDir, lis "%s\n\nNumber of logs: %d\nApplication: %s\nVersion: %s\nUser-Agent: %s\n", p.Text, len(p.Logs), p.AppName, p.Version, p.UserAgent, ) + fmt.Fprintf(&summaryBuf, "Labels: %s\n", strings.Join(p.Labels, ", ")) for k, v := range p.Data { fmt.Fprintf(&summaryBuf, "%s: %s\n", k, v) } @@ -405,8 +417,9 @@ func buildGithubIssueRequest(p payload, listingURL string) github.IssueRequest { body := bodyBuf.String() return github.IssueRequest{ - Title: &title, - Body: &body, + Title: &title, + Body: &body, + Labels: &p.Labels, } } diff --git a/src/github.com/matrix-org/rageshake/submit_test.go b/src/github.com/matrix-org/rageshake/submit_test.go index cc92910..669311a 100644 --- a/src/github.com/matrix-org/rageshake/submit_test.go +++ b/src/github.com/matrix-org/rageshake/submit_test.go @@ -139,6 +139,14 @@ Content-Disposition: form-data; name="user_agent" Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 ------WebKitFormBoundarySsdgl8Nq9voFyhdO +Content-Disposition: form-data; name="label" + +label1 +------WebKitFormBoundarySsdgl8Nq9voFyhdO +Content-Disposition: form-data; name="label" + +label2 +------WebKitFormBoundarySsdgl8Nq9voFyhdO Content-Disposition: form-data; name="test-field" Test data @@ -189,6 +197,10 @@ func checkParsedMultipartUpload(t *testing.T, p *payload) { if len(p.Data) != 1 { t.Errorf("Data length: got %d, want 1", len(p.Data)) } + wantedLabels := []string{"label1", "label2"} + if !stringSlicesEqual(p.Labels, wantedLabels) { + t.Errorf("Labels: got %v, want %v", p.Labels, wantedLabels) + } wanted = "Test data" if p.Data["test-field"] != wanted { t.Errorf("test-field: got %s, want %s", p.Data["test-field"], wanted) @@ -215,6 +227,19 @@ func checkParsedMultipartUpload(t *testing.T, p *payload) { } } +func stringSlicesEqual(got, want []string) bool { + if len(got) != len(want) { + return false + } + + for i := range got { + if got[i] != want[i] { + return false + } + } + return true +} + func TestEmptyFilename(t *testing.T) { body := `------WebKitFormBoundarySsdgl8Nq9voFyhdO Content-Disposition: form-data; name="file"