Merge pull request #735 from hotpheex/discord_notifications

Discord notifications
pull/738/head
Karolis Rusenas 2023-08-09 10:23:56 +01:00 committed by GitHub
commit bea3fb3511
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 182 additions and 0 deletions

View File

@ -27,6 +27,9 @@ data:
{{- if .Values.teams.enabled }}
TEAMS_WEBHOOK_URL: {{ .Values.teams.webhookUrl | b64enc }}
{{- end }}
{{- if .Values.discord.enabled }}
DISCORD_WEBHOOK_URL: {{ .Values.discord.webhookUrl | b64enc }}
{{- end }}
{{- if and .Values.mail.enabled .Values.mail.smtp.pass }}
MAIL_SMTP_PASS: {{ .Values.mail.smtp.pass | b64enc }}
{{- end }}

View File

@ -93,6 +93,11 @@ teams:
enabled: false
webhookUrl: ""
# Discord notifications
discord:
enabled: false
webhookUrl: ""
# Mail notifications
mail:
enabled: false

View File

@ -39,6 +39,7 @@ import (
// notification extensions
"github.com/keel-hq/keel/extension/notification/auditor"
_ "github.com/keel-hq/keel/extension/notification/discord"
_ "github.com/keel-hq/keel/extension/notification/hipchat"
_ "github.com/keel-hq/keel/extension/notification/mail"
_ "github.com/keel-hq/keel/extension/notification/mattermost"

View File

@ -34,6 +34,9 @@ const (
// MS Teams webhook url, see https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using#setting-up-a-custom-incoming-webhook
EnvTeamsWebhookUrl = "TEAMS_WEBHOOK_URL"
// Discord webhook url, see https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks
EnvDiscordWebhookUrl = "DISCORD_WEBHOOK_URL"
// Mail notification settings
EnvMailTo = "MAIL_TO"
EnvMailFrom = "MAIL_FROM"

View File

@ -0,0 +1,112 @@
package discord
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/keel-hq/keel/constants"
"github.com/keel-hq/keel/extension/notification"
"github.com/keel-hq/keel/types"
log "github.com/sirupsen/logrus"
)
const timeout = 5 * time.Second
type sender struct {
endpoint string
client *http.Client
}
// Config represents the configuration of a Discord Webhook Sender.
type Config struct {
Endpoint string
}
func init() {
log.Info(0)
notification.RegisterSender("discord", &sender{})
}
func (s *sender) Configure(config *notification.Config) (bool, error) {
log.Info(1)
// Get configuration
var httpConfig Config
if os.Getenv(constants.EnvDiscordWebhookUrl) != "" {
httpConfig.Endpoint = os.Getenv(constants.EnvDiscordWebhookUrl)
} else {
return false, nil
}
// Validate endpoint URL.
if httpConfig.Endpoint == "" {
return false, nil
}
if _, err := url.ParseRequestURI(httpConfig.Endpoint); err != nil {
return false, fmt.Errorf("could not parse endpoint URL: %s", err)
}
s.endpoint = httpConfig.Endpoint
// Setup HTTP client.
s.client = &http.Client{
Transport: http.DefaultTransport,
Timeout: timeout,
}
log.WithFields(log.Fields{
"name": "discord",
"endpoint": s.endpoint,
}).Info("extension.notification.discord: sender configured")
log.Info(2)
return true, nil
}
type DiscordMessage struct {
Username string `json:"username"`
Content string `json:"content"`
Embeds []Embed `json:"embeds"`
}
type Embed struct {
Title string `json:"title"`
Description string `json:"description"`
Footer Footer `json:"footer"`
}
type Footer struct {
Text string `json:"text"`
}
func (s *sender) Send(event types.EventNotification) error {
discordMessage := DiscordMessage{
Username: "Keel",
Embeds: []Embed{
{
Title: fmt.Sprintf("%s: %s", event.Type.String(), event.Name),
Description: event.Message,
Footer: Footer{Text: event.Level.String()},
},
},
}
jsonMessage, err := json.Marshal(discordMessage)
if err != nil {
return fmt.Errorf("could not marshal: %s", err)
}
resp, err := s.client.Post(s.endpoint, "application/json", bytes.NewBuffer(jsonMessage))
if err != nil || resp == nil || (resp.StatusCode != 200 && resp.StatusCode != 204) {
if resp != nil {
return fmt.Errorf("got status %d, expected 200/204", resp.StatusCode)
}
return err
}
defer resp.Body.Close()
return nil
}

View File

@ -0,0 +1,58 @@
package discord
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/keel-hq/keel/types"
)
func TestDiscordWebhookRequest(t *testing.T) {
currentTime := time.Now()
handler := func(resp http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(req.Body)
if err != nil {
t.Errorf("failed to parse body: %s", err)
}
bodyStr := string(body)
if !strings.Contains(bodyStr, types.NotificationPreDeploymentUpdate.String()) {
t.Errorf("missing deployment type")
}
if !strings.Contains(bodyStr, "debug") {
t.Errorf("missing level")
}
if !strings.Contains(bodyStr, "update deployment") {
t.Errorf("missing name")
}
if !strings.Contains(bodyStr, "message here") {
t.Errorf("missing message")
}
t.Log(bodyStr)
}
// create test server with handler
ts := httptest.NewServer(http.HandlerFunc(handler))
defer ts.Close()
s := &sender{
endpoint: ts.URL,
client: &http.Client{},
}
s.Send(types.EventNotification{
Name: "update deployment",
Message: "message here",
CreatedAt: currentTime,
Type: types.NotificationPreDeploymentUpdate,
Level: types.LevelDebug,
})
}