diff --git a/groups.go b/groups.go index 1040684f0..641c97f15 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 diff --git a/groups_test.go b/groups_test.go index d848e7424..dc0ae8ed1 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) + } +}