Skip to content

Commit

Permalink
Merge pull request #201 from michaelact/smtp/subject-template
Browse files Browse the repository at this point in the history
[SMTP] Customize Subject Email (by build template)
  • Loading branch information
prabenzom authored Sep 3, 2024
2 parents 6569f16 + 89522fa commit 5b080d6
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 14 deletions.
33 changes: 26 additions & 7 deletions smtp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import (
"bytes"
"context"
"fmt"
"html/template"
htmlTemplate "html/template"
textTemplate "text/template"
"mime/quotedprintable"
"net/smtp"
"strings"
Expand All @@ -41,15 +42,16 @@ func main() {

type smtpNotifier struct {
filter notifiers.EventFilter
tmpl *template.Template
htmlTmpl *htmlTemplate.Template
textTmpl *textTemplate.Template
mcfg mailConfig
br notifiers.BindingResolver
tmplView *notifiers.TemplateView
}

type mailConfig struct {
server, port, sender, from, password string
recipients []string
server, port, sender, from, password, subject string
recipients []string
}

func (s *smtpNotifier) SetUp(ctx context.Context, cfg *notifiers.Config, cfgTemplate string, sg notifiers.SecretGetter, br notifiers.BindingResolver) error {
Expand All @@ -58,11 +60,19 @@ func (s *smtpNotifier) SetUp(ctx context.Context, cfg *notifiers.Config, cfgTemp
return fmt.Errorf("failed to create CELPredicate: %w", err)
}
s.filter = prd
tmpl, err := template.New("email_template").Parse(cfgTemplate)
htmlTmpl, err := htmlTemplate.New("email_template").Parse(cfgTemplate)
if err != nil {
return fmt.Errorf("failed to parse HTML email template: %w", err)
}
s.tmpl = tmpl
s.htmlTmpl = htmlTmpl

if subject, subjectFound := cfg.Spec.Notification.Delivery["subject"]; subjectFound {
textTmpl, err := textTemplate.New("subject_template").Parse(subject.(string))
if err != nil {
return fmt.Errorf("failed to parse TEXT subject template: %w", err)
}
s.textTmpl = textTmpl
}

mcfg, err := getMailConfig(ctx, sg, cfg.Spec)
if err != nil {
Expand Down Expand Up @@ -175,11 +185,20 @@ func (s *smtpNotifier) buildEmail() (string, error) {
build.LogUrl = logURL

body := new(bytes.Buffer)
if err := s.tmpl.Execute(body, s.tmplView); err != nil {
if err := s.htmlTmpl.Execute(body, s.tmplView); err != nil {
return "", err
}

subject := fmt.Sprintf("Cloud Build [%s]: %s", build.ProjectId, build.Id)
if s.textTmpl != nil {
subjectTmpl := new(bytes.Buffer)
if err := s.textTmpl.Execute(subjectTmpl, s.tmplView); err != nil {
return "", err
}

// Escape any string formatter
subject = strings.Join(strings.Fields(subjectTmpl.String()), " ")
}

header := make(map[string]string)
if s.mcfg.from != s.mcfg.sender {
Expand Down
49 changes: 42 additions & 7 deletions smtp/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ const htmlBody = `<!doctype html>
</div>
<div class="card-content white">
<table class="bordered">
<tbody>
<tbody>
<tr>
<td>Status</td>
<td>{{.Params.buildStatus}}</td>
<td>Status</td>
<td>{{.Params.buildStatus}}</td>
</tr>
<tr>
<td>Log URL</td>
<td><a href="{{.Build.LogUrl}}">Click Here</a></td>
<td>Log URL</td>
<td><a href="{{.Build.LogUrl}}">Click Here</a></td>
</tr>
</tbody>
</tbody>
</table>
</div>
</div>
Expand All @@ -66,6 +66,8 @@ const htmlBody = `<!doctype html>
</div>
</html>`

const templateSubject = `Build {{.Build.Id}} Status: {{.Build.Status}}`

type fakeSecretGetter struct{}

func (f *fakeSecretGetter) GetSecret(_ context.Context, _ string) (string, error) {
Expand Down Expand Up @@ -147,7 +149,7 @@ metadata:
name: failed-build-email-notification
spec:
notification:
filter: event.buildTriggerStatus == STATUS_FAILED
filter: event.buildTriggerStatus == "STATUS_FAILED"
delivery:
server: smtp.example.com
port: '587'
Expand Down Expand Up @@ -194,6 +196,7 @@ func TestDefaultEmailTemplate(t *testing.T) {
if err != nil {
t.Fatalf("template.Parse failed: %v", err)
}

build := &cbpb.Build{
Id: "some-build-id",
ProjectId: "my-project-id",
Expand Down Expand Up @@ -226,3 +229,35 @@ func TestDefaultEmailTemplate(t *testing.T) {
t.Error("missing Log URL")
}
}

func TestSubjectEmailTemplate(t *testing.T) {
tmpl, err := template.New("subject_template").Parse(templateSubject)
if err != nil {
t.Fatalf("failed to parse subject template: %v", err)
}

build := &cbpb.Build{
Id: "some-build-id",
ProjectId: "my-project-id",
BuildTriggerId: "some-trigger-id",
Status: cbpb.Build_SUCCESS,
LogUrl: "https://some.example.com/log/url",
}

view := &notifiers.TemplateView{
Build: &notifiers.BuildView{
Build: build,
},
Params: map[string]string{"buildStatus": "SUCCESS"},
}

subject := new(bytes.Buffer)
if err := tmpl.Execute(subject, view); err != nil {
t.Fatalf("failed to execute subject template: %v", err)
}

expectedSubject := "Build some-build-id Status: SUCCESS"
if subject.String() != expectedSubject {
t.Errorf("expected subject %q, but got %q", expectedSubject, subject.String())
}
}
1 change: 1 addition & 0 deletions smtp/smtp.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ spec:
delivery:
server: smtp.gmail.com
port: '587'
subject: '{{ if eq .Build.Status 3 }}✅ Build Successful ({{ .Build.Substitutions.REPO_NAME }}){{ else }}❌ Build Failure ({{ .Build.Substitutions.REPO_NAME }}){{ end }} | {{ if .Build.Substitutions._COMMIT_MESSAGE }} {{ if gt (len .Build.Substitutions._COMMIT_MESSAGE) 100 }}{{ slice .Build.Substitutions._COMMIT_MESSAGE 0 100 }}{{ else }}{{ .Build.Substitutions._COMMIT_MESSAGE }}{{ end }}{{ else }}{{ .Build.Substitutions.COMMIT_SHA }}{{ end }} [...]'
sender: [email protected]
from: [email protected]
recipients:
Expand Down

0 comments on commit 5b080d6

Please sign in to comment.