Skip to content

Commit

Permalink
Support Slack Incoming webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
sue445 committed Nov 20, 2017
1 parent fbcebcf commit fbc14b9
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 22 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CHATWORK_API_TOKEN=
CHATWORK_ROOM_ID=
SLACK_API_TOKEN=
SLACK_WEBHOOK_URL=
SLACK_USER_NAME=zatsu_monitor
SLACK_CHANNEL=general
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ Usage of ./zatsu_monitor:
google:
type: slack
check_url: "https://www.google.com/"

api_token: "AAAAAAAA"
# or
# webhook_url: "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX"

channel: "#general"
user_name: "zatsu_monitor"
# check_only_top_of_status_code: true
Expand All @@ -60,7 +64,9 @@ github:
#### [Slack](https://slack.com/)
* `type` : *slack* (fixed value)
* `check_url` : URL for checking (required)
* `api_token` : Slack API Token (required)
* `api_token` : Slack API Token (either `api_token` or `webhook_url` is required)
* `webhook_url` : Slack Incoming Webhook URL (either `api_token` or `webhook_url` is required)
* https://slack.com/apps/A0F7XDUAZ-incoming-webhooks
* `channel` : Channel for post (required)
* `user_name` : Name for post (optional. default is *zatsu_monitor*)

Expand All @@ -80,7 +86,10 @@ github:
slack: &common
type: slack
channel: "#general"

api_token: "xoxp-0000000000-0000000000-0000000000-000000"
# or
# webhook_url: "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX"

