Skip to content

Commit

Permalink
Add bindings/templating to the Slack Notifier (#134)
Browse files Browse the repository at this point in the history
* add bindings/templating to the Slack Notifier
  • Loading branch information
Aric1088 committed Jun 1, 2022
1 parent 140b8ad commit b0668da
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 35 deletions.
61 changes: 38 additions & 23 deletions slack/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
package main

import (
"bytes"
"context"
"fmt"
"text/template"

"github.com/GoogleCloudPlatform/cloud-build-notifiers/lib/notifiers"
log "github.com/golang/glog"
Expand All @@ -35,12 +37,14 @@ func main() {
}

type slackNotifier struct {
filter notifiers.EventFilter

filter notifiers.EventFilter
tmpl *template.Template
webhookURL string
br notifiers.BindingResolver
tmplView *notifiers.TemplateView
}

func (s *slackNotifier) SetUp(ctx context.Context, cfg *notifiers.Config, _ string, sg notifiers.SecretGetter, _ notifiers.BindingResolver) error {
func (s *slackNotifier) SetUp(ctx context.Context, cfg *notifiers.Config, blockKitTemplate string, sg notifiers.SecretGetter, br notifiers.BindingResolver) error {
prd, err := notifiers.MakeCELPredicate(cfg.Spec.Notification.Filter)
if err != nil {
return fmt.Errorf("failed to make a CEL predicate: %w", err)
Expand All @@ -60,32 +64,47 @@ func (s *slackNotifier) SetUp(ctx context.Context, cfg *notifiers.Config, _ stri
return fmt.Errorf("failed to get token secret: %w", err)
}
s.webhookURL = wu
tmpl, err := template.New("blockkit_template").Parse(blockKitTemplate)
s.tmpl = tmpl
s.br = br

return nil
}

func (s *slackNotifier) SendNotification(ctx context.Context, build *cbpb.Build) error {

if !s.filter.Apply(ctx, build) {
return nil
}

log.Infof("sending Slack webhook for Build %q (status: %q)", build.Id, build.Status)
msg, err := s.writeMessage(build)

bindings, err := s.br.Resolve(ctx, nil, build)
if err != nil {
return fmt.Errorf("failed to resolve bindings: %w", err)
}

s.tmplView = &notifiers.TemplateView{
Build: &notifiers.BuildView{Build: build},
Params: bindings,
}

msg, err := s.writeMessage()

if err != nil {
return fmt.Errorf("failed to write Slack message: %w", err)
}

return slack.PostWebhook(s.webhookURL, msg)
}

func (s *slackNotifier) writeMessage(build *cbpb.Build) (*slack.WebhookMessage, error) {
txt := fmt.Sprintf(
"Cloud Build (%s, %s): %s",
build.ProjectId,
build.Id,
build.Status,
)
func (s *slackNotifier) writeMessage() (*slack.WebhookMessage, error) {
build := s.tmplView.Build
_, err := notifiers.AddUTMParams(build.LogUrl, notifiers.ChatMedium)

if err != nil {
return nil, fmt.Errorf("failed to add UTM params: %w", err)
}
var clr string
switch build.Status {
case cbpb.Build_SUCCESS:
Expand All @@ -96,20 +115,16 @@ func (s *slackNotifier) writeMessage(build *cbpb.Build) (*slack.WebhookMessage,
clr = "warning"
}

logURL, err := notifiers.AddUTMParams(build.LogUrl, notifiers.ChatMedium)
if err != nil {
return nil, fmt.Errorf("failed to add UTM params: %w", err)
var buf bytes.Buffer
if err := s.tmpl.Execute(&buf, s.tmplView); err != nil {
return nil, err
}
var blocks slack.Blocks

atch := slack.Attachment{
Text: txt,
Color: clr,
Actions: []slack.AttachmentAction{{
Text: "View Logs",
Type: "button",
URL: logURL,
}},
err = blocks.UnmarshalJSON(buf.Bytes())
if err != nil {
return nil, fmt.Errorf("failed to unmarshal templating JSON: %w", err)
}

return &slack.WebhookMessage{Attachments: []slack.Attachment{atch}}, nil
return &slack.WebhookMessage{Attachments: []slack.Attachment{{Color: clr}}, Blocks: &blocks}, nil
}
82 changes: 70 additions & 12 deletions slack/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,94 @@ package main

import (
"testing"
"text/template"

"github.com/GoogleCloudPlatform/cloud-build-notifiers/lib/notifiers"
"github.com/google/go-cmp/cmp"
"github.com/slack-go/slack"
cbpb "google.golang.org/genproto/googleapis/devtools/cloudbuild/v1"
)

func TestWriteMessage(t *testing.T) {
n := new(slackNotifier)
b := &cbpb.Build{

blockKitTemplate := `[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Build Status: {{.Build.Status}}"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "View Build Logs"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Logs"
},
"value": "click_me_123",
"url": "{{.Build.LogUrl}}",
"action_id": "button-action"
}
}
]`

tmpl, err := template.New("blockkit_template").Parse(blockKitTemplate)
if err != nil {
t.Fatalf("failed to parse template: %v", err)
}
n.tmpl = tmpl
n.tmplView = &notifiers.TemplateView{Build: &notifiers.BuildView{Build: &cbpb.Build{
ProjectId: "my-project-id",
Id: "some-build-id",
Status: cbpb.Build_SUCCESS,
LogUrl: "https://some.example.com/log/url?foo=bar",
}
}}}

got, err := n.writeMessage(b)
got, err := n.writeMessage()
if err != nil {
t.Fatalf("writeMessage failed: %v", err)
}

want := &slack.WebhookMessage{
Attachments: []slack.Attachment{{
Text: "Cloud Build (my-project-id, some-build-id): SUCCESS",
Color: "good",
Actions: []slack.AttachmentAction{{
Text: "View Logs",
Type: "button",
URL: "https://some.example.com/log/url?foo=bar&utm_campaign=google-cloud-build-notifiers&utm_medium=chat&utm_source=google-cloud-build",
}},
}},
Attachments: []slack.Attachment{{Color: "good"}},
Blocks: &slack.Blocks{
BlockSet: []slack.Block{
&slack.SectionBlock{
Type: "section",
Text: &slack.TextBlockObject{
Type: "mrkdwn",
Text: "Build Status: SUCCESS",
},
},
&slack.DividerBlock{
Type: "divider",
},
&slack.SectionBlock{
Type: "section",
Text: &slack.TextBlockObject{
Type: "mrkdwn",
Text: "View Build Logs",
},
Accessory: &slack.Accessory{ButtonElement: &slack.ButtonBlockElement{
Type: "button",
Text: &slack.TextBlockObject{Type: "plain_text", Text: "Logs"},
ActionID: "button-action",
URL: "https://some.example.com/log/url?foo=bar",
Value: "click_me_123",
}},
},
},
},
}

if diff := cmp.Diff(got, want); diff != "" {
Expand Down
30 changes: 30 additions & 0 deletions slack/slack.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Cloud Build {{.Build.ProjectId}} {{.Build.Id}} {{.Build.Status}}"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "View Build Logs"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Logs"
},
"value": "click_me_123",
"url": "{{.Build.LogUrl}}",
"action_id": "button-action"
}
}
]

0 comments on commit b0668da

Please sign in to comment.