...

Source file src/github.com/xanzy/go-gitlab/groups.go

Documentation: github.com/xanzy/go-gitlab

     1  //
     2  // Copyright 2021, Sander van Harmelen
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package gitlab
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  	"time"
    26  
    27  	retryablehttp "github.com/hashicorp/go-retryablehttp"
    28  )
    29  
    30  // GroupsService handles communication with the group related methods of
    31  // the GitLab API.
    32  //
    33  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html
    34  type GroupsService struct {
    35  	client *Client
    36  }
    37  
    38  // Group represents a GitLab group.
    39  //
    40  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html
    41  type Group struct {
    42  	ID                      int                        `json:"id"`
    43  	Name                    string                     `json:"name"`
    44  	Path                    string                     `json:"path"`
    45  	Description             string                     `json:"description"`
    46  	MembershipLock          bool                       `json:"membership_lock"`
    47  	Visibility              VisibilityValue            `json:"visibility"`
    48  	LFSEnabled              bool                       `json:"lfs_enabled"`
    49  	DefaultBranchProtection int                        `json:"default_branch_protection"`
    50  	AvatarURL               string                     `json:"avatar_url"`
    51  	WebURL                  string                     `json:"web_url"`
    52  	RequestAccessEnabled    bool                       `json:"request_access_enabled"`
    53  	RepositoryStorage       string                     `json:"repository_storage"`
    54  	FullName                string                     `json:"full_name"`
    55  	FullPath                string                     `json:"full_path"`
    56  	FileTemplateProjectID   int                        `json:"file_template_project_id"`
    57  	ParentID                int                        `json:"parent_id"`
    58  	Projects                []*Project                 `json:"projects"`
    59  	Statistics              *Statistics                `json:"statistics"`
    60  	CustomAttributes        []*CustomAttribute         `json:"custom_attributes"`
    61  	ShareWithGroupLock      bool                       `json:"share_with_group_lock"`
    62  	RequireTwoFactorAuth    bool                       `json:"require_two_factor_authentication"`
    63  	TwoFactorGracePeriod    int                        `json:"two_factor_grace_period"`
    64  	ProjectCreationLevel    ProjectCreationLevelValue  `json:"project_creation_level"`
    65  	AutoDevopsEnabled       bool                       `json:"auto_devops_enabled"`
    66  	SubGroupCreationLevel   SubGroupCreationLevelValue `json:"subgroup_creation_level"`
    67  	EmailsEnabled           bool                       `json:"emails_enabled"`
    68  	MentionsDisabled        bool                       `json:"mentions_disabled"`
    69  	RunnersToken            string                     `json:"runners_token"`
    70  	SharedProjects          []*Project                 `json:"shared_projects"`
    71  	SharedRunnersSetting    SharedRunnersSettingValue  `json:"shared_runners_setting"`
    72  	SharedWithGroups        []struct {
    73  		GroupID          int      `json:"group_id"`
    74  		GroupName        string   `json:"group_name"`
    75  		GroupFullPath    string   `json:"group_full_path"`
    76  		GroupAccessLevel int      `json:"group_access_level"`
    77  		ExpiresAt        *ISOTime `json:"expires_at"`
    78  	} `json:"shared_with_groups"`
    79  	LDAPCN                         string             `json:"ldap_cn"`
    80  	LDAPAccess                     AccessLevelValue   `json:"ldap_access"`
    81  	LDAPGroupLinks                 []*LDAPGroupLink   `json:"ldap_group_links"`
    82  	SAMLGroupLinks                 []*SAMLGroupLink   `json:"saml_group_links"`
    83  	SharedRunnersMinutesLimit      int                `json:"shared_runners_minutes_limit"`
    84  	ExtraSharedRunnersMinutesLimit int                `json:"extra_shared_runners_minutes_limit"`
    85  	PreventForkingOutsideGroup     bool               `json:"prevent_forking_outside_group"`
    86  	MarkedForDeletionOn            *ISOTime           `json:"marked_for_deletion_on"`
    87  	CreatedAt                      *time.Time         `json:"created_at"`
    88  	IPRestrictionRanges            string             `json:"ip_restriction_ranges"`
    89  	WikiAccessLevel                AccessControlValue `json:"wiki_access_level"`
    90  
    91  	// Deprecated: Use EmailsEnabled instead
    92  	EmailsDisabled bool `json:"emails_disabled"`
    93  }
    94  
    95  // GroupAvatar represents a GitLab group avatar.
    96  //
    97  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html
    98  type GroupAvatar struct {
    99  	Filename string
   100  	Image    io.Reader
   101  }
   102  
   103  // MarshalJSON implements the json.Marshaler interface.
   104  func (a *GroupAvatar) MarshalJSON() ([]byte, error) {
   105  	if a.Filename == "" && a.Image == nil {
   106  		return []byte(`""`), nil
   107  	}
   108  	type alias GroupAvatar
   109  	return json.Marshal((*alias)(a))
   110  }
   111  
   112  // LDAPGroupLink represents a GitLab LDAP group link.
   113  //
   114  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#ldap-group-links
   115  type LDAPGroupLink struct {
   116  	CN          string           `json:"cn"`
   117  	Filter      string           `json:"filter"`
   118  	GroupAccess AccessLevelValue `json:"group_access"`
   119  	Provider    string           `json:"provider"`
   120  }
   121  
   122  // SAMLGroupLink represents a GitLab SAML group link.
   123  //
   124  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#saml-group-links
   125  type SAMLGroupLink struct {
   126  	Name        string           `json:"name"`
   127  	AccessLevel AccessLevelValue `json:"access_level"`
   128  }
   129  
   130  // ListGroupsOptions represents the available ListGroups() options.
   131  //
   132  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#list-groups
   133  type ListGroupsOptions struct {
   134  	ListOptions
   135  	SkipGroups           *[]int            `url:"skip_groups,omitempty" del:"," json:"skip_groups,omitempty"`
   136  	AllAvailable         *bool             `url:"all_available,omitempty" json:"all_available,omitempty"`
   137  	Search               *string           `url:"search,omitempty" json:"search,omitempty"`
   138  	OrderBy              *string           `url:"order_by,omitempty" json:"order_by,omitempty"`
   139  	Sort                 *string           `url:"sort,omitempty" json:"sort,omitempty"`
   140  	Statistics           *bool             `url:"statistics,omitempty" json:"statistics,omitempty"`
   141  	WithCustomAttributes *bool             `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
   142  	Owned                *bool             `url:"owned,omitempty" json:"owned,omitempty"`
   143  	MinAccessLevel       *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
   144  	TopLevelOnly         *bool             `url:"top_level_only,omitempty" json:"top_level_only,omitempty"`
   145  	RepositoryStorage    *string           `url:"repository_storage,omitempty" json:"repository_storage,omitempty"`
   146  }
   147  
   148  // ListGroups gets a list of groups (as user: my groups, as admin: all groups).
   149  //
   150  // GitLab API docs:
   151  // https://docs.gitlab.com/ee/api/groups.html#list-groups
   152  func (s *GroupsService) ListGroups(opt *ListGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
   153  	req, err := s.client.NewRequest(http.MethodGet, "groups", opt, options)
   154  	if err != nil {
   155  		return nil, nil, err
   156  	}
   157  
   158  	var gs []*Group
   159  	resp, err := s.client.Do(req, &gs)
   160  	if err != nil {
   161  		return nil, resp, err
   162  	}
   163  
   164  	return gs, resp, nil
   165  }
   166  
   167  // ListSubGroupsOptions represents the available ListSubGroups() options.
   168  //
   169  // GitLab API docs:
   170  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-subgroups
   171  type ListSubGroupsOptions ListGroupsOptions
   172  
   173  // ListSubGroups gets a list of subgroups for a given group.
   174  //
   175  // GitLab API docs:
   176  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-subgroups
   177  func (s *GroupsService) ListSubGroups(gid interface{}, opt *ListSubGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
   178  	group, err := parseID(gid)
   179  	if err != nil {
   180  		return nil, nil, err
   181  	}
   182  	u := fmt.Sprintf("groups/%s/subgroups", PathEscape(group))
   183  
   184  	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
   185  	if err != nil {
   186  		return nil, nil, err
   187  	}
   188  
   189  	var gs []*Group
   190  	resp, err := s.client.Do(req, &gs)
   191  	if err != nil {
   192  		return nil, resp, err
   193  	}
   194  
   195  	return gs, resp, nil
   196  }
   197  
   198  // ListDescendantGroupsOptions represents the available ListDescendantGroups()
   199  // options.
   200  //
   201  // GitLab API docs:
   202  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-descendant-groups
   203  type ListDescendantGroupsOptions ListGroupsOptions
   204  
   205  // ListDescendantGroups gets a list of subgroups for a given project.
   206  //
   207  // GitLab API docs:
   208  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-descendant-groups
   209  func (s *GroupsService) ListDescendantGroups(gid interface{}, opt *ListDescendantGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
   210  	group, err := parseID(gid)
   211  	if err != nil {
   212  		return nil, nil, err
   213  	}
   214  	u := fmt.Sprintf("groups/%s/descendant_groups", PathEscape(group))
   215  
   216  	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
   217  	if err != nil {
   218  		return nil, nil, err
   219  	}
   220  
   221  	var gs []*Group
   222  	resp, err := s.client.Do(req, &gs)
   223  	if err != nil {
   224  		return nil, resp, err
   225  	}
   226  
   227  	return gs, resp, nil
   228  }
   229  
   230  // ListGroupProjectsOptions represents the available ListGroup() options.
   231  //
   232  // GitLab API docs:
   233  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-projects
   234  type ListGroupProjectsOptions struct {
   235  	ListOptions
   236  	Archived                 *bool             `url:"archived,omitempty" json:"archived,omitempty"`
   237  	IncludeSubGroups         *bool             `url:"include_subgroups,omitempty" json:"include_subgroups,omitempty"`
   238  	MinAccessLevel           *AccessLevelValue `url:"min_access_level,omitempty" json:"min_access_level,omitempty"`
   239  	OrderBy                  *string           `url:"order_by,omitempty" json:"order_by,omitempty"`
   240  	Owned                    *bool             `url:"owned,omitempty" json:"owned,omitempty"`
   241  	Search                   *string           `url:"search,omitempty" json:"search,omitempty"`
   242  	Simple                   *bool             `url:"simple,omitempty" json:"simple,omitempty"`
   243  	Sort                     *string           `url:"sort,omitempty" json:"sort,omitempty"`
   244  	Starred                  *bool             `url:"starred,omitempty" json:"starred,omitempty"`
   245  	Topic                    *string           `url:"topic,omitempty" json:"topic,omitempty"`
   246  	Visibility               *VisibilityValue  `url:"visibility,omitempty" json:"visibility,omitempty"`
   247  	WithCustomAttributes     *bool             `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
   248  	WithIssuesEnabled        *bool             `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"`
   249  	WithMergeRequestsEnabled *bool             `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"`
   250  	WithSecurityReports      *bool             `url:"with_security_reports,omitempty" json:"with_security_reports,omitempty"`
   251  	WithShared               *bool             `url:"with_shared,omitempty" json:"with_shared,omitempty"`
   252  }
   253  
   254  // ListGroupProjects get a list of group projects
   255  //
   256  // GitLab API docs:
   257  // https://docs.gitlab.com/ee/api/groups.html#list-a-groups-projects
   258  func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...RequestOptionFunc) ([]*Project, *Response, error) {
   259  	group, err := parseID(gid)
   260  	if err != nil {
   261  		return nil, nil, err
   262  	}
   263  	u := fmt.Sprintf("groups/%s/projects", PathEscape(group))
   264  
   265  	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
   266  	if err != nil {
   267  		return nil, nil, err
   268  	}
   269  
   270  	var ps []*Project
   271  	resp, err := s.client.Do(req, &ps)
   272  	if err != nil {
   273  		return nil, resp, err
   274  	}
   275  
   276  	return ps, resp, nil
   277  }
   278  
   279  // GetGroupOptions represents the available GetGroup() options.
   280  //
   281  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#details-of-a-group
   282  type GetGroupOptions struct {
   283  	ListOptions
   284  	WithCustomAttributes *bool `url:"with_custom_attributes,omitempty" json:"with_custom_attributes,omitempty"`
   285  	WithProjects         *bool `url:"with_projects,omitempty" json:"with_projects,omitempty"`
   286  }
   287  
   288  // GetGroup gets all details of a group.
   289  //
   290  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#details-of-a-group
   291  func (s *GroupsService) GetGroup(gid interface{}, opt *GetGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
   292  	group, err := parseID(gid)
   293  	if err != nil {
   294  		return nil, nil, err
   295  	}
   296  	u := fmt.Sprintf("groups/%s", PathEscape(group))
   297  
   298  	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
   299  	if err != nil {
   300  		return nil, nil, err
   301  	}
   302  
   303  	g := new(Group)
   304  	resp, err := s.client.Do(req, g)
   305  	if err != nil {
   306  		return nil, resp, err
   307  	}
   308  
   309  	return g, resp, nil
   310  }
   311  
   312  // DownloadAvatar downloads a group avatar.
   313  //
   314  // GitLab API docs:
   315  // https://docs.gitlab.com/ee/api/groups.html#download-a-group-avatar
   316  func (s *GroupsService) DownloadAvatar(gid interface{}, options ...RequestOptionFunc) (*bytes.Reader, *Response, error) {
   317  	group, err := parseID(gid)
   318  	if err != nil {
   319  		return nil, nil, err
   320  	}
   321  	u := fmt.Sprintf("groups/%s/avatar", PathEscape(group))
   322  
   323  	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
   324  	if err != nil {
   325  		return nil, nil, err
   326  	}
   327  
   328  	avatar := new(bytes.Buffer)
   329  	resp, err := s.client.Do(req, avatar)
   330  	if err != nil {
   331  		return nil, resp, err
   332  	}
   333  
   334  	return bytes.NewReader(avatar.Bytes()), resp, err
   335  }
   336  
   337  // CreateGroupOptions represents the available CreateGroup() options.
   338  //
   339  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#new-group
   340  type CreateGroupOptions struct {
   341  	Name                           *string                     `url:"name,omitempty" json:"name,omitempty"`
   342  	Path                           *string                     `url:"path,omitempty" json:"path,omitempty"`
   343  	Avatar                         *GroupAvatar                `url:"-" json:"-"`
   344  	Description                    *string                     `url:"description,omitempty" json:"description,omitempty"`
   345  	MembershipLock                 *bool                       `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
   346  	Visibility                     *VisibilityValue            `url:"visibility,omitempty" json:"visibility,omitempty"`
   347  	ShareWithGroupLock             *bool                       `url:"share_with_group_lock,omitempty" json:"share_with_group_lock,omitempty"`
   348  	RequireTwoFactorAuth           *bool                       `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"`
   349  	TwoFactorGracePeriod           *int                        `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"`
   350  	ProjectCreationLevel           *ProjectCreationLevelValue  `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
   351  	AutoDevopsEnabled              *bool                       `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
   352  	SubGroupCreationLevel          *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
   353  	EmailsEnabled                  *bool                       `url:"emails_enabled,omitempty" json:"emails_enabled,omitempty"`
   354  	MentionsDisabled               *bool                       `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
   355  	LFSEnabled                     *bool                       `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
   356  	DefaultBranchProtection        *int                        `url:"default_branch_protection,omitempty" json:"default_branch_protection"`
   357  	RequestAccessEnabled           *bool                       `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
   358  	ParentID                       *int                        `url:"parent_id,omitempty" json:"parent_id,omitempty"`
   359  	SharedRunnersMinutesLimit      *int                        `url:"shared_runners_minutes_limit,omitempty" json:"shared_runners_minutes_limit,omitempty"`
   360  	ExtraSharedRunnersMinutesLimit *int                        `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"`
   361  	IPRestrictionRanges            *string                     `url:"ip_restriction_ranges,omitempty" json:"ip_restriction_ranges,omitempty"`
   362  	WikiAccessLevel                *AccessControlValue         `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"`
   363  
   364  	// Deprecated: Use EmailsEnabled instead
   365  	EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
   366  }
   367  
   368  // CreateGroup creates a new project group. Available only for users who can
   369  // create groups.
   370  //
   371  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#new-group
   372  func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
   373  	var err error
   374  	var req *retryablehttp.Request
   375  
   376  	if opt.Avatar == nil {
   377  		req, err = s.client.NewRequest(http.MethodPost, "groups", opt, options)
   378  	} else {
   379  		req, err = s.client.UploadRequest(
   380  			http.MethodPost,
   381  			"groups",
   382  			opt.Avatar.Image,
   383  			opt.Avatar.Filename,
   384  			UploadAvatar,
   385  			opt,
   386  			options,
   387  		)
   388  	}
   389  	if err != nil {
   390  		return nil, nil, err
   391  	}
   392  
   393  	g := new(Group)
   394  	resp, err := s.client.Do(req, g)
   395  	if err != nil {
   396  		return nil, resp, err
   397  	}
   398  
   399  	return g, resp, nil
   400  }
   401  
   402  // TransferGroup transfers a project to the Group namespace. Available only
   403  // for admin.
   404  //
   405  // GitLab API docs:
   406  // https://docs.gitlab.com/ee/api/groups.html#transfer-project-to-group
   407  func (s *GroupsService) TransferGroup(gid interface{}, pid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) {
   408  	group, err := parseID(gid)
   409  	if err != nil {
   410  		return nil, nil, err
   411  	}
   412  	project, err := parseID(pid)
   413  	if err != nil {
   414  		return nil, nil, err
   415  	}
   416  	u := fmt.Sprintf("groups/%s/projects/%s", PathEscape(group), PathEscape(project))
   417  
   418  	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
   419  	if err != nil {
   420  		return nil, nil, err
   421  	}
   422  
   423  	g := new(Group)
   424  	resp, err := s.client.Do(req, g)
   425  	if err != nil {
   426  		return nil, resp, err
   427  	}
   428  
   429  	return g, resp, nil
   430  }
   431  
   432  // TransferSubGroupOptions represents the available TransferSubGroup() options.
   433  //
   434  // GitLab API docs:
   435  // https://docs.gitlab.com/ee/api/groups.html#transfer-a-group-to-a-new-parent-group--turn-a-subgroup-to-a-top-level-group
   436  type TransferSubGroupOptions struct {
   437  	GroupID *int `url:"group_id,omitempty" json:"group_id,omitempty"`
   438  }
   439  
   440  // TransferSubGroup transfers a group to a new parent group or turn a subgroup
   441  // to a top-level group. Available to administrators and users.
   442  //
   443  // GitLab API docs:
   444  // https://docs.gitlab.com/ee/api/groups.html#transfer-a-group-to-a-new-parent-group--turn-a-subgroup-to-a-top-level-group
   445  func (s *GroupsService) TransferSubGroup(gid interface{}, opt *TransferSubGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
   446  	group, err := parseID(gid)
   447  	if err != nil {
   448  		return nil, nil, err
   449  	}
   450  	u := fmt.Sprintf("groups/%s/transfer", PathEscape(group))
   451  
   452  	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
   453  	if err != nil {
   454  		return nil, nil, err
   455  	}
   456  
   457  	g := new(Group)
   458  	resp, err := s.client.Do(req, g)
   459  	if err != nil {
   460  		return nil, resp, err
   461  	}
   462  
   463  	return g, resp, nil
   464  }
   465  
   466  // UpdateGroupOptions represents the available UpdateGroup() options.
   467  //
   468  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#update-group
   469  type UpdateGroupOptions struct {
   470  	Name                                 *string                     `url:"name,omitempty" json:"name,omitempty"`
   471  	Path                                 *string                     `url:"path,omitempty" json:"path,omitempty"`
   472  	Avatar                               *GroupAvatar                `url:"-" json:"avatar,omitempty"`
   473  	Description                          *string                     `url:"description,omitempty" json:"description,omitempty"`
   474  	MembershipLock                       *bool                       `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
   475  	Visibility                           *VisibilityValue            `url:"visibility,omitempty" json:"visibility,omitempty"`
   476  	ShareWithGroupLock                   *bool                       `url:"share_with_group_lock,omitempty" json:"share_with_group_lock,omitempty"`
   477  	RequireTwoFactorAuth                 *bool                       `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"`
   478  	TwoFactorGracePeriod                 *int                        `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"`
   479  	ProjectCreationLevel                 *ProjectCreationLevelValue  `url:"project_creation_level,omitempty" json:"project_creation_level,omitempty"`
   480  	AutoDevopsEnabled                    *bool                       `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
   481  	SubGroupCreationLevel                *SubGroupCreationLevelValue `url:"subgroup_creation_level,omitempty" json:"subgroup_creation_level,omitempty"`
   482  	EmailsEnabled                        *bool                       `url:"emails_enabled,omitempty" json:"emails_enabled,omitempty"`
   483  	MentionsDisabled                     *bool                       `url:"mentions_disabled,omitempty" json:"mentions_disabled,omitempty"`
   484  	LFSEnabled                           *bool                       `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"`
   485  	RequestAccessEnabled                 *bool                       `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"`
   486  	DefaultBranchProtection              *int                        `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"`
   487  	FileTemplateProjectID                *int                        `url:"file_template_project_id,omitempty" json:"file_template_project_id,omitempty"`
   488  	SharedRunnersMinutesLimit            *int                        `url:"shared_runners_minutes_limit,omitempty" json:"shared_runners_minutes_limit,omitempty"`
   489  	ExtraSharedRunnersMinutesLimit       *int                        `url:"extra_shared_runners_minutes_limit,omitempty" json:"extra_shared_runners_minutes_limit,omitempty"`
   490  	PreventForkingOutsideGroup           *bool                       `url:"prevent_forking_outside_group,omitempty" json:"prevent_forking_outside_group,omitempty"`
   491  	SharedRunnersSetting                 *SharedRunnersSettingValue  `url:"shared_runners_setting,omitempty" json:"shared_runners_setting,omitempty"`
   492  	PreventSharingGroupsOutsideHierarchy *bool                       `url:"prevent_sharing_groups_outside_hierarchy,omitempty" json:"prevent_sharing_groups_outside_hierarchy,omitempty"`
   493  	IPRestrictionRanges                  *string                     `url:"ip_restriction_ranges,omitempty" json:"ip_restriction_ranges,omitempty"`
   494  	WikiAccessLevel                      *AccessControlValue         `url:"wiki_access_level,omitempty" json:"wiki_access_level,omitempty"`
   495  
   496  	// Deprecated: Use EmailsEnabled instead
   497  	EmailsDisabled *bool `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
   498  }
   499  
   500  // UpdateGroup updates an existing group; only available to group owners and
   501  // administrators.
   502  //
   503  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#update-group
   504  func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
   505  	group, err := parseID(gid)
   506  	if err != nil {
   507  		return nil, nil, err
   508  	}
   509  	u := fmt.Sprintf("groups/%s", PathEscape(group))
   510  
   511  	var req *retryablehttp.Request
   512  
   513  	if opt.Avatar == nil || (opt.Avatar.Filename == "" && opt.Avatar.Image == nil) {
   514  		req, err = s.client.NewRequest(http.MethodPut, u, opt, options)
   515  	} else {
   516  		req, err = s.client.UploadRequest(
   517  			http.MethodPut,
   518  			u,
   519  			opt.Avatar.Image,
   520  			opt.Avatar.Filename,
   521  			UploadAvatar,
   522  			opt,
   523  			options,
   524  		)
   525  	}
   526  	if err != nil {
   527  		return nil, nil, err
   528  	}
   529  
   530  	g := new(Group)
   531  	resp, err := s.client.Do(req, g)
   532  	if err != nil {
   533  		return nil, resp, err
   534  	}
   535  
   536  	return g, resp, nil
   537  }
   538  
   539  // UploadAvatar uploads a group avatar.
   540  //
   541  // GitLab API docs:
   542  // https://docs.gitlab.com/ee/api/groups.html#upload-a-group-avatar
   543  func (s *GroupsService) UploadAvatar(gid interface{}, avatar io.Reader, filename string, options ...RequestOptionFunc) (*Group, *Response, error) {
   544  	group, err := parseID(gid)
   545  	if err != nil {
   546  		return nil, nil, err
   547  	}
   548  	u := fmt.Sprintf("groups/%s", PathEscape(group))
   549  
   550  	req, err := s.client.UploadRequest(
   551  		http.MethodPut,
   552  		u,
   553  		avatar,
   554  		filename,
   555  		UploadAvatar,
   556  		nil,
   557  		options,
   558  	)
   559  	if err != nil {
   560  		return nil, nil, err
   561  	}
   562  
   563  	g := new(Group)
   564  	resp, err := s.client.Do(req, g)
   565  	if err != nil {
   566  		return nil, resp, err
   567  	}
   568  
   569  	return g, resp, nil
   570  }
   571  
   572  // DeleteGroupOptions represents the available DeleteGroup() options.
   573  //
   574  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#update-group
   575  type DeleteGroupOptions struct {
   576  	PermanentlyRemove *bool   `url:"permanently_remove,omitempty" json:"permanently_remove,omitempty"`
   577  	FullPath          *string `url:"full_path,omitempty" json:"full_path,omitempty"`
   578  }
   579  
   580  // DeleteGroup removes group with all projects inside.
   581  //
   582  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#remove-group
   583  func (s *GroupsService) DeleteGroup(gid interface{}, opt *DeleteGroupOptions, options ...RequestOptionFunc) (*Response, error) {
   584  	group, err := parseID(gid)
   585  	if err != nil {
   586  		return nil, err
   587  	}
   588  	u := fmt.Sprintf("groups/%s", PathEscape(group))
   589  
   590  	req, err := s.client.NewRequest(http.MethodDelete, u, opt, options)
   591  	if err != nil {
   592  		return nil, err
   593  	}
   594  
   595  	return s.client.Do(req, nil)
   596  }
   597  
   598  // RestoreGroup restores a previously deleted group
   599  //
   600  // GitLap API docs:
   601  // https://docs.gitlab.com/ee/api/groups.html#restore-group-marked-for-deletion
   602  func (s *GroupsService) RestoreGroup(gid interface{}, options ...RequestOptionFunc) (*Group, *Response, error) {
   603  	group, err := parseID(gid)
   604  	if err != nil {
   605  		return nil, nil, err
   606  	}
   607  	u := fmt.Sprintf("groups/%s/restore", PathEscape(group))
   608  
   609  	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
   610  	if err != nil {
   611  		return nil, nil, err
   612  	}
   613  
   614  	g := new(Group)
   615  	resp, err := s.client.Do(req, g)
   616  	if err != nil {
   617  		return nil, resp, err
   618  	}
   619  
   620  	return g, resp, nil
   621  }
   622  
   623  // SearchGroup get all groups that match your string in their name or path.
   624  //
   625  // GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#search-for-group
   626  func (s *GroupsService) SearchGroup(query string, options ...RequestOptionFunc) ([]*Group, *Response, error) {
   627  	var q struct {
   628  		Search string `url:"search,omitempty" json:"search,omitempty"`
   629  	}
   630  	q.Search = query
   631  
   632  	req, err := s.client.NewRequest(http.MethodGet, "groups", &q, options)
   633  	if err != nil {
   634  		return nil, nil, err
   635  	}
   636  
   637  	var gs []*Group
   638  	resp, err := s.client.Do(req, &gs)
   639  	if err != nil {
   640  		return nil, resp, err
   641  	}
   642  
   643  	return gs, resp, nil
   644  }
   645  
   646  // ListProvisionedUsersOptions represents the available ListProvisionedUsers()
   647  // options.
   648  //
   649  // GitLab API docs:
   650  // https://docs.gitlab.com/ee/api/groups.html#list-provisioned-users
   651  type ListProvisionedUsersOptions struct {
   652  	ListOptions
   653  	Username      *string    `url:"username,omitempty" json:"username,omitempty"`
   654  	Search        *string    `url:"search,omitempty" json:"search,omitempty"`
   655  	Active        *bool      `url:"active,omitempty" json:"active,omitempty"`
   656  	Blocked       *bool      `url:"blocked,omitempty" json:"blocked,omitempty"`
   657  	CreatedAfter  *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
   658  	CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
   659  }
   660  
   661  // ListProvisionedUsers gets a list of users provisioned by the given group.
   662  //
   663  // GitLab API docs:
   664  // https://docs.gitlab.com/ee/api/groups.html#list-provisioned-users
   665  func (s *GroupsService) ListProvisionedUsers(gid interface{}, opt *ListProvisionedUsersOptions, options ...RequestOptionFunc) ([]*User, *Response, error) {
   666  	group, err := parseID(gid)
   667  	if err != nil {
   668  		return nil, nil, err
   669  	}
   670  	u := fmt.Sprintf("groups/%s/provisioned_users", PathEscape(group))
   671  
   672  	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
   673  	if err != nil {
   674  		return nil, nil, err
   675  	}
   676  
   677  	var us []*User
   678  	resp, err := s.client.Do(req, &us)
   679  	if err != nil {
   680  		return nil, resp, err
   681  	}
   682  
   683  	return us, resp, nil
   684  }
   685  
   686  // ListGroupLDAPLinks lists the group's LDAP links. Available only for users who
   687  // can edit groups.
   688  //
   689  // GitLab API docs:
   690  // https://docs.gitlab.com/ee/api/groups.html#list-ldap-group-links
   691  func (s *GroupsService) ListGroupLDAPLinks(gid interface{}, options ...RequestOptionFunc) ([]*LDAPGroupLink, *Response, error) {
   692  	group, err := parseID(gid)
   693  	if err != nil {
   694  		return nil, nil, err
   695  	}
   696  	u := fmt.Sprintf("groups/%s/ldap_group_links", PathEscape(group))
   697  
   698  	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
   699  	if err != nil {
   700  		return nil, nil, err
   701  	}
   702  
   703  	var gls []*LDAPGroupLink
   704  	resp, err := s.client.Do(req, &gls)
   705  	if err != nil {
   706  		return nil, resp, err
   707  	}
   708  
   709  	return gls, resp, nil
   710  }
   711  
   712  // AddGroupLDAPLinkOptions represents the available AddGroupLDAPLink() options.
   713  //
   714  // GitLab API docs:
   715  // https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-with-cn-or-filter
   716  type AddGroupLDAPLinkOptions struct {
   717  	CN          *string           `url:"cn,omitempty" json:"cn,omitempty"`
   718  	Filter      *string           `url:"filter,omitempty" json:"filter,omitempty"`
   719  	GroupAccess *AccessLevelValue `url:"group_access,omitempty" json:"group_access,omitempty"`
   720  	Provider    *string           `url:"provider,omitempty" json:"provider,omitempty"`
   721  }
   722  
   723  // DeleteGroupLDAPLinkWithCNOrFilterOptions represents the available DeleteGroupLDAPLinkWithCNOrFilter() options.
   724  //
   725  // GitLab API docs:
   726  // https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
   727  type DeleteGroupLDAPLinkWithCNOrFilterOptions struct {
   728  	CN       *string `url:"cn,omitempty" json:"cn,omitempty"`
   729  	Filter   *string `url:"filter,omitempty" json:"filter,omitempty"`
   730  	Provider *string `url:"provider,omitempty" json:"provider,omitempty"`
   731  }
   732  
   733  // AddGroupLDAPLink creates a new group LDAP link. Available only for users who
   734  // can edit groups.
   735  //
   736  // GitLab API docs:
   737  // https://docs.gitlab.com/ee/api/groups.html#add-ldap-group-link-with-cn-or-filter
   738  func (s *GroupsService) AddGroupLDAPLink(gid interface{}, opt *AddGroupLDAPLinkOptions, options ...RequestOptionFunc) (*LDAPGroupLink, *Response, error) {
   739  	group, err := parseID(gid)
   740  	if err != nil {
   741  		return nil, nil, err
   742  	}
   743  	u := fmt.Sprintf("groups/%s/ldap_group_links", PathEscape(group))
   744  
   745  	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
   746  	if err != nil {
   747  		return nil, nil, err
   748  	}
   749  
   750  	gl := new(LDAPGroupLink)
   751  	resp, err := s.client.Do(req, gl)
   752  	if err != nil {
   753  		return nil, resp, err
   754  	}
   755  
   756  	return gl, resp, nil
   757  }
   758  
   759  // DeleteGroupLDAPLink deletes a group LDAP link. Available only for users who
   760  // can edit groups.
   761  //
   762  // GitLab API docs:
   763  // https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link
   764  func (s *GroupsService) DeleteGroupLDAPLink(gid interface{}, cn string, options ...RequestOptionFunc) (*Response, error) {
   765  	group, err := parseID(gid)
   766  	if err != nil {
   767  		return nil, err
   768  	}
   769  	u := fmt.Sprintf("groups/%s/ldap_group_links/%s", PathEscape(group), PathEscape(cn))
   770  
   771  	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
   772  	if err != nil {
   773  		return nil, err
   774  	}
   775  
   776  	return s.client.Do(req, nil)
   777  }
   778  
   779  // DeleteGroupLDAPLinkWithCNOrFilter deletes a group LDAP link. Available only for users who
   780  // can edit groups.
   781  //
   782  // GitLab API docs:
   783  // https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link-with-cn-or-filter
   784  func (s *GroupsService) DeleteGroupLDAPLinkWithCNOrFilter(gid interface{}, opts *DeleteGroupLDAPLinkWithCNOrFilterOptions, options ...RequestOptionFunc) (*Response, error) {
   785  	group, err := parseID(gid)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	u := fmt.Sprintf("groups/%s/ldap_group_links", PathEscape(group))
   790  
   791  	req, err := s.client.NewRequest(http.MethodDelete, u, opts, options)
   792  	if err != nil {
   793  		return nil, err
   794  	}
   795  
   796  	return s.client.Do(req, nil)
   797  }
   798  
   799  // DeleteGroupLDAPLinkForProvider deletes a group LDAP link from a specific
   800  // provider. Available only for users who can edit groups.
   801  //
   802  // GitLab API docs:
   803  // https://docs.gitlab.com/ee/api/groups.html#delete-ldap-group-link
   804  func (s *GroupsService) DeleteGroupLDAPLinkForProvider(gid interface{}, provider, cn string, options ...RequestOptionFunc) (*Response, error) {
   805  	group, err := parseID(gid)
   806  	if err != nil {
   807  		return nil, err
   808  	}
   809  	u := fmt.Sprintf(
   810  		"groups/%s/ldap_group_links/%s/%s",
   811  		PathEscape(group),
   812  		PathEscape(provider),
   813  		PathEscape(cn),
   814  	)
   815  
   816  	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
   817  	if err != nil {
   818  		return nil, err
   819  	}
   820  
   821  	return s.client.Do(req, nil)
   822  }
   823  
   824  // ListGroupSAMLLinks lists the group's SAML links. Available only for users who
   825  // can edit groups.
   826  //
   827  // GitLab API docs:
   828  // https://docs.gitlab.com/ee/api/groups.html#list-saml-group-links
   829  func (s *GroupsService) ListGroupSAMLLinks(gid interface{}, options ...RequestOptionFunc) ([]*SAMLGroupLink, *Response, error) {
   830  	group, err := parseID(gid)
   831  	if err != nil {
   832  		return nil, nil, err
   833  	}
   834  	u := fmt.Sprintf("groups/%s/saml_group_links", PathEscape(group))
   835  
   836  	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
   837  	if err != nil {
   838  		return nil, nil, err
   839  	}
   840  
   841  	var gl []*SAMLGroupLink
   842  	resp, err := s.client.Do(req, &gl)
   843  	if err != nil {
   844  		return nil, resp, err
   845  	}
   846  
   847  	return gl, resp, nil
   848  }
   849  
   850  // GetGroupSAMLLink get a specific group SAML link. Available only for users who
   851  // can edit groups.
   852  //
   853  // GitLab API docs:
   854  // https://docs.gitlab.com/ee/api/groups.html#get-saml-group-link
   855  func (s *GroupsService) GetGroupSAMLLink(gid interface{}, samlGroupName string, options ...RequestOptionFunc) (*SAMLGroupLink, *Response, error) {
   856  	group, err := parseID(gid)
   857  	if err != nil {
   858  		return nil, nil, err
   859  	}
   860  	u := fmt.Sprintf("groups/%s/saml_group_links/%s", PathEscape(group), PathEscape(samlGroupName))
   861  
   862  	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
   863  	if err != nil {
   864  		return nil, nil, err
   865  	}
   866  
   867  	gl := new(SAMLGroupLink)
   868  	resp, err := s.client.Do(req, &gl)
   869  	if err != nil {
   870  		return nil, resp, err
   871  	}
   872  
   873  	return gl, resp, nil
   874  }
   875  
   876  // AddGroupSAMLLinkOptions represents the available AddGroupSAMLLink() options.
   877  //
   878  // GitLab API docs:
   879  // https://docs.gitlab.com/ee/api/groups.html#add-saml-group-link
   880  type AddGroupSAMLLinkOptions struct {
   881  	SAMLGroupName *string           `url:"saml_group_name,omitempty" json:"saml_group_name,omitempty"`
   882  	AccessLevel   *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
   883  }
   884  
   885  // AddGroupSAMLLink creates a new group SAML link. Available only for users who
   886  // can edit groups.
   887  //
   888  // GitLab API docs:
   889  // https://docs.gitlab.com/ee/api/groups.html#add-saml-group-link
   890  func (s *GroupsService) AddGroupSAMLLink(gid interface{}, opt *AddGroupSAMLLinkOptions, options ...RequestOptionFunc) (*SAMLGroupLink, *Response, error) {
   891  	group, err := parseID(gid)
   892  	if err != nil {
   893  		return nil, nil, err
   894  	}
   895  	u := fmt.Sprintf("groups/%s/saml_group_links", PathEscape(group))
   896  
   897  	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
   898  	if err != nil {
   899  		return nil, nil, err
   900  	}
   901  
   902  	gl := new(SAMLGroupLink)
   903  	resp, err := s.client.Do(req, &gl)
   904  	if err != nil {
   905  		return nil, resp, err
   906  	}
   907  
   908  	return gl, resp, nil
   909  }
   910  
   911  // DeleteGroupSAMLLink deletes a group SAML link. Available only for users who
   912  // can edit groups.
   913  //
   914  // GitLab API docs:
   915  // https://docs.gitlab.com/ee/api/groups.html#delete-saml-group-link
   916  func (s *GroupsService) DeleteGroupSAMLLink(gid interface{}, samlGroupName string, options ...RequestOptionFunc) (*Response, error) {
   917  	group, err := parseID(gid)
   918  	if err != nil {
   919  		return nil, err
   920  	}
   921  	u := fmt.Sprintf("groups/%s/saml_group_links/%s", PathEscape(group), PathEscape(samlGroupName))
   922  
   923  	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
   924  	if err != nil {
   925  		return nil, err
   926  	}
   927  
   928  	return s.client.Do(req, nil)
   929  }
   930  
   931  // ShareGroupWithGroupOptions represents the available ShareGroupWithGroup() options.
   932  //
   933  // GitLab API docs:
   934  // https://docs.gitlab.com/ee/api/groups.html#share-groups-with-groups
   935  type ShareGroupWithGroupOptions struct {
   936  	GroupID     *int              `url:"group_id,omitempty" json:"group_id,omitempty"`
   937  	GroupAccess *AccessLevelValue `url:"group_access,omitempty" json:"group_access,omitempty"`
   938  	ExpiresAt   *ISOTime          `url:"expires_at,omitempty" json:"expires_at,omitempty"`
   939  }
   940  
   941  // ShareGroupWithGroup shares a group with another group.
   942  //
   943  // GitLab API docs:
   944  // https://docs.gitlab.com/ee/api/groups.html#create-a-link-to-share-a-group-with-another-group
   945  func (s *GroupsService) ShareGroupWithGroup(gid interface{}, opt *ShareGroupWithGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
   946  	group, err := parseID(gid)
   947  	if err != nil {
   948  		return nil, nil, err
   949  	}
   950  	u := fmt.Sprintf("groups/%s/share", PathEscape(group))
   951  
   952  	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
   953  	if err != nil {
   954  		return nil, nil, err
   955  	}
   956  
   957  	g := new(Group)
   958  	resp, err := s.client.Do(req, g)
   959  	if err != nil {
   960  		return nil, resp, err
   961  	}
   962  
   963  	return g, resp, nil
   964  }
   965  
   966  // UnshareGroupFromGroup unshares a group from another group.
   967  //
   968  // GitLab API docs:
   969  // https://docs.gitlab.com/ee/api/groups.html#delete-link-sharing-group-with-another-group
   970  func (s *GroupsService) UnshareGroupFromGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) {
   971  	group, err := parseID(gid)
   972  	if err != nil {
   973  		return nil, err
   974  	}
   975  	u := fmt.Sprintf("groups/%s/share/%d", PathEscape(group), groupID)
   976  
   977  	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
   978  	if err != nil {
   979  		return nil, err
   980  	}
   981  
   982  	return s.client.Do(req, nil)
   983  }
   984  
   985  // GroupPushRules represents a group push rule.
   986  //
   987  // GitLab API docs:
   988  // https://docs.gitlab.com/ee/api/groups.html#get-group-push-rules
   989  type GroupPushRules struct {
   990  	ID                         int        `json:"id"`
   991  	CreatedAt                  *time.Time `json:"created_at"`
   992  	CommitMessageRegex         string     `json:"commit_message_regex"`
   993  	CommitMessageNegativeRegex string     `json:"commit_message_negative_regex"`
   994  	BranchNameRegex            string     `json:"branch_name_regex"`
   995  	DenyDeleteTag              bool       `json:"deny_delete_tag"`
   996  	MemberCheck                bool       `json:"member_check"`
   997  	PreventSecrets             bool       `json:"prevent_secrets"`
   998  	AuthorEmailRegex           string     `json:"author_email_regex"`
   999  	FileNameRegex              string     `json:"file_name_regex"`
  1000  	MaxFileSize                int        `json:"max_file_size"`
  1001  	CommitCommitterCheck       bool       `json:"commit_committer_check"`
  1002  	RejectUnsignedCommits      bool       `json:"reject_unsigned_commits"`
  1003  }
  1004  
  1005  // GetGroupPushRules gets the push rules of a group.
  1006  //
  1007  // GitLab API docs:
  1008  // https://docs.gitlab.com/ee/api/groups.html#get-group-push-rules
  1009  func (s *GroupsService) GetGroupPushRules(gid interface{}, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
  1010  	group, err := parseID(gid)
  1011  	if err != nil {
  1012  		return nil, nil, err
  1013  	}
  1014  	u := fmt.Sprintf("groups/%s/push_rule", PathEscape(group))
  1015  
  1016  	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
  1017  	if err != nil {
  1018  		return nil, nil, err
  1019  	}
  1020  
  1021  	gpr := new(GroupPushRules)
  1022  	resp, err := s.client.Do(req, gpr)
  1023  	if err != nil {
  1024  		return nil, resp, err
  1025  	}
  1026  
  1027  	return gpr, resp, nil
  1028  }
  1029  
  1030  // AddGroupPushRuleOptions represents the available AddGroupPushRule()
  1031  // options.
  1032  //
  1033  // GitLab API docs:
  1034  // https://docs.gitlab.com/ee/api/groups.html#add-group-push-rule
  1035  type AddGroupPushRuleOptions struct {
  1036  	AuthorEmailRegex           *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
  1037  	BranchNameRegex            *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
  1038  	CommitCommitterCheck       *bool   `url:"commit_committer_check,omitempty" json:"commit_committer_check,omitempty"`
  1039  	CommitMessageNegativeRegex *string `url:"commit_message_negative_regex,omitempty" json:"commit_message_negative_regex,omitempty"`
  1040  	CommitMessageRegex         *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
  1041  	DenyDeleteTag              *bool   `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
  1042  	FileNameRegex              *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
  1043  	MaxFileSize                *int    `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
  1044  	MemberCheck                *bool   `url:"member_check,omitempty" json:"member_check,omitempty"`
  1045  	PreventSecrets             *bool   `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
  1046  	RejectUnsignedCommits      *bool   `url:"reject_unsigned_commits,omitempty" json:"reject_unsigned_commits,omitempty"`
  1047  }
  1048  
  1049  // AddGroupPushRule adds push rules to the specified group.
  1050  //
  1051  // GitLab API docs:
  1052  // https://docs.gitlab.com/ee/api/groups.html#add-group-push-rule
  1053  func (s *GroupsService) AddGroupPushRule(gid interface{}, opt *AddGroupPushRuleOptions, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
  1054  	group, err := parseID(gid)
  1055  	if err != nil {
  1056  		return nil, nil, err
  1057  	}
  1058  	u := fmt.Sprintf("groups/%s/push_rule", PathEscape(group))
  1059  
  1060  	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
  1061  	if err != nil {
  1062  		return nil, nil, err
  1063  	}
  1064  
  1065  	gpr := new(GroupPushRules)
  1066  	resp, err := s.client.Do(req, gpr)
  1067  	if err != nil {
  1068  		return nil, resp, err
  1069  	}
  1070  
  1071  	return gpr, resp, nil
  1072  }
  1073  
  1074  // EditGroupPushRuleOptions represents the available EditGroupPushRule()
  1075  // options.
  1076  //
  1077  // GitLab API docs:
  1078  // https://docs.gitlab.com/ee/api/groups.html#edit-group-push-rule
  1079  type EditGroupPushRuleOptions struct {
  1080  	AuthorEmailRegex           *string `url:"author_email_regex,omitempty" json:"author_email_regex,omitempty"`
  1081  	BranchNameRegex            *string `url:"branch_name_regex,omitempty" json:"branch_name_regex,omitempty"`
  1082  	CommitCommitterCheck       *bool   `url:"commit_committer_check,omitempty" json:"commit_committer_check,omitempty"`
  1083  	CommitMessageNegativeRegex *string `url:"commit_message_negative_regex,omitempty" json:"commit_message_negative_regex,omitempty"`
  1084  	CommitMessageRegex         *string `url:"commit_message_regex,omitempty" json:"commit_message_regex,omitempty"`
  1085  	DenyDeleteTag              *bool   `url:"deny_delete_tag,omitempty" json:"deny_delete_tag,omitempty"`
  1086  	FileNameRegex              *string `url:"file_name_regex,omitempty" json:"file_name_regex,omitempty"`
  1087  	MaxFileSize                *int    `url:"max_file_size,omitempty" json:"max_file_size,omitempty"`
  1088  	MemberCheck                *bool   `url:"member_check,omitempty" json:"member_check,omitempty"`
  1089  	PreventSecrets             *bool   `url:"prevent_secrets,omitempty" json:"prevent_secrets,omitempty"`
  1090  	RejectUnsignedCommits      *bool   `url:"reject_unsigned_commits,omitempty" json:"reject_unsigned_commits,omitempty"`
  1091  }
  1092  
  1093  // EditGroupPushRule edits a push rule for a specified group.
  1094  //
  1095  // GitLab API docs:
  1096  // https://docs.gitlab.com/ee/api/groups.html#edit-group-push-rule
  1097  func (s *GroupsService) EditGroupPushRule(gid interface{}, opt *EditGroupPushRuleOptions, options ...RequestOptionFunc) (*GroupPushRules, *Response, error) {
  1098  	group, err := parseID(gid)
  1099  	if err != nil {
  1100  		return nil, nil, err
  1101  	}
  1102  	u := fmt.Sprintf("groups/%s/push_rule", PathEscape(group))
  1103  
  1104  	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
  1105  	if err != nil {
  1106  		return nil, nil, err
  1107  	}
  1108  
  1109  	gpr := new(GroupPushRules)
  1110  	resp, err := s.client.Do(req, gpr)
  1111  	if err != nil {
  1112  		return nil, resp, err
  1113  	}
  1114  
  1115  	return gpr, resp, nil
  1116  }
  1117  
  1118  // DeleteGroupPushRule deletes the push rules of a group.
  1119  //
  1120  // GitLab API docs:
  1121  // https://docs.gitlab.com/ee/api/groups.html#delete-group-push-rule
  1122  func (s *GroupsService) DeleteGroupPushRule(gid interface{}, options ...RequestOptionFunc) (*Response, error) {
  1123  	group, err := parseID(gid)
  1124  	if err != nil {
  1125  		return nil, err
  1126  	}
  1127  	u := fmt.Sprintf("groups/%s/push_rule", PathEscape(group))
  1128  
  1129  	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
  1130  	if err != nil {
  1131  		return nil, err
  1132  	}
  1133  
  1134  	return s.client.Do(req, nil)
  1135  }
  1136  

View as plain text