diff --git a/internal/pipe/slack/slack.go b/internal/pipe/slack/slack.go index 3b921a932..fd17ba790 100644 --- a/internal/pipe/slack/slack.go +++ b/internal/pipe/slack/slack.go @@ -3,6 +3,7 @@ package slack import ( "encoding/json" "fmt" + "strings" "github.com/caarlos0/env/v9" "github.com/caarlos0/log" @@ -102,7 +103,11 @@ func unmarshal(ctx *context.Context, in interface{}, target interface{}) error { return fmt.Errorf("failed to marshal input as JSON: %w", err) } - tplApplied, err := tmpl.New(ctx).Apply(string(jazon)) + body := string(jazon) + // ensure that double quotes that are inside the string get un-escaped so they can be interpreted for templates + body = strings.ReplaceAll(body, "\\\"", "\"") + + tplApplied, err := tmpl.New(ctx).Apply(body) if err != nil { return fmt.Errorf("failed to evaluate template: %w", err) } diff --git a/internal/pipe/slack/slack_test.go b/internal/pipe/slack/slack_test.go index f64ab4498..5c0ee9a1f 100644 --- a/internal/pipe/slack/slack_test.go +++ b/internal/pipe/slack/slack_test.go @@ -2,6 +2,7 @@ package slack import ( "bytes" + "encoding/json" "testing" "github.com/goreleaser/goreleaser/internal/testctx" @@ -9,6 +10,7 @@ import ( "github.com/goreleaser/goreleaser/internal/yaml" "github.com/goreleaser/goreleaser/pkg/config" "github.com/slack-go/slack" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -33,6 +35,42 @@ func TestAnnounceInvalidTemplate(t *testing.T) { testlib.RequireTemplateError(t, Pipe{}.Announce(ctx)) } +func TestAnnounceWithQuotes(t *testing.T) { + t.Setenv("SLACK_WEBHOOK", slackTestHook()) + t.Setenv("USER", "bot-mc-botyson") + + t.Run("with a plain message", func(t *testing.T) { + ctx := testctx.NewWithCfg(config.Project{ + Announce: config.Announce{ + Slack: config.Slack{ + MessageTemplate: "{{ envOrDefault \"USER\" \"\" }}", + }, + }, + }) + require.NoError(t, Pipe{}.Announce(ctx)) + }) + + t.Run("with rich text", func(t *testing.T) { + var project config.Project + require.NoError(t, yaml.Unmarshal(goodRichSlackConfWithEnv(), &project)) + ctx := testctx.NewWithCfg(project) + blocks, attachments, err := parseAdvancedFormatting(ctx) + require.NoError(t, err) + assert.Len(t, blocks.BlockSet, 2) + + blocksBody, err := json.Marshal(blocks.BlockSet) + require.NoError(t, err) + + assert.Contains(t, string(blocksBody), `The current user is bot-mc-botyson`) + assert.Contains(t, string(blocksBody), `The current user is bot-mc-botyson\nnewline!`) + + assert.Len(t, attachments, 1) + attachmentsBody, err := json.Marshal(attachments) + require.NoError(t, err) + assert.Contains(t, string(attachmentsBody), `The current user is bot-mc-botyson\n\nIncluding newlines\n`) + }) +} + func TestAnnounceMissingEnv(t *testing.T) { ctx := testctx.NewWithCfg(config.Project{ Announce: config.Announce{ @@ -311,3 +349,33 @@ announce: return bytes.ReplaceAll(buf.Bytes(), []byte("\t"), []byte(" ")) } + +func goodRichSlackConfWithEnv() []byte { + const conf = ` +project_name: test +announce: + slack: + enabled: true + blocks: + - type: header + text: + type: plain_text + text: 'The current user is {{ envOrDefault "USER" "" }}' + - type: header + text: + type: plain_text + text: "The current user is {{ envOrDefault \"USER\" \"\" }}\nnewline!" + attachments: + - + title: Release artifacts + color: '#2eb886' + text: | + The current user is {{ envOrDefault "USER" "" }} + + Including newlines +` + + buf := bytes.NewBufferString(conf) + + return bytes.ReplaceAll(buf.Bytes(), []byte("\t"), []byte(" ")) +}