Repository: xanzy/go-gitlab
Pull request #1909 (2024-04-03 18:25:39)

Add support for EmailsEnabled to groups
This PR adds support for the `emails_enabled` attribute to the Group APIs. This allows us to support that attribute in the Terraform provider prior to its removal in GitLab 17.0


Patch:
diff --git a/groups.go b/groups.go
index 1040684..a62750b 100644
--- a/groups.go
+++ b/groups.go
@@ -64,7 +64,7 @@ type Group struct {
 	ProjectCreationLevel    ProjectCreationLevelValue  `json:"project_creation_level"`
 	AutoDevopsEnabled       bool                       `json:"auto_devops_enabled"`
 	SubGroupCreationLevel   SubGroupCreationLevelValue `json:"subgroup_creation_level"`
-	EmailsDisabled          bool                       `json:"emails_disabled"`
+	EmailsEnabled           bool                       `json:"emails_enabled"`
 	MentionsDisabled        bool                       `json:"mentions_disabled"`
 	RunnersToken            string                     `json:"runners_token"`
 	SharedProjects          []*Project                 `json:"shared_projects"`
@@ -87,6 +87,9 @@ type Group struct {
 	CreatedAt                      *time.Time         `json:"created_at"`
 	IPRestrictionRanges            string             `json:"ip_restriction_ranges"`
 	WikiAccessLevel                AccessControlValue `json:"wiki_access_level"`
+
+	// Deprecated: Use EmailsEnabled instead
+	EmailsDisabled bool `json:"emails_disabled"`
 }
 
 // GroupAvatar represents a GitLab group avatar.
@@ -347,7 +350,7 @@ type CreateGroupOptions struct {
 	ProjectCreationLevel           *ProjectCreationLevelValue  `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
 	AutoDevopsEnabled              *bool                       `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
 	SubGroupCreationLevel          *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
-	EmailsDisabled                 *bool                       `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
+	EmailsEnabled                  *bool                       `url:"emails_enabled,omitempty" json:"emails_enabled,omitempty"`
 	MentionsDisabled               *bool                       `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
 	LFSEnabled                     *bool                       `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
 	DefaultBranchProtection        *int                        `url:"default_branch_protection,omitempty" json:"default_branch_protection"`
@@ -357,6 +360,9 @@ type CreateGroupOptions struct {
 	ExtraSharedRunnersMinutesLimit *int                        `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"`
 	IPRestrictionRanges            *string                     `url:"ip_restriction_ranges,omitempty" json:"ip_restriction_ranges,omitempty"`
 	WikiAccessLevel                *AccessControlValue         `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"`
+
+	// Deprecated: Use EmailsEnabled instead
+	EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
 }
 
 // CreateGroup creates a new project group. Available only for users who can
@@ -473,7 +479,7 @@ type UpdateGroupOptions struct {
 	ProjectCreationLevel                 *ProjectCreationLevelValue  `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
 	AutoDevopsEnabled                    *bool                       `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
 	SubGroupCreationLevel                *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
-	EmailsDisabled                       *bool                       `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
+	EmailsEnabled                        *bool                       `url:"emails_enabled,omitempty" json:"emails_enabled,omitempty"`
 	MentionsDisabled                     *bool                       `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
 	LFSEnabled                           *bool                       `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
 	RequestAccessEnabled                 *bool                       `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
@@ -486,6 +492,9 @@ type UpdateGroupOptions struct {
 	PreventSharingGroupsOutsideHierarchy *bool                       `url:"prevent_sharing_groups_outside_hierarchy,omitempty" json:"prevent_sharing_groups_outside_hierarchy,omitempty"`
 	IPRestrictionRanges                  *string                     `url:"ip_restriction_ranges,omitempty" json:"ip_restriction_ranges,omitempty"`
 	WikiAccessLevel                      *AccessControlValue         `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"`
+
+	// Deprecated: Use EmailsEnabled instead
+	EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
 }
 
 // UpdateGroup updates an existing group; only available to group owners and


Test patch:
diff --git a/groups_test.go b/groups_test.go
index d848e74..dc0ae8e 100644
--- a/groups_test.go
+++ b/groups_test.go
@@ -1,7 +1,9 @@
 package gitlab
 
 import (
+	"encoding/json"
 	"fmt"
+	"io"
 	"net/http"
 	"net/url"
 	"reflect"
@@ -593,3 +595,115 @@ func TestUpdateGroupWithIPRestrictionRanges(t *testing.T) {
 		t.Errorf("Groups.UpdatedGroup returned %+v, want %+v", group, want)
 	}
 }
+
+func TestGetGroupWithEmailsEnabled(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/groups/1",
+		func(w http.ResponseWriter, r *http.Request) {
+			testMethod(t, r, http.MethodGet)
+
+			// Modified from https://docs.gitlab.com/ee/api/groups.html#details-of-a-group
+			fmt.Fprint(w, `
+			{
+				"id": 1,
+				"name": "test",
+				"path": "test",
+				"emails_enabled": true,
+				"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
+				"visibility": "public",
+				"avatar_url": null,
+				"web_url": "https://gitlab.example.com/groups/test",
+				"request_access_enabled": false,
+				"repository_storage": "default",
+				"full_name": "test",
+				"full_path": "test",
+				"runners_token": "ba324ca7b1c77fc20bb9",
+				"file_template_project_id": 1,
+				"parent_id": null,
+				"enabled_git_access_protocol": "all",
+				"created_at": "2020-01-15T12:36:29.590Z",
+				"prevent_sharing_groups_outside_hierarchy": false,
+				"ip_restriction_ranges": null,
+				"math_rendering_limits_enabled": true,
+				"lock_math_rendering_limits_enabled": false
+			  }`)
+		})
+
+	group, _, err := client.Groups.GetGroup(1, &GetGroupOptions{})
+	if err != nil {
+		t.Errorf("Groups.UpdateGroup returned error: %v", err)
+	}
+
+	if !group.EmailsEnabled {
+		t.Fatalf("Failed to parse `emails_enabled`. Wanted true, got %v", group.EmailsEnabled)
+	}
+}
+
+func TestCreateGroupWithEmailsEnabled(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/groups",
+		func(w http.ResponseWriter, r *http.Request) {
+			testMethod(t, r, http.MethodPost)
+
+			body, err := io.ReadAll(r.Body)
+			if err != nil {
+				t.Fatalf("Failed to read the request body. Error: %v", err)
+			}
+
+			// unmarshal into generic JSON since we don't want to test CreateGroupOptions using itself to validate.
+			var bodyJson map[string]interface{}
+			err = json.Unmarshal(body, &bodyJson)
+			if err != nil {
+				t.Fatalf("Failed to parse the request body into JSON. Error: %v", err)
+			}
+
+			if bodyJson["emails_enabled"] != true {
+				t.Fatalf("Test failed. `emails_enabled` expected to be true, got %v", bodyJson["emails_enabled"])
+			}
+
+			// Response is tested via the "GET" test, only test the actual request here.
+			fmt.Fprint(w, `
+			{}`)
+		})
+
+	_, _, err := client.Groups.CreateGroup(&CreateGroupOptions{EmailsEnabled: Ptr(true)})
+	if err != nil {
+		t.Errorf("Groups.CreateGroup returned error: %v", err)
+	}
+}
+
+func TestUpdateGroupWithEmailsEnabled(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/groups/1",
+		func(w http.ResponseWriter, r *http.Request) {
+			testMethod(t, r, http.MethodPut)
+
+			body, err := io.ReadAll(r.Body)
+			if err != nil {
+				t.Fatalf("Failed to read the request body. Error: %v", err)
+			}
+
+			// unmarshal into generic JSON since we don't want to test UpdateGroupOptions using itself to validate.
+			var bodyJson map[string]interface{}
+			err = json.Unmarshal(body, &bodyJson)
+			if err != nil {
+				t.Fatalf("Failed to parse the request body into JSON. Error: %v", err)
+			}
+
+			if bodyJson["emails_enabled"] != true {
+				t.Fatalf("Test failed. `emails_enabled` expected to be true, got %v", bodyJson["emails_enabled"])
+			}
+
+			// Response is tested via the "GET" test, only test the actual request here.
+			fmt.Fprint(w, `
+			{}`)
+		})
+
+	_, _, err := client.Groups.UpdateGroup(1, &UpdateGroupOptions{EmailsEnabled: Ptr(true)})
+	if err != nil {
+		t.Errorf("Groups.UpdateGroup returned error: %v", err)
+	}
+}