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

Fix #10 support conditional notification based on matching parse exitcode #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ notifier:
repository:
owner: "mercari"
name: "tfnotify"
filters:
parse_exit_code: 1
terraform:
fmt:
template: |
Expand Down Expand Up @@ -133,6 +135,8 @@ notifier:
token: $SLACK_TOKEN
channel: $SLACK_CHANNEL_ID
bot: $SLACK_BOT_NAME
filters:
parse_exit_code: 1
terraform:
plan:
template: |
Expand Down
18 changes: 15 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Notifier struct {
type GithubNotifier struct {
Token string `yaml:"token"`
Repository Repository `yaml:"repository"`
Filters *Filters `yaml:"filters"`
}

// Repository represents a GitHub repository
Expand All @@ -39,9 +40,15 @@ type Repository struct {

// SlackNotifier is a notifier for Slack
type SlackNotifier struct {
Token string `yaml:"token"`
Channel string `yaml:"channel"`
Bot string `yaml:"bot"`
Token string `yaml:"token"`
Channel string `yaml:"channel"`
Bot string `yaml:"bot"`
Filters *Filters `yaml:"filters"`
}

// Filters is conditions for notification
type Filters struct {
ParseExitCode int `yaml:"parse_exit_code"`
}

// Terraform represents terraform configurations
Expand Down Expand Up @@ -157,3 +164,8 @@ func (cfg *Config) Find(file string) (string, error) {
}
return "", errors.New("config for tfnotify is not found at all")
}

// Match returns terraform result matches conditions or not
func (filters *Filters) Match(exitCode int) bool {
return filters == nil || exitCode == filters.ParseExitCode
}
34 changes: 34 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,37 @@ func TestFind(t *testing.T) {
}
}
}

func TestFiltersMatch(t *testing.T) {
testCases := []struct {
filters *Filters
exitCode int
expect bool
}{
{
nil,
1,
true,
},
{
&Filters{
ParseExitCode: 1,
},
1,
true,
},
{
&Filters{
ParseExitCode: 1,
},
0,
false,
},
}
for _, testCase := range testCases {
actual := testCase.filters.Match(testCase.exitCode)
if actual != testCase.expect {
t.Errorf("got %t but want %t", actual, testCase.expect)
}
}
}
7 changes: 7 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"fmt"
"os"

"github.com/mercari/tfnotify/notifier"
)

// Exit codes are int values for the exit code that shell interpreter can interpret
Expand Down Expand Up @@ -57,6 +59,11 @@ func HandleExit(err error) int {
return ExitCodeOK
}

// Ignore nop
if err == notifier.ErrNop {
return ExitCodeOK
}

