package webhook import ( "context" "fmt" "strings" "time" "gitea.oblak.solutions/dimitar/gitFlow/internal/httpclient" ) // DiscordSender posts to a Discord webhook URL using a single rich embed. type DiscordSender struct { cfg Config http *httpclient.Client } func newDiscord(cfg Config) *DiscordSender { return &DiscordSender{cfg: cfg, http: httpclient.New(httpclient.WithTimeout(cfg.TimeoutOrDefault()))} } func (s *DiscordSender) Name() string { return s.cfg.Name } type discordMessage struct { Embeds []discordEmbed `json:"embeds"` } type discordEmbed struct { Title string `json:"title"` Description string `json:"description"` Color int `json:"color"` Footer *discordFooter `json:"footer,omitempty"` Timestamp string `json:"timestamp,omitempty"` } type discordFooter struct { Text string `json:"text"` } // Status-to-color mapping: green=clean, yellow=attention, red=errors. func embedColor(s Payload) int { switch { case s.Summary.Errored > 0: return 15158332 // red case s.Summary.Attention > 0: return 16776960 // yellow default: return 3066993 // green } } func (s *DiscordSender) Send(ctx context.Context, payload Payload) error { msg := discordMessage{ Embeds: []discordEmbed{{ Title: "gitflow scan", Description: discordBody(payload), Color: embedColor(payload), Footer: &discordFooter{Text: "gitflow"}, Timestamp: payload.Timestamp.Format(time.RFC3339), }}, } return s.http.PostJSON(ctx, s.cfg.URL, nil, msg, nil) } func discordBody(p Payload) string { var b strings.Builder s := p.Summary fmt.Fprintf(&b, "**%s** — %d repos: %d clean, %d attention, %d errors\n\n", p.ParentDir, s.Total, s.Clean, s.Attention, s.Errored) if len(p.Changed) > 0 { b.WriteString("**Changed:**\n") for _, r := range p.Changed { sym := statusSymbol(r.Status) line := fmt.Sprintf("%s **%s** — %s (%s)", sym, r.Name, r.Status, r.Branch) if r.AheadBy > 0 || r.BehindBy > 0 { line += fmt.Sprintf(" +%d/-%d", r.AheadBy, r.BehindBy) } if n := r.FileCount(); n > 0 { line += fmt.Sprintf(" %d file(s)", n) } b.WriteString(line + "\n") } } return b.String() }