Repository: xanzy/go-gitlab
Pull request #1814 (2023-10-04 14:03:19)

Support CreatePersonalAccessTokenForCurrentUser endpoint
Support new endpoint: https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token-with-limited-scopes-for-the-currently-authenticated-user


timofurrer: @svanharmelen this is ready for your review! As usual, I'd be super happy if a merge is followed by an immediate release 😇 

Patch:
diff --git a/gitlab.go b/gitlab.go
index 0f882bf..6586288 100644
--- a/gitlab.go
+++ b/gitlab.go
@@ -813,7 +813,6 @@ func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error
 		return c.Do(req, v)
 	}
 	defer resp.Body.Close()
-	defer io.Copy(io.Discard, resp.Body)
 
 	// If not yet configured, try to configure the rate limiter
 	// using the response headers we just received. Fail silently
diff --git a/jobs.go b/jobs.go
index 9ad0066..0feaee9 100644
--- a/jobs.go
+++ b/jobs.go
@@ -564,22 +564,3 @@ func (s *JobsService) DeleteArtifacts(pid interface{}, jobID int, options ...Req
 
 	return s.client.Do(req, nil)
 }
-
-// DeleteProjectArtifacts delete artifacts eligible for deletion in a project
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/job_artifacts.html#delete-project-artifacts
-func (s *JobsService) DeleteProjectArtifacts(pid interface{}, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/artifacts", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/users.go b/users.go
index 04a35ad..4489034 100644
--- a/users.go
+++ b/users.go
@@ -1301,6 +1301,38 @@ func (s *UsersService) CreatePersonalAccessToken(user int, opt *CreatePersonalAc
 	return t, resp, nil
 }
 
+// CreatePersonalAccessTokenForCurrentUserOptions represents the available
+// CreatePersonalAccessTokenForCurrentUser() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token-with-limited-scopes-for-the-currently-authenticated-user
+type CreatePersonalAccessTokenForCurrentUserOptions struct {
+	Name      *string   `url:"name,omitempty" json:"name,omitempty"`
+	Scopes    *[]string `url:"scopes,omitempty" json:"scopes,omitempty"`
+	ExpiresAt *ISOTime  `url:"expires_at,omitempty" json:"expires_at,omitempty"`
+}
+
+// CreatePersonalAccessTokenForCurrentUser creates a personal access token with limited scopes for the currently authenticated user.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/users.html#create-a-personal-access-token-with-limited-scopes-for-the-currently-authenticated-user
+func (s *UsersService) CreatePersonalAccessTokenForCurrentUser(opt *CreatePersonalAccessTokenForCurrentUserOptions, options ...RequestOptionFunc) (*PersonalAccessToken, *Response, error) {
+	u := "user/personal_access_tokens"
+
+	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	t := new(PersonalAccessToken)
+	resp, err := s.client.Do(req, &t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, nil
+}
+
 // UserActivity represents an entry in the user/activities response
 //
 // GitLab API docs:


Test patch:
diff --git a/testdata/post_user_personal_access_tokens.json b/testdata/post_user_personal_access_tokens.json
new file mode 100644
index 0000000..7aef8af
--- /dev/null
+++ b/testdata/post_user_personal_access_tokens.json
@@ -0,0 +1,13 @@
+{
+  "id": 3,
+  "name": "mytoken",
+  "revoked": false,
+  "created_at": "2020-10-14T11:58:53.526Z",
+  "scopes": [
+    "k8s_proxy"
+  ],
+  "user_id": 42,
+  "active": true,
+  "expires_at": "2020-10-15",
+  "token": "glpat-aaaaaaaa-bbbbbbbbb"
+}
diff --git a/users_test.go b/users_test.go
index 4ee6887..5525ab7 100644
--- a/users_test.go
+++ b/users_test.go
@@ -682,3 +682,37 @@ func TestCreateUserRunner(t *testing.T) {
 	require.Equal(t, "glrt-1234567890ABCD", response.Token)
 	require.Equal(t, (*time.Time)(nil), response.TokenExpiresAt)
 }
+
+func TestCreatePersonalAccessTokenForCurrentUser(t *testing.T) {
+	mux, client := setup(t)
+
+	path := "/api/v4/user/personal_access_tokens"
+
+	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodPost)
+		mustWriteHTTPResponse(t, w, "testdata/post_user_personal_access_tokens.json")
+	})
+
+	scopes := []string{"k8s_proxy"}
+	expiresAt := ISOTime(time.Date(2020, time.October, 15, 0, 0, 0, 0, time.UTC))
+	user, _, err := client.Users.CreatePersonalAccessTokenForCurrentUser(&CreatePersonalAccessTokenForCurrentUserOptions{
+		Name:      String("mytoken"),
+		Scopes:    &scopes,
+		ExpiresAt: &expiresAt,
+	})
+	require.NoError(t, err)
+
+	createdAt := time.Date(2020, time.October, 14, 11, 58, 53, 526000000, time.UTC)
+	want := &PersonalAccessToken{
+		ID:        3,
+		Name:      "mytoken",
+		Revoked:   false,
+		CreatedAt: &createdAt,
+		Scopes:    scopes,
+		UserID:    42,
+		Active:    true,
+		ExpiresAt: &expiresAt,
+		Token:     "glpat-aaaaaaaa-bbbbbbbbb",
+	}
+	require.Equal(t, want, user)
+}