Skip to content

Commit

Permalink
It works with gitlab MRs
Browse files Browse the repository at this point in the history
  • Loading branch information
pcarranza committed Sep 22, 2018
1 parent 1873bf7 commit 62351c0
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 35 deletions.
66 changes: 66 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions core/propaganda.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package core

// Announcement represents a message to be shouted out
type Announcement interface {
Title() string
Text() string
URL() string
ShouldAnnounce() bool
ProjectName() string
}
Expand Down
2 changes: 1 addition & 1 deletion gitlab/fixtures/gitlab-mr-close-no-merge.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"target_branch": "master",
"target_project_id": 13,
"time_estimate": 0,
"title": "Update README.md",
"title": "[announce] Update README.md",
"updated_at": "2018-09-19 20:48:28 UTC",
"updated_by_id": null,
"url": "https://git.yakshaving.art/pablo/testing-webhooks/merge_requests/2",
Expand Down
33 changes: 18 additions & 15 deletions gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,43 @@ package gitlab
// "Content-Type":[]string{"application/json"},

import (
"encoding/json"
"fmt"
"strings"

"encoding/json"

"gitlab.com/yakshaving.art/propaganda/core"
)

// Parser implements the core.Parser type for GitLab merge webhooks
type Parser struct {
MatchString string
}

// Match indicates that the headers match with the kind of request
func (Parser) Match(headers map[string][]string) bool {
if _, ok := headers["X-Gitlab-Event"]; ok {
return true
if event, ok := headers["X-Gitlab-Event"]; ok {
if len(event) != 1 {
return false
}
return event[0] == "Merge Request Hook"
}
return false
}

// Parse creates a new merge request object from the passed payload
func (Parser) Parse(payload []byte) (core.Announcement, error) {
func (p Parser) Parse(payload []byte) (core.Announcement, error) {
var mr MergeRequest
if err := json.Unmarshal(payload, &mr); err != nil {
return mr, fmt.Errorf("could not parse json payload: %s", err)
}
if mr.Kind != "merge_request" {
return MergeRequest{}, fmt.Errorf("json payload is not a merge request but a %s", mr.Kind)
}
if !strings.HasPrefix(mr.Attributes.Title, p.MatchString) {
return MergeRequest{}, fmt.Errorf("MR title '%s' is not annouceable", mr.Attributes.Title)
}
mr.Attributes.Title = strings.TrimSpace(mr.Attributes.Title[len(p.MatchString):])
return mr, nil
}

Expand All @@ -48,19 +58,12 @@ type MergeRequest struct {
Attributes Attributes `json:"object_attributes"`
}

// Title implements Annoucement
func (m MergeRequest) Title() string {
return m.Attributes.Title
}

// Text implements Annoucement
func (m MergeRequest) Text() string {
return ""
}

// URL implements Annoucement
func (m MergeRequest) URL() string {
return m.Attributes.URL
return fmt.Sprintf("*%s*\n\n%s\n\n*URL:* %s",
m.Attributes.Title,
m.Attributes.Description,
m.Attributes.URL)
}

// ShouldAnnounce implements Announcement
Expand Down
10 changes: 5 additions & 5 deletions gitlab/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
)

func TestParsingPayloads(t *testing.T) {
parser := gitlab.Parser{}
parser := gitlab.Parser{
MatchString: "[announce]",
}
tt := []struct {
name string
jsonFilename string
Expand All @@ -26,7 +28,7 @@ func TestParsingPayloads(t *testing.T) {
},
Attributes: gitlab.Attributes{
State: "opened",
Title: "[announce] Update README.md",
Title: "Update README.md",
Description: "Something in the description",
URL: "https://git.yakshaving.art/pablo/testing-webhooks/merge_requests/1",
Action: "open",
Expand All @@ -44,7 +46,7 @@ func TestParsingPayloads(t *testing.T) {
},
Attributes: gitlab.Attributes{
State: "merged",
Title: "[announce] Update README.md",
Title: "Update README.md",
Description: "Something in the description",
URL: "https://git.yakshaving.art/pablo/testing-webhooks/merge_requests/1",
Action: "merge",
Expand Down Expand Up @@ -84,9 +86,7 @@ func TestParsingPayloads(t *testing.T) {

a.EqualValuesf(tc.expected, mr, "parsed merge request is not as expected")

a.Equal(tc.expected.Title(), mr.Title())
a.Equal(tc.expected.Text(), mr.Text())
a.Equal(tc.expected.URL(), mr.URL())
a.Equal(tc.expected.ProjectName(), mr.ProjectName())
a.Equal(tc.shouldAnnounce, mr.ShouldAnnounce())
})
Expand Down
16 changes: 14 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"flag"
"os"

"gitlab.com/yakshaving.art/propaganda/core"
"gitlab.com/yakshaving.art/propaganda/gitlab"
Expand All @@ -21,9 +22,13 @@ func main() {
metrics.Register(args.MetricsPath)

s := server.New(
slack.Announcer{},
slack.Announcer{
WebhookURL: args.WebhookURL,
},
[]core.Parser{
gitlab.Parser{},
gitlab.Parser{
MatchString: "[announce]",
},
})

logrus.Fatal(s.ListenAndServe(args.Address))
Expand All @@ -41,14 +46,21 @@ func setupLogger() {
type Args struct {
Address string
MetricsPath string

WebhookURL string
}

func parseArgs() Args {
var args Args

flag.StringVar(&args.Address, "address", ":9092", "listening address")
flag.StringVar(&args.MetricsPath, "metrics", "/metrics", "metrics path")
flag.StringVar(&args.WebhookURL, "webhook-url", os.Getenv("SLACK_WEBHOOK_URL"), "slack webhook url")
flag.Parse()

if args.WebhookURL == "" {
logrus.Fatalf("No slack webhook url, define it through -webhook-url argument or SLACK_WEBHOOK_URL env var")
}

return args
}
16 changes: 12 additions & 4 deletions metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ var (
Name: "valid_total",
Help: "total number of valid webhooks",
}, []string{"project"})
AnnouncementSuccesses = prometheus.NewCounter(prometheus.CounterOpts{
AnnouncementSuccesses = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "announcer",
Name: "success_total",
Help: "total number of announcement successes",
})
AnnouncementErrors = prometheus.NewCounter(prometheus.CounterOpts{
}, []string{"project"})
AnnouncementErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: namespace,
Subsystem: "announcer",
Name: "errors_total",
Help: "total number of announcement errors",
})
}, []string{"status"})
)

