Add support for Slack notifications

Signed-off-by: Manuel Stahl <manuel.stahl@awesome-technologies.de>
This commit is contained in:
Manuel Stahl 2019-03-07 14:42:08 +01:00
parent 93419b0c18
commit addce09400
4 changed files with 116 additions and 26 deletions

12
main.go
View file

@ -49,6 +49,8 @@ type config struct {
GithubToken string `yaml:"github_token"` GithubToken string `yaml:"github_token"`
GithubProjectMappings map[string]string `yaml:"github_project_mappings"` GithubProjectMappings map[string]string `yaml:"github_project_mappings"`
SlackWebhookURL string `yaml:"slack_webhook_url"`
} }
func basicAuth(handler http.Handler, username, password, realm string) http.Handler { func basicAuth(handler http.Handler, username, password, realm string) http.Handler {
@ -89,6 +91,14 @@ func main() {
ghClient = github.NewClient(tc) ghClient = github.NewClient(tc)
} }
var slack *slackClient
if cfg.SlackWebhookURL == "" {
fmt.Println("No slack_webhook_url configured. Reporting bugs to slack is disabled.")
} else {
slack = NewSlackClient(cfg.SlackWebhookURL)
}
apiPrefix := cfg.APIPrefix apiPrefix := cfg.APIPrefix
if apiPrefix == "" { if apiPrefix == "" {
_, port, err := net.SplitHostPort(*bindAddr) _, port, err := net.SplitHostPort(*bindAddr)
@ -102,7 +112,7 @@ func main() {
} }
log.Printf("Using %s/listing as public URI", apiPrefix) log.Printf("Using %s/listing as public URI", apiPrefix)
http.Handle("/api/submit", &submitServer{ghClient, apiPrefix, cfg.GithubProjectMappings}) http.Handle("/api/submit", &submitServer{ghClient, apiPrefix, cfg.GithubProjectMappings, slack})
// Make sure bugs directory exists // Make sure bugs directory exists
_ = os.Mkdir("bugs", os.ModePerm) _ = os.Mkdir("bugs", os.ModePerm)

View file

@ -16,3 +16,7 @@ github_token: secrettoken
# mappings from app name (as submitted in the API) to github repo for issue reporting. # mappings from app name (as submitted in the API) to github repo for issue reporting.
github_project_mappings: github_project_mappings:
my-app: octocat/HelloWorld my-app: octocat/HelloWorld
# a Slack personal webhook URL (https://api.slack.com/incoming-webhooks), which
# will be used to post a notification on Slack for each report.
slack_webhook_url: https://hooks.slack.com/services/TTTTTTT/XXXXXXXXXX/YYYYYYYYYYY

48
slack.go Normal file
View file

@ -0,0 +1,48 @@
package main
import (
"strings"
"fmt"
"net/http"
)
type slackClient struct {
webHook string
name string
face string
}
func NewSlackClient(webHook string) *slackClient {
return &slackClient{
webHook: webHook,
name: "Notifier",
face: "robot_face"}
}
func (slack *slackClient) Name(name string) {
slack.name = name
}
func (slack *slackClient) Face(face string) {
slack.face = face
}
func (slack slackClient) Notify(text string) error {
json := buildRequest(text, slack)
req, err := http.NewRequest("POST", slack.webHook, strings.NewReader(json))
if err != nil {
return fmt.Errorf("Can't connect to host %s: %s", slack.webHook, err.Error())
}
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
_, err = client.Do(req)
return err
}
func buildRequest(text string, slack slackClient) string {
return fmt.Sprintf(`{"text":"%s", "username": "%s", "icon_emoji": ":%s:"}`, text, slack.name, slack.face)
}

View file

@ -51,6 +51,8 @@ type submitServer struct {
// mappings from application to github owner/project // mappings from application to github owner/project
githubProjectMappings map[string]string githubProjectMappings map[string]string
slack *slackClient
} }
// the type of payload which can be uploaded as JSON to the submit endpoint // the type of payload which can be uploaded as JSON to the submit endpoint
@ -460,38 +462,64 @@ func (s *submitServer) saveReport(ctx context.Context, p parsedPayload, reportDi
return nil, err return nil, err
} }
if s.ghClient == nil { if err := s.submitGithubIssue(ctx, p, listingURL, &resp); err != nil {
// we're done here
log.Println("GH issue submission disabled")
return &resp, nil
}
// submit a github issue
ghProj := s.githubProjectMappings[p.AppName]
if ghProj == "" {
log.Println("Not creating GH issue for unknown app", p.AppName)
return &resp, 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]
issueReq := buildGithubIssueRequest(p, listingURL)
issue, _, err := s.ghClient.Issues.Create(ctx, owner, repo, &issueReq)
if err != nil {
return nil, err return nil, err
} }
log.Println("Created issue:", *issue.HTMLURL) if err := s.submitSlackNotification(p, listingURL); err != nil {
return nil, err
resp.ReportURL = *issue.HTMLURL }
return &resp, nil return &resp, nil
} }
func (s *submitServer) submitGithubIssue(ctx context.Context, p parsedPayload, listingURL string, resp *submitResponse) error {
if s.ghClient == nil {
log.Println("GH issue submission disabled")
} else {
// submit a github issue
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]
issueReq := buildGithubIssueRequest(p, listingURL)
issue, _, err := s.ghClient.Issues.Create(ctx, owner, repo, &issueReq)
if err != nil {
return err
}
log.Println("Created issue:", *issue.HTMLURL)
resp.ReportURL = *issue.HTMLURL
}
return nil
}
func (s *submitServer) submitSlackNotification(p parsedPayload, listingURL string) error {
if s.slack == nil {
log.Println("Slack notifications disabled")
} else {
slackBuf := fmt.Sprintf(
"%s\nApplication: %s\nReport: %s",
p.UserText, p.AppName, listingURL,
)
err := s.slack.Notify(slackBuf)
if err != nil {
return err
}
}
return nil
}
func buildGithubIssueRequest(p parsedPayload, listingURL string) github.IssueRequest { func buildGithubIssueRequest(p parsedPayload, listingURL string) github.IssueRequest {
// set the title to the first (non-empty) line of the user's report, if any // set the title to the first (non-empty) line of the user's report, if any
var title string var title string