diff --git a/server/remote/bitbucket/bitbucket.go b/server/remote/bitbucket/bitbucket.go index f5d152776..759522070 100644 --- a/server/remote/bitbucket/bitbucket.go +++ b/server/remote/bitbucket/bitbucket.go @@ -278,8 +278,16 @@ func (c *config) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { // Branches returns the names of all branches for the named repository. func (c *config) Branches(ctx context.Context, u *model.User, r *model.Repo) ([]string, error) { - // TODO: fetch all branches - return []string{r.Branch}, nil + bitbucketBranches, err := c.newClient(ctx, u).ListBranches(r.Owner, r.Name) + if err != nil { + return nil, err + } + + branches := make([]string, 0) + for _, branch := range bitbucketBranches { + branches = append(branches, branch.Name) + } + return branches, nil } // Hook parses the incoming Bitbucket hook and returns the Repository and @@ -290,6 +298,9 @@ func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *mod // helper function to return the bitbucket oauth2 client func (c *config) newClient(ctx context.Context, u *model.User) *internal.Client { + if u == nil { + return c.newClientToken(ctx, "", "") + } return c.newClientToken(ctx, u.Token, u.Secret) } diff --git a/server/remote/bitbucket/internal/client.go b/server/remote/bitbucket/internal/client.go index 605288959..0f81e379d 100644 --- a/server/remote/bitbucket/internal/client.go +++ b/server/remote/bitbucket/internal/client.go @@ -45,6 +45,7 @@ const ( pathHooks = "%s/2.0/repositories/%s/%s/hooks?%s" pathSource = "%s/2.0/repositories/%s/%s/src/%s/%s" pathStatus = "%s/2.0/repositories/%s/%s/commit/%s/statuses/build" + pathBranches = "%s/2.0/repositories/%s/%s/refs/branches" ) type Client struct { @@ -174,6 +175,13 @@ func (c *Client) GetPermission(fullName string) (*RepoPerm, error) { return out.Values[0], nil } +func (c *Client) ListBranches(owner, name string) ([]*Branch, error) { + out := new(BranchResp) + uri := fmt.Sprintf(pathBranches, c.base, owner, name) + _, err := c.do(uri, get, nil, out) + return out.Values, err +} + func (c *Client) do(rawurl, method string, in, out interface{}) (*string, error) { uri, err := url.Parse(rawurl) if err != nil { diff --git a/server/remote/bitbucket/internal/types.go b/server/remote/bitbucket/internal/types.go index a1256c36a..803962585 100644 --- a/server/remote/bitbucket/internal/types.go +++ b/server/remote/bitbucket/internal/types.go @@ -227,3 +227,11 @@ type RepoPermResp struct { type RepoPerm struct { Permission string `json:"permission"` } + +type BranchResp struct { + Values []*Branch `json:"values"` +} + +type Branch struct { + Name string `json:"name"` +} diff --git a/server/remote/bitbucketserver/bitbucketserver.go b/server/remote/bitbucketserver/bitbucketserver.go index 60ae2c2ac..b317079ca 100644 --- a/server/remote/bitbucketserver/bitbucketserver.go +++ b/server/remote/bitbucketserver/bitbucketserver.go @@ -219,8 +219,16 @@ func (c *Config) Activate(ctx context.Context, u *model.User, r *model.Repo, lin // Branches returns the names of all branches for the named repository. func (c *Config) Branches(ctx context.Context, u *model.User, r *model.Repo) ([]string, error) { - // TODO: fetch all branches - return []string{r.Branch}, nil + bitbucketBranches, err := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token).ListBranches(r.Owner, r.Name) + if err != nil { + return nil, err + } + + branches := make([]string, 0) + for _, branch := range bitbucketBranches { + branches = append(branches, branch.Name) + } + return branches, nil } func (c *Config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { diff --git a/server/remote/bitbucketserver/internal/client.go b/server/remote/bitbucketserver/internal/client.go index a0ce36260..d383f805b 100644 --- a/server/remote/bitbucketserver/internal/client.go +++ b/server/remote/bitbucketserver/internal/client.go @@ -43,6 +43,7 @@ const ( pathHookEnabled = "%s/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled" pathHookSettings = "%s/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/settings" pathStatus = "%s/rest/build-status/1.0/commits/%s" + pathBranches = "%s/2.0/repositories/%s/%s/refs/branches" ) type Client struct { @@ -322,6 +323,20 @@ func (c *Client) paginatedRepos(start int) ([]*Repo, error) { return repoResponse.Values, nil } +func (c *Client) ListBranches(owner, name string) ([]*Branch, error) { + uri := fmt.Sprintf(pathBranches, c.base, owner, name) + response, err := c.doGet(uri) + if response != nil { + defer response.Body.Close() + } + if err != nil { + return nil, err + } + out := new(BranchResp) + err = json.NewDecoder(response.Body).Decode(&out) + return out.Values, err +} + func filter(vs []string, f func(string) bool) []string { var vsf []string for _, v := range vs { diff --git a/server/remote/bitbucketserver/internal/types.go b/server/remote/bitbucketserver/internal/types.go index 16e74384f..87054d6d0 100644 --- a/server/remote/bitbucketserver/internal/types.go +++ b/server/remote/bitbucketserver/internal/types.go @@ -219,3 +219,11 @@ type HookSettings struct { HookURL18 string `json:"hook-url-18,omitempty"` HookURL19 string `json:"hook-url-19,omitempty"` } + +type BranchResp struct { + Values []*Branch `json:"values"` +} + +type Branch struct { + Name string `json:"name"` +}