github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/discord/discord.go (about) 1 package discord 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/url" 9 "strconv" 10 11 "github.com/caarlos0/env/v9" 12 "github.com/caarlos0/log" 13 "github.com/goreleaser/goreleaser/internal/tmpl" 14 "github.com/goreleaser/goreleaser/pkg/context" 15 ) 16 17 const ( 18 defaultAuthor = `GoReleaser` 19 defaultColor = "3888754" 20 defaultIcon = "https://goreleaser.com/static/avatar.png" 21 defaultMessageTemplate = `{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}` 22 ) 23 24 type Pipe struct{} 25 26 func (Pipe) String() string { return "discord" } 27 func (Pipe) Skip(ctx *context.Context) bool { return !ctx.Config.Announce.Discord.Enabled } 28 29 type Config struct { 30 WebhookID string `env:"DISCORD_WEBHOOK_ID,notEmpty"` 31 WebhookToken string `env:"DISCORD_WEBHOOK_TOKEN,notEmpty"` 32 } 33 34 func (p Pipe) Default(ctx *context.Context) error { 35 if ctx.Config.Announce.Discord.MessageTemplate == "" { 36 ctx.Config.Announce.Discord.MessageTemplate = defaultMessageTemplate 37 } 38 if ctx.Config.Announce.Discord.IconURL == "" { 39 ctx.Config.Announce.Discord.IconURL = defaultIcon 40 } 41 if ctx.Config.Announce.Discord.Author == "" { 42 ctx.Config.Announce.Discord.Author = defaultAuthor 43 } 44 if ctx.Config.Announce.Discord.Color == "" { 45 ctx.Config.Announce.Discord.Color = defaultColor 46 } 47 return nil 48 } 49 50 func (p Pipe) Announce(ctx *context.Context) error { 51 msg, err := tmpl.New(ctx).Apply(ctx.Config.Announce.Discord.MessageTemplate) 52 if err != nil { 53 return fmt.Errorf("discord: %w", err) 54 } 55 56 var cfg Config 57 if err = env.Parse(&cfg); err != nil { 58 return fmt.Errorf("discord: %w", err) 59 } 60 61 log.Infof("posting: '%s'", msg) 62 63 color, err := strconv.Atoi(ctx.Config.Announce.Discord.Color) 64 if err != nil { 65 return fmt.Errorf("discord: %w", err) 66 } 67 68 u, err := url.Parse("https://discord.com/api") 69 if err != nil { 70 return fmt.Errorf("discord: %w", err) 71 } 72 u = u.JoinPath("webhooks", cfg.WebhookID, cfg.WebhookToken) 73 74 bts, err := json.Marshal(WebhookMessageCreate{ 75 Embeds: []Embed{ 76 { 77 Author: &EmbedAuthor{ 78 Name: ctx.Config.Announce.Discord.Author, 79 IconURL: ctx.Config.Announce.Discord.IconURL, 80 }, 81 Description: msg, 82 Color: color, 83 }, 84 }, 85 }) 86 if err != nil { 87 return fmt.Errorf("discord: %w", err) 88 } 89 90 resp, err := http.Post(u.String(), "application/json", bytes.NewReader(bts)) 91 if err != nil { 92 return fmt.Errorf("discord: %w", err) 93 } 94 95 if resp.StatusCode != 204 && resp.StatusCode != 200 { 96 return fmt.Errorf("discord: %s", resp.Status) 97 } 98 99 return nil 100 } 101 102 type WebhookMessageCreate struct { 103 Embeds []Embed `json:"embeds,omitempty"` 104 } 105 106 type Embed struct { 107 Description string `json:"description,omitempty"` 108 Color int `json:"color,omitempty"` 109 Author *EmbedAuthor `json:"author,omitempty"` 110 } 111 112 type EmbedAuthor struct { 113 Name string `json:"name,omitempty"` 114 IconURL string `json:"icon_url,omitempty"` 115 }