From 7b310c254f38878e4d69b14e4aa4f12ba106955b Mon Sep 17 00:00:00 2001 From: Tze Yang Ng Date: Sun, 31 Mar 2024 08:50:19 +0800 Subject: [PATCH] slack --- app/async/worker.go | 2 +- env/dev/dev.yaml | 9 +++- env/dev/docker-compose.yml | 2 +- env/test/test.yaml | 8 +++- .../dockerhub_fake.go | 2 +- external/dockerhub_test.go | 19 ++++---- external/slack.go | 47 +++++++++++++++++++ external/slack_fake.go | 11 +++++ external/slack_test.go | 47 +++++++++++++++++++ go.mod | 2 + go.sum | 9 ++++ main.go | 1 + 12 files changed, 144 insertions(+), 15 deletions(-) rename tests/fakes/dockerhub.go => external/dockerhub_fake.go (99%) create mode 100644 external/slack.go create mode 100644 external/slack_fake.go create mode 100644 external/slack_test.go diff --git a/app/async/worker.go b/app/async/worker.go index f922949..0b10a67 100644 --- a/app/async/worker.go +++ b/app/async/worker.go @@ -25,7 +25,7 @@ func (ww *WatcherWorker) Start() { func (ww *WatcherWorker) WatchDockerLogin() { for { - ww.Docker.Authorise("username", "password") + ww.Docker.Authorise(ww.Config.Docker.Username, ww.Config.Docker.Password) time.Sleep(time.Duration(10) * time.Minute) } } diff --git a/env/dev/dev.yaml b/env/dev/dev.yaml index d51763a..ec19d50 100644 --- a/env/dev/dev.yaml +++ b/env/dev/dev.yaml @@ -1 +1,8 @@ -Dsn: host=dev-db user=dev password=registrywatcher dbname=registrywatcher port=5432 sslmode=disable \ No newline at end of file +db: + dsn: host=dev-db user=registrywatcher password=4rEKcUsVGE dbname=registrywatcher port=5432 sslmode=disable +docker: + base_url: https://hub.docker.com + username: dsdlocus + +nomad: + base_url: http://localhost:4646 diff --git a/env/dev/docker-compose.yml b/env/dev/docker-compose.yml index d95b8ea..7f4a12f 100644 --- a/env/dev/docker-compose.yml +++ b/env/dev/docker-compose.yml @@ -32,7 +32,7 @@ services: - POSTGRES_PASSWORD=4rEKcUsVGE - POSTGRES_DB=registrywatcher healthcheck: - test: ["CMD-SHELL", "sh -c 'pg_isready -U dev -d registrywatcher'"] + test: ["CMD-SHELL", "sh -c 'pg_isready -U registrywatcher -d registrywatcher'"] interval: 10s timeout: 3s retries: 3 diff --git a/env/test/test.yaml b/env/test/test.yaml index 9da4a7c..b58447c 100644 --- a/env/test/test.yaml +++ b/env/test/test.yaml @@ -1,2 +1,8 @@ db: - dsn: host=test-db user=registrywatcher password=4rEKcUsVGE dbname=registrywatcher port=5432 sslmode=disable \ No newline at end of file + dsn: host=test-db user=registrywatcher password=4rEKcUsVGE dbname=registrywatcher port=5432 sslmode=disable +docker: + base_url: localhost:5000 + username: test + password: test +nomad: + base_url: http://localhost:4646 diff --git a/tests/fakes/dockerhub.go b/external/dockerhub_fake.go similarity index 99% rename from tests/fakes/dockerhub.go rename to external/dockerhub_fake.go index f00fedf..c567035 100644 --- a/tests/fakes/dockerhub.go +++ b/external/dockerhub_fake.go @@ -1,4 +1,4 @@ -package fakes +package external import ( "encoding/json" diff --git a/external/dockerhub_test.go b/external/dockerhub_test.go index 0d99a9d..c90ae47 100644 --- a/external/dockerhub_test.go +++ b/external/dockerhub_test.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "registrywatcher/app/models" - "registrywatcher/tests/fakes" "testing" "github.com/stretchr/testify/require" @@ -15,7 +14,7 @@ var external = flag.Bool("external", false, "set flag to perform tests against e func TestDockerhubClient_GetRepoTags(t *testing.T) { type seeds struct { - Tags func() []fakes.Tag + Tags func() []Tag } type fields struct { AccessToken string @@ -34,8 +33,8 @@ func TestDockerhubClient_GetRepoTags(t *testing.T) { { name: "Test GetRepoTags with 2 active tags", seeds: seeds{ - Tags: func() []fakes.Tag { - return []fakes.Tag{{ + Tags: func() []Tag { + return []Tag{{ Name: "tag1", TagStatus: "active", Digest: "digest1", @@ -75,10 +74,10 @@ func TestDockerhubClient_GetRepoTags(t *testing.T) { { name: "Test GetRepoTags pagination with more than 100 active tags", seeds: seeds{ - Tags: func() []fakes.Tag { - tags := []fakes.Tag{} + Tags: func() []Tag { + tags := []Tag{} for i := 0; i < 101; i++ { - tags = append(tags, fakes.Tag{ + tags = append(tags, Tag{ Name: fmt.Sprintf("tag%d", i), TagStatus: "active", Digest: fmt.Sprintf("digest%d", i), @@ -111,7 +110,7 @@ func TestDockerhubClient_GetRepoTags(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f := fakes.FakeDockerhub{ + f := FakeDockerhub{ Tokens: []string{tt.fields.AccessToken}, Tags: tt.seeds.Tags(), } @@ -208,8 +207,8 @@ func TestDockerhubClient_Authorise(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f := fakes.FakeDockerhub{ - Users: []fakes.User{ + f := FakeDockerhub{ + Users: []User{ { Username: "user", Password: "password", diff --git a/external/slack.go b/external/slack.go new file mode 100644 index 0000000..f8cdc30 --- /dev/null +++ b/external/slack.go @@ -0,0 +1,47 @@ +package external + +import ( + "log" + + "github.com/slack-go/slack" +) + +type MessageLevel int + +const ( + Info MessageLevel = iota + Success + Error +) + +type Slack interface { + SendMessage(message string, level MessageLevel) +} + +type SlackClient struct { + webhookURL string +} + +func (client *SlackClient) SendMessage(message string, level MessageLevel) { + slackAttachment := map[MessageLevel]slack.Attachment{ + Info: { + Color: "#FFA500", // Orange + }, + Success: { + Color: "#00FF00", // Green + ThumbURL: "https://i.imgur.com/LWRp6ZT.png", + }, + Error: { + Color: "#FF0000", // Red + ThumbURL: "https://i.imgur.com/MJ5Qx8f.jpg", + }, + }[level] + + slackAttachment.Text = message + + if err := slack.PostWebhook(client.webhookURL, &slack.WebhookMessage{ + Attachments: []slack.Attachment{slackAttachment}, + }); err != nil { + log.Panicln("Failed to send message to Slack:", err) + } +} diff --git a/external/slack_fake.go b/external/slack_fake.go new file mode 100644 index 0000000..c17bdd6 --- /dev/null +++ b/external/slack_fake.go @@ -0,0 +1,11 @@ +package external + +import ( + "log" +) + +type FakeSlackClient struct{} + +func (client *FakeSlackClient) SendMessage(message string, level MessageLevel) { + log.Println("Fake Slack message:", message, level) +} diff --git a/external/slack_test.go b/external/slack_test.go new file mode 100644 index 0000000..9c6ce43 --- /dev/null +++ b/external/slack_test.go @@ -0,0 +1,47 @@ +package external + +import ( + "os" + "testing" +) + +func TestSlackClient_SendMessage_External(t *testing.T) { + if !*external { + t.Skip("skipping test; set -external to run this test") + } + url := os.Getenv("SLACK_WEBHOOK_URL") + if url == "" { + t.Fatal("SLACK_WEBHOOK_URL not set") + } + + tests := []struct { + name string + level MessageLevel + message string + }{ + { + name: "Test send info message", + level: Info, + message: "test info message", + }, + { + name: "Test send success message", + level: Success, + message: "test success message", + }, + { + name: "Test send error message", + level: Error, + message: "test error message", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := &SlackClient{ + webhookURL: url, + } + client.SendMessage(tt.message, tt.level) + // Check the Slack channel for the message + }) + } +} diff --git a/go.mod b/go.mod index 1ab3a91..8f5753f 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.19.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect @@ -44,6 +45,7 @@ require ( github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/slack-go/slack v0.12.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect diff --git a/go.sum b/go.sum index 507ca3c..5d7bfd3 100644 --- a/go.sum +++ b/go.sum @@ -33,13 +33,18 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -88,6 +93,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/slack-go/slack v0.12.5 h1:ddZ6uz6XVaB+3MTDhoW04gG+Vc/M/X1ctC+wssy2cqs= +github.com/slack-go/slack v0.12.5/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -101,6 +108,7 @@ github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -155,6 +163,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/main.go b/main.go index bfb4d09..085eba5 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,7 @@ func main() { db := utilities.InitDB(c.DB.DSN) worker := async.WatcherWorker{ + Config: c, DB: db, Docker: &external.DockerhubClient{ BaseURL: "https://hub.docker.com",