Skip to content

Commit

Permalink
feat: added support of mattermost hook notifier
Browse files Browse the repository at this point in the history
  • Loading branch information
Semior001 committed Dec 28, 2022
1 parent cfd20a8 commit 93d30fd
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 21 deletions.
39 changes: 32 additions & 7 deletions app/cmd/flg/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import (

// NotifyGroup defines parameters for the notifier.
type NotifyGroup struct {
Telegram TelegramGroup `group:"telegram" namespace:"telegram" env-namespace:"TELEGRAM"`
Github GithubNotifierGroup `group:"github" namespace:"github" env-namespace:"GITHUB"`
Mattermost MattermostGroup `group:"mattermost" namespace:"mattermost" env-namespace:"MATTERMOST"`
Stdout bool `long:"stdout" env:"STDOUT" description:"print release notes to stdout"`
ConfLocation string `long:"conf_location" env:"CONF_LOCATION" description:"location to the config file"`
Extras map[string]string `long:"extras" env:"EXTRAS" env-delim:"," description:"extra variables to use in the template"`
Telegram TelegramGroup `group:"telegram" namespace:"telegram" env-namespace:"TELEGRAM"`
Github GithubNotifierGroup `group:"github" namespace:"github" env-namespace:"GITHUB"`
Mattermost MattermostGroup `group:"mattermost" namespace:"mattermost" env-namespace:"MATTERMOST"`
MattermostHook MattermostHookGroup `group:"mattermost-hook" namespace:"mattermost-hook" env-namespace:"MATTERMOST_HOOK"`
Stdout bool `long:"stdout" env:"STDOUT" description:"print release notes to stdout"`
ConfLocation string `long:"conf_location" env:"CONF_LOCATION" description:"location to the config file"`
Extras map[string]string `long:"extras" env:"EXTRAS" env-delim:"," description:"extra variables to use in the template"`
}

// GithubNotifierGroup defines parameters to make release in the github.
Expand Down Expand Up @@ -61,12 +62,24 @@ func (g MattermostGroup) Empty() bool {
return g.BaseURL == "" || g.ChannelID == "" || g.LoginID == "" || g.Password == ""
}

// MattermostHookGroup defines parameters for mattermost hook notifier.
type MattermostHookGroup struct {
BaseURL string `long:"base_url" env:"BASE_URL" description:"base url of the mattermost server"`
ID string `long:"id" env:"ID" description:"id of the hook, where the release notes will be sent"`
}

// Empty returns true if the config group is not filled.
func (g MattermostHookGroup) Empty() bool {
return g.BaseURL == "" || g.ID == ""
}

// Build builds the notifier.
func (r *NotifyGroup) Build() (destinations notify.Destinations, err error) {
logger := log.Default()

if r.Stdout {
destinations = append(destinations, &notify.WriterNotifier{Writer: os.Stdout, Name: "stdout"})
log.Printf("[INFO] printing notes to stdout is enabled")
}

if !r.Telegram.Empty() {
Expand All @@ -77,6 +90,7 @@ func (r *NotifyGroup) Build() (destinations notify.Destinations, err error) {
Token: r.Telegram.Token,
DisableWebPagePreview: !r.Telegram.WebPagePreview,
}))
log.Printf("[INFO] telegram notifier is enabled")
}

if !r.Github.Empty() {
Expand All @@ -93,10 +107,11 @@ func (r *NotifyGroup) Build() (destinations notify.Destinations, err error) {
}

destinations = append(destinations, gh)
log.Printf("[INFO] github releases notifier is enabled")
}

