diff --git a/remote/bitbucket/bitbucket.go b/remote/bitbucket/bitbucket.go index 26107f3ba..51502883f 100644 --- a/remote/bitbucket/bitbucket.go +++ b/remote/bitbucket/bitbucket.go @@ -360,12 +360,17 @@ func (bb *Bitbucket) Deactivate(u *model.User, r *model.Repo, link string) error // and returns the required data in a standard format. func (bb *Bitbucket) Hook(r *http.Request) (*model.Repo, *model.Build, error) { - // only a subset of hooks are processed by drone - if r.Header.Get("X-Event-Key") != "repo:push" { - return nil, nil, nil + switch r.Header.Get("X-Event-Key") { + case "repo:push": + return bb.pushHook(r) + case "pullrequest:created", "pullrequest:updated": + return bb.pullHook(r) } - // extract the hook payload + return nil, nil, nil +} + +func (bb *Bitbucket) pushHook(r *http.Request) (*model.Repo, *model.Build, error) { payload := []byte(r.FormValue("payload")) if len(payload) == 0 { defer r.Body.Close() @@ -405,3 +410,34 @@ func (bb *Bitbucket) Hook(r *http.Request) (*model.Repo, *model.Build, error) { return nil, nil, nil } + +func (bb *Bitbucket) pullHook(r *http.Request) (*model.Repo, *model.Build, error) { + payload := []byte(r.FormValue("payload")) + if len(payload) == 0 { + defer r.Body.Close() + payload, _ = ioutil.ReadAll(r.Body) + } + + hook := PullRequestHook{} + err := json.Unmarshal(payload, &hook) + if err != nil { + return nil, nil, err + } + if hook.PullRequest.State != "OPEN" { + return nil, nil, nil + } + + return convertRepo(&hook.Repo), &model.Build{ + Event: model.EventPull, + Commit: hook.PullRequest.Dest.Commit.Hash, + Ref: fmt.Sprintf("refs/heads/%s", hook.PullRequest.Dest.Branch.Name), + Refspec: fmt.Sprintf("https://bitbucket.org/%s.git", hook.PullRequest.Source.Repo.FullName), + Remote: cloneLink(hook.PullRequest.Dest.Repo), + Link: hook.PullRequest.Links.Html.Href, + Branch: hook.PullRequest.Dest.Branch.Name, + Message: hook.PullRequest.Desc, + Avatar: hook.Actor.Links.Avatar.Href, + Author: hook.Actor.Login, + Timestamp: hook.PullRequest.Updated.UTC().Unix(), + }, nil +} diff --git a/remote/bitbucket/helper.go b/remote/bitbucket/helper.go index 17b7c00b3..6d44b8bbb 100644 --- a/remote/bitbucket/helper.go +++ b/remote/bitbucket/helper.go @@ -53,6 +53,37 @@ func convertRepo(from *Repo) *model.Repo { return &repo } +// cloneLink is a helper function that tries to extract the +// clone url from the repository object. +func cloneLink(repo Repo) string { + var clone string + + // above we manually constructed the repository clone url. + // below we will iterate through the list of clone links and + // attempt to instead use the clone url provided by bitbucket. + for _, link := range repo.Links.Clone { + if link.Name == "https" { + clone = link.Href + } + } + + // if no repository name is provided, we use the Html link. + // this excludes the .git suffix, but will still clone the repo. + if len(clone) == 0 { + clone = repo.Links.Html.Href + } + + // if bitbucket tries to automatically populate the user + // in the url we must strip it out. + cloneurl, err := url.Parse(clone) + if err == nil { + cloneurl.User = nil + clone = cloneurl.String() + } + + return clone +} + // convertRepoLite is a helper function used to convert a Bitbucket // repository structure to the simplified Drone repository structure. func convertRepoLite(from *Repo) *model.RepoLite {