Repository: xanzy/go-gitlab
Pull request #1686 (2023-04-08 03:04:35)

feat: Add support for getting a single personal access token
added two endpoints to get the single personal access token
* self
* token by id https://github.com/xanzy/go-gitlab/issues/1684


Patch:
diff --git a/event_webhook_types.go b/event_webhook_types.go
index 5044444..cf79b37 100644
--- a/event_webhook_types.go
+++ b/event_webhook_types.go
@@ -143,16 +143,12 @@ type CommitCommentEvent struct {
 // GitLab API docs:
 // https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#deployment-events
 type DeploymentEvent struct {
-	ObjectKind             string `json:"object_kind"`
-	Status                 string `json:"status"`
-	StatusChangedAt        string `json:"status_changed_at"`
-	DeploymentID           int    `json:"deployment_id"`
-	DeployableID           int    `json:"deployable_id"`
-	DeployableURL          string `json:"deployable_url"`
-	Environment            string `json:"environment"`
-	EnvironmentSlug        string `json:"environment_slug"`
-	EnvironmentExternalURL string `json:"environment_external_url"`
-	Project                struct {
+	ObjectKind    string `json:"object_kind"`
+	Status        string `json:"status"`
+	DeployableID  int    `json:"deployable_id"`
+	DeployableURL string `json:"deployable_url"`
+	Environment   string `json:"environment"`
+	Project       struct {
 		ID                int     `json:"id"`
 		Name              string  `json:"name"`
 		Description       string  `json:"description"`
diff --git a/personal_access_tokens.go b/personal_access_tokens.go
index aceec13..07d6de2 100644
--- a/personal_access_tokens.go
+++ b/personal_access_tokens.go
@@ -79,6 +79,47 @@ func (s *PersonalAccessTokensService) ListPersonalAccessTokens(opt *ListPersonal
 	return pats, resp, err
 }
 
+// GetSinglePersonalAccessTokenByID get a single personal access token by its ID.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/personal_access_tokens.html#using-a-personal-access-token-id
+func (s *PersonalAccessTokensService) GetSinglePersonalAccessTokenByID(user int, options ...RequestOptionFunc) (*PersonalAccessToken, *Response, error) {
+	u := fmt.Sprintf("personal_access_tokens/%d", user)
+	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pat := new(PersonalAccessToken)
+	resp, err := s.client.Do(req, pat)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pat, resp, err
+}
+
+// GetSinglePersonalAccessToken get a single personal access token by using
+// passing the token in a header.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/personal_access_tokens.html#using-a-request-header
+func (s *PersonalAccessTokensService) GetSinglePersonalAccessToken(options ...RequestOptionFunc) (*PersonalAccessToken, *Response, error) {
+	u := "personal_access_tokens/self"
+	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	pat := new(PersonalAccessToken)
+	resp, err := s.client.Do(req, pat)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return pat, resp, err
+}
+
 // RevokePersonalAccessToken revokes a personal access token.
 //
 // GitLab API docs:


Test patch:
diff --git a/event_webhook_types_test.go b/event_webhook_types_test.go
index 421e3c6..1bc42c5 100644
--- a/event_webhook_types_test.go
+++ b/event_webhook_types_test.go
@@ -174,22 +174,6 @@ func TestDeploymentEventUnmarshal(t *testing.T) {
 	if event.Ref != "1.0.0" {
 		t.Errorf("Ref is %s, want %s", event.Ref, "1.0.0")
 	}
-
-	if event.StatusChangedAt != "2021-04-28 21:50:00 +0200" {
-		t.Errorf("StatusChangedAt is %s, want %s", event.StatusChangedAt, "2021-04-28 21:50:00 +0200")
-	}
-
-	if event.DeploymentID != 15 {
-		t.Errorf("DeploymentID is %d, want %d", event.DeploymentID, 15)
-	}
-
-	if event.EnvironmentSlug != "staging" {
-		t.Errorf("EnvironmentSlug is %s, want %s", event.EnvironmentSlug, "staging")
-	}
-
-	if event.EnvironmentExternalURL != "https://staging.example.com" {
-		t.Errorf("EnvironmentExternalURL is %s, want %s", event.EnvironmentExternalURL, "https://staging.example.com")
-	}
 }
 
 func TestIssueCommentEventUnmarshal(t *testing.T) {
diff --git a/personal_access_tokens_test.go b/personal_access_tokens_test.go
index 64c929c..7d4f09d 100644
--- a/personal_access_tokens_test.go
+++ b/personal_access_tokens_test.go
@@ -147,7 +147,85 @@ func TestListPersonalAccessTokensNoUserFilter(t *testing.T) {
 	}
 }
 
-func TestDeletePersonalAccessToken(t *testing.T) {
+func TestGetSinglePersonalAccessTokenByID(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/personal_access_tokens/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		mustWriteHTTPResponse(t, w, "testdata/list_personal_access_tokens_single.json")
+	})
+
+	token, _, err := client.PersonalAccessTokens.GetSinglePersonalAccessTokenByID(1)
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.RevokePersonalAccessToken returned error: %v", err)
+	}
+
+	createdAt, err := time.Parse(time.RFC3339, "2020-07-23T14:31:47.729Z")
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned error: %v", err)
+	}
+
+	lastUsedAt, err := time.Parse(time.RFC3339, "2021-10-06T17:58:37.550Z")
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned error: %v", err)
+	}
+
+	want := &PersonalAccessToken{
+		ID:         1,
+		Name:       "Test Token",
+		Revoked:    false,
+		CreatedAt:  &createdAt,
+		Scopes:     []string{"api"},
+		UserID:     1,
+		LastUsedAt: &lastUsedAt,
+		Active:     true,
+	}
+
+	if !reflect.DeepEqual(want, token) {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned %+v, want %+v", token, want)
+	}
+}
+
+func TestGetSinglePersonalAccessToken(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/personal_access_tokens/self", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		mustWriteHTTPResponse(t, w, "testdata/list_personal_access_tokens_single.json")
+	})
+
+	token, _, err := client.PersonalAccessTokens.GetSinglePersonalAccessToken()
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.RevokePersonalAccessToken returned error: %v", err)
+	}
+
+	createdAt, err := time.Parse(time.RFC3339, "2020-07-23T14:31:47.729Z")
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned error: %v", err)
+	}
+
+	lastUsedAt, err := time.Parse(time.RFC3339, "2021-10-06T17:58:37.550Z")
+	if err != nil {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned error: %v", err)
+	}
+
+	want := &PersonalAccessToken{
+		ID:         1,
+		Name:       "Test Token",
+		Revoked:    false,
+		CreatedAt:  &createdAt,
+		Scopes:     []string{"api"},
+		UserID:     1,
+		LastUsedAt: &lastUsedAt,
+		Active:     true,
+	}
+
+	if !reflect.DeepEqual(want, token) {
+		t.Errorf("PersonalAccessTokens.ListPersonalAccessTokens returned %+v, want %+v", token, want)
+	}
+}
+
+func TestRevokePersonalAccessToken(t *testing.T) {
 	mux, client := setup(t)
 
 	mux.HandleFunc("/api/v4/personal_access_tokens/1", func(w http.ResponseWriter, r *http.Request) {
diff --git a/testdata/list_personal_access_tokens_single.json b/testdata/list_personal_access_tokens_single.json
new file mode 100644
index 0000000..6c87a12
--- /dev/null
+++ b/testdata/list_personal_access_tokens_single.json
@@ -0,0 +1,11 @@
+{
+  "id": 1,
+  "name": "Test Token",
+  "revoked": false,
+  "created_at": "2020-07-23T14:31:47.729Z",
+  "scopes": ["api"],
+  "user_id": 1,
+  "last_used_at": "2021-10-06T17:58:37.550Z",
+  "active": true,
+  "expires_at": null
+}
diff --git a/testdata/list_personal_access_tokens_with_user_filter.json b/testdata/list_personal_access_tokens_with_user_filter.json
index 2278678..bcda5dd 100644
--- a/testdata/list_personal_access_tokens_with_user_filter.json
+++ b/testdata/list_personal_access_tokens_with_user_filter.json
@@ -4,9 +4,7 @@
     "name": "test 1",
     "revoked": true,
     "created_at": "2020-02-20T14:58:56.238Z",
-    "scopes": [
-      "api"
-    ],
+    "scopes": ["api"],
     "user_id": 1,
     "last_used_at": "2021-04-20T16:31:39.105Z",
     "active": false,
@@ -17,10 +15,7 @@
     "name": "test 2",
     "revoked": false,
     "created_at": "2022-03-20T03:56:18.968Z",
-    "scopes": [
-      "api",
-      "read_user"
-    ],
+    "scopes": ["api", "read_user"],
     "user_id": 1,
     "last_used_at": null,
     "active": false,
diff --git a/testdata/list_project_feature_flags.json b/testdata/list_project_feature_flags.json
index 660fd2f..2e1c540 100644
--- a/testdata/list_project_feature_flags.json
+++ b/testdata/list_project_feature_flags.json
@@ -1,12 +1,12 @@
 [
   {
-    "name":"merge_train",
-    "description":"This feature is about merge train",
+    "name": "merge_train",
+    "description": "This feature is about merge train",
     "active": true,
     "version": "new_version_flag",
-    "created_at":"2019-11-04T08:13:51Z",
-    "updated_at":"2019-11-04T08:13:11Z",
-    "scopes":[],
+    "created_at": "2019-11-04T08:13:51Z",
+    "updated_at": "2019-11-04T08:13:11Z",
+    "scopes": [],
     "strategies": [
       {
         "id": 1,
@@ -24,13 +24,13 @@
     ]
   },
   {
-    "name":"new_live_trace",
-    "description":"This is a new live trace feature",
+    "name": "new_live_trace",
+    "description": "This is a new live trace feature",
     "active": true,
     "version": "new_version_flag",
-    "created_at":"2019-11-04T08:13:10Z",
-    "updated_at":"2019-11-04T08:13:10Z",
-    "scopes":[],
+    "created_at": "2019-11-04T08:13:10Z",
+    "updated_at": "2019-11-04T08:13:10Z",
+    "scopes": [],
     "strategies": [
       {
         "id": 2,
diff --git a/testdata/webhooks/deployment.json b/testdata/webhooks/deployment.json
index 781935e..ce3c131 100644
--- a/testdata/webhooks/deployment.json
+++ b/testdata/webhooks/deployment.json
@@ -1,13 +1,9 @@
 {
   "object_kind": "deployment",
   "status": "success",
-  "status_changed_at":"2021-04-28 21:50:00 +0200",
-  "deployment_id": 15,
   "deployable_id": 796,
   "deployable_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796",
   "environment": "staging",
-  "environment_slug": "staging",
-  "environment_external_url": "https://staging.example.com",
   "project": {
     "id": 30,
     "name": "test-deployment-webhooks",