feat: announce: slack (#2429)

Fixes #2425

Signed-off-by: Furkan <furkan.turkal@trendyol.com>
This commit is contained in:
Furkan Türkal
2021-09-01 16:46:25 -03:00
committed by GitHub
parent b661a57105
commit aa28f31ab5
8 changed files with 209 additions and 23 deletions
+3
View File
@@ -95,6 +95,7 @@ require (
github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/slack-go/slack v0.9.4
github.com/spf13/pflag v1.0.5 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
go.opencensus.io v0.23.0 // indirect
@@ -115,3 +116,5 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
require github.com/gorilla/websocket v1.4.2 // indirect
+4
View File
@@ -244,6 +244,7 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
@@ -351,6 +352,7 @@ github.com/goreleaser/fileglob v1.2.0/go.mod h1:rFyb2pXaK3YdnYnSjn6lifw0h2Q6s8Of
github.com/goreleaser/nfpm/v2 v2.6.0 h1:bwDU9o4/CVTSpqASJA7+r+rkqpTGamQKYHMRH3wDlRE=
github.com/goreleaser/nfpm/v2 v2.6.0/go.mod h1:qaMnjBaZz/2vInOIWx0IbuKuaZpaVB6O8oLG0u4qH1Y=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -532,6 +534,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/slack-go/slack v0.9.4 h1:C+FC3zLxLxUTQjDy2RZeMHYon005zsCROiZNWVo+opQ=
github.com/slack-go/slack v0.9.4/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+2
View File
@@ -6,6 +6,7 @@ import (
"github.com/goreleaser/goreleaser/internal/middleware"
"github.com/goreleaser/goreleaser/internal/pipe/reddit"
"github.com/goreleaser/goreleaser/internal/pipe/slack"
"github.com/goreleaser/goreleaser/internal/pipe/twitter"
"github.com/goreleaser/goreleaser/pkg/context"
)
@@ -28,6 +29,7 @@ type Announcer interface {
var announcers = []Announcer{
twitter.Pipe{}, // announce to twitter
reddit.Pipe{}, // announce to twitter
slack.Pipe{}, // announce to slack
}
// Run the pipe.
+71
View File
@@ -0,0 +1,71 @@
package slack
import (
"fmt"
"github.com/slack-go/slack"
"github.com/apex/log"
"github.com/caarlos0/env/v6"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/context"
)
const (
defaultUsername = `GoReleaser`
defaultMessageTemplate = `{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .GitURL }}/releases/tag/{{ .Tag }}`
)
type Pipe struct{}
func (Pipe) String() string { return "slack" }
type Config struct {
Webhook string `env:"SLACK_WEBHOOK,notEmpty"`
}
func (Pipe) Default(ctx *context.Context) error {
if ctx.Config.Announce.Slack.MessageTemplate == "" {
ctx.Config.Announce.Slack.MessageTemplate = defaultMessageTemplate
}
if ctx.Config.Announce.Slack.Username == "" {
ctx.Config.Announce.Slack.Username = defaultUsername
}
return nil
}
func (Pipe) Announce(ctx *context.Context) error {
if ctx.SkipAnnounce {
return pipe.ErrSkipAnnounceEnabled
}
if !ctx.Config.Announce.Slack.Enabled {
return pipe.ErrSkipDisabledPipe
}
msg, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Slack.MessageTemplate)
if err != nil {
return fmt.Errorf("announce: failed to announce to slack: %w", err)
}
var cfg Config
if err := env.Parse(&cfg); err != nil {
return fmt.Errorf("announce: failed to announce to slack: %w", err)
}
log.Infof("posting: '%s'", msg)
wm := &slack.WebhookMessage{
Username: ctx.Config.Announce.Slack.Username,
IconEmoji: ctx.Config.Announce.Slack.IconEmoji,
IconURL: ctx.Config.Announce.Slack.IconURL,
Channel: ctx.Config.Announce.Slack.Channel,
Text: msg,
}
err = slack.PostWebhook(cfg.Webhook, wm)
if err != nil {
return fmt.Errorf("announce: failed to announce to slack: %w", err)
}
return nil
}
+62
View File
@@ -0,0 +1,62 @@
package slack
import (
"testing"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/stretchr/testify/require"
)
func TestStringer(t *testing.T) {
require.Equal(t, Pipe{}.String(), "slack")
}
func TestDefault(t *testing.T) {
ctx := context.New(config.Project{})
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ctx.Config.Announce.Slack.MessageTemplate, defaultMessageTemplate)
}
func TestAnnounceDisabled(t *testing.T) {
ctx := context.New(config.Project{})
require.NoError(t, Pipe{}.Default(ctx))
testlib.AssertSkipped(t, Pipe{}.Announce(ctx))
}
func TestAnnounceInvalidTemplate(t *testing.T) {
ctx := context.New(config.Project{
Announce: config.Announce{
Slack: config.Slack{
Enabled: true,
MessageTemplate: "{{ .Foo }",
},
},
})
require.EqualError(t, Pipe{}.Announce(ctx), `announce: failed to announce to slack: template: tmpl:1: unexpected "}" in operand`)
}
func TestAnnounceMissingEnv(t *testing.T) {
ctx := context.New(config.Project{
Announce: config.Announce{
Slack: config.Slack{
Enabled: true,
},
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.EqualError(t, Pipe{}.Announce(ctx), `announce: failed to announce to slack: env: environment variable "SLACK_WEBHOOK" should not be empty`)
}
func TestAnnounceSkipAnnounce(t *testing.T) {
ctx := context.New(config.Project{
Announce: config.Announce{
Slack: config.Slack{
Enabled: true,
},
},
})
ctx.SkipAnnounce = true
testlib.AssertSkipped(t, Pipe{}.Announce(ctx))
}
+31 -22
View File
@@ -90,28 +90,27 @@ func (r Repo) String() string {
// Homebrew contains the brew section.
type Homebrew struct {
Name string `yaml:",omitempty"`
Tap RepoRef `yaml:",omitempty"`
CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"`
CommitMessageTemplate string `yaml:"commit_msg_template,omitempty"`
Folder string `yaml:",omitempty"`
Caveats string `yaml:",omitempty"`
Plist string `yaml:",omitempty"`
Install string `yaml:",omitempty"`
PostInstall string `yaml:"post_install,omitempty"`
Dependencies []HomebrewDependency `yaml:",omitempty"`
Test string `yaml:",omitempty"`
Conflicts []string `yaml:",omitempty"`
Description string `yaml:",omitempty"`
Homepage string `yaml:",omitempty"`
License string `yaml:",omitempty"`
SkipUpload string `yaml:"skip_upload,omitempty"`
DownloadStrategy string `yaml:"download_strategy,omitempty"`
URLTemplate string `yaml:"url_template,omitempty"`
CustomRequire string `yaml:"custom_require,omitempty"`
CustomBlock string `yaml:"custom_block,omitempty"`
IDs []string `yaml:"ids,omitempty"`
Goarm string `yaml:"goarm,omitempty"`
Name string `yaml:",omitempty"`
Tap RepoRef `yaml:",omitempty"`
CommitAuthor CommitAuthor `yaml:"commit_author,omitempty"`
Folder string `yaml:",omitempty"`
Caveats string `yaml:",omitempty"`
Plist string `yaml:",omitempty"`
Install string `yaml:",omitempty"`
PostInstall string `yaml:"post_install,omitempty"`
Dependencies []HomebrewDependency `yaml:",omitempty"`
Test string `yaml:",omitempty"`
Conflicts []string `yaml:",omitempty"`
Description string `yaml:",omitempty"`
Homepage string `yaml:",omitempty"`
License string `yaml:",omitempty"`
SkipUpload string `yaml:"skip_upload,omitempty"`
DownloadStrategy string `yaml:"download_strategy,omitempty"`
URLTemplate string `yaml:"url_template,omitempty"`
CustomRequire string `yaml:"custom_require,omitempty"`
CustomBlock string `yaml:"custom_block,omitempty"`
IDs []string `yaml:"ids,omitempty"`
Goarm string `yaml:"goarm,omitempty"`
}
// Scoop contains the scoop.sh section.
@@ -692,6 +691,7 @@ type GoMod struct {
type Announce struct {
Twitter Twitter `yaml:"twitter,omitempty"`
Reddit Reddit `yaml:"reddit,omitempty"`
Slack Slack `yaml:"slack,omitempty"`
}
type Twitter struct {
@@ -708,6 +708,15 @@ type Reddit struct {
Sub string `yaml:"sub,omitempty"`
}
type Slack struct {
Enabled bool `yaml:"enabled,omitempty"`
MessageTemplate string `yaml:"message_template,omitempty"`
Channel string `yaml:"channel,omitempty"`
Username string `yaml:"username,omitempty"`
IconEmoji string `yaml:"icon_emoji,omitempty"`
IconURL string `yaml:"icon_url,omitempty"`
}
// Load config file.
func Load(file string) (config Project, err error) {
f, err := os.Open(file) // #nosec
+2
View File
@@ -17,6 +17,7 @@ import (
"github.com/goreleaser/goreleaser/internal/pipe/nfpm"
"github.com/goreleaser/goreleaser/internal/pipe/project"
"github.com/goreleaser/goreleaser/internal/pipe/reddit"
"github.com/goreleaser/goreleaser/internal/pipe/slack"
"github.com/goreleaser/goreleaser/internal/pipe/release"
"github.com/goreleaser/goreleaser/internal/pipe/scoop"
"github.com/goreleaser/goreleaser/internal/pipe/sign"
@@ -59,5 +60,6 @@ var Defaulters = []Defaulter{
scoop.Pipe{},
twitter.Pipe{},
reddit.Pipe{},
slack.Pipe{},
milestone.Pipe{},
}
+34 -1
View File
@@ -2,7 +2,7 @@
title: Announce
---
GoReleaser can also announce new releases, currently, to Twitter only.
GoReleaser can also announce new releases, currently, to Twitter and Slack only.
It runs at the very end of the pipeline.
@@ -30,6 +30,39 @@ announce:
message_template: 'Awesome project {{.Tag}} is out!'
```
## Slack
For it to work, you'll need to [create a new Incoming Webhook](https://api.slack.com/messaging/webhooks), and set some environment variables on your pipeline:
- `SLACK_WEBHOOK`
Then, you can add something like the following to your `.goreleaser.yml` config:
```yaml
# .goreleaser.yml
announce:
slack:
# Wether its enabled or not.
# Defaults to false.
enabled: true
# Message template to use while publishing.
# Defaults to `{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .GitURL }}/releases/tag/{{ .Tag }}`
message_template: 'Awesome project {{.Tag}} is out!'
# The name of the channel that the user selected as a destination for webhook messages.
channel: '#channel'
# Set your Webhook's user name.
username: ''
# Emoji to use as the icon for this message. Overrides icon_url.
icon_emoji: ''
# URL to an image to use as the icon for this message.
icon_url: ''
```
!!! tip
Learn more about the [name template engine](/customization/templates/).