Skip to content

Commit

Permalink
feat(telegram): ability to choose msg format, mdv2escape (#4036)
Browse files Browse the repository at this point in the history
this allows to choose parse mode between `HTML` and `Markdownv2`, and
adds a new template function, `mdv2escape`, to escape the characters
according to telegram docs:
https://core.telegram.org/bots/api#formatting-options


closes #4021
  • Loading branch information
caarlos0 committed May 27, 2023
1 parent 3bb9a9a commit e0dabc1
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 17 deletions.
43 changes: 30 additions & 13 deletions internal/pipe/telegram/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import (
"github.com/goreleaser/goreleaser/pkg/context"
)

const defaultMessageTemplate = `{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}`
const (
defaultMessageTemplate = `{{ .ProjectName }} {{ mdv2escape .Tag }} is out! Check it out at {{ mdv2escape .ReleaseURL }}`
parseModeHTML = "HTML"
parseModeMarkdown = "MarkdownV2"
)

type Pipe struct{}

Expand All @@ -26,23 +30,19 @@ func (Pipe) Default(ctx *context.Context) error {
if ctx.Config.Announce.Telegram.MessageTemplate == "" {
ctx.Config.Announce.Telegram.MessageTemplate = defaultMessageTemplate
}
switch ctx.Config.Announce.Telegram.ParseMode {
case parseModeHTML, parseModeMarkdown:
break
default:
ctx.Config.Announce.Telegram.ParseMode = parseModeMarkdown
}
return nil
}

func (Pipe) Announce(ctx *context.Context) error {
tpl := tmpl.New(ctx)
msg, err := tpl.Apply(ctx.Config.Announce.Telegram.MessageTemplate)
if err != nil {
return fmt.Errorf("telegram: %w", err)
}

chatIDStr, err := tpl.Apply(ctx.Config.Announce.Telegram.ChatID)
msg, chatID, err := getMessageDetails(ctx)
if err != nil {
return fmt.Errorf("telegram: %w", err)
}
chatID, err := strconv.ParseInt(chatIDStr, 10, 64)
if err != nil {
return fmt.Errorf("telegram: %w", err)
return err
}

var cfg Config
Expand All @@ -65,3 +65,20 @@ func (Pipe) Announce(ctx *context.Context) error {
log.Debug("message sent")
return nil
}

func getMessageDetails(ctx *context.Context) (string, int64, error) {
msg, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Telegram.MessageTemplate)
if err != nil {
return "", 0, fmt.Errorf("telegram: %w", err)
}
chatIDStr, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Telegram.ChatID)
if err != nil {
return "", 0, fmt.Errorf("telegram: %w", err)
}
chatID, err := strconv.ParseInt(chatIDStr, 10, 64)
if err != nil {
return "", 0, fmt.Errorf("telegram: %w", err)
}

return msg, chatID, nil
}
41 changes: 38 additions & 3 deletions internal/pipe/telegram/telegram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,24 @@ func TestStringer(t *testing.T) {
}

func TestDefault(t *testing.T) {
ctx := testctx.New()
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ctx.Config.Announce.Telegram.MessageTemplate, defaultMessageTemplate)
t.Run("empty", func(t *testing.T) {
ctx := testctx.New()
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ctx.Config.Announce.Telegram.MessageTemplate, defaultMessageTemplate)
require.Equal(t, ctx.Config.Announce.Telegram.ParseMode, parseModeMarkdown)
})
t.Run("markdownv2 parsemode", func(t *testing.T) {
ctx := testctx.New()
ctx.Config.Announce.Telegram.ParseMode = parseModeMarkdown
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ctx.Config.Announce.Telegram.ParseMode, parseModeMarkdown)
})
t.Run("html parsemode", func(t *testing.T) {
ctx := testctx.New()
ctx.Config.Announce.Telegram.ParseMode = parseModeHTML
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, ctx.Config.Announce.Telegram.ParseMode, parseModeHTML)
})
}

func TestAnnounceInvalidTemplate(t *testing.T) {
Expand Down Expand Up @@ -84,3 +99,23 @@ func TestSkip(t *testing.T) {
require.False(t, Pipe{}.Skip(ctx))
})
}

