/
mattermost.go
147 lines (122 loc) · 4.27 KB
/
mattermost.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package mattermost
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/apex/log"
"github.com/caarlos0/env/v6"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/context"
)
const (
defaultColor = "#2D313E"
defaultUsername = `GoReleaser`
defaultMessageTemplate = `{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}`
defaultMessageTitle = `{{ .ProjectName }} {{ .Tag }} is out!`
)
type Pipe struct{}
func (Pipe) String() string { return "mattermost" }
func (Pipe) Skip(ctx *context.Context) bool { return !ctx.Config.Announce.Mattermost.Enabled }
type Config struct {
Webhook string `env:"MATTERMOST_WEBHOOK,notEmpty"`
}
func (Pipe) Default(ctx *context.Context) error {
if ctx.Config.Announce.Mattermost.MessageTemplate == "" {
ctx.Config.Announce.Mattermost.MessageTemplate = defaultMessageTemplate
}
if ctx.Config.Announce.Mattermost.TitleTemplate == "" {
ctx.Config.Announce.Mattermost.TitleTemplate = defaultMessageTitle
}
if ctx.Config.Announce.Mattermost.Username == "" {
ctx.Config.Announce.Mattermost.Username = defaultUsername
}
if ctx.Config.Announce.Teams.Color == "" {
ctx.Config.Announce.Teams.Color = defaultColor
}
return nil
}
func (Pipe) Announce(ctx *context.Context) error {
msg, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Mattermost.MessageTemplate)
if err != nil {
return fmt.Errorf("announce: failed to announce to mattermost: %w", err)
}
title, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Mattermost.TitleTemplate)
if err != nil {
return fmt.Errorf("announce: failed to announce to teams: %w", err)
}
var cfg Config
if err := env.Parse(&cfg); err != nil {
return fmt.Errorf("announce: failed to announce to mattermost: %w", err)
}
log.Infof("posting: %q", msg)
wm := &incomingWebhookRequest{
Username: ctx.Config.Announce.Mattermost.Username,
IconEmoji: ctx.Config.Announce.Mattermost.IconEmoji,
IconURL: ctx.Config.Announce.Mattermost.IconURL,
ChannelName: ctx.Config.Announce.Mattermost.Channel,
Attachments: []*mattermostAttachment{
{
Title: title,
Text: msg,
Color: ctx.Config.Announce.Teams.Color,
},
},
}
err = postWebhook(ctx, cfg.Webhook, wm)
if err != nil {
return fmt.Errorf("announce: failed to announce to mattermost: %w", err)
}
return nil
}
func postWebhook(ctx *context.Context, url string, msg *incomingWebhookRequest) error {
payload, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("failed to marshal the message: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(payload))
if err != nil {
return fmt.Errorf("failed new request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
r, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("announce: failed to announce to mattermost: %w", err)
}
closeBody(r)
return nil
}
func closeBody(r *http.Response) {
if r.Body != nil {
_, _ = io.Copy(io.Discard, r.Body)
_ = r.Body.Close()
}
}
type incomingWebhookRequest struct {
Text string `json:"text"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
ChannelName string `json:"channel"`
Attachments []*mattermostAttachment `json:"attachments"`
IconEmoji string `json:"icon_emoji"`
}
type mattermostAttachment struct {
Fallback string `json:"fallback"`
Color string `json:"color"`
Pretext string `json:"pretext"`
AuthorName string `json:"author_name"`
AuthorLink string `json:"author_link"`
AuthorIcon string `json:"author_icon"`
Title string `json:"title"`
TitleLink string `json:"title_link"`
Text string `json:"text"`
Fields []*mattermostAttachmentField `json:"fields"`
Footer string `json:"footer"`
FooterIcon string `json:"footer_icon"`
}
type mattermostAttachmentField struct {
Title string `json:"title"`
Value interface{} `json:"value"`
Short bool `json:"short"`
}