// Register registers all the metrics and sets the http handler
Expand All @@ -71,6 +71,14 @@ func Register(metricsPath string) {
Up.Set(0)

prometheus.MustRegister(bootTime)
prometheus.MustRegister(Up)
prometheus.MustRegister(WebhooksReceived)
prometheus.MustRegister(WebhooksBytesRead)
prometheus.MustRegister(WebhooksErrors)
prometheus.MustRegister(WebhooksInvalid)
prometheus.MustRegister(WebhooksValid)
prometheus.MustRegister(AnnouncementSuccesses)
prometheus.MustRegister(AnnouncementErrors)

http.Handle(metricsPath, prometheus.Handler())
}
7 changes: 2 additions & 5 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,15 @@ func (s Server) handle(w http.ResponseWriter, r *http.Request) {

metrics.WebhooksValid.WithLabelValues(a.ProjectName()).Inc()

logrus.Debugf("announcing webhook %#v", a)
s.announcer.Announce(a)

w.WriteHeader(http.StatusAccepted)
logrus.Debugf("received Webhook\nHeaders: %#v\nPayload: %s", r.Header, string(body))
// logrus.Debugf("received Webhook\nHeaders: %#v\nPayload: %s", r.Header, string(body))
return
}
}

metrics.WebhooksInvalid.WithLabelValues("no_parser").Inc()
http.Error(w, fmt.Sprintf("No parser defined for this hook"), http.StatusUnprocessableEntity)
}

func (s Server) process(a core.Announcement) {

}
Loading

0 comments on commit 62351c0

Please sign in to comment.