From 88068046c049059878b9809acbadc38b0967662a Mon Sep 17 00:00:00 2001 From: cointem Date: Sun, 30 Nov 2025 22:06:57 +0800 Subject: [PATCH 1/5] credentials: implement POST /credentials/revoke and tests --- github/credentials.go | 37 +++++++++++++++++++++++++++++ github/credentials_test.go | 48 ++++++++++++++++++++++++++++++++++++++ github/github.go | 2 ++ 3 files changed, 87 insertions(+) create mode 100644 github/credentials.go create mode 100644 github/credentials_test.go diff --git a/github/credentials.go b/github/credentials.go new file mode 100644 index 00000000000..55c4a9142af --- /dev/null +++ b/github/credentials.go @@ -0,0 +1,37 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" +) + +// CredentialsService handles credentials related methods of the GitHub API. +type CredentialsService service + +// RevokeCredentialsRequest represents the request body for revoking credentials. +type RevokeCredentialsRequest struct { + // The list of credential strings (tokens) to revoke. + Credentials []string `json:"credentials"` +} + +// Revoke revokes a list of credentials. +// +// GitHub API docs: https://docs.github.com/rest/credentials/revoke#revoke-a-list-of-credentials +// +//meta:operation POST /credentials/revoke +func (s *CredentialsService) Revoke(ctx context.Context, credentials []string) (*Response, error) { + u := "credentials/revoke" + + reqBody := &RevokeCredentialsRequest{Credentials: credentials} + + req, err := s.client.NewRequest("POST", u, reqBody) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} diff --git a/github/credentials_test.go b/github/credentials_test.go new file mode 100644 index 00000000000..4322ccf26b8 --- /dev/null +++ b/github/credentials_test.go @@ -0,0 +1,48 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "encoding/json" + "errors" + "net/http" + "testing" +) + +func TestCredentialsService_Revoke(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + creds := []string{ + "ghp_1234567890abcdef1234567890abcdef12345678", + "ghp_abcdef1234567890abcdef1234567890abcdef12", + } + expectedBodyBytes, _ := json.Marshal(map[string][]string{"credentials": creds}) + expectedBody := string(expectedBodyBytes) + "\n" + + mux.HandleFunc("/credentials/revoke", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testBody(t, r, expectedBody) + w.WriteHeader(http.StatusAccepted) + }) + + ctx := t.Context() + resp, err := client.Credentials.Revoke(ctx, creds) + if !errors.As(err, new(*AcceptedError)) { + t.Errorf("Credentials.Revoke returned error: %v (want AcceptedError)", err) + } + if resp == nil { + t.Fatalf("Credentials.Revoke returned nil response") + } + if resp.StatusCode != http.StatusAccepted { + t.Errorf("Credentials.Revoke returned status %d, want %d", resp.StatusCode, http.StatusAccepted) + } + + const methodName = "Revoke" + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Credentials.Revoke(ctx, []string{"a"}) + }) +} diff --git a/github/github.go b/github/github.go index eba55176108..e9e67f032fb 100644 --- a/github/github.go +++ b/github/github.go @@ -197,6 +197,7 @@ type Client struct { Apps *AppsService Authorizations *AuthorizationsService Billing *BillingService + Credentials *CredentialsService Checks *ChecksService Classroom *ClassroomService CodeScanning *CodeScanningService @@ -439,6 +440,7 @@ func (c *Client) initialize() { c.Apps = (*AppsService)(&c.common) c.Authorizations = (*AuthorizationsService)(&c.common) c.Billing = (*BillingService)(&c.common) + c.Credentials = (*CredentialsService)(&c.common) c.Checks = (*ChecksService)(&c.common) c.Classroom = (*ClassroomService)(&c.common) c.CodeScanning = (*CodeScanningService)(&c.common) From b2b08fa8bba91206a2a8d112593c9be4d63ac70c Mon Sep 17 00:00:00 2001 From: cointem Date: Sun, 30 Nov 2025 22:27:37 +0800 Subject: [PATCH 2/5] ci: trigger CLA recheck From 1d3d4bebc61190f637495131997ccf4812391add Mon Sep 17 00:00:00 2001 From: cointem Date: Mon, 1 Dec 2025 18:27:28 +0800 Subject: [PATCH 3/5] test: Improve error messages in Credentials.Revoke tests --- github/credentials_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github/credentials_test.go b/github/credentials_test.go index 4322ccf26b8..997c33fc9ec 100644 --- a/github/credentials_test.go +++ b/github/credentials_test.go @@ -35,10 +35,10 @@ func TestCredentialsService_Revoke(t *testing.T) { t.Errorf("Credentials.Revoke returned error: %v (want AcceptedError)", err) } if resp == nil { - t.Fatalf("Credentials.Revoke returned nil response") + t.Fatal("Credentials.Revoke returned nil response") } if resp.StatusCode != http.StatusAccepted { - t.Errorf("Credentials.Revoke returned status %d, want %d", resp.StatusCode, http.StatusAccepted) + t.Errorf("Credentials.Revoke returned status %v, want %v", resp.StatusCode, http.StatusAccepted) } const methodName = "Revoke" From a46fd1f2bf7c76c4b5320dd35e2d63d11ada212f Mon Sep 17 00:00:00 2001 From: cointem Date: Tue, 2 Dec 2025 01:02:06 +0800 Subject: [PATCH 4/5] refactor: rename RevokeCredentialsRequest to revokeCredentialsRequest for consistency --- github/credentials.go | 6 +++--- github/github.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/github/credentials.go b/github/credentials.go index 55c4a9142af..ff6e6f6913a 100644 --- a/github/credentials.go +++ b/github/credentials.go @@ -12,8 +12,8 @@ import ( // CredentialsService handles credentials related methods of the GitHub API. type CredentialsService service -// RevokeCredentialsRequest represents the request body for revoking credentials. -type RevokeCredentialsRequest struct { +// revokeCredentialsRequest represents the request body for revoking credentials. +type revokeCredentialsRequest struct { // The list of credential strings (tokens) to revoke. Credentials []string `json:"credentials"` } @@ -26,7 +26,7 @@ type RevokeCredentialsRequest struct { func (s *CredentialsService) Revoke(ctx context.Context, credentials []string) (*Response, error) { u := "credentials/revoke" - reqBody := &RevokeCredentialsRequest{Credentials: credentials} + reqBody := &revokeCredentialsRequest{Credentials: credentials} req, err := s.client.NewRequest("POST", u, reqBody) if err != nil { diff --git a/github/github.go b/github/github.go index e9e67f032fb..43043119a4e 100644 --- a/github/github.go +++ b/github/github.go @@ -197,13 +197,13 @@ type Client struct { Apps *AppsService Authorizations *AuthorizationsService Billing *BillingService - Credentials *CredentialsService Checks *ChecksService Classroom *ClassroomService CodeScanning *CodeScanningService CodesOfConduct *CodesOfConductService Codespaces *CodespacesService Copilot *CopilotService + Credentials *CredentialsService Dependabot *DependabotService DependencyGraph *DependencyGraphService Emojis *EmojisService From 74ae15b19ec976d306bac35ba2b4b8a1937500cf Mon Sep 17 00:00:00 2001 From: cointem Date: Tue, 2 Dec 2025 01:14:13 +0800 Subject: [PATCH 5/5] fix: restore CredentialsService initialization in github.go --- github/github.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/github.go b/github/github.go index 43043119a4e..b9efa3b4e89 100644 --- a/github/github.go +++ b/github/github.go @@ -440,13 +440,13 @@ func (c *Client) initialize() { c.Apps = (*AppsService)(&c.common) c.Authorizations = (*AuthorizationsService)(&c.common) c.Billing = (*BillingService)(&c.common) - c.Credentials = (*CredentialsService)(&c.common) c.Checks = (*ChecksService)(&c.common) c.Classroom = (*ClassroomService)(&c.common) c.CodeScanning = (*CodeScanningService)(&c.common) c.Codespaces = (*CodespacesService)(&c.common) c.CodesOfConduct = (*CodesOfConductService)(&c.common) c.Copilot = (*CopilotService)(&c.common) + c.Credentials = (*CredentialsService)(&c.common) c.Dependabot = (*DependabotService)(&c.common) c.DependencyGraph = (*DependencyGraphService)(&c.common) c.Emojis = (*EmojisService)(&c.common)