From 75ee91c29cdb69cc028f0926243e6c118ba6d632 Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Sat, 6 Dec 2025 04:06:05 +0000 Subject: [PATCH 1/2] added enterprise team support --- github/enterprise_team.go | 147 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 github/enterprise_team.go diff --git a/github/enterprise_team.go b/github/enterprise_team.go new file mode 100644 index 00000000000..a5696264b9f --- /dev/null +++ b/github/enterprise_team.go @@ -0,0 +1,147 @@ +// 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" + "fmt" +) + +type EnterpriseTeam struct { + ID int64 `json:"id"` + URL string `json:"url"` + MemberURL string `json:"member_url"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + HTMLURL string `json:"html_url"` + Slug string `json:"slug"` + CreatedAt Timestamp `json:"created_at"` + UpdatedAt Timestamp `json:"updated_at"` + GroupID int64 `json:"group_id"` + OrganizationSelectionType *string `json:"organization_selection_type,omitempty"` + SyncToOrganizations *string `json:"sync_to_organizations,omitempty"` +} + +type EnterpriseTeamCreateRequest struct { + Name string `json:"name"` + Description *string `json:"description,omitempty"` + SyncToOrganizations *string `json:"sync_to_organizations,omitempty"` + OrganizationSelectionType *string `json:"organization_selection_type,omitempty"` + GroupID *int64 `json:"group_id,omitempty"` +} + +// ListTeams lists all teams in an enterprise. +// +// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#list-enterprise-teams +// +//meta:operation GET /enterprises/{enterprise}/teams +func (s *EnterpriseService) ListTeams(ctx context.Context, enterprise string, opt *ListOptions) ([]*EnterpriseTeam, *Response, error) { + u := fmt.Sprintf("enterprises/%v/teams", enterprise) + u, err := addOptions(u, opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var teams []*EnterpriseTeam + resp, err := s.client.Do(ctx, req, &teams) + if err != nil { + return nil, resp, err + } + + return teams, resp, nil +} + +// CreateTeam creates a new team in an enterprise. +// +// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#create-an-enterprise-team +// +//meta:operation POST /enterprises/{enterprise}/teams +func (s *EnterpriseService) CreateTeam(ctx context.Context, enterprise string, team EnterpriseTeamCreateRequest) (*EnterpriseTeam, *Response, error) { + u := fmt.Sprintf("enterprises/%v/teams", enterprise) + + req, err := s.client.NewRequest("POST", u, team) + if err != nil { + return nil, nil, err + } + + var createdTeam *EnterpriseTeam + resp, err := s.client.Do(ctx, req, &createdTeam) + if err != nil { + return nil, resp, err + } + + return createdTeam, resp, nil +} + +// GetTeam retrieves a team in an enterprise. +// +// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#get-an-enterprise-team +// +//meta:operation GET /enterprises/{enterprise}/teams/{team_slug} +func (s *EnterpriseService) GetTeam(ctx context.Context, enterprise, teamSlug string) (*EnterpriseTeam, *Response, error) { + u := fmt.Sprintf("enterprises/%v/teams/%v", enterprise, teamSlug) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var team *EnterpriseTeam + resp, err := s.client.Do(ctx, req, &team) + if err != nil { + return nil, resp, err + } + + return team, resp, nil +} + +// UpdateTeam updates a team in an enterprise. +// +// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#update-an-enterprise-team +// +//meta:operation PATCH /enterprises/{enterprise}/teams/{team_slug} +func (s *EnterpriseService) UpdateTeam(ctx context.Context, enterprise, teamSlug string, team EnterpriseTeamCreateRequest) (*EnterpriseTeam, *Response, error) { + u := fmt.Sprintf("enterprises/%v/teams/%v", enterprise, teamSlug) + + req, err := s.client.NewRequest("PATCH", u, team) + if err != nil { + return nil, nil, err + } + + var updatedTeam *EnterpriseTeam + resp, err := s.client.Do(ctx, req, &updatedTeam) + if err != nil { + return nil, resp, err + } + + return updatedTeam, resp, nil +} + +// DeleteTeam deletes a team in an enterprise. +// +// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#delete-an-enterprise-team +// +//meta:operation DELETE /enterprises/{enterprise}/teams/{team_slug} +func (s *EnterpriseService) DeleteTeam(ctx context.Context, enterprise, teamSlug string) (*Response, error) { + u := fmt.Sprintf("enterprises/%v/teams/%v", enterprise, teamSlug) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} From f44befc8f49a68f739e531ff1efd9df425c9bef5 Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Sat, 6 Dec 2025 11:07:32 +0000 Subject: [PATCH 2/2] add tests for enterprise team --- github/enterprise_team.go | 32 +++-- github/enterprise_team_test.go | 236 ++++++++++++++++++++++++++++++++ github/github-accessors.go | 32 +++++ github/github-accessors_test.go | 44 ++++++ 4 files changed, 330 insertions(+), 14 deletions(-) create mode 100644 github/enterprise_team_test.go diff --git a/github/enterprise_team.go b/github/enterprise_team.go index a5696264b9f..3f2a59d9bc2 100644 --- a/github/enterprise_team.go +++ b/github/enterprise_team.go @@ -10,32 +10,36 @@ import ( "fmt" ) +// EnterpriseTeam represent a team in a GitHub Enterprise. type EnterpriseTeam struct { ID int64 `json:"id"` URL string `json:"url"` MemberURL string `json:"member_url"` Name string `json:"name"` - Description *string `json:"description,omitempty"` HTMLURL string `json:"html_url"` Slug string `json:"slug"` CreatedAt Timestamp `json:"created_at"` UpdatedAt Timestamp `json:"updated_at"` GroupID int64 `json:"group_id"` OrganizationSelectionType *string `json:"organization_selection_type,omitempty"` - SyncToOrganizations *string `json:"sync_to_organizations,omitempty"` } -type EnterpriseTeamCreateRequest struct { - Name string `json:"name"` - Description *string `json:"description,omitempty"` - SyncToOrganizations *string `json:"sync_to_organizations,omitempty"` +// EnterpriseTeamCreateOrUpdateRequest is used to create or update an enterprise team. +type EnterpriseTeamCreateOrUpdateRequest struct { + // The name of the team. + Name string `json:"name"` + // A description of the team. + Description *string `json:"description,omitempty"` + // Specifies which organizations in the enterprise should have access to this team. + // Possible values are "disabled" , "all" and "selected". If not specified, the default is "disabled". OrganizationSelectionType *string `json:"organization_selection_type,omitempty"` - GroupID *int64 `json:"group_id,omitempty"` + // The ID of the IdP group to assign team membership with. + GroupID *int64 `json:"group_id,omitempty"` } // ListTeams lists all teams in an enterprise. // -// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#list-enterprise-teams +// GitHub API docs: https://docs.github.com/rest/enterprise-teams/enterprise-teams#list-enterprise-teams // //meta:operation GET /enterprises/{enterprise}/teams func (s *EnterpriseService) ListTeams(ctx context.Context, enterprise string, opt *ListOptions) ([]*EnterpriseTeam, *Response, error) { @@ -61,10 +65,10 @@ func (s *EnterpriseService) ListTeams(ctx context.Context, enterprise string, op // CreateTeam creates a new team in an enterprise. // -// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#create-an-enterprise-team +// GitHub API docs: https://docs.github.com/rest/enterprise-teams/enterprise-teams#create-an-enterprise-team // //meta:operation POST /enterprises/{enterprise}/teams -func (s *EnterpriseService) CreateTeam(ctx context.Context, enterprise string, team EnterpriseTeamCreateRequest) (*EnterpriseTeam, *Response, error) { +func (s *EnterpriseService) CreateTeam(ctx context.Context, enterprise string, team EnterpriseTeamCreateOrUpdateRequest) (*EnterpriseTeam, *Response, error) { u := fmt.Sprintf("enterprises/%v/teams", enterprise) req, err := s.client.NewRequest("POST", u, team) @@ -83,7 +87,7 @@ func (s *EnterpriseService) CreateTeam(ctx context.Context, enterprise string, t // GetTeam retrieves a team in an enterprise. // -// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#get-an-enterprise-team +// GitHub API docs: https://docs.github.com/rest/enterprise-teams/enterprise-teams#get-an-enterprise-team // //meta:operation GET /enterprises/{enterprise}/teams/{team_slug} func (s *EnterpriseService) GetTeam(ctx context.Context, enterprise, teamSlug string) (*EnterpriseTeam, *Response, error) { @@ -105,10 +109,10 @@ func (s *EnterpriseService) GetTeam(ctx context.Context, enterprise, teamSlug st // UpdateTeam updates a team in an enterprise. // -// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#update-an-enterprise-team +// GitHub API docs: https://docs.github.com/rest/enterprise-teams/enterprise-teams#update-an-enterprise-team // //meta:operation PATCH /enterprises/{enterprise}/teams/{team_slug} -func (s *EnterpriseService) UpdateTeam(ctx context.Context, enterprise, teamSlug string, team EnterpriseTeamCreateRequest) (*EnterpriseTeam, *Response, error) { +func (s *EnterpriseService) UpdateTeam(ctx context.Context, enterprise, teamSlug string, team EnterpriseTeamCreateOrUpdateRequest) (*EnterpriseTeam, *Response, error) { u := fmt.Sprintf("enterprises/%v/teams/%v", enterprise, teamSlug) req, err := s.client.NewRequest("PATCH", u, team) @@ -127,7 +131,7 @@ func (s *EnterpriseService) UpdateTeam(ctx context.Context, enterprise, teamSlug // DeleteTeam deletes a team in an enterprise. // -// GitHub API docs: https://docs.github.com/en/rest/enterprise-teams/enterprise-teams#delete-an-enterprise-team +// GitHub API docs: https://docs.github.com/rest/enterprise-teams/enterprise-teams#delete-an-enterprise-team // //meta:operation DELETE /enterprises/{enterprise}/teams/{team_slug} func (s *EnterpriseService) DeleteTeam(ctx context.Context, enterprise, teamSlug string) (*Response, error) { diff --git a/github/enterprise_team_test.go b/github/enterprise_team_test.go new file mode 100644 index 00000000000..0da554a9f4c --- /dev/null +++ b/github/enterprise_team_test.go @@ -0,0 +1,236 @@ +// 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 ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/google/go-cmp/cmp" +) + +func TestEnterpriseService_ListTeams(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/teams", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `[{ + "id": 1, + "url": "https://example.com/team1", + "member_url": "https://example.com/members", + "name": "Team One", + "html_url": "https://example.com/html", + "slug": "team-one", + "created_at": "2020-01-01T00:00:00Z", + "updated_at": "2020-01-02T00:00:00Z", + "group_id": 99 + }]`) + }) + + ctx := t.Context() + opts := &ListOptions{Page: 1, PerPage: 10} + got, _, err := client.Enterprise.ListTeams(ctx, "e", opts) + if err != nil { + t.Fatalf("Enterprise.ListTeams returned error: %v", err) + } + + want := []*EnterpriseTeam{ + { + ID: 1, + URL: "https://example.com/team1", + MemberURL: "https://example.com/members", + Name: "Team One", + HTMLURL: "https://example.com/html", + Slug: "team-one", + GroupID: 99, + CreatedAt: Timestamp{Time: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)}, + UpdatedAt: Timestamp{Time: time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC)}, + }, + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.ListTeams = %+v, want %+v", got, want) + } + + const methodName = "ListTeams" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.ListTeams(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.ListTeams(ctx, "e", opts) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_CreateTeam(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := EnterpriseTeamCreateOrUpdateRequest{ + Name: "New Team", + } + + mux.HandleFunc("/enterprises/e/teams", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testBody(t, r, `{"name":"New Team"}`+"\n") + fmt.Fprint(w, `{ + "id": 10, + "name": "New Team", + "slug": "new-team", + "url": "https://example.com/team" + }`) + }) + + ctx := t.Context() + got, _, err := client.Enterprise.CreateTeam(ctx, "e", input) + if err != nil { + t.Fatalf("Enterprise.CreateTeam returned error: %v", err) + } + + want := &EnterpriseTeam{ + ID: 10, + Name: "New Team", + Slug: "new-team", + URL: "https://example.com/team", + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.CreateTeam = %+v, want %+v", got, want) + } + + const methodName = "CreateTeam" + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.CreateTeam(ctx, "e", input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_GetTeam(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/teams/t1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "id": 2, + "name": "Team One", + "slug": "t1" + }`) + }) + + ctx := t.Context() + got, _, err := client.Enterprise.GetTeam(ctx, "e", "t1") + if err != nil { + t.Fatalf("Enterprise.GetTeam returned error: %v", err) + } + + want := &EnterpriseTeam{ + ID: 2, + Name: "Team One", + Slug: "t1", + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.GetTeam = %+v, want %+v", got, want) + } + + const methodName = "GetTeam" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.GetTeam(ctx, "\n", "t1") + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.GetTeam(ctx, "e", "t1") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_UpdateTeam(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := EnterpriseTeamCreateOrUpdateRequest{ + Name: "Updated Team", + } + + mux.HandleFunc("/enterprises/e/teams/t1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + testBody(t, r, `{"name":"Updated Team"}`+"\n") + fmt.Fprint(w, `{ + "id": 3, + "name": "Updated Team", + "slug": "t1" + }`) + }) + + ctx := t.Context() + got, _, err := client.Enterprise.UpdateTeam(ctx, "e", "t1", input) + if err != nil { + t.Fatalf("Enterprise.UpdateTeam returned error: %v", err) + } + + want := &EnterpriseTeam{ + ID: 3, + Name: "Updated Team", + Slug: "t1", + } + + if !cmp.Equal(got, want) { + t.Errorf("Enterprise.UpdateTeam = %+v, want %+v", got, want) + } + + const methodName = "UpdateTeam" + testBadOptions(t, methodName, func() error { + _, _, err := client.Enterprise.UpdateTeam(ctx, "\n", "t1", input) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Enterprise.UpdateTeam(ctx, "e", "t1", input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestEnterpriseService_DeleteTeam(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/teams/t1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + _, err := client.Enterprise.DeleteTeam(ctx, "e", "t1") + if err != nil { + t.Fatalf("Enterprise.DeleteTeam returned error: %v", err) + } + + const methodName = "DeleteTeam" + testBadOptions(t, methodName, func() error { + _, err := client.Enterprise.DeleteTeam(ctx, "\n", "t1") + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Enterprise.DeleteTeam(ctx, "e", "t1") + }) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index 76af1d2d588..9af89f213cd 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -9446,6 +9446,38 @@ func (e *EnterpriseSecurityAnalysisSettings) GetSecretScanningValidityChecksEnab return *e.SecretScanningValidityChecksEnabled } +// GetOrganizationSelectionType returns the OrganizationSelectionType field if it's non-nil, zero value otherwise. +func (e *EnterpriseTeam) GetOrganizationSelectionType() string { + if e == nil || e.OrganizationSelectionType == nil { + return "" + } + return *e.OrganizationSelectionType +} + +// GetDescription returns the Description field if it's non-nil, zero value otherwise. +func (e *EnterpriseTeamCreateOrUpdateRequest) GetDescription() string { + if e == nil || e.Description == nil { + return "" + } + return *e.Description +} + +// GetGroupID returns the GroupID field if it's non-nil, zero value otherwise. +func (e *EnterpriseTeamCreateOrUpdateRequest) GetGroupID() int64 { + if e == nil || e.GroupID == nil { + return 0 + } + return *e.GroupID +} + +// GetOrganizationSelectionType returns the OrganizationSelectionType field if it's non-nil, zero value otherwise. +func (e *EnterpriseTeamCreateOrUpdateRequest) GetOrganizationSelectionType() string { + if e == nil || e.OrganizationSelectionType == nil { + return "" + } + return *e.OrganizationSelectionType +} + // GetCanAdminsBypass returns the CanAdminsBypass field if it's non-nil, zero value otherwise. func (e *Environment) GetCanAdminsBypass() bool { if e == nil || e.CanAdminsBypass == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 937aff97dc9..8d61ff9c5c3 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -12246,6 +12246,50 @@ func TestEnterpriseSecurityAnalysisSettings_GetSecretScanningValidityChecksEnabl e.GetSecretScanningValidityChecksEnabled() } +func TestEnterpriseTeam_GetOrganizationSelectionType(tt *testing.T) { + tt.Parallel() + var zeroValue string + e := &EnterpriseTeam{OrganizationSelectionType: &zeroValue} + e.GetOrganizationSelectionType() + e = &EnterpriseTeam{} + e.GetOrganizationSelectionType() + e = nil + e.GetOrganizationSelectionType() +} + +func TestEnterpriseTeamCreateOrUpdateRequest_GetDescription(tt *testing.T) { + tt.Parallel() + var zeroValue string + e := &EnterpriseTeamCreateOrUpdateRequest{Description: &zeroValue} + e.GetDescription() + e = &EnterpriseTeamCreateOrUpdateRequest{} + e.GetDescription() + e = nil + e.GetDescription() +} + +func TestEnterpriseTeamCreateOrUpdateRequest_GetGroupID(tt *testing.T) { + tt.Parallel() + var zeroValue int64 + e := &EnterpriseTeamCreateOrUpdateRequest{GroupID: &zeroValue} + e.GetGroupID() + e = &EnterpriseTeamCreateOrUpdateRequest{} + e.GetGroupID() + e = nil + e.GetGroupID() +} + +func TestEnterpriseTeamCreateOrUpdateRequest_GetOrganizationSelectionType(tt *testing.T) { + tt.Parallel() + var zeroValue string + e := &EnterpriseTeamCreateOrUpdateRequest{OrganizationSelectionType: &zeroValue} + e.GetOrganizationSelectionType() + e = &EnterpriseTeamCreateOrUpdateRequest{} + e.GetOrganizationSelectionType() + e = nil + e.GetOrganizationSelectionType() +} + func TestEnvironment_GetCanAdminsBypass(tt *testing.T) { tt.Parallel() var zeroValue bool