func TestGetMessageDetails(t *testing.T) {
t.Run("default message template", func(t *testing.T) {
ctx := testctx.NewWithCfg(
config.Project{
ProjectName: "foo",
Announce: config.Announce{
Telegram: config.Telegram{
ChatID: "1230212",
},
},
},
testctx.WithCurrentTag("v1.0.0"),
)
require.NoError(t, Pipe{}.Default(ctx))
msg, _, err := getMessageDetails(ctx)
require.NoError(t, err)
require.Equal(t, "foo v1\\.0\\.0 is out! Check it out at ", msg)
})
}
24 changes: 24 additions & 0 deletions internal/tmpl/tmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ func (t *Template) Apply(s string) (string, error) {
"incpatch": incPatch,
"filter": filter(false),
"reverseFilter": filter(true),
"mdv2escape": mdv2Escape,
}).
Parse(s)
if err != nil {
Expand Down Expand Up @@ -322,3 +323,26 @@ func filter(reverse bool) func(content, exp string) string {
return strings.Join(lines, "\n")
}
}

func mdv2Escape(s string) string {
return strings.NewReplacer(
"_", "\\_",
"*", "\\*",
"[", "\\[",
"]", "\\]",
"(", "\\(",
")", "\\)",
"~", "\\~",
"`", "\\`",
">", "\\>",
"#", "\\#",
"+", "\\+",
"-", "\\-",
"=", "\\=",
"|", "\\|",
"{", "\\{",
"}", "\\}",
".", "\\.",
"!", "\\!",
).Replace(s)
}
7 changes: 7 additions & 0 deletions internal/tmpl/tmpl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,10 @@ func TestBool(t *testing.T) {
}
})
}

func TestMdv2Escape(t *testing.T) {
require.Equal(
t,
"aaa\\_\\*\\[\\]\\(\\)\\~\\`\\>\\#\\+\\-\\=\\|\\{\\}\\.\\!",
mdv2Escape("aaa_*[]()~`>#+-=|{}.!"))
}
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ type Telegram struct {
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
MessageTemplate string `yaml:"message_template,omitempty" json:"message_template,omitempty"`
ChatID string `yaml:"chat_id,omitempty" json:"chat_id,omitempty" jsonschema:"oneof_type=string;integer"`
ParseMode string `yaml:"parse_mode,omitempty" json:"parse_mode,omitempty" jsonschema:"enum=MarkdownV2,enum=HTML,default=MarkdownV2"`
}

type OpenCollective struct {
Expand Down
12 changes: 11 additions & 1 deletion www/docs/customization/announce/telegram.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,23 @@ announce:

# Message template to use while publishing.
#
# Default: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
# Default: '{{ .ProjectName }} {{ mdv2escape .Tag }} is out! Check it out at {{ mdv2escape .ReleaseURL }}'
# Templates: allowed
message_template: 'Awesome project {{.Tag}} is out!'

# Parse mode.
#
# Valid options are MarkdownV2 and HTML.
#
# Default: MarkdownV2
# Since: v1.19
parse_mode: HTML
```

You can format your message using `MarkdownV2`, for reference, see the
[Telegram Bot API](https://core.telegram.org/bots/api#markdownv2-style).

!!! tip
Learn more about the [name template engine](/customization/templates/).
In the specific case of `MarkdownV2`, you'll probably need the `mdv2escape`
function.
1 change: 1 addition & 0 deletions www/docs/customization/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ Usage |Description
`filter "text" "regex"` |keeps only the lines matching the given regex, analogous to `grep -E`. Since v1.6.
`reverseFilter "text" "regex"`|keeps only the lines **not** matching the given regex, analogous to `grep -vE`. Since v1.6.
`title "foo"` |"titlenize" the string using english as language. See [Title](https://pkg.go.dev/golang.org/x/text/cases#Title). Since v1.14.
`mdv2escape "foo"` |escape characteres according to MarkdownV2, especially useful in the Telegram integration. Since v1.19.

With all those fields, you may be able to compose the name of your artifacts
pretty much the way you want:
Expand Down

0 comments on commit e0dabc1

Please sign in to comment.