Skip to content

Commit

Permalink
Add user SSH keys. Add List deploy keys. Fix keyword search in List r…
Browse files Browse the repository at this point in the history
…epositories (#294)
  • Loading branch information
fernandoStrong authored Oct 15, 2024
1 parent c56d071 commit 90ada25
Show file tree
Hide file tree
Showing 11 changed files with 494 additions and 13 deletions.
7 changes: 7 additions & 0 deletions bitbucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,3 +663,10 @@ func (dk *DeployKeyOptions) WithContext(ctx context.Context) *DeployKeyOptions {
dk.ctx = ctx
return dk
}

type SSHKeyOptions struct {
Owner string `json:"owner"`
Uuid string `json:"uuid"`
Label string `json:"label"`
Key string `json:"key"`
}
7 changes: 5 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func apiBaseUrl() (*url.URL, error) {

type Client struct {
Auth *auth
Users users
Users *Users
User user
Teams teams
Repositories *Repositories
Expand Down Expand Up @@ -191,7 +191,10 @@ func injectClient(a *auth) *Client {
Downloads: &Downloads{c: c},
DeployKeys: &DeployKeys{c: c},
}
c.Users = &Users{c: c}
c.Users = &Users{
c: c,
SSHKeys: &SSHKeys{c: c},
}
c.User = &User{c: c}
c.Teams = &Teams{c: c}
c.Workspaces = &Workspace{c: c, Repositories: c.Repositories, Permissions: &Permission{c: c}}
Expand Down
63 changes: 63 additions & 0 deletions deploykeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bitbucket

import (
"encoding/json"
"errors"

"github.com/mitchellh/mapstructure"
)
Expand All @@ -17,6 +18,14 @@ type DeployKey struct {
Comment string `json:"comment"`
}

type DeployKeysRes struct {
Page int32
Pagelen int32
MaxDepth int32
Size int32
Items []DeployKey
}

func decodeDeployKey(response interface{}) (*DeployKey, error) {
respMap := response.(map[string]interface{})

Expand All @@ -33,6 +42,50 @@ func decodeDeployKey(response interface{}) (*DeployKey, error) {
return deployKey, nil
}

func decodeDeployKeys(deployKeysResponse interface{}) (*DeployKeysRes, error) {
deployKeysResponseMap, ok := deployKeysResponse.(map[string]interface{})
if !ok {
return nil, errors.New("not a valid format")
}

repoArray := deployKeysResponseMap["values"].([]interface{})
var deployKeys []DeployKey
for _, deployKeyEntry := range repoArray {
var deployKey DeployKey
err := mapstructure.Decode(deployKeyEntry, &deployKey)
if err == nil {
deployKeys = append(deployKeys, deployKey)
}
}

page, ok := deployKeysResponseMap["page"].(float64)
if !ok {
page = 0
}

pagelen, ok := deployKeysResponseMap["pagelen"].(float64)
if !ok {
pagelen = 0
}
maxDepth, ok := deployKeysResponseMap["max_width"].(float64)
if !ok {
maxDepth = 0
}
size, ok := deployKeysResponseMap["size"].(float64)
if !ok {
size = 0
}

repositories := DeployKeysRes{
Page: int32(page),
Pagelen: int32(pagelen),
MaxDepth: int32(maxDepth),
Size: int32(size),
Items: deployKeys,
}
return &repositories, nil
}

func buildDeployKeysBody(opt *DeployKeyOptions) (string, error) {
body := map[string]interface{}{}
body["label"] = opt.Label
Expand Down Expand Up @@ -74,3 +127,13 @@ func (dk *DeployKeys) Delete(opt *DeployKeyOptions) (interface{}, error) {
urlStr := dk.c.requestUrl("/repositories/%s/%s/deploy-keys/%d", opt.Owner, opt.RepoSlug, opt.Id)
return dk.c.execute("DELETE", urlStr, "")
}

func (dk *DeployKeys) List(opt *DeployKeyOptions) (*DeployKeysRes, error) {
urlStr := dk.c.requestUrl("/repositories/%s/%s/deploy-keys", opt.Owner, opt.RepoSlug)
response, err := dk.c.execute("GET", urlStr, "")
if err != nil {
return nil, err
}

return decodeDeployKeys(response)
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ require (
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
github.com/k0kubun/pp v3.0.1+incompatible
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/mapstructure v1.5.0
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/stretchr/testify v1.9.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
Expand Down
16 changes: 11 additions & 5 deletions repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bitbucket
import (
"errors"
"fmt"
"net/url"
)

//"github.com/k0kubun/pp"
Expand Down Expand Up @@ -35,16 +36,21 @@ func (r *Repositories) ListForAccount(ro *RepositoriesOptions) (*RepositoriesRes
urlPath += fmt.Sprintf("/%s", ro.Owner)
}
urlStr := r.c.requestUrl(urlPath)
urlAsUrl, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
q := urlAsUrl.Query()
if ro.Role != "" {
urlStr += "?role=" + ro.Role
q.Set("role", ro.Role)
}
if ro.Keyword != nil && *ro.Keyword != "" {
if ro.Role == "" {
urlStr += "?"
}
// https://developer.atlassian.com/cloud/bitbucket/rest/intro/#operators
urlStr += fmt.Sprintf("q=full_name ~ \"%s\"", *ro.Keyword)
query := fmt.Sprintf("full_name ~ \"%s\"", *ro.Keyword)
q.Set("q", query)
}
urlAsUrl.RawQuery = q.Encode()
urlStr = urlAsUrl.String()
repos, err := r.c.executePaginated("GET", urlStr, "", ro.Page)
if err != nil {
return nil, err
Expand Down
130 changes: 130 additions & 0 deletions ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package bitbucket

import (
"encoding/json"
"errors"

"github.com/mitchellh/mapstructure"
)

type SSHKeys struct {
c *Client
}

type SSHKey struct {
Uuid string `json:"uuid"`
Label string `json:"label"`
Key string `json:"key"`
Comment string `json:"comment"`
CreatedOm string `json:"created_on"`
}

type SSHKeyRes struct {
Page int32
Pagelen int32
MaxDepth int32
Size int32
Items []SSHKey
}

func decodeSSHKey(response interface{}) (*SSHKey, error) {
respMap := response.(map[string]interface{})

if respMap["type"] == "error" {
return nil, DecodeError(respMap)
}

var sshKey = new(SSHKey)
err := mapstructure.Decode(respMap, sshKey)
if err != nil {
return nil, err
}

return sshKey, nil
}

func buildSSHKeysBody(opt *SSHKeyOptions) (string, error) {
body := map[string]interface{}{}
body["label"] = opt.Label
body["key"] = opt.Key

data, err := json.Marshal(body)
if err != nil {
return "", err
}

return string(data), nil
}

func decodeSSHKeys(keysResponse interface{}) (*SSHKeyRes, error) {
keysResponseMap, ok := keysResponse.(map[string]interface{})
if !ok {
return nil, errors.New("Not a valid format")
}

keyArray := keysResponseMap["values"].([]interface{})
var keys []SSHKey
for _, keyEntry := range keyArray {
var key SSHKey
err := mapstructure.Decode(keyEntry, &key)
if err == nil {
keys = append(keys, key)
}
}

page, ok := keysResponseMap["page"].(float64)
if !ok {
page = 0
}

pagelen, ok := keysResponseMap["pagelen"].(float64)
if !ok {
pagelen = 0
}
max_depth, ok := keysResponseMap["max_width"].(float64)
if !ok {
max_depth = 0
}
size, ok := keysResponseMap["size"].(float64)
if !ok {
size = 0
}

keysResp := &SSHKeyRes{
Page: int32(page),
Pagelen: int32(pagelen),
MaxDepth: int32(max_depth),
Size: int32(size),
Items: keys,
}
return keysResp, nil
}

func (sk *SSHKeys) Create(ro *SSHKeyOptions) (*SSHKey, error) {
data, err := buildSSHKeysBody(ro)
if err != nil {
return nil, err
}
urlStr := sk.c.requestUrl("/users/%s/ssh-keys", ro.Owner)
response, err := sk.c.execute("POST", urlStr, data)
if err != nil {
return nil, err
}

return decodeSSHKey(response)
}

func (sk *SSHKeys) Get(ro *SSHKeyOptions) (*SSHKey, error) {
urlStr := sk.c.requestUrl("/users/%s/ssh-keys/%s", ro.Owner, ro.Uuid)
response, err := sk.c.execute("GET", urlStr, "")
if err != nil {
return nil, err
}

return decodeSSHKey(response)
}

func (sk *SSHKeys) Delete(ro *SSHKeyOptions) (interface{}, error) {
urlStr := sk.c.requestUrl("/users/%s/ssh-keys/%s", ro.Owner, ro.Uuid)
return sk.c.execute("DELETE", urlStr, "")
}
Loading

0 comments on commit 90ada25

Please sign in to comment.