diff --git a/trigger/http/http.go b/trigger/http/http.go index a841b99f..e53d636b 100644 --- a/trigger/http/http.go +++ b/trigger/http/http.go @@ -79,6 +79,7 @@ func (s *TriggerServer) registerRoutes(mux *mux.Router) { // dockerhub webhooks handler mux.HandleFunc("/v1/webhooks/dockerhub", s.dockerHubHandler).Methods("POST", "OPTIONS") + mux.HandleFunc("/v1/webhooks/quay", s.quayHandler).Methods("POST", "OPTIONS") } func (s *TriggerServer) healthHandler(resp http.ResponseWriter, req *http.Request) { diff --git a/trigger/http/quay_webhook_trigger.go b/trigger/http/quay_webhook_trigger.go new file mode 100644 index 00000000..e33e6cfd --- /dev/null +++ b/trigger/http/quay_webhook_trigger.go @@ -0,0 +1,71 @@ +package http + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/rusenask/keel/types" + + log "github.com/Sirupsen/logrus" +) + +// Example of quay trigger +// { +// "name": "repository", +// "repository": "mynamespace/repository", +// "namespace": "mynamespace", +// "docker_url": "quay.io/mynamespace/repository", +// "homepage": "https://quay.io/repository/mynamespace/repository", +// "updated_tags": [ +// "latest" +// ] +// } + +type quayWebhook struct { + Name string `json:"name"` + Repository string `json:"repository"` + Namespace string `json:"namespace"` + DockerURL string `json:"docker_url"` + Homepage string `json:"homepage"` + UpdatedTags []string `json:"updated_tags"` +} + +func (s *TriggerServer) quayHandler(resp http.ResponseWriter, req *http.Request) { + qw := quayWebhook{} + if err := json.NewDecoder(req.Body).Decode(&qw); err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Error("trigger.quayHandler: failed to decode request") + resp.WriteHeader(http.StatusBadRequest) + return + } + + if qw.DockerURL == "" { + resp.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(resp, "docker_url cannot be empty") + return + } + + if len(qw.UpdatedTags) == 0 { + resp.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(resp, "updated_tags cannot be empty") + return + } + + // for every updated tag generating event + for _, tag := range qw.UpdatedTags { + event := types.Event{} + event.CreatedAt = time.Now() + event.TriggerName = "quay" + event.Repository.Name = qw.DockerURL + event.Repository.Tag = tag + + s.trigger(event) + + resp.WriteHeader(http.StatusOK) + } + + return +} diff --git a/trigger/http/quay_webhook_trigger_test.go b/trigger/http/quay_webhook_trigger_test.go new file mode 100644 index 00000000..8890084c --- /dev/null +++ b/trigger/http/quay_webhook_trigger_test.go @@ -0,0 +1,58 @@ +package http + +import ( + "bytes" + "net/http" + + "github.com/rusenask/keel/provider" + + "net/http/httptest" + "testing" +) + +var fakeQuayWebhook = `{ + "name": "repository", + "repository": "mynamespace/repository", + "namespace": "mynamespace", + "docker_url": "quay.io/mynamespace/repository", + "homepage": "https://quay.io/repository/mynamespace/repository", + "updated_tags": [ + "1.2.3" + ] +} +` + +func TestQuayWebhookHandler(t *testing.T) { + + fp := &fakeProvider{} + providers := provider.New([]provider.Provider{fp}) + srv := NewTriggerServer(&Opts{Providers: providers}) + srv.registerRoutes(srv.router) + + req, err := http.NewRequest("POST", "/v1/webhooks/quay", bytes.NewBuffer([]byte(fakeQuayWebhook))) + if err != nil { + t.Fatalf("failed to create req: %s", err) + } + + //The response recorder used to record HTTP responses + rec := httptest.NewRecorder() + + srv.router.ServeHTTP(rec, req) + if rec.Code != 200 { + t.Errorf("unexpected status code: %d", rec.Code) + + t.Log(rec.Body.String()) + } + + if len(fp.submitted) != 1 { + t.Fatalf("unexpected number of events submitted: %d", len(fp.submitted)) + } + + if fp.submitted[0].Repository.Name != "quay.io/mynamespace/repository" { + t.Errorf("expected quay.io/mynamespace/repository but got %s", fp.submitted[0].Repository.Name) + } + + if fp.submitted[0].Repository.Tag != "1.2.3" { + t.Errorf("expected 1.2.3 but got %s", fp.submitted[0].Repository.Tag) + } +}