Skip to content

Commit 6ea9fac

Browse files
committed
feat: Add Copilot coding agent and content exclusion org endpoints
Implement support for two Copilot organization management endpoints under the CopilotService. - Add ListCopilotCodingAgentRepositories for GET /orgs/{org}/copilot/coding-agent/permissions/repositories. - Add GetCopilotOrganizationContentExclusionDetails for GET /orgs/{org}/copilot/content_exclusion. - Add tests covering both endpoints, JSON round-trip tests for the new types, and regenerate accessors and iterators. API docs: - https://docs.github.com/rest/copilot/copilot-coding-agent-management#list-repositories-enabled-for-copilot-coding-agent-in-an-organization - https://docs.github.com/rest/copilot/copilot-content-exclusion-management#get-copilot-content-exclusion-rules-for-an-organization Fixes: #4175
1 parent daaa203 commit 6ea9fac

6 files changed

Lines changed: 326 additions & 0 deletions

File tree

github/copilot.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,66 @@ func (s *CopilotService) ListCopilotEnterpriseSeats(ctx context.Context, enterpr
356356
return copilotSeats, resp, nil
357357
}
358358

359+
// ListCopilotCodingAgentRepositoriesResponse represents the response from listing
360+
// repositories enabled for the Copilot coding agent in an organization.
361+
type ListCopilotCodingAgentRepositoriesResponse struct {
362+
TotalCount int `json:"total_count"`
363+
Repositories []*Repository `json:"repositories"`
364+
}
365+
366+
// ListCopilotCodingAgentRepositories lists repositories enabled for the Copilot coding agent in an organization.
367+
//
368+
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-coding-agent-management?apiVersion=2022-11-28#list-repositories-enabled-for-copilot-coding-agent-in-an-organization
369+
//
370+
//meta:operation GET /orgs/{org}/copilot/coding-agent/permissions/repositories
371+
func (s *CopilotService) ListCopilotCodingAgentRepositories(ctx context.Context, org string, opts *ListOptions) (*ListCopilotCodingAgentRepositoriesResponse, *Response, error) {
372+
u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions/repositories", org)
373+
u, err := addOptions(u, opts)
374+
if err != nil {
375+
return nil, nil, err
376+
}
377+
378+
req, err := s.client.NewRequest("GET", u, nil)
379+
if err != nil {
380+
return nil, nil, err
381+
}
382+
383+
var result *ListCopilotCodingAgentRepositoriesResponse
384+
resp, err := s.client.Do(ctx, req, &result)
385+
if err != nil {
386+
return nil, resp, err
387+
}
388+
389+
return result, resp, nil
390+
}
391+
392+
// CopilotOrganizationContentExclusionDetails lists all Copilot content exclusion
393+
// rules for an organization, keyed by repository full name. Each value is the
394+
// list of file paths excluded from Copilot for that repository.
395+
type CopilotOrganizationContentExclusionDetails map[string][]string
396+
397+
// GetCopilotOrganizationContentExclusionDetails gets the Copilot content exclusion rules for an organization.
398+
//
399+
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-content-exclusion-management?apiVersion=2022-11-28#get-copilot-content-exclusion-rules-for-an-organization
400+
//
401+
//meta:operation GET /orgs/{org}/copilot/content_exclusion
402+
func (s *CopilotService) GetCopilotOrganizationContentExclusionDetails(ctx context.Context, org string) (CopilotOrganizationContentExclusionDetails, *Response, error) {
403+
u := fmt.Sprintf("orgs/%v/copilot/content_exclusion", org)
404+
405+
req, err := s.client.NewRequest("GET", u, nil)
406+
if err != nil {
407+
return nil, nil, err
408+
}
409+
410+
details := CopilotOrganizationContentExclusionDetails{}
411+
resp, err := s.client.Do(ctx, req, &details)
412+
if err != nil {
413+
return nil, resp, err
414+
}
415+
416+
return details, resp, nil
417+
}
418+
359419
// AddCopilotTeams adds teams to the Copilot for Business subscription for an organization.
360420
//
361421
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#add-teams-to-the-copilot-subscription-for-an-organization

github/copilot_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,130 @@ func TestCopilotService_ListCopilotEnterpriseSeats(t *testing.T) {
776776
})
777777
}
778778