if !r.Mattermost.Empty() {
mm, err := notify.NewMattermost(notify.MattermostParams{
mm, err := notify.NewMattermostBot(notify.MattermostBotParams{
Client: http.Client{Timeout: 5 * time.Second},
BaseURL: r.Mattermost.BaseURL,
ChannelID: r.Mattermost.ChannelID,
Expand All @@ -109,6 +124,16 @@ func (r *NotifyGroup) Build() (destinations notify.Destinations, err error) {
}

destinations = append(destinations, mm)
log.Printf("[INFO] mattermost bot notifier is enabled")
}

if !r.MattermostHook.Empty() {
destinations = append(destinations, notify.NewMattermostHook(
http.Client{Timeout: 5 * time.Second},
r.MattermostHook.BaseURL,
r.MattermostHook.ID,
))
log.Printf("[INFO] mattermost hook notifier is enabled")
}

return destinations, nil
Expand Down
71 changes: 57 additions & 14 deletions app/notify/mattermost.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ import (
"github.com/go-pkgz/requester/middleware"
)

// Mattermost is a notifier for Mattermost.
type Mattermost struct {
MattermostParams
// MattermostBot is a notifier for MattermostBot.
type MattermostBot struct {
MattermostBotParams
token struct {
value string
mu *sync.Mutex
}
cl *http.Client
}

// MattermostParams are Mattermost notifier params.
type MattermostParams struct {
// MattermostBotParams are MattermostBot notifier params.
type MattermostBotParams struct {
Client http.Client
BaseURL string
ChannelID string
Expand All @@ -36,11 +36,11 @@ type MattermostParams struct {
LDAP bool
}

// NewMattermost makes a new Mattermost notifier.
func NewMattermost(params MattermostParams) (*Mattermost, error) {
// NewMattermostBot makes a new MattermostBot notifier.
func NewMattermostBot(params MattermostBotParams) (*MattermostBot, error) {
params.BaseURL = strings.TrimRight(params.BaseURL, "/")

svc := &Mattermost{MattermostParams: params}
svc := &MattermostBot{MattermostBotParams: params}
svc.token.mu = &sync.Mutex{}

svc.cl = requester.New(svc.Client, svc.reloginMiddleware).Client()
Expand All @@ -56,7 +56,7 @@ func NewMattermost(params MattermostParams) (*Mattermost, error) {
return svc, nil
}

func (m *Mattermost) login(ctx context.Context) (token string, err error) {
func (m *MattermostBot) login(ctx context.Context) (token string, err error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

Expand Down Expand Up @@ -97,7 +97,7 @@ func (m *Mattermost) login(ctx context.Context) (token string, err error) {
return m.token.value, nil
}

func (m *Mattermost) ping(ctx context.Context) error {
func (m *MattermostBot) ping(ctx context.Context) error {
u := fmt.Sprintf("%s/api/v4/config/client?format=old", m.BaseURL)

req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, http.NoBody)
Expand All @@ -118,12 +118,12 @@ func (m *Mattermost) ping(ctx context.Context) error {
}

// String returns the name of the notifier.
func (m *Mattermost) String() string {
return fmt.Sprintf("mattermost at: %s", m.BaseURL)
func (m *MattermostBot) String() string {
return fmt.Sprintf("mattermost bot at: %s", m.BaseURL)
}

// Send sends a message to Mattermost.
func (m *Mattermost) Send(ctx context.Context, _, text string) error {
func (m *MattermostBot) Send(ctx context.Context, _, text string) error {
u := fmt.Sprintf("%s/api/v4/posts", m.BaseURL)

b, err := json.Marshal(map[string]string{"channel_id": m.ChannelID, "message": text})
Expand All @@ -148,7 +148,7 @@ func (m *Mattermost) Send(ctx context.Context, _, text string) error {
return nil
}

func (m *Mattermost) reloginMiddleware(next http.RoundTripper) http.RoundTripper {
func (m *MattermostBot) reloginMiddleware(next http.RoundTripper) http.RoundTripper {
return middleware.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
resp, err := next.RoundTrip(req)
if err != nil {
Expand All @@ -168,3 +168,46 @@ func (m *Mattermost) reloginMiddleware(next http.RoundTripper) http.RoundTripper
return resp, nil
})
}

// MattermostHook sends messages to Mattermost via webhook.
type MattermostHook struct {
cl *http.Client
baseURL string
hookID string
}

// NewMattermostHook makes a new MattermostHook notifier.
func NewMattermostHook(cl http.Client, baseURL, hookID string) *MattermostHook {
return &MattermostHook{cl: &cl, baseURL: baseURL, hookID: hookID}
}

// String returns the name of the notifier.
func (m *MattermostHook) String() string {
return fmt.Sprintf("mattermost hook at: %s", m.baseURL)
}

// Send sends a message to Mattermost.
func (m *MattermostHook) Send(ctx context.Context, _, text string) error {
u := fmt.Sprintf("%s/hooks/%s", m.baseURL, m.hookID)

b, err := json.Marshal(map[string]string{"text": text})
if err != nil {
return fmt.Errorf("marshal body: %w", err)
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewReader(b))
if err != nil {
return fmt.Errorf("build request: %w", err)
}

resp, err := m.cl.Do(req)
if err != nil {
return fmt.Errorf("do request: %w", err)
}

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

return nil
}

0 comments on commit 93d30fd

Please sign in to comment.