mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-23 00:46:30 +00:00
Add pull_request webhook support to Gogs remote
This commit is contained in:
parent
f8f5fdfb40
commit
141eb4ea57
5 changed files with 261 additions and 3 deletions
|
@ -83,3 +83,55 @@ var HookPushTag = `{
|
|||
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}`
|
||||
|
||||
// HookPullRequest is a sample pull_request webhook payload
|
||||
var HookPullRequest = `{
|
||||
"action": "opened",
|
||||
"number": 1,
|
||||
"pull_request": {
|
||||
"html_url": "http://gogs.golang.org/gordon/hello-world/pull/1",
|
||||
"state": "open",
|
||||
"title": "Update the README with new information",
|
||||
"body": "please merge",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"username": "gordon",
|
||||
"full_name": "Gordon the Gopher",
|
||||
"email": "gordon@golang.org",
|
||||
"avatar_url": "http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
},
|
||||
"base": {
|
||||
"label": "master",
|
||||
"ref": "master",
|
||||
"sha": "9353195a19e45482665306e466c832c46560532d"
|
||||
},
|
||||
"head": {
|
||||
"label": "feature/changes",
|
||||
"ref": "feature/changes",
|
||||
"sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"id": 35129377,
|
||||
"name": "hello-world",
|
||||
"full_name": "gordon/hello-world",
|
||||
"owner": {
|
||||
"id": 1,
|
||||
"username": "gordon",
|
||||
"full_name": "Gordon the Gopher",
|
||||
"email": "gordon@golang.org",
|
||||
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
},
|
||||
"private": true,
|
||||
"html_url": "http://gogs.golang.org/gordon/hello-world",
|
||||
"clone_url": "https://gogs.golang.org/gordon/hello-world.git",
|
||||
"default_branch": "master"
|
||||
},
|
||||
"sender": {
|
||||
"id": 1,
|
||||
"username": "gordon",
|
||||
"full_name": "Gordon the Gopher",
|
||||
"email": "gordon@golang.org",
|
||||
"avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}`
|
||||
|
|
|
@ -112,6 +112,30 @@ func buildFromTag(hook *pushHook) *model.Build {
|
|||
}
|
||||
}
|
||||
|
||||
// helper function that extracts the Build data from a Gogs pull_request hook
|
||||
func buildFromPullRequest(hook *pullRequestHook) *model.Build {
|
||||
avatar := expandAvatar(
|
||||
hook.Repo.URL,
|
||||
fixMalformedAvatar(hook.PullRequest.User.Avatar),
|
||||
)
|
||||
build := &model.Build{
|
||||
Event: model.EventPull,
|
||||
Commit: hook.PullRequest.Head.Sha,
|
||||
Link: hook.PullRequest.URL,
|
||||
Ref: fmt.Sprintf("refs/pull/%d/head", hook.Number),
|
||||
Branch: hook.PullRequest.Base.Ref,
|
||||
Message: hook.PullRequest.Title,
|
||||
Author: hook.PullRequest.User.Username,
|
||||
Avatar: avatar,
|
||||
Title: hook.PullRequest.Title,
|
||||
Refspec: fmt.Sprintf("%s:%s",
|
||||
hook.PullRequest.Head.Ref,
|
||||
hook.PullRequest.Base.Ref,
|
||||
),
|
||||
}
|
||||
return build
|
||||
}
|
||||
|
||||
// helper function that extracts the Repository data from a Gogs push hook
|
||||
func repoFromPush(hook *pushHook) *model.Repo {
|
||||
return &model.Repo{
|
||||
|
@ -122,6 +146,16 @@ func repoFromPush(hook *pushHook) *model.Repo {
|
|||
}
|
||||
}
|
||||
|
||||
// helper function that extracts the Repository data from a Gogs pull_request hook
|
||||
func repoFromPullRequest(hook *pullRequestHook) *model.Repo {
|
||||
return &model.Repo{
|
||||
Name: hook.Repo.Name,
|
||||
Owner: hook.Repo.Owner.Username,
|
||||
FullName: hook.Repo.FullName,
|
||||
Link: hook.Repo.URL,
|
||||
}
|
||||
}
|
||||
|
||||
// helper function that parses a push hook from a read closer.
|
||||
func parsePush(r io.Reader) (*pushHook, error) {
|
||||
push := new(pushHook)
|
||||
|
@ -129,6 +163,12 @@ func parsePush(r io.Reader) (*pushHook, error) {
|
|||
return push, err
|
||||
}
|
||||
|
||||
func parsePullRequest(r io.Reader) (*pullRequestHook, error) {
|
||||
pr := new(pullRequestHook)
|
||||
err := json.NewDecoder(r).Decode(pr)
|
||||
return pr, err
|
||||
}
|
||||
|
||||
// fixMalformedAvatar is a helper function that fixes an avatar url if malformed
|
||||
// (currently a known bug with gogs)
|
||||
func fixMalformedAvatar(url string) string {
|
||||
|
|
|
@ -53,6 +53,32 @@ func Test_parse(t *testing.T) {
|
|||
g.Assert(hook.Sender.Avatar).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
|
||||
})
|
||||
|
||||
g.It("Should parse pull_request hook payload", func() {
|
||||
buf := bytes.NewBufferString(fixtures.HookPullRequest)
|
||||
hook, err := parsePullRequest(buf)
|
||||
g.Assert(err == nil).IsTrue()
|
||||
g.Assert(hook.Action).Equal("opened")
|
||||
g.Assert(hook.Number).Equal(int64(1))
|
||||
|
||||
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.Assert(hook.PullRequest.Title).Equal("Update the README with new information")
|
||||
g.Assert(hook.PullRequest.Body).Equal("please merge")
|
||||
g.Assert(hook.PullRequest.State).Equal("open")
|
||||
g.Assert(hook.PullRequest.User.Username).Equal("gordon")
|
||||
g.Assert(hook.PullRequest.Base.Label).Equal("master")
|
||||
g.Assert(hook.PullRequest.Base.Ref).Equal("master")
|
||||
g.Assert(hook.PullRequest.Head.Label).Equal("feature/changes")
|
||||
g.Assert(hook.PullRequest.Head.Ref).Equal("feature/changes")
|
||||
})
|
||||
|
||||
g.It("Should return a Build struct from a push hook", func() {
|
||||
buf := bytes.NewBufferString(fixtures.HookPush)
|
||||
hook, _ := parsePush(buf)
|
||||
|
@ -78,6 +104,31 @@ func Test_parse(t *testing.T) {
|
|||
g.Assert(repo.Link).Equal(hook.Repo.URL)
|
||||
})
|
||||
|
||||
g.It("Should return a Build struct from a pull_request hook", func() {
|
||||
buf := bytes.NewBufferString(fixtures.HookPullRequest)
|
||||
hook, _ := parsePullRequest(buf)
|
||||
build := buildFromPullRequest(hook)
|
||||
g.Assert(build.Event).Equal(model.EventPull)
|
||||
g.Assert(build.Commit).Equal(hook.PullRequest.Head.Sha)
|
||||
g.Assert(build.Ref).Equal("refs/pull/1/head")
|
||||
g.Assert(build.Link).Equal(hook.PullRequest.URL)
|
||||
g.Assert(build.Branch).Equal("master")
|
||||
g.Assert(build.Message).Equal(hook.PullRequest.Title)
|
||||
g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
|
||||
g.Assert(build.Author).Equal(hook.PullRequest.User.Username)
|
||||
|
||||
})
|
||||
|
||||
g.It("Should return a Repo struct from a pull_request hook", func() {
|
||||
buf := bytes.NewBufferString(fixtures.HookPullRequest)
|
||||
hook, _ := parsePullRequest(buf)
|
||||
repo := repoFromPullRequest(hook)
|
||||
g.Assert(repo.Name).Equal(hook.Repo.Name)
|
||||
g.Assert(repo.Owner).Equal(hook.Repo.Owner.Username)
|
||||
g.Assert(repo.FullName).Equal("gordon/hello-world")
|
||||
g.Assert(repo.Link).Equal(hook.Repo.URL)
|
||||
})
|
||||
|
||||
g.It("Should return a Perm struct from a Gogs Perm", func() {
|
||||
perms := []gogs.Permission{
|
||||
{true, true, true},
|
||||
|
|
|
@ -8,9 +8,15 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
hookEvent = "X-Gogs-Event"
|
||||
hookPush = "push"
|
||||
hookCreated = "create"
|
||||
hookEvent = "X-Gogs-Event"
|
||||
hookPush = "push"
|
||||
hookCreated = "create"
|
||||
hookPullRequest = "pull_request"
|
||||
|
||||
actionOpen = "opened"
|
||||
actionSync = "synchronize"
|
||||
|
||||
stateOpen = "open"
|
||||
|
||||
refBranch = "branch"
|
||||
refTag = "tag"
|
||||
|
@ -24,6 +30,8 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
|
|||
return parsePushHook(r.Body)
|
||||
case hookCreated:
|
||||
return parseCreatedHook(r.Body)
|
||||
case hookPullRequest:
|
||||
return parsePullRequestHook(r.Body)
|
||||
}
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
@ -72,3 +80,28 @@ func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Build, error) {
|
|||
build = buildFromTag(push)
|
||||
return repo, build, err
|
||||
}
|
||||
|
||||
// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details.
|
||||
func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) {
|
||||
var (
|
||||
repo *model.Repo
|
||||
build *model.Build
|
||||
)
|
||||
|
||||
pr, err := parsePullRequest(payload)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Don't trigger builds for non-code changes, or if PR is not open
|
||||
if pr.Action != actionOpen && pr.Action != actionSync {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if pr.PullRequest.State != stateOpen {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
repo = repoFromPullRequest(pr)
|
||||
build = buildFromPullRequest(pr)
|
||||
return repo, build, err
|
||||
}
|
||||
|
|
|
@ -40,3 +40,85 @@ type pushHook struct {
|
|||
Avatar string `json:"avatar_url"`
|
||||
} `json:"sender"`
|
||||
}
|
||||
|
||||
type pullRequestHook struct {
|
||||
Action string `json:"action"`
|
||||
Number int64 `json:"number"`
|
||||
PullRequest struct {
|
||||
ID int64 `json:"id"`
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar_url"`
|
||||
} `json:"user"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
Labels []string `json:"labels"`
|
||||
State string `json:"state"`
|
||||
URL string `json:"html_url"`
|
||||
Mergeable bool `json:"mergeable"`
|
||||
Merged bool `json:"merged"`
|
||||
MergeBase string `json:"merge_base"`
|
||||
Base struct {
|
||||
Label string `json:"label"`
|
||||
Ref string `json:"ref"`
|
||||
Sha string `json:"sha"`
|
||||
Repo 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 {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar_url"`
|
||||
} `json:"owner"`
|
||||
} `json:"repo"`
|
||||
} `json:"base"`
|
||||
Head struct {
|
||||
Label string `json:"label"`
|
||||
Ref string `json:"ref"`
|
||||
Sha string `json:"sha"`
|
||||
Repo 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 {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar_url"`
|
||||
} `json:"owner"`
|
||||
} `json:"repo"`
|
||||
} `json:"head"`
|
||||
} `json:"pull_request"`
|
||||
Repo 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 {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar_url"`
|
||||
} `json:"owner"`
|
||||
} `json:"repository"`
|
||||
Sender struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
Avatar string `json:"avatar_url"`
|
||||
} `json:"sender"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue