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
This commit is contained in:
parent
112158fd47
commit
3b5b19cc90
4 changed files with 81 additions and 6 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Reference in a new issue