Repository: xanzy/go-gitlab
Pull request #1379 (2022-02-13 12:56:20)

Align `/deploy_keys` API to get instance-wide deploy keys
Apparently, the response here has changed from GitLab v13 to GitLab v14.

see https://docs.gitlab.com/ee/api/deploy_keys.html

We'd love to have this in the next release for the terraform provider, see:

* https://github.com/gitlabhq/terraform-provider-gitlab/issues/373


Patch:
diff --git a/deploy_keys.go b/deploy_keys.go
index 14ba0c8..52b27c3 100644
--- a/deploy_keys.go
+++ b/deploy_keys.go
@@ -30,30 +30,70 @@ type DeployKeysService struct {
 	client *Client
 }
 
-// DeployKey represents a GitLab deploy key.
-type DeployKey struct {
+// InstanceDeployKey represents a GitLab deploy key with the associated
+// projects it has write access to.
+type InstanceDeployKey struct {
+	ID                      int                 `json:"id"`
+	Title                   string              `json:"title"`
+	CreatedAt               *time.Time          `json:"created_at"`
+	Key                     string              `json:"key"`
+	Fingerprint             string              `json:"fingerprint"`
+	ProjectsWithWriteAccess []*DeployKeyProject `json:"projects_with_write_access"`
+}
+
+func (k InstanceDeployKey) String() string {
+	return Stringify(k)
+}
+
+// DeployKeyProject refers to a project an InstanceDeployKey has write access to.
+type DeployKeyProject struct {
+	ID                int        `json:"id"`
+	Description       string     `json:"description"`
+	Name              string     `json:"name"`
+	NameWithNamespace string     `json:"name_with_namespace"`
+	Path              string     `json:"path"`
+	PathWithNamespace string     `json:"path_with_namespace"`
+	CreatedAt         *time.Time `json:"created_at"`
+}
+
+func (k DeployKeyProject) String() string {
+	return Stringify(k)
+}
+
+// ProjectDeployKey represents a GitLab project deploy key.
+type ProjectDeployKey struct {
 	ID        int        `json:"id"`
 	Title     string     `json:"title"`
 	Key       string     `json:"key"`
-	CanPush   *bool      `json:"can_push"`
 	CreatedAt *time.Time `json:"created_at"`
+	CanPush   bool       `json:"can_push"`
 }
 
-func (k DeployKey) String() string {
+func (k ProjectDeployKey) String() string {
 	return Stringify(k)
 }
 
+// ListProjectDeployKeysOptions represents the available ListAllDeployKeys()
+// options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys
+type ListInstanceDeployKeysOptions struct {
+	ListOptions
+	Public *bool `url:"public,omitempty" json:"public,omitempty"`
+}
+
 // ListAllDeployKeys gets a list of all deploy keys
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys
-func (s *DeployKeysService) ListAllDeployKeys(options ...RequestOptionFunc) ([]*DeployKey, *Response, error) {
-	req, err := s.client.NewRequest(http.MethodGet, "deploy_keys", nil, options)
+func (s *DeployKeysService) ListAllDeployKeys(opt *ListInstanceDeployKeysOptions, options ...RequestOptionFunc) ([]*InstanceDeployKey, *Response, error) {
+	req, err := s.client.NewRequest(http.MethodGet, "deploy_keys", opt, options)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	var ks []*DeployKey
+	var ks []*InstanceDeployKey
 	resp, err := s.client.Do(req, &ks)
 	if err != nil {
 		return nil, resp, err
@@ -73,7 +113,7 @@ type ListProjectDeployKeysOptions ListOptions
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys
-func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...RequestOptionFunc) ([]*DeployKey, *Response, error) {
+func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...RequestOptionFunc) ([]*ProjectDeployKey, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
@@ -85,7 +125,7 @@ func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProj
 		return nil, nil, err
 	}
 
-	var ks []*DeployKey
+	var ks []*ProjectDeployKey
 	resp, err := s.client.Do(req, &ks)
 	if err != nil {
 		return nil, resp, err
@@ -98,7 +138,7 @@ func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProj
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key
-func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
+func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*ProjectDeployKey, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
@@ -110,7 +150,7 @@ func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options
 		return nil, nil, err
 	}
 
-	k := new(DeployKey)
+	k := new(ProjectDeployKey)
 	resp, err := s.client.Do(req, k)
 	if err != nil {
 		return nil, resp, err
@@ -135,7 +175,7 @@ type AddDeployKeyOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key
-func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
+func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...RequestOptionFunc) (*ProjectDeployKey, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
@@ -147,7 +187,7 @@ func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptio
 		return nil, nil, err
 	}
 
-	k := new(DeployKey)
+	k := new(ProjectDeployKey)
 	resp, err := s.client.Do(req, k)
 	if err != nil {
 		return nil, resp, err
@@ -179,7 +219,7 @@ func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int, opti
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#enable-a-deploy-key
-func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
+func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...RequestOptionFunc) (*ProjectDeployKey, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
@@ -191,7 +231,7 @@ func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, opti
 		return nil, nil, err
 	}
 
-	k := new(DeployKey)
+	k := new(ProjectDeployKey)
 	resp, err := s.client.Do(req, k)
 	if err != nil {
 		return nil, resp, err
@@ -213,7 +253,7 @@ type UpdateDeployKeyOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/deploy_keys.html#update-deploy-key
-func (s *DeployKeysService) UpdateDeployKey(pid interface{}, deployKey int, opt *UpdateDeployKeyOptions, options ...RequestOptionFunc) (*DeployKey, *Response, error) {
+func (s *DeployKeysService) UpdateDeployKey(pid interface{}, deployKey int, opt *UpdateDeployKeyOptions, options ...RequestOptionFunc) (*ProjectDeployKey, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
@@ -225,7 +265,7 @@ func (s *DeployKeysService) UpdateDeployKey(pid interface{}, deployKey int, opt
 		return nil, nil, err
 	}
 
-	k := new(DeployKey)
+	k := new(ProjectDeployKey)
 	resp, err := s.client.Do(req, k)
 	if err != nil {
 		return nil, resp, err
diff --git a/notes.go b/notes.go
index 40e41d4..1b77d2a 100644
--- a/notes.go
+++ b/notes.go
@@ -68,8 +68,7 @@ type Note struct {
 		AvatarURL string `json:"avatar_url"`
 		WebURL    string `json:"web_url"`
 	} `json:"resolved_by"`
-	ResolvedAt  *time.Time `json:"resolved_at"`
-	NoteableIID int        `json:"noteable_iid"`
+	NoteableIID int `json:"noteable_iid"`
 }
 
 // NotePosition represents the position attributes of a note.


Test patch:
diff --git a/deploy_keys_test.go b/deploy_keys_test.go
index 7a157c3..96efb43 100644
--- a/deploy_keys_test.go
+++ b/deploy_keys_test.go
@@ -31,48 +31,89 @@ func TestListAllDeployKeys(t *testing.T) {
 	mux.HandleFunc("/api/v4/deploy_keys", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
 		fmt.Fprintf(w, `[
+		{
+			"id": 1,
+			"title": "Public key",
+			"key": "ssh-rsa AAAA...",
+			"fingerprint": "7f:72:08:7d:0e:47:48:ec:37:79:b2:76:68:b5:87:65",
+			"created_at": "2013-10-02T10:12:29Z",
+			"projects_with_write_access": [
 			{
-			  "id": 1,
-			  "title": "Public key",
-			  "key": "ssh-rsa AAAA...",
-			  "created_at": "2013-10-02T10:12:29Z"
+				"id": 73,
+				"description": null,
+				"name": "project2",
+				"name_with_namespace": "Sidney Jones / project2",
+				"path": "project2",
+				"path_with_namespace": "sidney_jones/project2",
+				"created_at": "2021-10-25T18:33:17.550Z"
 			},
 			{
-			  "id": 3,
-			  "title": "Another Public key",
-			  "key": "ssh-rsa AAAA...",
-			  "created_at": "2013-10-02T11:12:29Z"
+				"id": 74,
+				"description": null,
+				"name": "project3",
+				"name_with_namespace": "Sidney Jones / project3",
+				"path": "project3",
+				"path_with_namespace": "sidney_jones/project3",
+				"created_at": "2021-10-25T18:33:17.666Z"
+			}
+			]
+		},
+			{
+				"id": 3,
+				"title": "Another Public key",
+				"key": "ssh-rsa AAAA...",
+				"fingerprint": "64:d3:73:d4:83:70:ab:41:96:68:d5:3d:a5:b0:34:ea",
+				"created_at": "2013-10-02T11:12:29Z",
+				"projects_with_write_access": []
 			}
 		  ]`)
 	})
 
-	deployKeys, _, err := client.DeployKeys.ListAllDeployKeys()
+	deployKeys, _, err := client.DeployKeys.ListAllDeployKeys(&ListInstanceDeployKeysOptions{})
 	if err != nil {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned error: %v", err)
 	}
 
-	createdAt, err := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
-	if err != nil {
-		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
-	}
-
-	createdAt2, err := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
-	if err != nil {
-		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
-	}
+	createdAtKey1, _ := time.Parse(timeLayout, "2013-10-02T10:12:29Z")
+	createdAtKey1Enable1, _ := time.Parse(timeLayout, "2021-10-25T18:33:17.550Z")
+	createdAtKey1Enable2, _ := time.Parse(timeLayout, "2021-10-25T18:33:17.666Z")
+	createdAtKey2, _ := time.Parse(timeLayout, "2013-10-02T11:12:29Z")
 
-	want := []*DeployKey{
+	want := []*InstanceDeployKey{
 		{
-			ID:        1,
-			Title:     "Public key",
-			Key:       "ssh-rsa AAAA...",
-			CreatedAt: &createdAt,
+			ID:          1,
+			Title:       "Public key",
+			Key:         "ssh-rsa AAAA...",
+			CreatedAt:   &createdAtKey1,
+			Fingerprint: "7f:72:08:7d:0e:47:48:ec:37:79:b2:76:68:b5:87:65",
+			ProjectsWithWriteAccess: []*DeployKeyProject{
+				{
+					ID:                73,
+					Description:       "",
+					Name:              "project2",
+					NameWithNamespace: "Sidney Jones / project2",
+					Path:              "project2",
+					PathWithNamespace: "sidney_jones/project2",
+					CreatedAt:         &createdAtKey1Enable1,
+				},
+				{
+					ID:                74,
+					Description:       "",
+					Name:              "project3",
+					NameWithNamespace: "Sidney Jones / project3",
+					Path:              "project3",
+					PathWithNamespace: "sidney_jones/project3",
+					CreatedAt:         &createdAtKey1Enable2,
+				},
+			},
 		},
 		{
-			ID:        3,
-			Title:     "Another Public key",
-			Key:       "ssh-rsa AAAA...",
-			CreatedAt: &createdAt2,
+			ID:                      3,
+			Title:                   "Another Public key",
+			Key:                     "ssh-rsa AAAA...",
+			Fingerprint:             "64:d3:73:d4:83:70:ab:41:96:68:d5:3d:a5:b0:34:ea",
+			CreatedAt:               &createdAtKey2,
+			ProjectsWithWriteAccess: []*DeployKeyProject{},
 		},
 	}
 	if !reflect.DeepEqual(want, deployKeys) {
@@ -119,20 +160,20 @@ func TestListProjectDeployKeys(t *testing.T) {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
 	}
 
-	want := []*DeployKey{
+	want := []*ProjectDeployKey{
 		{
 			ID:        1,
 			Title:     "Public key",
 			Key:       "ssh-rsa AAAA...",
 			CreatedAt: &createdAt,
-			CanPush:   Bool(false),
+			CanPush:   false,
 		},
 		{
 			ID:        3,
 			Title:     "Another Public key",
 			Key:       "ssh-rsa AAAA...",
 			CreatedAt: &createdAt2,
-			CanPush:   Bool(false),
+			CanPush:   false,
 		},
 	}
 	if !reflect.DeepEqual(want, deployKeys) {
@@ -165,12 +206,12 @@ func TestGetDeployKey(t *testing.T) {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
 	}
 
-	want := &DeployKey{
+	want := &ProjectDeployKey{
 		ID:        1,
 		Title:     "Public key",
 		Key:       "ssh-rsa AAAA...",
 		CreatedAt: &createdAt,
-		CanPush:   Bool(false),
+		CanPush:   false,
 	}
 	if !reflect.DeepEqual(want, deployKey) {
 		t.Errorf("DeployKeys.GetDeployKey returned %+v, want %+v", deployKey, want)
@@ -207,12 +248,12 @@ func TestAddDeployKey(t *testing.T) {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
 	}
 
-	want := &DeployKey{
+	want := &ProjectDeployKey{
 		Title:     *String("My deploy key"),
 		ID:        12,
 		Key:       *String("ssh-rsa AAAA..."),
-		CanPush:   Bool(true),
 		CreatedAt: &createdAt,
+		CanPush:   true,
 	}
 	if !reflect.DeepEqual(want, deployKey) {
 		t.Errorf("DeployKeys.AddDeployKey returned %+v, want %+v", deployKey, want)
@@ -257,7 +298,7 @@ func TestEnableDeployKey(t *testing.T) {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
 	}
 
-	want := &DeployKey{
+	want := &ProjectDeployKey{
 		ID:        12,
 		Title:     "My deploy key",
 		Key:       "ssh-rsa AAAA...",
@@ -297,12 +338,12 @@ func TestUpdateDeployKey(t *testing.T) {
 		t.Errorf("DeployKeys.ListAllDeployKeys returned an error while parsing time: %v", err)
 	}
 
-	want := &DeployKey{
+	want := &ProjectDeployKey{
 		ID:        11,
 		Title:     *String("New deploy key"),
 		Key:       "ssh-rsa AAAA...",
-		CanPush:   Bool(true),
 		CreatedAt: &createdAt,
+		CanPush:   true,
 	}
 	if !reflect.DeepEqual(want, deployKey) {
 		t.Errorf("DeployKeys.UpdateDeployKey returned %+v, want %+v", deployKey, want)