diff --git a/.res/notif-gotify.png b/.res/notif-gotify.png index 136e1044..7bac1d7f 100644 Binary files a/.res/notif-gotify.png and b/.res/notif-gotify.png differ diff --git a/.res/notif-mail.png b/.res/notif-mail.png index 1990dfdb..aa688a24 100644 Binary files a/.res/notif-mail.png and b/.res/notif-mail.png differ diff --git a/.res/notif-rocketchat.png b/.res/notif-rocketchat.png index 45889abc..edd534d9 100644 Binary files a/.res/notif-rocketchat.png and b/.res/notif-rocketchat.png differ diff --git a/.res/notif-slack.png b/.res/notif-slack.png index c2f46295..8e0f1a86 100644 Binary files a/.res/notif-slack.png and b/.res/notif-slack.png differ diff --git a/.res/notif-telegram.png b/.res/notif-telegram.png index 3442f036..db8df08e 100644 Binary files a/.res/notif-telegram.png and b/.res/notif-telegram.png differ diff --git a/doc/notifications.md b/doc/notifications.md index fd34f7eb..79e7a3f3 100644 --- a/doc/notifications.md +++ b/doc/notifications.md @@ -47,6 +47,7 @@ The JSON response will look like this: "status": "new", "provider": "file", "image": "docker.io/crazymax/swarm-cronjob:0.2.1", + "hub_link": "https://hub.docker.com/r/crazymax/swarm-cronjob", "mime_type": "application/vnd.docker.distribution.manifest.v2+json", "digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79", "created": "2019-01-24T10:26:49.152006005Z", @@ -148,10 +149,11 @@ DIUN_VERSION=3.0.0 DIUN_ENTRY_STATUS=new DIUN_ENTRY_PROVIDER=file DIUN_ENTRY_IMAGE=docker.io/crazymax/diun:latest +DIUN_ENTRY_HUBLINK=https://hub.docker.com/r/crazymax/diun DIUN_ENTRY_MIMETYPE=application/vnd.docker.distribution.manifest.list.v2+json DIUN_ENTRY_DIGEST=sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01 DIUN_ENTRY_CREATED=2020-03-26 12:23:56 +0000 UTC -DIUN_ENTRY_PLATFORM=linux/adm64 +DIUN_ENTRY_PLATFORM=linux/amd64 ``` ### Configuration file @@ -252,13 +254,14 @@ The JSON response will look like this: ```json { - "diun_version": "0.3.0", + "diun_version": "4.0.0", "status": "new", "provider": "file", - "image": "docker.io/crazymax/swarm-cronjob:0.2.1", - "mime_type": "application/vnd.docker.distribution.manifest.v2+json", - "digest": "sha256:5913d4b5e8dc15430c2f47f40e43ab2ca7f2b8df5eee5db4d5c42311e08dfb79", - "created": "2019-01-24T10:26:49.152006005Z", + "image": "docker.io/crazymax/diun:latest", + "hub_link": "https://hub.docker.com/r/crazymax/diun", + "mime_type": "application/vnd.docker.distribution.manifest.list.v2+json", + "digest": "sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01", + "created": "2020-03-26T12:23:56Z", "platform": "linux/amd64" } ``` diff --git a/internal/app/diun.go b/internal/app/diun.go index c1ef4483..2d8c24b8 100644 --- a/internal/app/diun.go +++ b/internal/app/diun.go @@ -179,7 +179,7 @@ func (di *Diun) TestNotif() { "sha256:c6a5bfed445b3ed7e85523cd73c6532ac9f9b72bb588ca728fd5b33987ca6538", "sha256:df2140efb8abeb727ef0b27ff158b7010a7941eb1cfdade505f510a6e1eaf016", }, - Platform: "linux/adm64", + Platform: "linux/amd64", }, }) } diff --git a/internal/notif/amqp/client.go b/internal/notif/amqp/client.go index 80fa445e..6a58c906 100644 --- a/internal/notif/amqp/client.go +++ b/internal/notif/amqp/client.go @@ -75,6 +75,7 @@ func (c *Client) Send(entry model.NotifEntry) error { Status string `json:"status"` Provider string `json:"provider"` Image string `json:"image"` + HubLink string `json:"hub_link"` MIMEType string `json:"mime_type"` Digest digest.Digest `json:"digest"` Created *time.Time `json:"created"` @@ -84,6 +85,7 @@ func (c *Client) Send(entry model.NotifEntry) error { Status: string(entry.Status), Provider: entry.Provider, Image: entry.Image.String(), + HubLink: entry.Image.HubLink, MIMEType: entry.Manifest.MIMEType, Digest: entry.Manifest.Digest, Created: entry.Manifest.Created, diff --git a/internal/notif/gotify/client.go b/internal/notif/gotify/client.go index 325ab30f..8d1b6dee 100644 --- a/internal/notif/gotify/client.go +++ b/internal/notif/gotify/client.go @@ -8,7 +8,6 @@ import ( "net/url" "path" "strconv" - "strings" "text/template" "github.com/crazy-max/diun/v4/internal/model" @@ -48,16 +47,35 @@ func (c *Client) Send(entry model.NotifEntry) error { title = fmt.Sprintf("New image %s has been added", entry.Image.String()) } + tagTpl := "`{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}`" + if len(entry.Image.HubLink) > 0 { + tagTpl = "[`{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}`]({{ .Image.HubLink }})" + } + var msgBuf bytes.Buffer - msgTpl := template.Must(template.New("gotify").Parse(`Docker 🐳 tag {{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }} which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}.`)) + msgTpl := template.Must(template.New("gotify").Parse(fmt.Sprintf("Docker tag %s which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status \"new\") }}newly added{{ else }}updated{{ end }}.", tagTpl))) if err := msgTpl.Execute(&msgBuf, entry); err != nil { return err } - data := url.Values{} - data.Set("message", msgBuf.String()) - data.Set("title", title) - data.Set("priority", strconv.Itoa(c.cfg.Priority)) + var body, err = json.Marshal(struct { + Message string `json:"message"` + Title string `json:"title"` + Priority int `json:"priority"` + Extras map[string]interface{} `json:"extras"` + }{ + Message: msgBuf.String(), + Title: title, + Priority: c.cfg.Priority, + Extras: map[string]interface{}{ + "client::display": map[string]string{ + "contentType": "text/markdown", + }, + }, + }) + if err != nil { + return err + } u, err := url.Parse(c.cfg.Endpoint) if err != nil { @@ -69,13 +87,13 @@ func (c *Client) Send(entry model.NotifEntry) error { q.Set("token", c.cfg.Token) u.RawQuery = q.Encode() - req, err := http.NewRequest("POST", u.String(), strings.NewReader(data.Encode())) + req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(body)) if err != nil { return err } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) + req.Header.Set("Content-Type", "application/json") + req.Header.Add("Content-Length", strconv.Itoa(len(string(body)))) req.Header.Set("User-Agent", c.meta.UserAgent) resp, err := hc.Do(req) diff --git a/internal/notif/mail/client.go b/internal/notif/mail/client.go index dc438c1d..55ffe261 100644 --- a/internal/notif/mail/client.go +++ b/internal/notif/mail/client.go @@ -59,17 +59,23 @@ func (c *Client) Send(entry model.NotifEntry) error { subject = fmt.Sprintf("New image %s has been added", entry.Image.String()) } + tagTpl := "**{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}**" + if len(entry.Image.HubLink) > 0 { + tagTpl = "[**{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}**]({{ .Image.HubLink }})" + } + // Body var emailBuf bytes.Buffer - emailTpl := template.Must(template.New("email").Parse(` + emailTpl := template.Must(template.New("email").Parse(fmt.Sprintf(` -Docker 🐳 tag **{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}** which you subscribed to through **{{ .Provider }}** provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}. +Docker tag %s which you subscribed to through **{{ .Provider }}** provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}. -This image has been {{ if (eq .Status "new") }}created{{ else }}updated{{ end }} at {{ .Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Manifest.Digest }} for {{ .Manifest.Platform }} platform. +This image has been {{ if (eq .Status "new") }}created{{ else }}updated{{ end }} at {{ .Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} +with digest {{ .Manifest.Digest }} for {{ .Manifest.Platform }} platform. Need help, or have questions? Go to https://github.com/crazy-max/diun and leave an issue. -`)) +`, tagTpl))) if err := emailTpl.Execute(&emailBuf, entry); err != nil { return err } diff --git a/internal/notif/rocketchat/client.go b/internal/notif/rocketchat/client.go index ed21ddd2..457d50e0 100644 --- a/internal/notif/rocketchat/client.go +++ b/internal/notif/rocketchat/client.go @@ -50,48 +50,55 @@ func (c *Client) Send(entry model.NotifEntry) error { } var textBuf bytes.Buffer - textTpl := template.Must(template.New("rocketchat").Parse(`Docker 🐳 tag {{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }} which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}.`)) + textTpl := template.Must(template.New("rocketchat").Parse(`Docker tag {{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }} which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}.`)) if err := textTpl.Execute(&textBuf, entry); err != nil { return err } - data := Message{ + fields := []AttachmentField{ + { + Title: "Provider", + Value: entry.Provider, + Short: false, + }, + { + Title: "Created", + Value: entry.Manifest.Created.Format("Jan 02, 2006 15:04:05 UTC"), + Short: false, + }, + { + Title: "Digest", + Value: entry.Manifest.Digest.String(), + Short: false, + }, + { + Title: "Platform", + Value: entry.Manifest.Platform, + Short: false, + }, + } + if len(entry.Image.HubLink) > 0 { + fields = append(fields, AttachmentField{ + Title: "HubLink", + Value: entry.Image.HubLink, + Short: false, + }) + } + + dataBuf := new(bytes.Buffer) + if err := json.NewEncoder(dataBuf).Encode(Message{ Alias: c.meta.Name, Avatar: c.meta.Logo, Channel: c.cfg.Channel, Text: title, Attachments: []Attachment{ { - Text: textBuf.String(), - Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), - Fields: []AttachmentField{ - { - Title: "Provider", - Value: entry.Provider, - Short: false, - }, - { - Title: "Created", - Value: entry.Manifest.Created.Format("Jan 02, 2006 15:04:05 UTC"), - Short: false, - }, - { - Title: "Digest", - Value: entry.Manifest.Digest.String(), - Short: false, - }, - { - Title: "Platform", - Value: entry.Manifest.Platform, - Short: false, - }, - }, + Text: textBuf.String(), + Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), + Fields: fields, }, }, - } - - dataBuf := new(bytes.Buffer) - if err := json.NewEncoder(dataBuf).Encode(data); err != nil { + }); err != nil { return err } diff --git a/internal/notif/script/client.go b/internal/notif/script/client.go index ac61d904..a86f1241 100644 --- a/internal/notif/script/client.go +++ b/internal/notif/script/client.go @@ -56,6 +56,7 @@ func (c *Client) Send(entry model.NotifEntry) error { fmt.Sprintf("DIUN_ENTRY_STATUS=%s", string(entry.Status)), fmt.Sprintf("DIUN_ENTRY_PROVIDER=%s", entry.Provider), fmt.Sprintf("DIUN_ENTRY_IMAGE=%s", entry.Image.String()), + fmt.Sprintf("DIUN_ENTRY_HUBLINK=%s", entry.Image.HubLink), fmt.Sprintf("DIUN_ENTRY_MIMETYPE=%s", entry.Manifest.MIMEType), fmt.Sprintf("DIUN_ENTRY_DIGEST=%s", entry.Manifest.Digest), fmt.Sprintf("DIUN_ENTRY_CREATED=%s", entry.Manifest.Created), diff --git a/internal/notif/slack/slack.go b/internal/notif/slack/slack.go index 36f5e2cf..93bc9e68 100644 --- a/internal/notif/slack/slack.go +++ b/internal/notif/slack/slack.go @@ -48,6 +48,36 @@ func (c *Client) Send(entry model.NotifEntry) error { color = "#0054ca" } + fields := []slack.AttachmentField{ + { + Title: "Provider", + Value: entry.Provider, + Short: false, + }, + { + Title: "Created", + Value: entry.Manifest.Created.Format("Jan 02, 2006 15:04:05 UTC"), + Short: false, + }, + { + Title: "Digest", + Value: entry.Manifest.Digest.String(), + Short: false, + }, + { + Title: "Platform", + Value: entry.Manifest.Platform, + Short: false, + }, + } + if len(entry.Image.HubLink) > 0 { + fields = append(fields, slack.AttachmentField{ + Title: "HubLink", + Value: entry.Image.HubLink, + Short: false, + }) + } + return slack.PostWebhook(c.cfg.WebhookURL, &slack.WebhookMessage{ Attachments: []slack.Attachment{ { @@ -58,29 +88,8 @@ func (c *Client) Send(entry model.NotifEntry) error { AuthorIcon: c.meta.Logo, Text: textBuf.String(), Footer: fmt.Sprintf("%s © %d %s %s", c.meta.Author, time.Now().Year(), c.meta.Name, c.meta.Version), - Fields: []slack.AttachmentField{ - { - Title: "Provider", - Value: entry.Provider, - Short: false, - }, - { - Title: "Created", - Value: entry.Manifest.Created.Format("Jan 02, 2006 15:04:05 UTC"), - Short: false, - }, - { - Title: "Digest", - Value: entry.Manifest.Digest.String(), - Short: false, - }, - { - Title: "Platform", - Value: entry.Manifest.Platform, - Short: false, - }, - }, - Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), + Fields: fields, + Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), }, }, }) diff --git a/internal/notif/teams/client.go b/internal/notif/teams/client.go index a1028e63..efba45ab 100644 --- a/internal/notif/teams/client.go +++ b/internal/notif/teams/client.go @@ -3,6 +3,7 @@ package teams import ( "bytes" "encoding/json" + "fmt" "net/http" "text/template" "time" @@ -52,8 +53,13 @@ func (c *Client) Send(entry model.NotifEntry) error { Timeout: time.Duration(10) * time.Second, } + tagTpl := "`{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}`" + if len(entry.Image.HubLink) > 0 { + tagTpl = "[`{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}`]({{ .Image.HubLink }})" + } + var textBuf bytes.Buffer - textTpl := template.Must(template.New("text").Parse("Docker tag `{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}` {{ if (eq .Status \"new\") }}newly added{{ else }}updated{{ end }}.")) + textTpl := template.Must(template.New("text").Parse(fmt.Sprintf("Docker tag %s {{ if (eq .Status \"new\") }}newly added{{ else }}updated{{ end }}.", tagTpl))) if err := textTpl.Execute(&textBuf, entry); err != nil { return err } diff --git a/internal/notif/telegram/telegram.go b/internal/notif/telegram/telegram.go index 467e5960..7ed6adaf 100644 --- a/internal/notif/telegram/telegram.go +++ b/internal/notif/telegram/telegram.go @@ -2,6 +2,7 @@ package telegram import ( "bytes" + "fmt" "text/template" "github.com/crazy-max/diun/v4/internal/model" @@ -38,16 +39,27 @@ func (c *Client) Send(entry model.NotifEntry) error { return err } + tagTpl := "{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}" + if len(entry.Image.HubLink) > 0 { + tagTpl = "[{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}]({{ .Image.HubLink }})" + } + var msgBuf bytes.Buffer - msgTpl := template.Must(template.New("email").Parse(`Docker 🐳 tag {{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }} which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}.`)) + msgTpl := template.Must(template.New("email").Parse(fmt.Sprintf("Docker tag %s which you subscribed to through {{ .Provider }} provider has been {{ if (eq .Status \"new\") }}newly added{{ else }}updated{{ end }}.", tagTpl))) if err := msgTpl.Execute(&msgBuf, entry); err != nil { return err } for _, chatID := range c.cfg.ChatIDs { - msg := tgbotapi.NewMessage(chatID, bot.Self.UserName) - msg.Text = msgBuf.String() - if _, err := bot.Send(msg); err != nil { + _, err := bot.Send(tgbotapi.MessageConfig{ + BaseChat: tgbotapi.BaseChat{ + ChatID: chatID, + }, + Text: msgBuf.String(), + ParseMode: "markdown", + DisableWebPagePreview: true, + }) + if err != nil { return err } } diff --git a/internal/notif/webhook/client.go b/internal/notif/webhook/client.go index 157d07a0..fbd6588c 100644 --- a/internal/notif/webhook/client.go +++ b/internal/notif/webhook/client.go @@ -44,6 +44,7 @@ func (c *Client) Send(entry model.NotifEntry) error { Status string `json:"status"` Provider string `json:"provider"` Image string `json:"image"` + HubLink string `json:"hub_link"` MIMEType string `json:"mime_type"` Digest digest.Digest `json:"digest"` Created *time.Time `json:"created"` @@ -53,6 +54,7 @@ func (c *Client) Send(entry model.NotifEntry) error { Status: string(entry.Status), Provider: entry.Provider, Image: entry.Image.String(), + HubLink: entry.Image.HubLink, MIMEType: entry.Manifest.MIMEType, Digest: entry.Manifest.Digest, Created: entry.Manifest.Created, diff --git a/pkg/registry/manifest_test.go b/pkg/registry/manifest_test.go index 639777e5..0252ac1b 100644 --- a/pkg/registry/manifest_test.go +++ b/pkg/registry/manifest_test.go @@ -14,7 +14,7 @@ func TestManifestVariant(t *testing.T) { ImageVariant: "v7", }) if err != nil { - panic(err.Error()) + t.Error(err) } img, err := registry.ParseImage(registry.ParseImageOptions{