Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
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
40 changes: 0 additions & 40 deletions internal/interactor/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package interactor

import (
"context"
"fmt"
"time"

"github.com/gitploy-io/gitploy/ent"
"github.com/gitploy-io/gitploy/ent/event"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -52,41 +50,3 @@ func (i *Interactor) SubscribeEvent(fn func(e *ent.Event)) error {
func (i *Interactor) UnsubscribeEvent(fn func(e *ent.Event)) error {
return i.events.Unsubscribe(gitployEvent, fn)
}

func (i *Interactor) ListUsersOfEvent(ctx context.Context, e *ent.Event) ([]*ent.User, error) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migrate this logic into the slack pkg.

if e.Kind == event.KindDeployment {
d, err := i.Store.FindDeploymentByID(ctx, e.DeploymentID)
if err != nil {
return nil, fmt.Errorf("It has failed to find the deployment: %w", err)
}

return []*ent.User{d.Edges.User}, nil
}

// Notify to who has the request of approval.
if e.Kind == event.KindApproval && e.Type == event.TypeCreated {
a, err := i.Store.FindApprovalByID(ctx, e.ApprovalID)
if err != nil {
return nil, fmt.Errorf("It has failed to find the approval: %w", err)
}

return []*ent.User{a.Edges.User}, nil
}

// Notify to who has requested the approval.
if e.Kind == event.KindApproval && e.Type == event.TypeUpdated {
a, err := i.Store.FindApprovalByID(ctx, e.ApprovalID)
if err != nil {
return nil, fmt.Errorf("It has failed to find the approval: %w", err)
}

d, err := i.Store.FindDeploymentByID(ctx, a.DeploymentID)
if err != nil {
return nil, fmt.Errorf("It has failed to find the deployment of the approval: %w", err)
}

return []*ent.User{d.Edges.User}, nil
}

return nil, fmt.Errorf("It is out of use-cases.")
}
1 change: 0 additions & 1 deletion internal/server/slack/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ type (
SubscribeEvent(fn func(e *ent.Event)) error
UnsubscribeEvent(fn func(e *ent.Event)) error

ListUsersOfEvent(ctx context.Context, e *ent.Event) ([]*ent.User, error)
CheckNotificationRecordOfEvent(ctx context.Context, e *ent.Event) bool
CreateEvent(ctx context.Context, e *ent.Event) (*ent.Event, error)

Expand Down
184 changes: 100 additions & 84 deletions internal/server/slack/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,111 +20,127 @@ const (
colorRed = "#f5222d"
)

func (s *Slack) Notify(ctx context.Context, e *ent.Event) error {
if s.i.CheckNotificationRecordOfEvent(ctx, e) {
return nil
func (s *Slack) Notify(ctx context.Context, e *ent.Event) {
if e.Kind == event.KindDeployment {
s.notifyDeploymentEvent(ctx, e)
}

var (
users []*ent.User
err error
)

if users, err = s.i.ListUsersOfEvent(ctx, e); err != nil {
return err
if e.Kind == event.KindApproval {
s.notifyApprovalEvent(ctx, e)
}
}

for _, u := range users {
// Eager loading for chat user.
if u, err = s.i.FindUserByID(ctx, u.ID); err != nil {
s.log.Error("It has failed to eager load.", zap.Error(err))
continue
}
if u.Edges.ChatUser == nil {
continue
}
func (s *Slack) notifyDeploymentEvent(ctx context.Context, e *ent.Event) {
if err := e.CheckEagerLoading(); err != nil {
s.log.Error("The eager loading of event has failed.")
return
}

if err := s.notify(ctx, u.Edges.ChatUser, e); err != nil {
s.log.Error("It has failed to notify the event.", zap.Error(err))
}
d := e.Edges.Deployment
if err := d.CheckEagerLoading(); err != nil {
s.log.Error("The eager loading of deployment has failed.")
return
}

return nil
}
owner, err := s.i.FindUserByID(ctx, d.Edges.User.ID)
if err != nil {
s.log.Error("It has failed to find the owner of the deployment.", zap.Error(err))
return
}
if owner.Edges.ChatUser == nil {
s.log.Debug("Skip the notification. The owner is not connected with Slack.")
return
}

func (s *Slack) notify(ctx context.Context, cu *ent.ChatUser, e *ent.Event) error {
// Build the message and post it.
var option slack.MsgOption

// Check the event has processed eager loading.
if e.Type == event.TypeCreated {
option = slack.MsgOptionAttachments(slack.Attachment{
Color: mapDeploymentStatusToColor(d.Status),
Pretext: fmt.Sprintf("*New Deployment #%d*", d.Number),
Text: fmt.Sprintf("*%s* deploys `%s` to the `%s` environment of `%s`. <%s|• View Details> ", owner.Login, d.GetShortRef(), d.Env, d.Edges.Repo.GetFullName(), s.buildDeploymentLink(d.Edges.Repo, d)),
})
} else if e.Type == event.TypeUpdated {
option = slack.MsgOptionAttachments(slack.Attachment{
Color: mapDeploymentStatusToColor(d.Status),
Pretext: fmt.Sprintf("*Deployment Updated #%d*", d.Number),
Text: fmt.Sprintf("The deployment <%s|#%d> of `%s` is updated `%s`.", s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName(), d.Status),
})
}

if _, _, err := slack.
New(owner.Edges.ChatUser.BotToken).
PostMessageContext(ctx, owner.Edges.ChatUser.ID, option); err != nil {
s.log.Error("It has failed to post the message.", zap.Error(err))
}
}

func (s *Slack) notifyApprovalEvent(ctx context.Context, e *ent.Event) {
if err := e.CheckEagerLoading(); err != nil {
return err
s.log.Error("The eager loading of event has failed.")
return
}

if e.Kind == event.KindDeployment {
d := e.Edges.Deployment
if err := d.CheckEagerLoading(); err != nil {
return err
}
a := e.Edges.Approval
if err := a.CheckEagerLoading(); err != nil {
s.log.Error("The eager loading of approval has failed.")
return
}

var (
r = d.Edges.Repo
u = d.Edges.User
)

if e.Type == event.TypeCreated {
option = slack.MsgOptionAttachments(
slack.Attachment{
Color: mapDeploymentStatusToColor(d.Status),
Pretext: fmt.Sprintf("*New Deployment #%d*", d.Number),
Text: fmt.Sprintf("*%s* deploys `%s` to the `%s` environment of `%s`. <%s|• View Details> ", u.Login, d.GetShortRef(), d.Env, r.GetFullName(), s.buildDeploymentLink(r, d)),
},
)
} else if e.Type == event.TypeUpdated {
option = slack.MsgOptionAttachments(
slack.Attachment{
Color: mapDeploymentStatusToColor(d.Status),
Pretext: fmt.Sprintf("*Deployment Updated #%d*", d.Number),
Text: fmt.Sprintf("The deployment <%s|#%d> of `%s` is updated `%s`.", s.buildDeploymentLink(r, d), d.Number, r.GetFullName(), d.Status),
},
)
d := e.Edges.Deployment
if err := d.CheckEagerLoading(); err != nil {
s.log.Error("The eager loading of deployment has failed.")
return
}

if e.Type == event.TypeCreated {
option := slack.MsgOptionAttachments(slack.Attachment{
Color: colorPurple,
Pretext: "*Approval Requested*",
Text: fmt.Sprintf("%s has requested the approval for the deployment <%s|#%d> of `%s`.", d.Edges.User.Login, s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName()),
})

recipient, err := s.i.FindUserByID(ctx, a.Edges.User.ID)
if err != nil {
s.log.Error("It has failed to find the recipient of the approval.", zap.Error(err))
return
}
} else if e.Kind == event.KindApproval {
a := e.Edges.Approval
if err := a.CheckEagerLoading(); err != nil {
return err
if recipient.Edges.ChatUser == nil {
s.log.Debug("Skip the notification. The recipient is not connected with Slack.")
return
}

var (
u *ent.User = a.Edges.User
d *ent.Deployment = a.Edges.Deployment
r *ent.Repo
)
if _, _, err := slack.
New(recipient.Edges.ChatUser.BotToken).
PostMessageContext(ctx, recipient.Edges.ChatUser.ID, option); err != nil {
s.log.Error("It has failed to post the message.", zap.Error(err))
}
}

// Approval have to process eager loading for the deployment, too.
if err := d.CheckEagerLoading(); err != nil {
return err
if e.Type == event.TypeUpdated {
option := slack.MsgOptionAttachments(slack.Attachment{
Color: mapApprovalStatusToColor(a.Status),
Pretext: "*Approval Responded*",
Text: fmt.Sprintf("%s has *%s* for the deployment <%s|#%d> of `%s`.", a.Edges.User.Login, a.Status, s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName()),
})

requester, err := s.i.FindUserByID(ctx, d.Edges.User.ID)
if err != nil {
s.log.Error("It has failed to find the requester of the approval.", zap.Error(err))
return
}
r = d.Edges.Repo

if e.Type == event.TypeCreated {
option = slack.MsgOptionAttachments(slack.Attachment{
Color: colorPurple,
Pretext: "*Approval Requested*",
Text: fmt.Sprintf("%s has requested the approval for the deployment <%s|#%d> of `%s`.", u.Login, s.buildDeploymentLink(r, d), d.Number, r.GetFullName()),
})
} else if e.Type == event.TypeUpdated {
option = slack.MsgOptionAttachments(slack.Attachment{
Color: mapApprovalStatusToColor(a.Status),
Pretext: "*Approval Responded*",
Text: fmt.Sprintf("%s has *%s* for the deployment <%s|#%d> of `%s`.", u.Login, a.Status, s.buildDeploymentLink(r, d), d.Number, r.GetFullName()),
})
if requester.Edges.ChatUser == nil {
s.log.Debug("Skip the notification. The requester is not connected with Slack.")
return
}
}

_, _, err := slack.
New(cu.BotToken).
PostMessageContext(ctx, cu.ID, option)
return err
if _, _, err := slack.
New(requester.Edges.ChatUser.BotToken).
PostMessageContext(ctx, requester.Edges.ChatUser.ID, option); err != nil {
s.log.Error("It has failed to post the message.", zap.Error(err))
}
}
}

func (s *Slack) buildDeploymentLink(r *ent.Repo, d *ent.Deployment) string {
Expand Down
4 changes: 1 addition & 3 deletions internal/server/slack/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ func NewSlack(c *SlackConfig) *Slack {
}

s.i.SubscribeEvent(func(e *ent.Event) {
if err := s.Notify(context.Background(), e); err != nil {
s.log.Error("It has failed to push notificaitons.", zap.Error(err))
}
s.Notify(context.Background(), e)
})

return s
Expand Down