diff --git a/pkg/notifications/email.go b/pkg/notifications/email.go index 19542a9..b6883a2 100644 --- a/pkg/notifications/email.go +++ b/pkg/notifications/email.go @@ -15,16 +15,15 @@ const ( ) type emailTypeNotifier struct { - From, To string - Server, User, Password, SubjectTag string - Port int - tlsSkipVerify bool - entries []*log.Entry - logLevels []log.Level - delay time.Duration + From, To string + Server, User, Password string + Port int + tlsSkipVerify bool + entries []*log.Entry + delay time.Duration } -func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertibleNotifier { +func newEmailNotifier(c *cobra.Command) t.ConvertibleNotifier { flags := c.Flags() from, _ := flags.GetString("notification-email-from") @@ -35,7 +34,6 @@ func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Convert port, _ := flags.GetInt("notification-email-server-port") tlsSkipVerify, _ := flags.GetBool("notification-email-server-tls-skip-verify") delay, _ := flags.GetInt("notification-email-delay") - subjecttag, _ := flags.GetString("notification-email-subjecttag") n := &emailTypeNotifier{ entries: []*log.Entry{}, @@ -46,22 +44,19 @@ func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Convert Password: password, Port: port, tlsSkipVerify: tlsSkipVerify, - logLevels: acceptedLogLevels, delay: time.Duration(delay) * time.Second, - SubjectTag: subjecttag, } return n } -func (e *emailTypeNotifier) GetURL(c *cobra.Command, title string) (string, error) { +func (e *emailTypeNotifier) GetURL(c *cobra.Command) (string, error) { conf := &shoutrrrSmtp.Config{ FromAddress: e.From, FromName: "Watchtower", ToAddresses: []string{e.To}, Port: uint16(e.Port), Host: e.Server, - Subject: e.getSubject(c, title), Username: e.User, Password: e.Password, UseStartTLS: !e.tlsSkipVerify, @@ -84,11 +79,3 @@ func (e *emailTypeNotifier) GetURL(c *cobra.Command, title string) (string, erro func (e *emailTypeNotifier) GetDelay() time.Duration { return e.delay } - -func (e *emailTypeNotifier) getSubject(_ *cobra.Command, title string) string { - if e.SubjectTag != "" { - return e.SubjectTag + " " + title - } - - return title -} diff --git a/pkg/notifications/gotify.go b/pkg/notifications/gotify.go index 973dde6..c36eb4b 100644 --- a/pkg/notifications/gotify.go +++ b/pkg/notifications/gotify.go @@ -19,10 +19,9 @@ type gotifyTypeNotifier struct { gotifyURL string gotifyAppToken string gotifyInsecureSkipVerify bool - logLevels []log.Level } -func newGotifyNotifier(c *cobra.Command, levels []log.Level) t.ConvertibleNotifier { +func newGotifyNotifier(c *cobra.Command) t.ConvertibleNotifier { flags := c.Flags() apiURL := getGotifyURL(flags) @@ -34,7 +33,6 @@ func newGotifyNotifier(c *cobra.Command, levels []log.Level) t.ConvertibleNotifi gotifyURL: apiURL, gotifyAppToken: token, gotifyInsecureSkipVerify: skipVerify, - logLevels: levels, } return n @@ -62,7 +60,7 @@ func getGotifyURL(flags *pflag.FlagSet) string { return gotifyURL } -func (n *gotifyTypeNotifier) GetURL(c *cobra.Command, title string) (string, error) { +func (n *gotifyTypeNotifier) GetURL(c *cobra.Command) (string, error) { apiURL, err := url.Parse(n.gotifyURL) if err != nil { return "", err @@ -72,7 +70,6 @@ func (n *gotifyTypeNotifier) GetURL(c *cobra.Command, title string) (string, err Host: apiURL.Host, Path: apiURL.Path, DisableTLS: apiURL.Scheme == "http", - Title: title, Token: n.gotifyAppToken, } diff --git a/pkg/notifications/msteams.go b/pkg/notifications/msteams.go index 232d535..cfca30e 100644 --- a/pkg/notifications/msteams.go +++ b/pkg/notifications/msteams.go @@ -15,11 +15,10 @@ const ( type msTeamsTypeNotifier struct { webHookURL string - levels []log.Level data bool } -func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.ConvertibleNotifier { +func newMsTeamsNotifier(cmd *cobra.Command) t.ConvertibleNotifier { flags := cmd.Flags() @@ -30,7 +29,6 @@ func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Con withData, _ := flags.GetBool("notification-msteams-data") n := &msTeamsTypeNotifier{ - levels: acceptedLogLevels, webHookURL: webHookURL, data: withData, } @@ -38,7 +36,7 @@ func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Con return n } -func (n *msTeamsTypeNotifier) GetURL(c *cobra.Command, title string) (string, error) { +func (n *msTeamsTypeNotifier) GetURL(c *cobra.Command) (string, error) { webhookURL, err := url.Parse(n.webHookURL) if err != nil { return "", err @@ -50,7 +48,6 @@ func (n *msTeamsTypeNotifier) GetURL(c *cobra.Command, title string) (string, er } config.Color = ColorHex - config.Title = title return config.GetURL().String(), nil } diff --git a/pkg/notifications/notifier.go b/pkg/notifications/notifier.go index 03ea644..ff7b6b5 100644 --- a/pkg/notifications/notifier.go +++ b/pkg/notifications/notifier.go @@ -6,7 +6,6 @@ import ( "time" ty "github.com/containrrr/watchtower/pkg/types" - "github.com/johntdyer/slackrus" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -21,25 +20,19 @@ func NewNotifier(c *cobra.Command) ty.Notifier { log.Fatalf("Notifications invalid log level: %s", err.Error()) } - levels := slackrus.LevelThreshold(logLevel) - // slackrus does not allow log level TRACE, even though it's an accepted log level for logrus - if len(levels) == 0 { - log.Fatalf("Unsupported notification log level provided: %s", level) - } - reportTemplate, _ := f.GetBool("notification-report") stdout, _ := f.GetBool("notification-log-stdout") tplString, _ := f.GetString("notification-template") urls, _ := f.GetStringArray("notification-url") data := GetTemplateData(c) - urls, delay := AppendLegacyUrls(urls, c, data.Title) + urls, delay := AppendLegacyUrls(urls, c) - return createNotifier(urls, levels, tplString, !reportTemplate, data, stdout, delay) + return createNotifier(urls, logLevel, tplString, !reportTemplate, data, stdout, delay) } // AppendLegacyUrls creates shoutrrr equivalent URLs from legacy notification flags -func AppendLegacyUrls(urls []string, cmd *cobra.Command, title string) ([]string, time.Duration) { +func AppendLegacyUrls(urls []string, cmd *cobra.Command) ([]string, time.Duration) { // Parse types and create notifiers. types, err := cmd.Flags().GetStringSlice("notifications") @@ -56,13 +49,13 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command, title string) ([]string switch t { case emailType: - legacyNotifier = newEmailNotifier(cmd, []log.Level{}) + legacyNotifier = newEmailNotifier(cmd) case slackType: - legacyNotifier = newSlackNotifier(cmd, []log.Level{}) + legacyNotifier = newSlackNotifier(cmd) case msTeamsType: - legacyNotifier = newMsTeamsNotifier(cmd, []log.Level{}) + legacyNotifier = newMsTeamsNotifier(cmd) case gotifyType: - legacyNotifier = newGotifyNotifier(cmd, []log.Level{}) + legacyNotifier = newGotifyNotifier(cmd) case shoutrrrType: continue default: @@ -71,7 +64,7 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command, title string) ([]string continue } - shoutrrrURL, err := legacyNotifier.GetURL(cmd, title) + shoutrrrURL, err := legacyNotifier.GetURL(cmd) if err != nil { log.Fatal("failed to create notification config: ", err) } diff --git a/pkg/notifications/notifier_test.go b/pkg/notifications/notifier_test.go index 1b004dc..96d513c 100644 --- a/pkg/notifications/notifier_test.go +++ b/pkg/notifications/notifier_test.go @@ -3,7 +3,6 @@ package notifications_test import ( "fmt" "net/url" - "os" "time" "github.com/containrrr/watchtower/cmd" @@ -147,11 +146,9 @@ var _ = Describe("notifications", func() { channel := "123456789" token := "abvsihdbau" color := notifications.ColorInt - data := notifications.GetTemplateData(command) - title := url.QueryEscape(data.Title) username := "containrrrbot" iconURL := "https://containrrr.dev/watchtower-sq180.png" - expected := fmt.Sprintf("discord://%s@%s?color=0x%x&colordebug=0x0&colorerror=0x0&colorinfo=0x0&colorwarn=0x0&title=%s&username=watchtower", token, channel, color, title) + expected := fmt.Sprintf("discord://%s@%s?color=0x%x&colordebug=0x0&colorerror=0x0&colorinfo=0x0&colorwarn=0x0&username=watchtower", token, channel, color) buildArgs := func(url string) []string { return []string{ "--notifications", @@ -172,7 +169,7 @@ var _ = Describe("notifications", func() { When("icon URL and username are specified", func() { It("should return the expected URL", func() { hookURL := fmt.Sprintf("https://%s/api/webhooks/%s/%s/slack", "discord.com", channel, token) - expectedOutput := fmt.Sprintf("discord://%s@%s?avatar=%s&color=0x%x&colordebug=0x0&colorerror=0x0&colorinfo=0x0&colorwarn=0x0&title=%s&username=%s", token, channel, url.QueryEscape(iconURL), color, title, username) + expectedOutput := fmt.Sprintf("discord://%s@%s?avatar=%s&color=0x%x&colordebug=0x0&colorerror=0x0&colorinfo=0x0&colorwarn=0x0&username=%s", token, channel, url.QueryEscape(iconURL), color, username) expectedDelay := time.Duration(7) * time.Second args := []string{ "--notifications", @@ -199,8 +196,6 @@ var _ = Describe("notifications", func() { tokenB := "BBBBBBBBB" tokenC := "123456789123456789123456" color := url.QueryEscape(notifications.ColorHex) - data := notifications.GetTemplateData(command) - title := url.QueryEscape(data.Title) iconURL := "https://containrrr.dev/watchtower-sq180.png" iconEmoji := "whale" @@ -208,7 +203,7 @@ var _ = Describe("notifications", func() { It("should return the expected URL", func() { hookURL := fmt.Sprintf("https://hooks.slack.com/services/%s/%s/%s", tokenA, tokenB, tokenC) - expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s&title=%s", tokenA, tokenB, tokenC, username, color, url.QueryEscape(iconURL), title) + expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s", tokenA, tokenB, tokenC, username, color, url.QueryEscape(iconURL)) expectedDelay := time.Duration(7) * time.Second args := []string{ @@ -231,7 +226,7 @@ var _ = Describe("notifications", func() { When("icon emoji is specified", func() { It("should return the expected URL", func() { hookURL := fmt.Sprintf("https://hooks.slack.com/services/%s/%s/%s", tokenA, tokenB, tokenC) - expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s&title=%s", tokenA, tokenB, tokenC, username, color, iconEmoji, title) + expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s", tokenA, tokenB, tokenC, username, color, iconEmoji) args := []string{ "--notifications", @@ -258,10 +253,8 @@ var _ = Describe("notifications", func() { token := "aaa" host := "shoutrrr.local" - data := notifications.GetTemplateData(command) - title := url.QueryEscape(data.Title) - expectedOutput := fmt.Sprintf("gotify://%s/%s?title=%s", host, token, title) + expectedOutput := fmt.Sprintf("gotify://%s/%s?title=", host, token) args := []string{ "--notifications", @@ -287,11 +280,9 @@ var _ = Describe("notifications", func() { tokenB := "33333333012222222222333333333344" tokenC := "44444444-4444-4444-8444-cccccccccccc" color := url.QueryEscape(notifications.ColorHex) - data := notifications.GetTemplateData(command) - title := url.QueryEscape(data.Title) hookURL := fmt.Sprintf("https://outlook.office.com/webhook/%s/IncomingWebhook/%s/%s", tokenA, tokenB, tokenC) - expectedOutput := fmt.Sprintf("teams://%s/%s/%s?color=%s&title=%s", tokenA, tokenB, tokenC, color, title) + expectedOutput := fmt.Sprintf("teams://%s/%s/%s?color=%s", tokenA, tokenB, tokenC, color) args := []string{ "--notifications", @@ -362,18 +353,12 @@ var _ = Describe("notifications", func() { }) func buildExpectedURL(username string, password string, host string, port int, from string, to string, auth string) string { - hostname, err := os.Hostname() - Expect(err).NotTo(HaveOccurred()) - - subject := fmt.Sprintf("Watchtower updates on %s", hostname) - - var template = "smtp://%s:%s@%s:%d/?auth=%s&fromaddress=%s&fromname=Watchtower&subject=%s&toaddresses=%s" + var template = "smtp://%s:%s@%s:%d/?auth=%s&fromaddress=%s&fromname=Watchtower&subject=&toaddresses=%s" return fmt.Sprintf(template, url.QueryEscape(username), url.QueryEscape(password), host, port, auth, url.QueryEscape(from), - url.QueryEscape(subject), url.QueryEscape(to)) } @@ -385,8 +370,7 @@ func testURL(args []string, expectedURL string, expectedDelay time.Duration) { Expect(command.ParseFlags(args)).To(Succeed()) - data := notifications.GetTemplateData(command) - urls, delay := notifications.AppendLegacyUrls([]string{}, command, data.Title) + urls, delay := notifications.AppendLegacyUrls([]string{}, command) Expect(urls).To(ContainElement(expectedURL)) Expect(delay).To(Equal(expectedDelay)) diff --git a/pkg/notifications/shoutrrr.go b/pkg/notifications/shoutrrr.go index 6eccd33..47141e8 100644 --- a/pkg/notifications/shoutrrr.go +++ b/pkg/notifications/shoutrrr.go @@ -32,7 +32,7 @@ type shoutrrrTypeNotifier struct { Urls []string Router router entries []*log.Entry - logLevels []log.Level + logLevel log.Level template *template.Template messages chan string done chan bool @@ -78,7 +78,7 @@ func (n *shoutrrrTypeNotifier) AddLogHook() { go sendNotifications(n) } -func createNotifier(urls []string, levels []log.Level, tplString string, legacy bool, data StaticData, stdout bool, delay time.Duration) *shoutrrrTypeNotifier { +func createNotifier(urls []string, level log.Level, tplString string, legacy bool, data StaticData, stdout bool, delay time.Duration) *shoutrrrTypeNotifier { tpl, err := getShoutrrrTemplate(tplString, legacy) if err != nil { log.Errorf("Could not use configured notification template: %s. Using default template", err) @@ -105,7 +105,7 @@ func createNotifier(urls []string, levels []log.Level, tplString string, legacy Router: r, messages: make(chan string, 1), done: make(chan bool), - logLevels: levels, + logLevel: level, template: tpl, legacyTemplate: legacy, data: data, @@ -188,7 +188,7 @@ func (n *shoutrrrTypeNotifier) Close() { // Levels return what log levels trigger notifications func (n *shoutrrrTypeNotifier) Levels() []log.Level { - return n.logLevels + return log.AllLevels[:n.logLevel+1] } // Fire is the hook that logrus calls on a new log message diff --git a/pkg/notifications/shoutrrr_test.go b/pkg/notifications/shoutrrr_test.go index c2f94fb..89b86dd 100644 --- a/pkg/notifications/shoutrrr_test.go +++ b/pkg/notifications/shoutrrr_test.go @@ -14,7 +14,7 @@ import ( "github.com/spf13/cobra" ) -var allButTrace = logrus.AllLevels[0:logrus.TraceLevel] +var allButTrace = logrus.DebugLevel var legacyMockData = Data{ Entries: []*logrus.Entry{ @@ -90,7 +90,7 @@ updt1 (mock/updt1:latest): Updated cmd := new(cobra.Command) flags.RegisterNotificationFlags(cmd) - shoutrrr := createNotifier([]string{}, logrus.AllLevels, "", true, StaticData{}, false, time.Second) + shoutrrr := createNotifier([]string{}, logrus.TraceLevel, "", true, StaticData{}, false, time.Second) entries := []*logrus.Entry{ { diff --git a/pkg/notifications/slack.go b/pkg/notifications/slack.go index f72ae4d..9118527 100644 --- a/pkg/notifications/slack.go +++ b/pkg/notifications/slack.go @@ -6,7 +6,6 @@ import ( shoutrrrDisco "github.com/containrrr/shoutrrr/pkg/services/discord" shoutrrrSlack "github.com/containrrr/shoutrrr/pkg/services/slack" t "github.com/containrrr/watchtower/pkg/types" - "github.com/johntdyer/slackrus" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -16,10 +15,14 @@ const ( ) type slackTypeNotifier struct { - slackrus.SlackrusHook + HookURL string + Username string + Channel string + IconEmoji string + IconURL string } -func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertibleNotifier { +func newSlackNotifier(c *cobra.Command) t.ConvertibleNotifier { flags := c.Flags() hookURL, _ := flags.GetString("notification-slack-hook-url") @@ -29,19 +32,16 @@ func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Convert iconURL, _ := flags.GetString("notification-slack-icon-url") n := &slackTypeNotifier{ - SlackrusHook: slackrus.SlackrusHook{ - HookURL: hookURL, - Username: userName, - Channel: channel, - IconEmoji: emoji, - IconURL: iconURL, - AcceptedLevels: acceptedLogLevels, - }, + HookURL: hookURL, + Username: userName, + Channel: channel, + IconEmoji: emoji, + IconURL: iconURL, } return n } -func (s *slackTypeNotifier) GetURL(c *cobra.Command, title string) (string, error) { +func (s *slackTypeNotifier) GetURL(c *cobra.Command) (string, error) { trimmedURL := strings.TrimRight(s.HookURL, "/") trimmedURL = strings.TrimPrefix(trimmedURL, "https://") parts := strings.Split(trimmedURL, "/") @@ -52,7 +52,6 @@ func (s *slackTypeNotifier) GetURL(c *cobra.Command, title string) (string, erro WebhookID: parts[len(parts)-3], Token: parts[len(parts)-2], Color: ColorInt, - Title: title, SplitLines: true, Username: s.Username, } @@ -70,7 +69,6 @@ func (s *slackTypeNotifier) GetURL(c *cobra.Command, title string) (string, erro BotName: s.Username, Color: ColorHex, Channel: "webhook", - Title: title, } if s.IconURL != "" { diff --git a/pkg/types/convertible_notifier.go b/pkg/types/convertible_notifier.go index 37d8872..82d7b7b 100644 --- a/pkg/types/convertible_notifier.go +++ b/pkg/types/convertible_notifier.go @@ -1,16 +1,17 @@ package types import ( - "github.com/spf13/cobra" "time" + + "github.com/spf13/cobra" ) // ConvertibleNotifier is a notifier capable of creating a shoutrrr URL type ConvertibleNotifier interface { - GetURL(c *cobra.Command, title string) (string, error) + GetURL(c *cobra.Command) (string, error) } // DelayNotifier is a notifier that might need to be delayed before sending notifications type DelayNotifier interface { GetDelay() time.Duration -} \ No newline at end of file +}