Skip to content

Commit

Permalink
Switch channelInfo encoding from string to JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
Kuixz committed Aug 16, 2024
1 parent 2b3479e commit 3349149
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 49 deletions.
93 changes: 49 additions & 44 deletions pkg/slack/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package slack

import (
"context"
"encoding/json"
"errors"
"fmt"
"regexp"
Expand All @@ -13,7 +14,6 @@ import (
"github.com/slack-go/slack/socketmode"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"k8s.io/utils/strings/slices"
)

var repoRegex = regexp.MustCompile("[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+)?")
Expand All @@ -31,6 +31,28 @@ type ChannelInfo struct {
conclusions []string
}

type exposedChannelInfo struct {
ChannelID string `json:"channelID"`
Conclusions []string `json:"messageFilters"`
}

func (f ChannelInfo) MarshalJSON() ([]byte, error) {
return json.Marshal(exposedChannelInfo{
ChannelID: f.channelID,
Conclusions: f.conclusions,
})
}

func (f *ChannelInfo) UnmarshalJSON(data []byte) error {
aux := &exposedChannelInfo{}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
f.channelID = aux.ChannelID
f.conclusions = aux.Conclusions
return nil
}

func NewApp(logger *zap.Logger, config *Config, store kv.Store) *App {
logger = logger.Named("slack-app")
return &App{
Expand All @@ -50,13 +72,12 @@ func (a *App) Disabled() bool {
return a.disabled
}

// Format of channel info string: "<channel_Id>:<conclusion_1>,<conclusion_2>"
func toChannelInfoString(channelInfo ChannelInfo) string {
if len(channelInfo.conclusions) == 0 {
return channelInfo.channelID
func toChannelInfoString(channelInfo ChannelInfo) (string, error) {
json, err := json.Marshal(channelInfo)
if err != nil {
return "", err
}
conclusionsString := strings.Join(channelInfo.conclusions, ",")
return channelInfo.channelID + ":" + conclusionsString
return string(json), nil
}

func (a *App) GetChannels(ctx context.Context, repo string) ([]ChannelInfo, error) {
Expand All @@ -66,23 +87,12 @@ func (a *App) GetChannels(ctx context.Context, repo string) ([]ChannelInfo, erro
} else if data == "" {
return nil, nil
}
channelInfoStrings := strings.Split(data, ";")
var channelInfos []ChannelInfo

for _, channelString := range channelInfoStrings {
channelID, conclusionsString, _ := strings.Cut(channelString, ":")
var conclusions []string
for _, conclusion := range strings.Split(conclusionsString, ",") {
if len(conclusion) > 0 {
conclusions = append(conclusions, conclusion)
}
}
channelInfos = append(channelInfos, ChannelInfo{
channelID: channelID,
conclusions: conclusions,
})
var channelInfos []ChannelInfo
err = json.Unmarshal([]byte(data), &channelInfos)
if err != nil {
return nil, err
}

return channelInfos, nil
}

Expand All @@ -92,31 +102,22 @@ func (a *App) AddChannel(ctx context.Context, repo string, channelInfo ChannelIn
return err
}

// Ref: https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28#create-a-check-run--parameters
supportedConclusions := []string{"action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"}
var unsupportedConclusions []string
for _, c := range channelInfo.conclusions {
if !slices.Contains(supportedConclusions, c) {
unsupportedConclusions = append(unsupportedConclusions, c)
}
}

if len(unsupportedConclusions) > 0 {
return fmt.Errorf("unsupported conclusions: %s", strings.Join(unsupportedConclusions, ", "))
}

var newChannelInfoStrings []string
var newChannelInfos []ChannelInfo
for _, c := range channelInfos {
if c.channelID == channelInfo.channelID {
// Skip the old subscription and will replace with the new conclusion filter options
continue
}
newChannelInfoStrings = append(newChannelInfoStrings, toChannelInfoString(c))
newChannelInfos = append(newChannelInfos, c)
}
newChannelInfoStrings = append(newChannelInfoStrings, toChannelInfoString(channelInfo))
data := strings.Join(newChannelInfoStrings, ";")
newChannelInfos = append(newChannelInfos, channelInfo)

return a.store.Set(ctx, kvNamespace, repo, data)
data, err := json.Marshal(newChannelInfos)
if err != nil {
return err
}

return a.store.Set(ctx, kvNamespace, repo, string(data))
}

func (a *App) DelChannel(ctx context.Context, repo string, channelID string) error {
Expand All @@ -125,21 +126,25 @@ func (a *App) DelChannel(ctx context.Context, repo string, channelID string) err
return err
}

var newChannelInfoStrings []string
var newChannelInfos []ChannelInfo
found := false
for _, c := range channelInfos {
if c.channelID == channelID {
found = true
continue
}
newChannelInfoStrings = append(newChannelInfoStrings, toChannelInfoString(c))
newChannelInfos = append(newChannelInfos, c)
}
if !found {
return fmt.Errorf("not subscribed to repo")
}
data := strings.Join(newChannelInfoStrings, ";")

return a.store.Set(ctx, kvNamespace, repo, data)
data, err := json.Marshal(newChannelInfos)
if err != nil {
return err
}

return a.store.Set(ctx, kvNamespace, repo, string(data))
}

func (a *App) SendMessage(ctx context.Context, channel string, options ...slack.MsgOption) error {
Expand Down
31 changes: 26 additions & 5 deletions pkg/slack/filter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package slack

import (
"encoding/json"
"fmt"
"strings"

Expand All @@ -9,19 +10,39 @@ import (
)

type messageFilterRule struct {
conclusions []string
Conclusions []string `json:"conclusions"`
// branches []string
workflows []string
Workflows []string `json:"workflows"`
}

type MessageFilter struct {
whitelists []messageFilterRule
}

type exposedMessageFilter struct {
Whitelists []messageFilterRule `json:"filters"`
}

func (mf MessageFilter) MarshalJSON() ([]byte, error) {
return json.Marshal(exposedMessageFilter{
Whitelists: mf.whitelists,
})
}

func (mf *MessageFilter) UnmarshalJSON(data []byte) error {
aux := &exposedMessageFilter{}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
mf.whitelists = aux.Whitelists
return nil
}

func (rule messageFilterRule) Pass(run *jobs.WorkflowRun) bool {
if len(rule.conclusions) > 0 && !slices.Contains(rule.conclusions, run.Conclusion) {
if len(rule.Conclusions) > 0 && !slices.Contains(rule.Conclusions, run.Conclusion) {
return false
}
if len(rule.workflows) > 0 && !slices.Contains(rule.workflows, run.Name) {
if len(rule.Workflows) > 0 && !slices.Contains(rule.Workflows, run.Name) {
return false
}
return true
Expand Down Expand Up @@ -59,7 +80,7 @@ func (rule *messageFilterRule) setConclusions(conclusions []string) error {
return fmt.Errorf("unsupported conclusions: %s", strings.Join(unsupportedConclusions, ", "))
}

rule.conclusions = conclusions
rule.Conclusions = conclusions
return nil
}

Expand Down

0 comments on commit 3349149

Please sign in to comment.