From 3b5b19cc90533503eec999eb11d0068c43cb8958 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 12 Apr 2017 15:06:40 +0100 Subject: [PATCH] Make github issue a bit more useful (#7) * include the text from the report and other useful info * include a link to the report details * Pick github repo based on submitted app name --- README.md | 4 +- rageshake.yaml | 8 +++ src/github.com/matrix-org/rageshake/main.go | 24 ++++++++- src/github.com/matrix-org/rageshake/submit.go | 51 +++++++++++++++++-- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dfa7f73..082849b 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,9 @@ The body of the request should be a JSON object with the following fields: * `user_agent`: Application user-agent. Included in the `details.log.gz` file. -* `app`: Identifier for the application (eg 'riot-web'). +* `app`: Identifier for the application (eg 'riot-web'). Should correspond to a + mapping configured in the configuration file for github issue reporting to + work. * `version`: Application version. Included in the `details.log.gz` file. diff --git a/rageshake.yaml b/rageshake.yaml index bf15201..1891b07 100644 --- a/rageshake.yaml +++ b/rageshake.yaml @@ -4,7 +4,15 @@ listings_auth_user: alice listings_auth_pass: secret +# the external URL at which /api is accessible; it is used to add a link to the +# report to the GitHub issue. If unspecified, based on the listen address. +# api_prefix: https://riot.im/bugreports + # a GitHub personal access token (https://github.com/settings/tokens), which # will be used to create a GitHub issue for each report. It requires # `public_repo` scope. If omitted, no issues will be created. github_token: secrettoken + +# mappings from app name (as submitted in the API) to github repo for issue reporting. +github_project_mappings: + my-app: octocat/HelloWorld diff --git a/src/github.com/matrix-org/rageshake/main.go b/src/github.com/matrix-org/rageshake/main.go index 7bfab7f..01743eb 100644 --- a/src/github.com/matrix-org/rageshake/main.go +++ b/src/github.com/matrix-org/rageshake/main.go @@ -25,8 +25,11 @@ import ( "golang.org/x/oauth2" "io/ioutil" "log" + "net" "net/http" "os" + "strings" + "time" yaml "gopkg.in/yaml.v2" ) @@ -39,8 +42,13 @@ type config struct { BugsUser string `yaml:"listings_auth_user"` BugsPass string `yaml:"listings_auth_pass"` + // External URI to /api + APIPrefix string `yaml:"api_prefix"` + // A GitHub personal access token, to create a GitHub issue for each report. GithubToken string `yaml:"github_token"` + + GithubProjectMappings map[string]string `yaml:"github_project_mappings"` } func basicAuth(handler http.Handler, username, password, realm string) http.Handler { @@ -77,10 +85,24 @@ func main() { &oauth2.Token{AccessToken: cfg.GithubToken}, ) tc := oauth2.NewClient(ctx, ts) + tc.Timeout = time.Duration(5) * time.Minute ghClient = github.NewClient(tc) } - http.Handle("/api/submit", &submitServer{ghClient}) + apiPrefix := cfg.APIPrefix + if apiPrefix == "" { + _, port, err := net.SplitHostPort(*bindAddr) + if err != nil { + log.Fatal(err) + } + apiPrefix = fmt.Sprintf("http://localhost:%s/api", port) + } else { + // remove trailing / + apiPrefix = strings.TrimRight(apiPrefix, "/") + } + log.Printf("Using %s/listing as public URI", apiPrefix) + + http.Handle("/api/submit", &submitServer{ghClient, apiPrefix, cfg.GithubProjectMappings}) // Make sure bugs directory exists _ = os.Mkdir("bugs", os.ModePerm) diff --git a/src/github.com/matrix-org/rageshake/submit.go b/src/github.com/matrix-org/rageshake/submit.go index 58152dd..04442e0 100644 --- a/src/github.com/matrix-org/rageshake/submit.go +++ b/src/github.com/matrix-org/rageshake/submit.go @@ -29,6 +29,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "time" ) @@ -38,6 +39,12 @@ type submitServer struct { // github client for reporting bugs. may be nil, in which case, // reporting is disabled. ghClient *github.Client + + // External URI to /api + apiPrefix string + + // mappings from application to github owner/project + githubProjectMappings map[string]string } type payload struct { @@ -95,12 +102,17 @@ func (s *submitServer) saveReport(ctx context.Context, p payload) error { // "bugreport-20170115-112233-N.log.gz" => oldest log t := time.Now().UTC() prefix := t.Format("2006-01-02/150405") + listingURL := s.apiPrefix + "/listing/" + prefix + + log.Println("Handling report submission; listing URI will be %s", listingURL) + + userText := strings.TrimSpace(p.Text) var summaryBuf bytes.Buffer fmt.Fprintf( &summaryBuf, "%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, + userText, len(p.Logs), p.AppName, p.Version, p.UserAgent, ) for k, v := range p.Data { fmt.Fprintf(&summaryBuf, "%s: %s\n", k, v) @@ -117,15 +129,46 @@ func (s *submitServer) saveReport(ctx context.Context, p payload) error { if s.ghClient == nil { // we're done here + log.Println("GH issue submission disabled") return nil } // submit a github issue - owner := "richvdh" - repo := "test" - title := "Automated bug report" + + ghProj := s.githubProjectMappings[p.AppName] + if ghProj == "" { + log.Println("Not creating GH issue for unknown app", p.AppName) + return nil + } + splits := strings.SplitN(ghProj, "/", 2) + if len(splits) < 2 { + log.Println("Can't create GH issue for invalid repo", ghProj) + } + owner, repo := splits[0], splits[1] + + var title string + if userText == "" { + title = "Untitled report" + } else { + // set the title to the first line of the user's report + if i := strings.IndexAny(userText, "\r\n"); i < 0 { + title = userText + } else { + title = userText[0:i] + } + } + + body := fmt.Sprintf( + "User message:\n```\n%s\n```\nVersion: %s\n[Details](%s) / [Logs](%s)", + userText, + p.Version, + listingURL+"/details.log.gz", + listingURL, + ) + issueReq := github.IssueRequest{ Title: &title, + Body: &body, } issue, _, err := s.ghClient.Issues.Create(ctx, owner, repo, &issueReq)