diff --git a/github/github-accessors.go b/github/github-accessors.go index 7bd870167e6..00051f8ce21 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -4372,6 +4372,78 @@ func (e *Event) GetType() string { return *e.Type } +// GetGroupID returns the GroupID field if it's non-nil, zero value otherwise. +func (e *ExternalGroup) GetGroupID() int64 { + if e == nil || e.GroupID == nil { + return 0 + } + return *e.GroupID +} + +// GetGroupName returns the GroupName field if it's non-nil, zero value otherwise. +func (e *ExternalGroup) GetGroupName() string { + if e == nil || e.GroupName == nil { + return "" + } + return *e.GroupName +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (e *ExternalGroup) GetUpdatedAt() Timestamp { + if e == nil || e.UpdatedAt == nil { + return Timestamp{} + } + return *e.UpdatedAt +} + +// GetMemberEmail returns the MemberEmail field if it's non-nil, zero value otherwise. +func (e *ExternalGroupMember) GetMemberEmail() string { + if e == nil || e.MemberEmail == nil { + return "" + } + return *e.MemberEmail +} + +// GetMemberID returns the MemberID field if it's non-nil, zero value otherwise. +func (e *ExternalGroupMember) GetMemberID() int64 { + if e == nil || e.MemberID == nil { + return 0 + } + return *e.MemberID +} + +// GetMemberLogin returns the MemberLogin field if it's non-nil, zero value otherwise. +func (e *ExternalGroupMember) GetMemberLogin() string { + if e == nil || e.MemberLogin == nil { + return "" + } + return *e.MemberLogin +} + +// GetMemberName returns the MemberName field if it's non-nil, zero value otherwise. +func (e *ExternalGroupMember) GetMemberName() string { + if e == nil || e.MemberName == nil { + return "" + } + return *e.MemberName +} + +// GetTeamID returns the TeamID field if it's non-nil, zero value otherwise. +func (e *ExternalGroupTeam) GetTeamID() int64 { + if e == nil || e.TeamID == nil { + return 0 + } + return *e.TeamID +} + +// GetTeamName returns the TeamName field if it's non-nil, zero value otherwise. +func (e *ExternalGroupTeam) GetTeamName() string { + if e == nil || e.TeamName == nil { + return "" + } + return *e.TeamName +} + // GetHRef returns the HRef field if it's non-nil, zero value otherwise. func (f *FeedLink) GetHRef() string { if f == nil || f.HRef == nil { @@ -7532,6 +7604,14 @@ func (l *ListCollaboratorOptions) GetAffiliation() string { return *l.Affiliation } +// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. +func (l *ListExternalGroupsOptions) GetDisplayName() string { + if l == nil || l.DisplayName == nil { + return "" + } + return *l.DisplayName +} + // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. func (l *ListRepositories) GetTotalCount() int { if l == nil || l.TotalCount == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index bbdff0ad3f5..710e64889c7 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -5121,6 +5121,96 @@ func TestEvent_GetType(tt *testing.T) { e.GetType() } +func TestExternalGroup_GetGroupID(tt *testing.T) { + var zeroValue int64 + e := &ExternalGroup{GroupID: &zeroValue} + e.GetGroupID() + e = &ExternalGroup{} + e.GetGroupID() + e = nil + e.GetGroupID() +} + +func TestExternalGroup_GetGroupName(tt *testing.T) { + var zeroValue string + e := &ExternalGroup{GroupName: &zeroValue} + e.GetGroupName() + e = &ExternalGroup{} + e.GetGroupName() + e = nil + e.GetGroupName() +} + +func TestExternalGroup_GetUpdatedAt(tt *testing.T) { + var zeroValue Timestamp + e := &ExternalGroup{UpdatedAt: &zeroValue} + e.GetUpdatedAt() + e = &ExternalGroup{} + e.GetUpdatedAt() + e = nil + e.GetUpdatedAt() +} + +func TestExternalGroupMember_GetMemberEmail(tt *testing.T) { + var zeroValue string + e := &ExternalGroupMember{MemberEmail: &zeroValue} + e.GetMemberEmail() + e = &ExternalGroupMember{} + e.GetMemberEmail() + e = nil + e.GetMemberEmail() +} + +func TestExternalGroupMember_GetMemberID(tt *testing.T) { + var zeroValue int64 + e := &ExternalGroupMember{MemberID: &zeroValue} + e.GetMemberID() + e = &ExternalGroupMember{} + e.GetMemberID() + e = nil + e.GetMemberID() +} + +func TestExternalGroupMember_GetMemberLogin(tt *testing.T) { + var zeroValue string + e := &ExternalGroupMember{MemberLogin: &zeroValue} + e.GetMemberLogin() + e = &ExternalGroupMember{} + e.GetMemberLogin() + e = nil + e.GetMemberLogin() +} + +func TestExternalGroupMember_GetMemberName(tt *testing.T) { + var zeroValue string + e := &ExternalGroupMember{MemberName: &zeroValue} + e.GetMemberName() + e = &ExternalGroupMember{} + e.GetMemberName() + e = nil + e.GetMemberName() +} + +func TestExternalGroupTeam_GetTeamID(tt *testing.T) { + var zeroValue int64 + e := &ExternalGroupTeam{TeamID: &zeroValue} + e.GetTeamID() + e = &ExternalGroupTeam{} + e.GetTeamID() + e = nil + e.GetTeamID() +} + +func TestExternalGroupTeam_GetTeamName(tt *testing.T) { + var zeroValue string + e := &ExternalGroupTeam{TeamName: &zeroValue} + e.GetTeamName() + e = &ExternalGroupTeam{} + e.GetTeamName() + e = nil + e.GetTeamName() +} + func TestFeedLink_GetHRef(tt *testing.T) { var zeroValue string f := &FeedLink{HRef: &zeroValue} @@ -8840,6 +8930,16 @@ func TestListCollaboratorOptions_GetAffiliation(tt *testing.T) { l.GetAffiliation() } +func TestListExternalGroupsOptions_GetDisplayName(tt *testing.T) { + var zeroValue string + l := &ListExternalGroupsOptions{DisplayName: &zeroValue} + l.GetDisplayName() + l = &ListExternalGroupsOptions{} + l.GetDisplayName() + l = nil + l.GetDisplayName() +} + func TestListRepositories_GetTotalCount(tt *testing.T) { var zeroValue int l := &ListRepositories{TotalCount: &zeroValue} diff --git a/github/teams.go b/github/teams.go index 7a8a5d8a7b7..71cbbab6a9a 100644 --- a/github/teams.go +++ b/github/teams.go @@ -854,3 +854,116 @@ func (s *TeamsService) CreateOrUpdateIDPGroupConnectionsBySlug(ctx context.Conte return groups, resp, nil } + +// ExternalGroupMember represents a member of an external group. +type ExternalGroupMember struct { + MemberID *int64 `json:"member_id,omitempty"` + MemberLogin *string `json:"member_login,omitempty"` + MemberName *string `json:"member_name,omitempty"` + MemberEmail *string `json:"member_email,omitempty"` +} + +// ExternalGroupTeam represents a team connected to an external group. +type ExternalGroupTeam struct { + TeamID *int64 `json:"team_id,omitempty"` + TeamName *string `json:"team_name,omitempty"` +} + +// ExternalGroup represents an external group. +type ExternalGroup struct { + GroupID *int64 `json:"group_id,omitempty"` + GroupName *string `json:"group_name,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` + Teams []*ExternalGroupTeam `json:"teams,omitempty"` + Members []*ExternalGroupMember `json:"members,omitempty"` +} + +// ExternalGroupList represents a list of external groups. +type ExternalGroupList struct { + Groups []*ExternalGroup `json:"groups"` +} + +// GetExternalGroup fetches an external group. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#get-an-external-group +func (s *TeamsService) GetExternalGroup(ctx context.Context, org string, groupID int64) (*ExternalGroup, *Response, error) { + u := fmt.Sprintf("orgs/%v/external-group/%v", org, groupID) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + externalGroup := new(ExternalGroup) + resp, err := s.client.Do(ctx, req, externalGroup) + if err != nil { + return nil, resp, err + } + + return externalGroup, resp, nil +} + +// ListExternalGroupsOptions specifies the optional parameters to the +// TeamsService.ListExternalGroups method. +type ListExternalGroupsOptions struct { + DisplayName *string `url:"display_name,omitempty"` + + ListOptions +} + +// ListExternalGroups lists external groups connected to a team on GitHub. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#list-external-groups-in-an-organization +func (s *TeamsService) ListExternalGroups(ctx context.Context, org string, opts *ListExternalGroupsOptions) (*ExternalGroupList, *Response, error) { + u := fmt.Sprintf("orgs/%v/external-groups", org) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + externalGroups := new(ExternalGroupList) + resp, err := s.client.Do(ctx, req, externalGroups) + if err != nil { + return nil, resp, err + } + + return externalGroups, resp, nil +} + +// UpdateConnectedExternalGroup updates the connection between an external group and a team. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#update-the-connection-between-an-external-group-and-a-team +func (s *TeamsService) UpdateConnectedExternalGroup(ctx context.Context, org, slug string, eg *ExternalGroup) (*ExternalGroup, *Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug) + + req, err := s.client.NewRequest("PATCH", u, eg) + if err != nil { + return nil, nil, err + } + + externalGroup := new(ExternalGroup) + resp, err := s.client.Do(ctx, req, externalGroup) + if err != nil { + return nil, resp, err + } + + return externalGroup, resp, nil +} + +// RemoveConnectedExternalGroup removes the connection between an external group and a team. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/reference/teams#remove-the-connection-between-an-external-group-and-a-team +func (s *TeamsService) RemoveConnectedExternalGroup(ctx context.Context, org, slug string) (*Response, error) { + u := fmt.Sprintf("orgs/%v/teams/%v/external-groups", org, slug) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(ctx, req, nil) +} diff --git a/github/teams_test.go b/github/teams_test.go index 26cf2c030fb..83f559beff8 100644 --- a/github/teams_test.go +++ b/github/teams_test.go @@ -1745,3 +1745,356 @@ func TestIDPGroup_Marshal(t *testing.T) { testJSONMarshal(t, u, want) } + +func TestTeamsService_GetExternalGroup(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/external-group/123", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "group_id": 123, + "group_name": "Octocat admins", + "updated_at": "2006-01-02T15:04:05Z", + "teams": [ + { + "team_id": 1, + "team_name": "team-test" + }, + { + "team_id": 2, + "team_name": "team-test2" + } + ], + "members": [ + { + "member_id": 1, + "member_login": "mona-lisa_eocsaxrs", + "member_name": "Mona Lisa", + "member_email": "mona_lisa@github.com" + }, + { + "member_id": 2, + "member_login": "octo-lisa_eocsaxrs", + "member_name": "Octo Lisa", + "member_email": "octo_lisa@github.com" + } + ] + }`) + }) + + ctx := context.Background() + externalGroup, _, err := client.Teams.GetExternalGroup(ctx, "o", 123) + if err != nil { + t.Errorf("Teams.GetExternalGroup returned error: %v", err) + } + + want := &ExternalGroup{ + GroupID: Int64(123), + GroupName: String("Octocat admins"), + UpdatedAt: &Timestamp{Time: referenceTime}, + Teams: []*ExternalGroupTeam{ + { + TeamID: Int64(1), + TeamName: String("team-test"), + }, + { + TeamID: Int64(2), + TeamName: String("team-test2"), + }, + }, + Members: []*ExternalGroupMember{ + { + MemberID: Int64(1), + MemberLogin: String("mona-lisa_eocsaxrs"), + MemberName: String("Mona Lisa"), + MemberEmail: String("mona_lisa@github.com"), + }, + { + MemberID: Int64(2), + MemberLogin: String("octo-lisa_eocsaxrs"), + MemberName: String("Octo Lisa"), + MemberEmail: String("octo_lisa@github.com"), + }, + }, + } + if !cmp.Equal(externalGroup, want) { + t.Errorf("Teams.GetExternalGroup returned %+v, want %+v", externalGroup, want) + } + + const methodName = "GetExternalGroup" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Teams.GetExternalGroup(ctx, "\n", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Teams.GetExternalGroup(ctx, "o", 123) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestTeamsService_GetExternalGroup_notFound(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/external-group/123", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + ctx := context.Background() + eg, resp, err := client.Teams.GetExternalGroup(ctx, "o", 123) + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.GetExternalGroup returned status %d, want %d", got, want) + } + if eg != nil { + t.Errorf("Teams.GetExternalGroup returned %+v, want nil", eg) + } +} + +func TestTeamsService_ListExternalGroups(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "groups": [ + { + "group_id": 123, + "group_name": "Octocat admins", + "updated_at": "2006-01-02T15:04:05Z" + } + ] + }`) + }) + + ctx := context.Background() + opts := &ListExternalGroupsOptions{ + DisplayName: String("Octocat"), + } + list, _, err := client.Teams.ListExternalGroups(ctx, "o", opts) + if err != nil { + t.Errorf("Teams.ListExternalGroups returned error: %v", err) + } + + want := &ExternalGroupList{ + Groups: []*ExternalGroup{ + { + GroupID: Int64(123), + GroupName: String("Octocat admins"), + UpdatedAt: &Timestamp{Time: referenceTime}, + }, + }, + } + if !cmp.Equal(list, want) { + t.Errorf("Teams.ListExternalGroups returned %+v, want %+v", list, want) + } + + const methodName = "ListExternalGroups" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Teams.ListExternalGroups(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Teams.ListExternalGroups(ctx, "o", opts) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestTeamsService_ListExternalGroups_notFound(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + ctx := context.Background() + eg, resp, err := client.Teams.ListExternalGroups(ctx, "o", nil) + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.ListExternalGroups returned status %d, want %d", got, want) + } + if eg != nil { + t.Errorf("Teams.ListExternalGroups returned %+v, want nil", eg) + } +} + +func TestTeamsService_UpdateConnectedExternalGroup(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + fmt.Fprint(w, `{ + "group_id": 123, + "group_name": "Octocat admins", + "updated_at": "2006-01-02T15:04:05Z", + "teams": [ + { + "team_id": 1, + "team_name": "team-test" + }, + { + "team_id": 2, + "team_name": "team-test2" + } + ], + "members": [ + { + "member_id": 1, + "member_login": "mona-lisa_eocsaxrs", + "member_name": "Mona Lisa", + "member_email": "mona_lisa@github.com" + }, + { + "member_id": 2, + "member_login": "octo-lisa_eocsaxrs", + "member_name": "Octo Lisa", + "member_email": "octo_lisa@github.com" + } + ] + }`) + }) + + ctx := context.Background() + body := &ExternalGroup{ + GroupID: Int64(123), + } + externalGroup, _, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body) + if err != nil { + t.Errorf("Teams.UpdateConnectedExternalGroup returned error: %v", err) + } + + want := &ExternalGroup{ + GroupID: Int64(123), + GroupName: String("Octocat admins"), + UpdatedAt: &Timestamp{Time: referenceTime}, + Teams: []*ExternalGroupTeam{ + { + TeamID: Int64(1), + TeamName: String("team-test"), + }, + { + TeamID: Int64(2), + TeamName: String("team-test2"), + }, + }, + Members: []*ExternalGroupMember{ + { + MemberID: Int64(1), + MemberLogin: String("mona-lisa_eocsaxrs"), + MemberName: String("Mona Lisa"), + MemberEmail: String("mona_lisa@github.com"), + }, + { + MemberID: Int64(2), + MemberLogin: String("octo-lisa_eocsaxrs"), + MemberName: String("Octo Lisa"), + MemberEmail: String("octo_lisa@github.com"), + }, + }, + } + if !cmp.Equal(externalGroup, want) { + t.Errorf("Teams.GetExternalGroup returned %+v, want %+v", externalGroup, want) + } + + const methodName = "UpdateConnectedExternalGroup" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Teams.UpdateConnectedExternalGroup(ctx, "\n", "\n", body) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestTeamsService_UpdateConnectedExternalGroup_notFound(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PATCH") + w.WriteHeader(http.StatusNotFound) + }) + + ctx := context.Background() + body := &ExternalGroup{ + GroupID: Int64(123), + } + eg, resp, err := client.Teams.UpdateConnectedExternalGroup(ctx, "o", "t", body) + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.UpdateConnectedExternalGroup returned status %d, want %d", got, want) + } + if eg != nil { + t.Errorf("Teams.UpdateConnectedExternalGroup returned %+v, want nil", eg) + } +} + +func TestTeamsService_RemoveConnectedExternalGroup(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := context.Background() + _, err := client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t") + if err != nil { + t.Errorf("Teams.RemoveConnectedExternalGroup returned error: %v", err) + } + + const methodName = "RemoveConnectedExternalGroup" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Teams.RemoveConnectedExternalGroup(ctx, "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t") + }) +} + +func TestTeamsService_RemoveConnectedExternalGroup_notFound(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/orgs/o/teams/t/external-groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNotFound) + }) + + ctx := context.Background() + resp, err := client.Teams.RemoveConnectedExternalGroup(ctx, "o", "t") + if err == nil { + t.Errorf("Expected HTTP 404 response") + } + if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want { + t.Errorf("Teams.GetExternalGroup returned status %d, want %d", got, want) + } +}