779+
func TestCopilotService_ListCopilotCodingAgentRepositories(t *testing.T) {
780+
t.Parallel()
781+
client, mux, _ := setup(t)
782+
783+
mux.HandleFunc("/orgs/o/copilot/coding-agent/permissions/repositories", func(w http.ResponseWriter, r *http.Request) {
784+
testMethod(t, r, "GET")
785+
testFormValues(t, r, values{
786+
"per_page": "100",
787+
"page": "1",
788+
})
789+
fmt.Fprint(w, `{
790+
"total_count": 2,
791+
"repositories": [
792+
{"id": 1, "name": "Hello-World", "full_name": "octocat/Hello-World"},
793+
{"id": 2, "name": "Hello-World-2", "full_name": "octocat/Hello-World-2"}
794+
]
795+
}`)
796+
})
797+
798+
ctx := t.Context()
799+
opts := &ListOptions{Page: 1, PerPage: 100}
800+
got, _, err := client.Copilot.ListCopilotCodingAgentRepositories(ctx, "o", opts)
801+
if err != nil {
802+
t.Errorf("Copilot.ListCopilotCodingAgentRepositories returned error: %v", err)
803+
}
804+
805+
want := &ListCopilotCodingAgentRepositoriesResponse{
806+
TotalCount: 2,
807+
Repositories: []*Repository{
808+
{ID: Ptr(int64(1)), Name: Ptr("Hello-World"), FullName: Ptr("octocat/Hello-World")},
809+
{ID: Ptr(int64(2)), Name: Ptr("Hello-World-2"), FullName: Ptr("octocat/Hello-World-2")},
810+
},
811+
}
812+
if !cmp.Equal(got, want) {
813+
t.Errorf("Copilot.ListCopilotCodingAgentRepositories returned %+v, want %+v", got, want)
814+
}
815+
816+
const methodName = "ListCopilotCodingAgentRepositories"
817+
818+
testBadOptions(t, methodName, func() (err error) {
819+
_, _, err = client.Copilot.ListCopilotCodingAgentRepositories(ctx, "\n", opts)
820+
return err
821+
})
822+
823+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
824+
got, resp, err := client.Copilot.ListCopilotCodingAgentRepositories(ctx, "o", opts)
825+
if got != nil {
826+
t.Errorf("Copilot.ListCopilotCodingAgentRepositories returned %+v, want nil", got)
827+
}
828+
return resp, err
829+
})
830+
}
831+
832+
func TestCopilotService_GetCopilotOrganizationContentExclusionDetails(t *testing.T) {
833+
t.Parallel()
834+
client, mux, _ := setup(t)
835+
836+
mux.HandleFunc("/orgs/o/copilot/content_exclusion", func(w http.ResponseWriter, r *http.Request) {
837+
testMethod(t, r, "GET")
838+
fmt.Fprint(w, `{
839+
"octo-repo": ["/src/some-dir/kernel.rs"],
840+
"octo-repo-2": ["/docs/secret.md", "**/*.env"]
841+
}`)
842+
})
843+
844+
ctx := t.Context()
845+
got, _, err := client.Copilot.GetCopilotOrganizationContentExclusionDetails(ctx, "o")
846+
if err != nil {
847+
t.Errorf("Copilot.GetCopilotOrganizationContentExclusionDetails returned error: %v", err)
848+
}
849+
850+
want := CopilotOrganizationContentExclusionDetails{
851+
"octo-repo": {"/src/some-dir/kernel.rs"},
852+
"octo-repo-2": {"/docs/secret.md", "**/*.env"},
853+
}
854+
if !cmp.Equal(got, want) {
855+
t.Errorf("Copilot.GetCopilotOrganizationContentExclusionDetails returned %+v, want %+v", got, want)
856+
}
857+
858+
const methodName = "GetCopilotOrganizationContentExclusionDetails"
859+
860+
testBadOptions(t, methodName, func() (err error) {
861+
_, _, err = client.Copilot.GetCopilotOrganizationContentExclusionDetails(ctx, "\n")
862+
return err
863+
})
864+
865+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
866+
got, resp, err := client.Copilot.GetCopilotOrganizationContentExclusionDetails(ctx, "o")
867+
if got != nil {
868+
t.Errorf("Copilot.GetCopilotOrganizationContentExclusionDetails returned %+v, want nil", got)
869+
}
870+
return resp, err
871+
})
872+
}
873+
874+
func TestListCopilotCodingAgentRepositoriesResponse_Marshal(t *testing.T) {
875+
t.Parallel()
876+
testJSONMarshal(t, &ListCopilotCodingAgentRepositoriesResponse{}, `{"total_count":0,"repositories":null}`)
877+
878+
r := &ListCopilotCodingAgentRepositoriesResponse{
879+
TotalCount: 1,
880+
Repositories: []*Repository{
881+
{ID: Ptr(int64(1)), Name: Ptr("Hello-World"), FullName: Ptr("octocat/Hello-World")},
882+
},
883+
}
884+
want := `{
885+
"total_count": 1,
886+
"repositories": [
887+
{"id": 1, "name": "Hello-World", "full_name": "octocat/Hello-World"}
888+
]
889+
}`
890+
testJSONMarshal(t, r, want)
891+
}
892+
893+
func TestCopilotOrganizationContentExclusionDetails_Marshal(t *testing.T) {
894+
t.Parallel()
895+
testJSONMarshal(t, CopilotOrganizationContentExclusionDetails{}, `{}`)
896+
897+
d := CopilotOrganizationContentExclusionDetails{
898+
"octo-repo": {"/src/some-dir/kernel.rs"},
899+
}
900+
testJSONMarshal(t, d, `{"octo-repo":["/src/some-dir/kernel.rs"]}`)
901+
}
902+
779903
func TestCopilotService_AddCopilotTeams(t *testing.T) {
780904
t.Parallel()
781905
client, mux, _ := setup(t)

github/github-accessors.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-accessors_test.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-iterators.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

github/github-iterators_test.go

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)