Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Slack notifications #28

Merged
merged 1 commit into from
Aug 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type config struct {
GithubToken string `yaml:"github_token"`

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 {
Expand Down Expand Up @@ -89,6 +91,14 @@ func main() {
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
if apiPrefix == "" {
_, port, err := net.SplitHostPort(*bindAddr)
Expand All @@ -102,7 +112,7 @@ func main() {
}
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
_ = os.Mkdir("bugs", os.ModePerm)
Expand Down
4 changes: 4 additions & 0 deletions rageshake.sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ 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

# 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 changes: 48 additions & 0 deletions slack.go
Original file line number Diff line number Diff line change
@@ -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)
}
72 changes: 50 additions & 22 deletions submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type submitServer struct {

// mappings from application to github owner/project
githubProjectMappings map[string]string

slack *slackClient
}

// the type of payload which can be uploaded as JSON to the submit endpoint
Expand Down Expand Up @@ -460,36 +462,62 @@ func (s *submitServer) saveReport(ctx context.Context, p parsedPayload, reportDi
return nil, err
}

if s.ghClient == nil {
// we're done here
log.Println("GH issue submission disabled")
return &resp, nil
if err := s.submitGithubIssue(ctx, p, listingURL, &resp); err != nil {
return nil, err
}

// 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)
if err := s.submitSlackNotification(p, listingURL); err != nil {
return nil, err
}
owner, repo := splits[0], splits[1]

issueReq := buildGithubIssueRequest(p, listingURL)
return &resp, nil
}

issue, _, err := s.ghClient.Issues.Create(ctx, owner, repo, &issueReq)
if err != nil {
return nil, err
}
func (s *submitServer) submitGithubIssue(ctx context.Context, p parsedPayload, listingURL string, resp *submitResponse) error {
if s.ghClient == nil {
log.Println("GH issue submission disabled")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record: generally I prefer an early return to lots of else statements (hence return nil here), though I'm aware of counterarguments to it.

} 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]

log.Println("Created issue:", *issue.HTMLURL)
issueReq := buildGithubIssueRequest(p, listingURL)

resp.ReportURL = *issue.HTMLURL
issue, _, err := s.ghClient.Issues.Create(ctx, owner, repo, &issueReq)
if err != nil {
return err
}

return &resp, nil
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 {
Expand Down