Skip to content

Commit

Permalink
split larger slack notifications into multiple messages to prevent co…
Browse files Browse the repository at this point in the history
…de block formatting from breaking (#746)

* refactor slack notification to use interface
  • Loading branch information
motatoes authored Nov 8, 2023
1 parent 698d3da commit bddc423
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 43 deletions.
49 changes: 6 additions & 43 deletions pkg/digger/digger.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package digger

import (
"bytes"
"encoding/json"
"errors"
"fmt"
config "github.com/diggerhq/digger/libs/digger_config"
Expand All @@ -17,11 +15,10 @@ import (
"github.com/diggerhq/digger/pkg/core/terraform"
"github.com/diggerhq/digger/pkg/core/utils"
"github.com/diggerhq/digger/pkg/locking"
"github.com/diggerhq/digger/pkg/notification"
"github.com/diggerhq/digger/pkg/reporting"
"github.com/diggerhq/digger/pkg/usage"
"io"
"log"
"net/http"
"os"
"path"
"strings"
Expand Down Expand Up @@ -576,54 +573,20 @@ func runDriftDetection(policyChecker policy.Checker, SCMOrganisation string, SCM
}

if planPerformed && nonEmptyPlan {
httpClient := &http.Client{}
slackNotificationUrl := os.Getenv("INPUT_DRIFT_DETECTION_SLACK_NOTIFICATION_URL")

if slackNotificationUrl == "" {
msg := "no INPUT_DRIFT_DETECTION_SLACK_NOTIFICATION_URL set, not sending notification"
log.Printf(msg)
return msg, fmt.Errorf(msg)
}

type SlackMessage struct {
Text string `json:"text"`
}
slackMessage := SlackMessage{
Text: fmt.Sprintf(":bangbang: Drift detected in digger project %v details below: \n\n```\n%v\n```", projectName, plan),
}

jsonData, err := json.Marshal(slackMessage)
if err != nil {
msg := fmt.Sprintf("failed to marshal slack message. %v", err)
log.Printf(msg)
return msg, fmt.Errorf(msg)
}

request, err := http.NewRequest("POST", slackNotificationUrl, bytes.NewBuffer(jsonData))
if err != nil {
msg := fmt.Sprintf("failed to create slack notification request. %v", err)
log.Printf(msg)
return msg, fmt.Errorf(msg)
}

request.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(request)
// send notification
notificationMessage := fmt.Sprintf(":bangbang: Drift detected in digger project %v details below: \n\n```\n%v\n```", projectName, plan)
notification := notification.SlackNotification{Url: slackNotificationUrl}
err := notification.Send(notificationMessage)
if err != nil {
msg := fmt.Sprintf("failed to send slack notification request. %v", err)
log.Printf(msg)
}
if resp.StatusCode != 200 {
body, err := io.ReadAll(resp.Body)
if err != nil {
msg := fmt.Sprintf("failed to read response body. %v", err)
log.Printf(msg)
return msg, fmt.Errorf(msg)
}
msg := fmt.Sprintf("failed to send slack notification request. %v. Message: %v", resp.Status, body)
log.Printf(msg)
return msg, fmt.Errorf(msg)
log.Printf("Erorr sending drift notification: %v", err)
}
defer resp.Body.Close()
} else if planPerformed && !nonEmptyPlan {
log.Printf("No drift detected")
} else {
Expand Down
94 changes: 94 additions & 0 deletions pkg/notification/slack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package notification

import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"regexp"
"strings"
)

type Notification interface {
Send(message string) error
}

type SlackNotification struct {
Url string
}

func SplitCodeBlocks(message string) []string {
var res []string

if strings.Count(message, "```") < 2 {
res = append(res, message)
return res
}

regex := regexp.MustCompile("\n")
split := regex.Split(message, -1)
part := ""
for _, line := range split {
if len(part+line) > 4000 {
res = append(res, part+"\n"+line+"\n```")
part = "```\n" + line
} else {
part = part + "\n" + line
}
}
if len(part) > 0 {
res = append(res, part)
}
return res
}

func (slack SlackNotification) Send(message string) error {
httpClient := &http.Client{}
type SlackMessage struct {
Text string `json:"text"`
}
parts := SplitCodeBlocks(message)
for _, part := range parts {
slackMessage := SlackMessage{
Text: part,
}

jsonData, err := json.Marshal(slackMessage)
if err != nil {
msg := fmt.Sprintf("failed to marshal slack message. %v", err)
log.Printf(msg)
return fmt.Errorf(msg)
}

request, err := http.NewRequest("POST", slack.Url, bytes.NewBuffer(jsonData))
if err != nil {
msg := fmt.Sprintf("failed to create slack notification request. %v", err)
log.Printf(msg)
return fmt.Errorf(msg)
}

request.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(request)
if err != nil {
msg := fmt.Sprintf("failed to send slack notification request. %v", err)
log.Printf(msg)
return fmt.Errorf(msg)
}
if resp.StatusCode != 200 {
body, err := io.ReadAll(resp.Body)
if err != nil {
msg := fmt.Sprintf("failed to read response body. %v", err)
log.Printf(msg)
return fmt.Errorf(msg)
}
msg := fmt.Sprintf("failed to send slack notification request. %v. Message: %v", resp.Status, body)
log.Printf(msg)
return fmt.Errorf(msg)
}
resp.Body.Close()
}

return nil
}
Loading

0 comments on commit bddc423

Please sign in to comment.