diff --git a/github/github-accessors.go b/github/github-accessors.go index 41cd582c1a1..c7089951a34 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -18806,6 +18806,14 @@ func (r *ReviewersRequest) GetNodeID() string { return *r.NodeID } +// GetReason returns the Reason field if it's non-nil, zero value otherwise. +func (r *ReviewPersonalAccessTokenRequestOptions) GetReason() string { + if r == nil || r.Reason == nil { + return "" + } + return *r.Reason +} + // GetDescription returns the Description field if it's non-nil, zero value otherwise. func (r *Rule) GetDescription() string { if r == nil || r.Description == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 993a12484b9..7d151331cbb 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -21933,6 +21933,16 @@ func TestReviewersRequest_GetNodeID(tt *testing.T) { r.GetNodeID() } +func TestReviewPersonalAccessTokenRequestOptions_GetReason(tt *testing.T) { + var zeroValue string + r := &ReviewPersonalAccessTokenRequestOptions{Reason: &zeroValue} + r.GetReason() + r = &ReviewPersonalAccessTokenRequestOptions{} + r.GetReason() + r = nil + r.GetReason() +} + func TestRule_GetDescription(tt *testing.T) { var zeroValue string r := &Rule{Description: &zeroValue} diff --git a/github/orgs_personal_access_tokens.go b/github/orgs_personal_access_tokens.go new file mode 100644 index 00000000000..c30ff2843ee --- /dev/null +++ b/github/orgs_personal_access_tokens.go @@ -0,0 +1,34 @@ +// Copyright 2023 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" + "fmt" + "net/http" +) + +// ReviewPersonalAccessTokenRequestOptions specifies the parameters to the ReviewPersonalAccessTokenRequest method. +type ReviewPersonalAccessTokenRequestOptions struct { + Action string `json:"action"` + Reason *string `json:"reason,omitempty"` +} + +// ReviewPersonalAccessTokenRequest approves or denies a pending request to access organization resources via a fine-grained personal access token. +// Only GitHub Apps can call this API, using the `organization_personal_access_token_requests: write` permission. +// `action` can be one of `approve` or `deny`. +// +// GitHub API docs: https://docs.github.com/en/rest/orgs/personal-access-tokens?apiVersion=2022-11-28#review-a-request-to-access-organization-resources-with-a-fine-grained-personal-access-token +func (s *OrganizationsService) ReviewPersonalAccessTokenRequest(ctx context.Context, org string, requestID int64, opts ReviewPersonalAccessTokenRequestOptions) (*Response, error) { + u := fmt.Sprintf("orgs/%v/personal-access-token-requests/%v", org, requestID) + + req, err := s.client.NewRequest(http.MethodPost, u, &opts) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} diff --git a/github/orgs_personal_access_tokens_test.go b/github/orgs_personal_access_tokens_test.go new file mode 100644 index 00000000000..93ee1b3db93 --- /dev/null +++ b/github/orgs_personal_access_tokens_test.go @@ -0,0 +1,73 @@ +// Copyright 2023 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" + "encoding/json" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_ReviewPersonalAccessTokenRequest(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := ReviewPersonalAccessTokenRequestOptions{ + Action: "a", + Reason: String("r"), + } + + mux.HandleFunc("/orgs/o/personal-access-token-requests/1", func(w http.ResponseWriter, r *http.Request) { + v := new(ReviewPersonalAccessTokenRequestOptions) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, http.MethodPost) + if !cmp.Equal(v, &input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + res, err := client.Organizations.ReviewPersonalAccessTokenRequest(ctx, "o", 1, input) + if err != nil { + t.Errorf("Organizations.ReviewPersonalAccessTokenRequest returned error: %v", err) + } + + if res.StatusCode != http.StatusNoContent { + t.Errorf("Organizations.ReviewPersonalAccessTokenRequest returned %v, want %v", res.StatusCode, http.StatusNoContent) + } + + const methodName = "ReviewPersonalAccessTokenRequest" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Organizations.ReviewPersonalAccessTokenRequest(ctx, "\n", 0, input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.ReviewPersonalAccessTokenRequest(ctx, "o", 1, input) + }) +} + +func TestReviewPersonalAccessTokenRequestOptions_Marshal(t *testing.T) { + testJSONMarshal(t, &ReviewPersonalAccessTokenRequestOptions{}, "{}") + + u := &ReviewPersonalAccessTokenRequestOptions{ + Action: "a", + Reason: String("r"), + } + + want := `{ + "action": "a", + "reason": "r" + }` + + testJSONMarshal(t, u, want) +}