if exitErr, ok := err.(ExitCoder); ok {
if err.Error() != "" {
if _, ok := exitErr.(ErrorFormatter); ok {
Expand Down
6 changes: 6 additions & 0 deletions error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"errors"
"testing"

"github.com/mercari/tfnotify/notifier"
)

func TestHandleError(t *testing.T) {
Expand Down Expand Up @@ -34,6 +36,10 @@ func TestHandleError(t *testing.T) {
err: nil,
exitCode: 0,
},
{
err: notifier.ErrNop,
exitCode: 0,
},
}

for _, testCase := range testCases {
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func (t *tfnotify) Run() error {
CI: ci.URL,
Parser: t.parser,
Template: t.template,
Filters: t.config.Notifier.Github.Filters,
})
if err != nil {
return err
Expand All @@ -87,6 +88,7 @@ func (t *tfnotify) Run() error {
CI: ci.URL,
Parser: t.parser,
Template: t.template,
Filters: t.config.Notifier.Slack.Filters,
})
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions notifier/github/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/google/go-github/github"
"github.com/mercari/tfnotify/config"
"github.com/mercari/tfnotify/terraform"
"golang.org/x/oauth2"
)
Expand Down Expand Up @@ -38,6 +39,7 @@ type Config struct {
CI string
Parser terraform.Parser
Template terraform.Template
Filters *config.Filters
}

// PullRequest represents GitHub Pull Request metadata
Expand Down
6 changes: 6 additions & 0 deletions notifier/github/notify.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github

import (
"github.com/mercari/tfnotify/notifier"
"github.com/mercari/tfnotify/terraform"
)

Expand All @@ -13,6 +14,7 @@ func (g *NotifyService) Notify(body string) (exit int, err error) {
cfg := g.client.Config
parser := g.client.Config.Parser
template := g.client.Config.Template
filters := g.client.Config.Filters

result := parser.Parse(body)
if result.Error != nil {
Expand All @@ -22,6 +24,10 @@ func (g *NotifyService) Notify(body string) (exit int, err error) {
return result.ExitCode, result.Error
}

if !filters.Match(result.ExitCode) {
return result.ExitCode, notifier.ErrNop
}

template.SetValue(terraform.CommonTemplate{
Message: cfg.PR.Message,
Result: result.Result,
Expand Down
28 changes: 28 additions & 0 deletions notifier/github/notify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package github
import (
"testing"

"github.com/mercari/tfnotify/config"
"github.com/mercari/tfnotify/terraform"
)

Expand All @@ -26,6 +27,7 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "body",
ok: false,
Expand All @@ -44,6 +46,7 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Plan: 1 to add",
ok: false,
Expand All @@ -62,6 +65,7 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Error: hoge",
ok: true,
Expand All @@ -80,6 +84,7 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Plan: 1 to add",
ok: true,
Expand All @@ -98,11 +103,33 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Plan: 1 to add",
ok: true,
exitCode: 0,
},
{
// valid, filter mismatch
config: Config{
Token: "token",
Owner: "owner",
Repo: "repo",
PR: PullRequest{
Revision: "",
Number: 1,
Message: "message",
},
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: &config.Filters{
ParseExitCode: 1,
},
},
body: "Plan: 1 to add", // ParseExitCode is 0
ok: false, // nop
exitCode: 0,
},
{
// apply case
config: Config{
Expand All @@ -116,6 +143,7 @@ func TestNotifyNotify(t *testing.T) {
},
Parser: terraform.NewApplyParser(),
Template: terraform.NewApplyTemplate(terraform.DefaultApplyTemplate),
Filters: nil,
},
body: "Apply complete!",
ok: true,
Expand Down
8 changes: 8 additions & 0 deletions notifier/notifier.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package notifier

import (
"errors"
)

var (
ErrNop = errors.New("notification wasn't operated")
)

// Notifier is a notification interface
type Notifier interface {
Notify(body string) (exit int, err error)
Expand Down
4 changes: 3 additions & 1 deletion notifier/slack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"os"
"strings"

"github.com/mercari/tfnotify/terraform"
"github.com/lestrrat-go/slack"
"github.com/mercari/tfnotify/config"
"github.com/mercari/tfnotify/terraform"
)

// EnvToken is Slack API Token
Expand Down Expand Up @@ -34,6 +35,7 @@ type Config struct {
CI string
Parser terraform.Parser
Template terraform.Template
Filters *config.Filters
}

type service struct {
Expand Down
8 changes: 7 additions & 1 deletion notifier/slack/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import (
"context"
"errors"

"github.com/mercari/tfnotify/terraform"
"github.com/lestrrat-go/slack/objects"
"github.com/mercari/tfnotify/notifier"
"github.com/mercari/tfnotify/terraform"
)

// NotifyService handles communication with the notification related
Expand All @@ -17,6 +18,7 @@ func (s *NotifyService) Notify(body string) (exit int, err error) {
cfg := s.client.Config
parser := s.client.Config.Parser
template := s.client.Config.Template
filters := s.client.Config.Filters

if cfg.Channel == "" {
return terraform.ExitFail, errors.New("channel id is required")
Expand All @@ -30,6 +32,10 @@ func (s *NotifyService) Notify(body string) (exit int, err error) {
return result.ExitCode, result.Error
}

if !filters.Match(result.ExitCode) {
return result.ExitCode, notifier.ErrNop
}

color := "warning"
switch result.ExitCode {
case terraform.ExitPass:
Expand Down
21 changes: 20 additions & 1 deletion notifier/slack/notify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import (
"context"
"testing"

"github.com/mercari/tfnotify/terraform"
"github.com/lestrrat-go/slack/objects"
"github.com/mercari/tfnotify/config"
"github.com/mercari/tfnotify/terraform"
)

func TestNotify(t *testing.T) {
Expand All @@ -23,6 +24,7 @@ func TestNotify(t *testing.T) {
Message: "",
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Plan: 1 to add",
exitCode: 0,
Expand All @@ -36,11 +38,28 @@ func TestNotify(t *testing.T) {
Message: "",
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: nil,
},
body: "Plan: 1 to add",
exitCode: 1,
ok: false,
},
{
config: Config{
Token: "token",
Channel: "channel",
Botname: "botname",
Message: "",
Parser: terraform.NewPlanParser(),
Template: terraform.NewPlanTemplate(terraform.DefaultPlanTemplate),
Filters: &config.Filters{
ParseExitCode: 1,
},
},
body: "Plan: 1 to add", // ParseExitCode is 0
exitCode: 0,
ok: false, // nop
},
}
fake := fakeAPI{
FakeChatPostMessage: func(ctx context.Context, attachments []*objects.Attachment) (*objects.ChatResponse, error) {
Expand Down