github:
# inherit common values
Expand Down
6 changes: 6 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ func TestLoadConfigFromData(t *testing.T) {
check_url: "http://example.com/1"
type: slack
api_token: "xoxp-0000000000-0000000000-0000000000-000000"
webhook_url: "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX"
user_name: "zatsu_monitor"
channel: "#general"
name2:
Expand All @@ -25,6 +26,7 @@ name2:
assert.Equal(t, "http://example.com/1", config["name1"]["check_url"])
assert.Equal(t, "slack", config["name1"]["type"])
assert.Equal(t, "xoxp-0000000000-0000000000-0000000000-000000", config["name1"]["api_token"])
assert.Equal(t, "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX", config["name1"]["webhook_url"])
assert.Equal(t, "zatsu_monitor", config["name1"]["user_name"])
assert.Equal(t, "#general", config["name1"]["channel"])

Expand All @@ -39,6 +41,7 @@ func TestLoadConfigFromData2(t *testing.T) {
check_url: "http://example.com/1"
type: slack
api_token: "xoxp-0000000000-0000000000-0000000000-000000"
webhook_url: "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX"
user_name: "zatsu_monitor"
channel: "#general"
name2:
Expand All @@ -52,12 +55,14 @@ name2:
assert.Equal(t, "http://example.com/1", config["name1"]["check_url"])
assert.Equal(t, "slack", config["name1"]["type"])
assert.Equal(t, "xoxp-0000000000-0000000000-0000000000-000000", config["name1"]["api_token"])
assert.Equal(t, "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX", config["name1"]["webhook_url"])
assert.Equal(t, "zatsu_monitor", config["name1"]["user_name"])
assert.Equal(t, "#general", config["name1"]["channel"])

assert.Equal(t, "http://example.com/1", config["name2"]["check_url"])
assert.Equal(t, "slack", config["name2"]["type"])
assert.Equal(t, "xoxp-0000000000-0000000000-0000000000-000000", config["name2"]["api_token"])
assert.Equal(t, "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX", config["name2"]["webhook_url"])
assert.Equal(t, "zatsu_monitor", config["name2"]["user_name"])
assert.Equal(t, "#random", config["name2"]["channel"])
}
Expand All @@ -70,6 +75,7 @@ func TestLoadConfigFromFile(t *testing.T) {
assert.Equal(t, "http://example.com/1", config["name1"]["check_url"])
assert.Equal(t, "slack", config["name1"]["type"])
assert.Equal(t, "xoxp-0000000000-0000000000-0000000000-000000", config["name1"]["api_token"])
assert.Equal(t, "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX", config["name1"]["webhook_url"])
assert.Equal(t, "zatsu_monitor", config["name1"]["user_name"])
assert.Equal(t, "#general", config["name1"]["channel"])
assert.Equal(t, "", config["name1"]["check_only_top_of_status_code"])
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func perform(name string, values map[string]string) {
case "chatwork":
notifier = NewChatworkNotifier(values["api_token"], values["room_id"])
case "slack":
notifier = NewSlackNotifier(values["api_token"], values["user_name"], values["channel"])
notifier = NewSlackNotifier(values["api_token"], values["webhook_url"], values["user_name"], values["channel"])
default:
panic(fmt.Sprintf("Unknown type: %s in %s", notifierType, configFile))
}
Expand Down
39 changes: 28 additions & 11 deletions slack_notifier.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
package main

import (
"errors"
"fmt"
"github.com/bluele/slack"
)

var slackExpectedKeys = []string{"type", "check_url", "api_token", "channel"}
var slackExpectedKeys = []string{"type", "api_token", "channel"}

// SlackNotifier represents notifier for Slack
type SlackNotifier struct {
apiToken string
userName string
channel string
apiToken string
webhookURL string
userName string
channel string
}

// NewSlackNotifier create new SlackNotifier instance
func NewSlackNotifier(apiToken string, userName string, channel string) *SlackNotifier {
func NewSlackNotifier(apiToken string, webhookURL string, userName string, channel string) *SlackNotifier {
s := new(SlackNotifier)
s.apiToken = apiToken
s.webhookURL = webhookURL
s.channel = channel

if len(userName) == 0 {
Expand Down Expand Up @@ -59,13 +62,27 @@ responseTime: %f sec`
message += fmt.Sprintf("\nhttpError: %v", param.HTTPError)
}

params := slack.ChatPostMessageOpt{}
params.Username = userName
params.IconEmoji = iconEmoji
if len(s.apiToken) > 0 {
params := slack.ChatPostMessageOpt{
Username: userName,
IconEmoji: iconEmoji,
}

api := slack.New(s.apiToken)
api := slack.New(s.apiToken)

err := api.ChatPostMessage(s.channel, message, &params)
return api.ChatPostMessage(s.channel, message, &params)

return err
} else if len(s.webhookURL) > 0 {
hook := slack.NewWebHook(s.webhookURL)
params := slack.WebHookPostPayload{
Text: message,
Channel: s.channel,
Username: userName,
IconEmoji: iconEmoji,
}
return hook.PostMessage(&params)

} else {
return errors.New("Either `api_token` or `webhook_url` is required")
}
}
104 changes: 95 additions & 9 deletions slack_notifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,44 @@ import (
"testing"
)

func NewTestSlackNotifier() *SlackNotifier {
type SlackNotifierMode int

const (
WithAPIToken = iota
WithWebhookURL
Nothing
)

func NewTestSlackNotifier(mode SlackNotifierMode) *SlackNotifier {
godotenv.Load()

apiToken := os.Getenv("SLACK_API_TOKEN")
webhookURL := os.Getenv("SLACK_WEBHOOK_URL")
userName := os.Getenv("SLACK_USER_NAME")
channel := os.Getenv("SLACK_CHANNEL")

if len(userName) == 0 {
userName = "zatsu_monitor"
}

if len(apiToken) == 0 || len(channel) == 0 {
if len(apiToken) == 0 || len(webhookURL) == 0 || len(channel) == 0 {
return nil
}

return NewSlackNotifier(apiToken, userName, "#"+channel)
switch mode {
case WithAPIToken:
return NewSlackNotifier(apiToken, "", userName, "#"+channel)
case WithWebhookURL:
return NewSlackNotifier("", webhookURL, userName, "#"+channel)
case Nothing:
return NewSlackNotifier("", "", userName, "#"+channel)
default:
return NewSlackNotifier("", "", userName, "#"+channel)
}
}

func TestSlackNotifier_PostStatus_Successful(t *testing.T) {
notifier := NewTestSlackNotifier()
func TestSlackNotifier_WithApiToken_PostStatus_Successful(t *testing.T) {
notifier := NewTestSlackNotifier(WithAPIToken)

if notifier == nil {
return
Expand All @@ -43,8 +61,8 @@ func TestSlackNotifier_PostStatus_Successful(t *testing.T) {
assert.NoError(t, err)
}

func TestSlackNotifier_PostStatus_Failure(t *testing.T) {
notifier := NewTestSlackNotifier()
func TestSlackNotifier_WithApiToken_PostStatus_Failure(t *testing.T) {
notifier := NewTestSlackNotifier(WithAPIToken)

if notifier == nil {
return
Expand All @@ -60,8 +78,8 @@ func TestSlackNotifier_PostStatus_Failure(t *testing.T) {
assert.NoError(t, err)
}

func TestSlackNotifier_PostStatus_HasError(t *testing.T) {
notifier := NewTestSlackNotifier()
func TestSlackNotifier_WithApiToken_PostStatus_HasError(t *testing.T) {
notifier := NewTestSlackNotifier(WithAPIToken)

if notifier == nil {
return
Expand All @@ -76,3 +94,71 @@ func TestSlackNotifier_PostStatus_HasError(t *testing.T) {
err := notifier.PostStatus(&param)
assert.NoError(t, err)
}

func TestSlackNotifier_WithWebhookURL_PostStatus_Successful(t *testing.T) {
notifier := NewTestSlackNotifier(WithWebhookURL)

if notifier == nil {
return
}

param := PostStatusParam{
CheckURL: "https://www.google.com/",
BeforeStatusCode: 500,
CurrentStatusCode: 200,
HTTPError: nil,
}
err := notifier.PostStatus(&param)
assert.NoError(t, err)
}

func TestSlackNotifier_WithWebhookURL_PostStatus_Failure(t *testing.T) {
notifier := NewTestSlackNotifier(WithWebhookURL)

if notifier == nil {
return
}

param := PostStatusParam{
CheckURL: "https://www.google.com/aaa",
BeforeStatusCode: 0,
CurrentStatusCode: 404,
HTTPError: nil,
}
err := notifier.PostStatus(&param)
assert.NoError(t, err)
}

func TestSlackNotifier_WithWebhookURL_PostStatus_HasError(t *testing.T) {
notifier := NewTestSlackNotifier(WithWebhookURL)

if notifier == nil {
return
}

param := PostStatusParam{
CheckURL: "https://bbbbbbbbb/",
BeforeStatusCode: 0,
CurrentStatusCode: 0,
HTTPError: errors.New("Test"),
}
err := notifier.PostStatus(&param)
assert.NoError(t, err)
}

func TestSlackNotifier_Nothing_PostStatus_Successful(t *testing.T) {
notifier := NewTestSlackNotifier(Nothing)

if notifier == nil {
return
}

param := PostStatusParam{
CheckURL: "https://www.google.co.jp/",
BeforeStatusCode: 500,
CurrentStatusCode: 200,
HTTPError: nil,
}
err := notifier.PostStatus(&param)
assert.Error(t, err, "Either `api_token` or `webhook_url` is required")
}
1 change: 1 addition & 0 deletions test/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name1:
check_url: "http://example.com/1"
type: slack
api_token: "xoxp-0000000000-0000000000-0000000000-000000"
webhook_url: "https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXX"
user_name: "zatsu_monitor"
channel: "#general"
name2:
Expand Down

0 comments on commit fbc14b9

Please sign in to comment.