From 1d8e6c1c4fc5e7f954eb36f1a555aedf3981c4e4 Mon Sep 17 00:00:00 2001 From: zubeen Date: Tue, 11 Nov 2025 00:25:26 +0530 Subject: [PATCH 1/2] feat (project_members): Add show_seat_info option to ProjectMembers --- group_members.go | 6 ++-- group_members_test.go | 67 +++++++++++++++++++++++++++++++++++++++++ project_members.go | 6 ++-- project_members_test.go | 63 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) diff --git a/group_members.go b/group_members.go index 14f835e9..656aa798 100644 --- a/group_members.go +++ b/group_members.go @@ -62,6 +62,7 @@ type GroupMember struct { PublicEmail string `json:"public_email,omitempty"` GroupSAMLIdentity *GroupMemberSAMLIdentity `json:"group_saml_identity"` MemberRole *MemberRole `json:"member_role"` + IsUsingSeat bool `json:"is_using_seat,omitempty"` } // GroupMemberSAMLIdentity represents the SAML Identity link for the group member. @@ -115,8 +116,9 @@ type BillableUserMembership struct { // https://docs.gitlab.com/api/members/#list-all-members-of-a-group-or-project type ListGroupMembersOptions struct { ListOptions - Query *string `url:"query,omitempty" json:"query,omitempty"` - UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` + Query *string `url:"query,omitempty" json:"query,omitempty"` + UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` + ShowSeatInfo bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` } // ListGroupMembers get a list of group members viewable by the authenticated diff --git a/group_members_test.go b/group_members_test.go index cd6f36d4..d7ed37e8 100644 --- a/group_members_test.go +++ b/group_members_test.go @@ -524,3 +524,70 @@ func TestGetGroupMemberAll(t *testing.T) { require.Nil(t, member) require.Equal(t, http.StatusNotFound, resp.StatusCode) } + +func TestListGroupMembersWithSeatInfo(t *testing.T) { + t.Parallel() + mux, client := setup(t) + + mux.HandleFunc("/api/v4/groups/1/members", + func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + // Verify that the show_seat_info parameter is passed correctly + assert.Equal(t, "true", r.URL.Query().Get("show_seat_info")) + fmt.Fprint(w, + `[ + { + "id": 1, + "username": "raymond_smith", + "name": "Raymond Smith", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + "web_url": "http://192.168.1.8:3000/root", + "created_at": "2012-10-21T14:13:35Z", + "created_by": { + "id": 2, + "username": "john_doe", + "name": "John Doe", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + "web_url": "http://192.168.1.8:3000/root" + }, + "expires_at": "2012-10-22", + "access_level": 30, + "is_using_seat": true, + "group_saml_identity": null + } + ]`) + }) + + members, _, err := client.Groups.ListGroupMembers(1, &ListGroupMembersOptions{ + ShowSeatInfo: true, + }) + require.NoError(t, err) + + expiresAt := mustParseTime("2012-10-22T00:00:00Z") + expiresAtISOTime := ISOTime(*expiresAt) + want := []*GroupMember{ + { + ID: 1, + Username: "raymond_smith", + Name: "Raymond Smith", + State: "active", + AvatarURL: "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + WebURL: "http://192.168.1.8:3000/root", + CreatedAt: mustParseTime("2012-10-21T14:13:35Z"), + CreatedBy: &MemberCreatedBy{ + ID: 2, + Username: "john_doe", + Name: "John Doe", + State: "active", + AvatarURL: "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + WebURL: "http://192.168.1.8:3000/root", + }, + ExpiresAt: &expiresAtISOTime, + AccessLevel: 30, + IsUsingSeat: true, + }, + } + assert.Equal(t, want, members) +} diff --git a/project_members.go b/project_members.go index e12a2fa6..6991a04d 100644 --- a/project_members.go +++ b/project_members.go @@ -61,6 +61,7 @@ type ProjectMember struct { WebURL string `json:"web_url"` AvatarURL string `json:"avatar_url"` MemberRole *MemberRole `json:"member_role"` + IsUsingSeat bool `json:"is_using_seat,omitempty"` } type MemberCreatedBy struct { @@ -79,8 +80,9 @@ type MemberCreatedBy struct { // https://docs.gitlab.com/api/members/#list-all-members-of-a-group-or-project type ListProjectMembersOptions struct { ListOptions - Query *string `url:"query,omitempty" json:"query,omitempty"` - UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` + Query *string `url:"query,omitempty" json:"query,omitempty"` + UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` + ShowSeatInfo bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` } // ListProjectMembers gets a list of a project's team members viewable by the diff --git a/project_members_test.go b/project_members_test.go index 62d9593c..0f001ab2 100644 --- a/project_members_test.go +++ b/project_members_test.go @@ -560,3 +560,66 @@ func TestProjectMembersService_CustomRole(t *testing.T) { assert.NoError(t, err) assert.Equal(t, want, member) } + +func TestProjectMembersService_ListProjectMembersWithSeatInfo(t *testing.T) { + t.Parallel() + mux, client := setup(t) + + mux.HandleFunc("/api/v4/projects/1/members", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + // Verify that the show_seat_info parameter is passed correctly + assert.Equal(t, "true", r.URL.Query().Get("show_seat_info")) + fmt.Fprintf(w, ` + [ + { + "id": 1, + "username": "venkatesh_thalluri", + "name": "Venkatesh Thalluri", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + "web_url": "http://192.168.1.8:3000/root", + "created_at": "2012-10-22T14:13:35Z", + "created_by": { + "id": 2, + "username": "john_doe", + "name": "John Doe", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + "web_url": "http://192.168.1.8:3000/root" + }, + "access_level": 30, + "is_using_seat": true, + "group_saml_identity": null + } + ] + `) + }) + + want := []*ProjectMember{{ + ID: 1, + Username: "venkatesh_thalluri", + Email: "", + Name: "Venkatesh Thalluri", + State: "active", + AccessLevel: 30, + WebURL: "http://192.168.1.8:3000/root", + AvatarURL: "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + CreatedAt: mustParseTime("2012-10-22T14:13:35Z"), + CreatedBy: &MemberCreatedBy{ + ID: 2, + Username: "john_doe", + Name: "John Doe", + State: "active", + AvatarURL: "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon", + WebURL: "http://192.168.1.8:3000/root", + }, + IsUsingSeat: true, + }} + + pms, resp, err := client.ProjectMembers.ListProjectMembers(1, &ListProjectMembersOptions{ + ShowSeatInfo: true, + }, nil) + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, want, pms) +} -- GitLab From f789ec5bb0d8ddf735ae6eaf1bde13d301dd83d3 Mon Sep 17 00:00:00 2001 From: zubeen Date: Tue, 11 Nov 2025 01:47:38 +0530 Subject: [PATCH 2/2] resolve review commentss --- group_members.go | 2 +- group_members_test.go | 2 +- project_members.go | 2 +- project_members_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/group_members.go b/group_members.go index 656aa798..afdab93d 100644 --- a/group_members.go +++ b/group_members.go @@ -118,7 +118,7 @@ type ListGroupMembersOptions struct { ListOptions Query *string `url:"query,omitempty" json:"query,omitempty"` UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` - ShowSeatInfo bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` + ShowSeatInfo *bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` } // ListGroupMembers get a list of group members viewable by the authenticated diff --git a/group_members_test.go b/group_members_test.go index d7ed37e8..a4031b20 100644 --- a/group_members_test.go +++ b/group_members_test.go @@ -561,7 +561,7 @@ func TestListGroupMembersWithSeatInfo(t *testing.T) { }) members, _, err := client.Groups.ListGroupMembers(1, &ListGroupMembersOptions{ - ShowSeatInfo: true, + ShowSeatInfo: Ptr(true), }) require.NoError(t, err) diff --git a/project_members.go b/project_members.go index 6991a04d..22257a41 100644 --- a/project_members.go +++ b/project_members.go @@ -82,7 +82,7 @@ type ListProjectMembersOptions struct { ListOptions Query *string `url:"query,omitempty" json:"query,omitempty"` UserIDs *[]int `url:"user_ids[],omitempty" json:"user_ids,omitempty"` - ShowSeatInfo bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` + ShowSeatInfo *bool `url:"show_seat_info,omitempty" json:"show_seat_info,omitempty"` } // ListProjectMembers gets a list of a project's team members viewable by the diff --git a/project_members_test.go b/project_members_test.go index 0f001ab2..b19910f3 100644 --- a/project_members_test.go +++ b/project_members_test.go @@ -617,7 +617,7 @@ func TestProjectMembersService_ListProjectMembersWithSeatInfo(t *testing.T) { }} pms, resp, err := client.ProjectMembers.ListProjectMembers(1, &ListProjectMembersOptions{ - ShowSeatInfo: true, + ShowSeatInfo: Ptr(true), }, nil) require.NoError(t, err) require.NotNil(t, resp) -- GitLab