Repository: xanzy/go-gitlab
Pull request #1908 (2024-04-03 04:05:05)

Add new custom role permissions, allow GET to retrieve MemberRole
This PR adds support for several new custom role permissions. It also resolves an issue where you could previous add or update customer roles, but you would be unable to read them from the API after they were set.

- Update `GroupMember` to include `MemberRole`, allowing the GET APIs to retrieve the custom roles
- Add the following new Permissions
  - Admin CI/CD Variables
  - Admin Terraform States
  - Admin Group Members
  - Manage Group Access Tokens
  - Archive Projects
  - Remove Projects
  
- Fixed typos in the JSON tags for 2 permissions
  - Manage Project Access Tokens (wasn't plural, should have been)
  - Admin Merge Requests (was plural, shouldn't have been)

There is one additional permission in the example JSON I got from the API (`admin_push_rules`) that I didn't include, because it's not documented in the member roles documentation yet: https://docs.gitlab.com/ee/api/member_roles.html


Patch:
diff --git a/group_members.go b/group_members.go
index f0018ca..cc7bbd6 100644
--- a/group_members.go
+++ b/group_members.go
@@ -56,6 +56,7 @@ type GroupMember struct {
 	AccessLevel       AccessLevelValue         `json:"access_level"`
 	Email             string                   `json:"email,omitempty"`
 	GroupSAMLIdentity *GroupMemberSAMLIdentity `json:"group_saml_identity"`
+	MemberRole        *MemberRole              `json:"member_role"`
 }
 
 // ListGroupMembersOptions represents the available ListGroupMembers() and
diff --git a/member_roles.go b/member_roles.go
index e3f1285..cefb94b 100644
--- a/member_roles.go
+++ b/member_roles.go
@@ -22,12 +22,18 @@ type MemberRole struct {
 	Description              string           `json:"description,omitempty"`
 	GroupId                  int              `json:"group_id"`
 	BaseAccessLevel          AccessLevelValue `json:"base_access_level"`
-	AdminMergeRequests       bool             `json:"admin_merge_requests,omitempty"`
+	AdminCICDVariables       bool             `json:"admin_cicd_variables,omitempty"`
+	AdminMergeRequests       bool             `json:"admin_merge_request,omitempty"`
+	AdminTerraformState      bool             `json:"admin_terraform_state,omitempty"`
 	AdminVulnerability       bool             `json:"admin_vulnerability,omitempty"`
 	ReadCode                 bool             `json:"read_code,omitempty"`
 	ReadDependency           bool             `json:"read_dependency,omitempty"`
 	ReadVulnerability        bool             `json:"read_vulnerability,omitempty"`
-	ManageProjectAccessToken bool             `json:"manage_project_access_token,omitempty"`
+	AdminGroupMembers        bool             `json:"admin_group_member,omitempty"`
+	ManageProjectAccessToken bool             `json:"manage_project_access_tokens,omitempty"`
+	ArchiveProject           bool             `json:"archive_project,omitempty"`
+	RemoveProject            bool             `json:"remove_project,omitempty"`
+	ManageGroupAccesToken    bool             `json:"manage_group_access_tokens,omitempty"`
 }
 
 // ListMemberRoles gets a list of member roles for a specified group.


Test patch:
diff --git a/group_members_test.go b/group_members_test.go
index 43b9dae..6ee93ce 100644
--- a/group_members_test.go
+++ b/group_members_test.go
@@ -287,3 +287,62 @@ func TestListGroupMembersWithSAML(t *testing.T) {
 		t.Errorf("Groups.ListBillableGroupMembers returned %+v, want %+v", members[0], want[0])
 	}
 }
+
+func TestGetGroupMemberCustomRole(t *testing.T) {
+	mux, client := setup(t)
+
+	path := fmt.Sprintf("/%sgroups/1/members/2", apiVersionPath)
+	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+
+		// This is pulled straight from a `/group/<group_id>/members/<user_id>` call, then obfuscated.
+		fmt.Fprint(w, `
+		{
+			"id":1,
+			"username":"test",
+			"name":"testName",
+			"access_level":30,
+			"member_role":{
+				"id":1,
+				"group_id":2,
+				"name":"TestingCustomRole",
+				"description":"",
+				"base_access_level":30,
+				"admin_cicd_variables":true,
+				"admin_group_member":null,
+				"admin_merge_request":null,
+				"admin_push_rules":null,
+				"admin_terraform_state":null,
+				"admin_vulnerability":null,
+				"archive_project":null,
+				"manage_group_access_tokens":null,
+				"manage_project_access_tokens":null,
+				"read_code":null,
+				"read_dependency":null,
+				"read_vulnerability":null,
+				"remove_group":null,
+				"remove_project":null
+			}
+		}
+		`)
+	})
+
+	want := &GroupMember{
+		ID:          1,
+		Username:    "test",
+		Name:        "testName",
+		AccessLevel: AccessLevelValue(30),
+		MemberRole: &MemberRole{
+			ID:                 1,
+			GroupId:            2,
+			Name:               "TestingCustomRole",
+			Description:        "",
+			BaseAccessLevel:    AccessLevelValue(30),
+			AdminCICDVariables: true,
+		},
+	}
+	member, _, err := client.GroupMembers.GetGroupMember(1, 2)
+
+	assert.NoError(t, err)
+	assert.Equal(t, want, member)
+}