From 538f82c8989be6c8e8e9cab69a990fa9450afb93 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Fri, 25 Nov 2016 13:06:07 +0100 Subject: [PATCH] improve Gogs tag implementation --- remote/gogs/fixtures/hooks.go | 240 ++++------------------------------ remote/gogs/gogs.go | 17 +-- remote/gogs/helper.go | 51 +++++--- remote/gogs/helper_test.go | 16 +++ remote/gogs/parse.go | 74 +++++++++++ remote/gogs/parse_test.go | 1 + remote/gogs/types.go | 19 +-- 7 files changed, 163 insertions(+), 255 deletions(-) create mode 100644 remote/gogs/parse.go create mode 100644 remote/gogs/parse_test.go diff --git a/remote/gogs/fixtures/hooks.go b/remote/gogs/fixtures/hooks.go index 2779616c..fb04b2b3 100644 --- a/remote/gogs/fixtures/hooks.go +++ b/remote/gogs/fixtures/hooks.go @@ -1,6 +1,6 @@ package fixtures -// old version ? +// Sample Gogs push hook var HookPush = ` { "ref": "refs/heads/master", @@ -22,7 +22,10 @@ var HookPush = ` "repository": { "id": 1, "name": "hello-world", - "url": "http://gogs.golang.org/gordon/hello-world", + "full_name": "gordon/hello-world", + "html_url": "http://gogs.golang.org/gordon/hello-world", + "ssh_url": "git@gogs.golang.org:gordon/hello-world.git", + "clone_url": "http://gogs.golang.org/gordon/hello-world.git", "description": "", "website": "", "watchers": 1, @@ -46,222 +49,37 @@ var HookPush = ` } ` -// Sampled from Gogs version 0.9.97 -// X-Gogs-Event: push -var HookPushNew = ` -{ - "secret": "a_secret", - "ref": "refs/heads/master", - "before": "117b1990205dbc6395656ef1ed2125719aa7f4d3", - "after": "7d7605add378b55e6154d96b3e0957d392e2cc14", - "compare_url": "http://cdb:3000/org1/test3/compare/117b1990205dbc6395656ef1ed2125719aa7f4d3...7d7605add378b55e6154d96b3e0957d392e2cc14", - "commits": [ - { - "id": "7d7605add378b55e6154d96b3e0957d392e2cc14", - "message": "Capitalize\n", - "url": "http://cdb:3000/org1/test3/commit/7d7605add378b55e6154d96b3e0957d392e2cc14", - "author": { - "name": "Sandro Santilli", - "email": "strk@kbt.io", - "username": "strk" - }, - "committer": { - "name": "Sandro Santilli", - "email": "strk@kbt.io", - "username": "strk" - }, - "timestamp": "2016-08-31T22:51:59+02:00" - }, - { - "id": "85800d8ecf8107626dc43a0cbdf218c31cd04779", - "message": "dot\n", - "url": "http://cdb:3000/org1/test3/commit/85800d8ecf8107626dc43a0cbdf218c31cd04779", - "author": { - "name": "Sandro Santilli", - "email": "strk@kbt.io", - "username": "strk" - }, - "committer": { - "name": "Sandro Santilli", - "email": "strk@kbt.io", - "username": "strk" - }, - "timestamp": "2016-08-31T22:46:53+02:00" - } - ], +// Sample Gogs tag hook +var HookPushTag = `{ + "secret": "l26Un7G7HXogLAvsyf2hOA4EMARSTsR3", + "ref": "v1.0.0", + "ref_type": "tag", "repository": { - "id": 5, + "id": 1, "owner": { - "id": 5, - "username": "org1", - "full_name": "org1", - "email": "", - "avatar_url": "http://cdb:3000/avatars/5" - }, - "name": "test3", - "full_name": "org1/test3", - "description": "just a test", - "private": false, - "fork": false, - "html_url": "http://cdb:3000/org1/test3", - "ssh_url": "strk@git.osgeo.org:org1/test3.git", - "clone_url": "http://cdb:3000/org1/test3.git", - "website": "", - "stars_count": 0, - "forks_count": 1, - "watchers_count": 2, - "open_issues_count": 0, - "default_branch": "master", - "created_at": "2016-08-31T22:45:16+02:00", - "updated_at": "2016-08-31T22:45:31+02:00" - }, - "pusher": { - "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" - }, - "sender": { - "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" - } -} -` - -// Sampled from Gogs version 0.9.97 -// X-Gogs-Event: pull_request -var HookPullRequestOpenNew = ` -{ - "secret": "a_secret", - "action": "opened", - "number": 1, - "pull_request": { - "id": 2, - "number": 1, - "user": { "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" + "username": "gordon", + "full_name": "Gordon the Gopher", + "email": "gordon@golang.org", + "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" }, - "title": "dot", - "body": "could you figure", - "labels": [], - "milestone": null, - "assignee": null, - "state": "open", - "comments": 0, - "html_url": "http://cdb:3000/org1/test3/pulls/1", - "mergeable": true, - "merged": false, - "merged_at": null, - "merge_commit_sha": null, - "merged_by": null - }, - "repository": { - "id": 5, - "owner": { - "id": 5, - "username": "org1", - "full_name": "org1", - "email": "", - "avatar_url": "http://cdb:3000/avatars/5" - }, - "name": "test3", - "full_name": "org1/test3", - "description": "just a test", - "private": false, + "name": "hello-world", + "full_name": "gordon/hello-world", + "description": "", + "private": true, "fork": false, - "html_url": "http://cdb:3000/org1/test3", - "ssh_url": "strk@git.osgeo.org:org1/test3.git", - "clone_url": "http://cdb:3000/org1/test3.git", - "website": "", - "stars_count": 0, - "forks_count": 1, - "watchers_count": 2, - "open_issues_count": 0, + "html_url": "http://gogs.golang.org/gordon/hello-world", + "ssh_url": "git@gogs.golang.org:gordon/hello-world.git", + "clone_url": "http://gogs.golang.org/gordon/hello-world.git", "default_branch": "master", - "created_at": "2016-08-31T22:45:16+02:00", - "updated_at": "2016-08-31T22:45:31+02:00" + "created_at": "2015-10-22T19:32:44Z", + "updated_at": "2016-11-24T13:37:16Z" }, "sender": { "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" + "username": "gordon", + "full_name": "Gordon the Gopher", + "email": "gordon@golang.org", + "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" } -} -` - -// Sampled from Gogs version 0.9.97 -// X-Gogs-Event: pull_request -var HookPullRequestSynchronize = ` -{ - "secret": "a_secret", - "action": "synchronized", - "number": 1, - "pull_request": { - "id": 2, - "number": 1, - "user": { - "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" - }, - "title": "dot", - "body": "could you figure", - "labels": [], - "milestone": null, - "assignee": null, - "state": "open", - "comments": 0, - "html_url": "http://cdb:3000/org1/test3/pulls/1", - "mergeable": true, - "merged": false, - "merged_at": null, - "merge_commit_sha": null, - "merged_by": null - }, - "repository": { - "id": 5, - "owner": { - "id": 5, - "username": "org1", - "full_name": "org1", - "email": "", - "avatar_url": "http://cdb:3000/avatars/5" - }, - "name": "test3", - "full_name": "org1/test3", - "description": "just a test", - "private": false, - "fork": false, - "html_url": "http://cdb:3000/org1/test3", - "ssh_url": "strk@git.osgeo.org:org1/test3.git", - "clone_url": "http://cdb:3000/org1/test3.git", - "website": "", - "stars_count": 0, - "forks_count": 1, - "watchers_count": 2, - "open_issues_count": 0, - "default_branch": "master", - "created_at": "2016-08-31T22:45:16+02:00", - "updated_at": "2016-08-31T22:45:31+02:00" - }, - "sender": { - "id": 1, - "username": "strk", - "full_name": "", - "email": "strk@kbt.io", - "avatar_url": "https://avatars.kbt.io/avatar/fe2a9e759730ee64c44bf8901bf4ccc3" - } -} -` +}` diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index 373843c0..55795d42 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -227,22 +227,7 @@ func (c *client) Deactivate(u *model.User, r *model.Repo, link string) error { // Hook parses the incoming Gogs hook and returns the Repository and Build // details. If the hook is unsupported nil values are returned. func (c *client) Hook(r *http.Request) (*model.Repo, *model.Build, error) { - var ( - err error - repo *model.Repo - build *model.Build - ) - - switch r.Header.Get("X-Gogs-Event") { - case "push": - var push *pushHook - push, err = parsePush(r.Body) - if err == nil && push.RefType != "branch" { - repo = repoFromPush(push) - build = buildFromPush(push) - } - } - return repo, build, err + return parseHook(r) } // helper function to return the Gogs client diff --git a/remote/gogs/helper.go b/remote/gogs/helper.go index eb75937f..15717101 100644 --- a/remote/gogs/helper.go +++ b/remote/gogs/helper.go @@ -70,43 +70,54 @@ func buildFromPush(hook *pushHook) *model.Build { hook.Repo.URL, fixMalformedAvatar(hook.Sender.Avatar), ) - - var eventType string - var message string - - switch { - case hook.RefType == "tag": - eventType = model.EventTag - message = "Tag " + hook.Ref - default: - eventType = model.EventPush - message = hook.Commits[0].Message + author := hook.Sender.Login + if author == "" { + author = hook.Sender.Username } return &model.Build{ - Event: eventType, + Event: model.EventPush, Commit: hook.After, Ref: hook.Ref, Link: hook.Compare, Branch: strings.TrimPrefix(hook.Ref, "refs/heads/"), - Message: message, + Message: hook.Commits[0].Message, Avatar: avatar, - Author: hook.Sender.Login, + Author: author, + Timestamp: time.Now().UTC().Unix(), + } +} + +// helper function that extracts the Build data from a Gogs tag hook +func buildFromTag(hook *pushHook) *model.Build { + avatar := expandAvatar( + hook.Repo.URL, + fixMalformedAvatar(hook.Sender.Avatar), + ) + author := hook.Sender.Login + if author == "" { + author = hook.Sender.Username + } + + return &model.Build{ + Event: model.EventTag, + Commit: hook.After, + Ref: fmt.Sprintf("refs/tags/%s", hook.Ref), + Link: fmt.Sprintf("%s/src/%s", hook.Repo.URL, hook.Ref), + Branch: fmt.Sprintf("refs/tags/%s", hook.Ref), + Message: fmt.Sprintf("created tag %s", hook.Ref), + Avatar: avatar, + Author: author, Timestamp: time.Now().UTC().Unix(), } } // helper function that extracts the Repository data from a Gogs push hook func repoFromPush(hook *pushHook) *model.Repo { - fullName := fmt.Sprintf( - "%s/%s", - hook.Repo.Owner.Username, - hook.Repo.Name, - ) return &model.Repo{ Name: hook.Repo.Name, Owner: hook.Repo.Owner.Username, - FullName: fullName, + FullName: hook.Repo.FullName, Link: hook.Repo.URL, } } diff --git a/remote/gogs/helper_test.go b/remote/gogs/helper_test.go index e6e63a02..b3f91c6c 100644 --- a/remote/gogs/helper_test.go +++ b/remote/gogs/helper_test.go @@ -27,6 +27,7 @@ func Test_parse(t *testing.T) { g.Assert(hook.Repo.Name).Equal("hello-world") g.Assert(hook.Repo.URL).Equal("http://gogs.golang.org/gordon/hello-world") g.Assert(hook.Repo.Owner.Name).Equal("gordon") + g.Assert(hook.Repo.FullName).Equal("gordon/hello-world") g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org") g.Assert(hook.Repo.Owner.Username).Equal("gordon") g.Assert(hook.Repo.Private).Equal(true) @@ -37,6 +38,21 @@ func Test_parse(t *testing.T) { g.Assert(hook.Sender.Avatar).Equal("http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") }) + g.It("Should parse tag hook payload", func() { + buf := bytes.NewBufferString(fixtures.HookPushTag) + hook, err := parsePush(buf) + g.Assert(err == nil).IsTrue() + g.Assert(hook.Ref).Equal("v1.0.0") + g.Assert(hook.Repo.Name).Equal("hello-world") + g.Assert(hook.Repo.URL).Equal("http://gogs.golang.org/gordon/hello-world") + g.Assert(hook.Repo.FullName).Equal("gordon/hello-world") + g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org") + g.Assert(hook.Repo.Owner.Username).Equal("gordon") + g.Assert(hook.Repo.Private).Equal(true) + g.Assert(hook.Sender.Username).Equal("gordon") + g.Assert(hook.Sender.Avatar).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") + }) + g.It("Should return a Build struct from a push hook", func() { buf := bytes.NewBufferString(fixtures.HookPush) hook, _ := parsePush(buf) diff --git a/remote/gogs/parse.go b/remote/gogs/parse.go new file mode 100644 index 00000000..f1e4f442 --- /dev/null +++ b/remote/gogs/parse.go @@ -0,0 +1,74 @@ +package gogs + +import ( + "io" + "net/http" + + "github.com/drone/drone/model" +) + +const ( + hookEvent = "X-Gogs-Event" + hookPush = "push" + hookCreated = "create" + + refBranch = "branch" + refTag = "tag" +) + +// parseHook parses a Bitbucket hook from an http.Request request and returns +// Repo and Build detail. If a hook type is unsupported nil values are returned. +func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { + switch r.Header.Get(hookEvent) { + case hookPush: + return parsePushHook(r.Body) + case hookCreated: + return parseCreatedHook(r.Body) + } + return nil, nil, nil +} + +// parsePushHook parses a push hook and returns the Repo and Build details. +// If the commit type is unsupported nil values are returned. +func parsePushHook(payload io.Reader) (*model.Repo, *model.Build, error) { + var ( + repo *model.Repo + build *model.Build + ) + + push, err := parsePush(payload) + if err != nil { + return nil, nil, err + } + + // is this even needed? + if push.RefType == refBranch { + return nil, nil, nil + } + + repo = repoFromPush(push) + build = buildFromPush(push) + return repo, build, err +} + +// parseCreatedHook parses a push hook and returns the Repo and Build details. +// If the commit type is unsupported nil values are returned. +func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Build, error) { + var ( + repo *model.Repo + build *model.Build + ) + + push, err := parsePush(payload) + if err != nil { + return nil, nil, err + } + + if push.RefType != refTag { + return nil, nil, nil + } + + repo = repoFromPush(push) + build = buildFromTag(push) + return repo, build, err +} diff --git a/remote/gogs/parse_test.go b/remote/gogs/parse_test.go new file mode 100644 index 00000000..be8cf935 --- /dev/null +++ b/remote/gogs/parse_test.go @@ -0,0 +1 @@ +package gogs diff --git a/remote/gogs/types.go b/remote/gogs/types.go index a2de2a0e..53e21bb5 100644 --- a/remote/gogs/types.go +++ b/remote/gogs/types.go @@ -10,15 +10,17 @@ type pushHook struct { Pusher struct { Name string `json:"name"` Email string `json:"email"` + Login string `json:"login"` Username string `json:"username"` } `json:"pusher"` Repo struct { - ID int64 `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - Private bool `json:"private"` - Owner struct { + ID int64 `json:"id"` + Name string `json:"name"` + FullName string `json:"full_name"` + URL string `json:"html_url"` + Private bool `json:"private"` + Owner struct { Name string `json:"name"` Email string `json:"email"` Username string `json:"username"` @@ -32,8 +34,9 @@ type pushHook struct { } `json:"commits"` Sender struct { - ID int64 `json:"id"` - Login string `json:"login"` - Avatar string `json:"avatar_url"` + ID int64 `json:"id"` + Login string `json:"login"` + Username string `json:"username"` + Avatar string `json:"avatar_url"` } `json:"sender"` }