Repository: xanzy/go-gitlab
Pull request #940 (2020-09-11 17:38:43)

Add managed attribute to instance cluster
Add managed attribute to instance cluster


Patch:
diff --git a/client_options.go b/client_options.go
index 4d9b0d6..dfc4089 100644
--- a/client_options.go
+++ b/client_options.go
@@ -24,16 +24,6 @@ func WithCustomBackoff(backoff retryablehttp.Backoff) ClientOptionFunc {
 	}
 }
 
-// WithCustomLimiter injects a custom rate limiter to the client.
-func WithCustomLimiter(limiter RateLimiter) ClientOptionFunc {
-	return func(c *Client) error {
-		c.configureLimiterOnce.Do(func() {
-			c.limiter = limiter
-		})
-		return nil
-	}
-}
-
 // WithCustomRetry can be used to configure a custom retry policy.
 func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc {
 	return func(c *Client) error {
diff --git a/epics.go b/epics.go
index 7f24c50..87dbe20 100644
--- a/epics.go
+++ b/epics.go
@@ -30,12 +30,16 @@ type Epic struct {
 	ID                      int         `json:"id"`
 	IID                     int         `json:"iid"`
 	GroupID                 int         `json:"group_id"`
-	ParentID                int         `json:"parent_id"`
-	Title                   string      `json:"title"`
+	Author                  *EpicAuthor `json:"author"`
 	Description             string      `json:"description"`
 	State                   string      `json:"state"`
-	WebURL                  string      `json:"web_url"`
-	Author                  *EpicAuthor `json:"author"`
+	Upvotes                 int         `json:"upvotes"`
+	Downvotes               int         `json:"downvotes"`
+	Labels                  []string    `json:"labels"`
+	Title                   string      `json:"title"`
+	UpdatedAt               *time.Time  `json:"updated_at"`
+	CreatedAt               *time.Time  `json:"created_at"`
+	UserNotesCount          int         `json:"user_notes_count"`
 	StartDate               *ISOTime    `json:"start_date"`
 	StartDateIsFixed        bool        `json:"start_date_is_fixed"`
 	StartDateFixed          *ISOTime    `json:"start_date_fixed"`
@@ -44,13 +48,6 @@ type Epic struct {
 	DueDateIsFixed          bool        `json:"due_date_is_fixed"`
 	DueDateFixed            *ISOTime    `json:"due_date_fixed"`
 	DueDateFromMilestones   *ISOTime    `json:"due_date_from_milestones"`
-	CreatedAt               *time.Time  `json:"created_at"`
-	UpdatedAt               *time.Time  `json:"updated_at"`
-	Labels                  []string    `json:"labels"`
-	Upvotes                 int         `json:"upvotes"`
-	Downvotes               int         `json:"downvotes"`
-	UserNotesCount          int         `json:"user_notes_count"`
-	URL                     string      `json:"url"`
 }
 
 func (e Epic) String() string {
@@ -62,20 +59,12 @@ func (e Epic) String() string {
 // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
 type ListGroupEpicsOptions struct {
 	ListOptions
-	AuthorID                *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	Labels                  Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	WithLabelDetails        *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
-	OrderBy                 *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Sort                    *string    `url:"sort,omitempty" json:"sort,omitempty"`
-	Search                  *string    `url:"search,omitempty" json:"search,omitempty"`
-	State                   *string    `url:"state,omitempty" json:"state,omitempty"`
-	CreatedAfter            *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore           *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter            *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore           *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	IncludeAncestorGroups   *bool      `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"`
-	IncludeDescendantGroups *bool      `url:"include_descendant_groups,omitempty" json:"include_descendant_groups,omitempty"`
-	MyReactionEmoji         *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
+	State    *string `url:"state,omitempty" json:"state,omitempty"`
+	Labels   Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	AuthorID *int    `url:"author_id,omitempty" json:"author_id,omitempty"`
+	OrderBy  *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort     *string `url:"sort,omitempty" json:"sort,omitempty"`
+	Search   *string `url:"search,omitempty" json:"search,omitempty"`
 }
 
 // ListGroupEpics gets a list of group epics. This function accepts pagination
@@ -127,30 +116,6 @@ func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOpti
 	return e, resp, err
 }
 
-// GetEpicLinks gets all child epics of an epic.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/epic_links.html
-func (s *EpicsService) GetEpicLinks(gid interface{}, epic int, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/epics/%d/epics", pathEscape(group), epic)
-
-	req, err := s.client.NewRequest("GET", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var e []*Epic
-	resp, err := s.client.Do(req, &e)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return e, resp, err
-}
-
 // CreateEpicOptions represents the available CreateEpic() options.
 //
 // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
diff --git a/event_webhook_types.go b/event_webhook_types.go
index d41379a..ef3057f 100644
--- a/event_webhook_types.go
+++ b/event_webhook_types.go
@@ -85,7 +85,6 @@ type TagEvent struct {
 	UserID      int    `json:"user_id"`
 	UserName    string `json:"user_name"`
 	UserAvatar  string `json:"user_avatar"`
-	UserEmail   string `json:"user_email"`
 	ProjectID   int    `json:"project_id"`
 	Message     string `json:"message"`
 	Project     struct {
@@ -594,10 +593,6 @@ type MergeEvent struct {
 			Previous int `json:"previous"`
 			Current  int `json:"current"`
 		} `json:"source_project_id"`
-		StateID struct {
-			Previous int `json:"previous"`
-			Current  int `json:"current"`
-		} `json:"state_id"`
 		TargetBranch struct {
 			Previous string `json:"previous"`
 			Current  string `json:"current"`
diff --git a/gitlab.go b/gitlab.go
index f8e4ee2..063bbe0 100644
--- a/gitlab.go
+++ b/gitlab.go
@@ -80,7 +80,7 @@ type Client struct {
 	configureLimiterOnce sync.Once
 
 	// Limiter is used to limit API calls and prevent 429 responses.
-	limiter RateLimiter
+	limiter *rate.Limiter
 
 	// Token type used to make authenticated API calls.
 	authType authType
@@ -127,10 +127,8 @@ type Client struct {
 	GroupVariables        *GroupVariablesService
 	Groups                *GroupsService
 	InstanceCluster       *InstanceClustersService
-	InstanceVariables     *InstanceVariablesService
 	IssueLinks            *IssueLinksService
 	Issues                *IssuesService
-	IssuesStatistics      *IssuesStatisticsService
 	Jobs                  *JobsService
 	Keys                  *KeysService
 	Labels                *LabelsService
@@ -186,11 +184,6 @@ type ListOptions struct {
 	PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"`
 }
 
-// RateLimiter describes the interface that all (custom) rate limiters must implement.
-type RateLimiter interface {
-	Wait(context.Context) error
-}
-
 // NewClient returns a new GitLab API client. To use API methods which require
 // authentication, provide a valid private or personal token.
 func NewClient(token string, options ...ClientOptionFunc) (*Client, error) {
@@ -292,7 +285,6 @@ func newClient(options ...ClientOptionFunc) (*Client, error) {
 	c.InstanceCluster = &InstanceClustersService{client: c}
 	c.IssueLinks = &IssueLinksService{client: c}
 	c.Issues = &IssuesService{client: c, timeStats: timeStats}
-	c.IssuesStatistics = &IssuesStatisticsService{client: c}
 	c.Jobs = &JobsService{client: c}
 	c.Keys = &KeysService{client: c}
 	c.Labels = &LabelsService{client: c}
@@ -632,16 +624,15 @@ func (c *Client) Do(req *retryablehttp.Request, v interface{}) (*Response, error
 	if err != nil {
 		return nil, err
 	}
+	defer resp.Body.Close()
 
 	if resp.StatusCode == http.StatusUnauthorized && c.authType == basicAuth {
-		resp.Body.Close()
 		// The token most likely expired, so we need to request a new one and try again.
 		if _, err := c.requestOAuthToken(req.Context(), basicAuthToken); err != nil {
 			return nil, err
 		}
 		return c.Do(req, v)
 	}
-	defer resp.Body.Close()
 
 	response := newResponse(resp)
 
@@ -674,8 +665,8 @@ func (c *Client) requestOAuthToken(ctx context.Context, token string) (string, e
 
 	config := &oauth2.Config{
 		Endpoint: oauth2.Endpoint{
-			AuthURL:  strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/authorize",
-			TokenURL: strings.TrimSuffix(c.baseURL.String(), apiVersionPath) + "oauth/token",
+			AuthURL:  fmt.Sprintf("%s://%s/oauth/authorize", c.BaseURL().Scheme, c.BaseURL().Host),
+			TokenURL: fmt.Sprintf("%s://%s/oauth/token", c.BaseURL().Scheme, c.BaseURL().Host),
 		},
 	}
 
diff --git a/group_boards.go b/group_boards.go
index 8618654..d9d2ee6 100644
--- a/group_boards.go
+++ b/group_boards.go
@@ -144,7 +144,7 @@ type UpdateGroupIssueBoardOptions struct {
 	Name        *string `url:"name,omitempty" json:"name,omitempty"`
 	AssigneeID  *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	MilestoneID *int    `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
-	Labels      Labels  `url:"labels,omitempty" json:"labels,omitempty"`
+	Labels      *Labels `url:"labels,omitempty" json:"labels,omitempty"`
 	Weight      *int    `url:"weight,omitempty" json:"weight,omitempty"`
 }
 
diff --git a/group_clusters.go b/group_clusters.go
index e91cbd2..6e893ea 100644
--- a/group_clusters.go
+++ b/group_clusters.go
@@ -93,13 +93,13 @@ func (s *GroupClustersService) GetCluster(pid interface{}, cluster int, options
 		return nil, nil, err
 	}
 
-	gc := new(GroupCluster)
-	resp, err := s.client.Do(req, &gc)
+	pc := new(GroupCluster)
+	resp, err := s.client.Do(req, &pc)
 	if err != nil {
 		return nil, resp, err
 	}
 
-	return gc, resp, err
+	return pc, resp, err
 }
 
 // AddGroupClusterOptions represents the available AddCluster() options.
@@ -141,13 +141,13 @@ func (s *GroupClustersService) AddCluster(pid interface{}, opt *AddGroupClusterO
 		return nil, nil, err
 	}
 
-	gc := new(GroupCluster)
-	resp, err := s.client.Do(req, gc)
+	pc := new(GroupCluster)
+	resp, err := s.client.Do(req, pc)
 	if err != nil {
 		return nil, resp, err
 	}
 
-	return gc, resp, err
+	return pc, resp, err
 }
 
 // EditGroupClusterOptions represents the available EditCluster() options.
@@ -185,13 +185,13 @@ func (s *GroupClustersService) EditCluster(pid interface{}, cluster int, opt *Ed
 		return nil, nil, err
 	}
 
-	gc := new(GroupCluster)
-	resp, err := s.client.Do(req, gc)
+	pc := new(GroupCluster)
+	resp, err := s.client.Do(req, pc)
 	if err != nil {
 		return nil, resp, err
 	}
 
-	return gc, resp, err
+	return pc, resp, err
 }
 
 // DeleteCluster deletes an existing group cluster.
diff --git a/group_members.go b/group_members.go
index 7fc1d4c..1ea9719 100644
--- a/group_members.go
+++ b/group_members.go
@@ -201,25 +201,6 @@ func (s *GroupMembersService) ShareWithGroup(gid interface{}, opt *ShareWithGrou
 	return g, resp, err
 }
 
-// DeleteShareWithGroup allows to unshare a group from a group.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/groups.html#delete-link-sharing-group-with-another-group
-func (s *GroupMembersService) DeleteShareWithGroup(gid interface{}, groupID int, options ...RequestOptionFunc) (*Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("groups/%s/share/%d", pathEscape(group), groupID)
-
-	req, err := s.client.NewRequest("DELETE", u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
 // EditGroupMemberOptions represents the available EditGroupMember()
 // options.
 //
diff --git a/group_milestones.go b/group_milestones.go
index b3249f7..4cf91f9 100644
--- a/group_milestones.go
+++ b/group_milestones.go
@@ -43,7 +43,6 @@ type GroupMilestone struct {
 	State       string     `json:"state"`
 	UpdatedAt   *time.Time `json:"updated_at"`
 	CreatedAt   *time.Time `json:"created_at"`
-	Expired     *bool      `json:"expired"`
 }
 
 func (m GroupMilestone) String() string {
@@ -57,11 +56,9 @@ func (m GroupMilestone) String() string {
 // https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones
 type ListGroupMilestonesOptions struct {
 	ListOptions
-	IIDs                    []int   `url:"iids,omitempty" json:"iids,omitempty"`
-	State                   *string `url:"state,omitempty" json:"state,omitempty"`
-	Title                   *string `url:"title,omitempty" json:"title,omitempty"`
-	Search                  *string `url:"search,omitempty" json:"search,omitempty"`
-	IncludeParentMilestones *bool   `url:"include_parent_milestones,omitempty" json:"include_parent_milestones,omitempty"`
+	IIDs   []int  `url:"iids,omitempty" json:"iids,omitempty"`
+	State  string `url:"state,omitempty" json:"state,omitempty"`
+	Search string `url:"search,omitempty" json:"search,omitempty"`
 }
 
 // ListGroupMilestones returns a list of group milestones.
diff --git a/groups.go b/groups.go
index 8706f6b..d3789d6 100644
--- a/groups.go
+++ b/groups.go
@@ -33,46 +33,39 @@ type GroupsService struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html
 type Group struct {
-	ID                    int                        `json:"id"`
-	Name                  string                     `json:"name"`
-	Path                  string                     `json:"path"`
-	Description           string                     `json:"description"`
-	MembershipLock        bool                       `json:"membership_lock"`
-	Visibility            VisibilityValue            `json:"visibility"`
-	LFSEnabled            bool                       `json:"lfs_enabled"`
-	AvatarURL             string                     `json:"avatar_url"`
-	WebURL                string                     `json:"web_url"`
-	RequestAccessEnabled  bool                       `json:"request_access_enabled"`
-	FullName              string                     `json:"full_name"`
-	FullPath              string                     `json:"full_path"`
-	ParentID              int                        `json:"parent_id"`
-	Projects              []*Project                 `json:"projects"`
-	Statistics            *StorageStatistics         `json:"statistics"`
-	CustomAttributes      []*CustomAttribute         `json:"custom_attributes"`
-	ShareWithGroupLock    bool                       `json:"share_with_group_lock"`
-	RequireTwoFactorAuth  bool                       `json:"require_two_factor_authentication"`
-	TwoFactorGracePeriod  int                        `json:"two_factor_grace_period"`
-	ProjectCreationLevel  ProjectCreationLevelValue  `json:"project_creation_level"`
-	AutoDevopsEnabled     bool                       `json:"auto_devops_enabled"`
-	SubGroupCreationLevel SubGroupCreationLevelValue `json:"subgroup_creation_level"`
-	EmailsDisabled        bool                       `json:"emails_disabled"`
-	MentionsDisabled      bool                       `json:"mentions_disabled"`
-	RunnersToken          string                     `json:"runners_token"`
-	SharedProjects        []*Project                 `json:"shared_projects"`
-	SharedWithGroups      []struct {
-		GroupID          int      `json:"group_id"`
-		GroupName        string   `json:"group_name"`
-		GroupFullPath    string   `json:"group_full_path"`
-		GroupAccessLevel int      `json:"group_access_level"`
-		ExpiresAt        *ISOTime `json:"expires_at"`
-	} `json:"shared_with_groups"`
-	LDAPCN                         string           `json:"ldap_cn"`
-	LDAPAccess                     AccessLevelValue `json:"ldap_access"`
-	LDAPGroupLinks                 []*LDAPGroupLink `json:"ldap_group_links"`
-	SharedRunnersMinutesLimit      int              `json:"shared_runners_minutes_limit"`
-	ExtraSharedRunnersMinutesLimit int              `json:"extra_shared_runners_minutes_limit"`
-	MarkedForDeletionOn            *ISOTime         `json:"marked_for_deletion_on"`
-	CreatedAt                      *time.Time       `json:"created_at"`
+	ID                             int                        `json:"id"`
+	Name                           string                     `json:"name"`
+	Path                           string                     `json:"path"`
+	Description                    string                     `json:"description"`
+	MembershipLock                 bool                       `json:"membership_lock"`
+	Visibility                     VisibilityValue            `json:"visibility"`
+	LFSEnabled                     bool                       `json:"lfs_enabled"`
+	AvatarURL                      string                     `json:"avatar_url"`
+	WebURL                         string                     `json:"web_url"`
+	RequestAccessEnabled           bool                       `json:"request_access_enabled"`
+	FullName                       string                     `json:"full_name"`
+	FullPath                       string                     `json:"full_path"`
+	ParentID                       int                        `json:"parent_id"`
+	Projects                       []*Project                 `json:"projects"`
+	Statistics                     *StorageStatistics         `json:"statistics"`
+	CustomAttributes               []*CustomAttribute         `json:"custom_attributes"`
+	ShareWithGroupLock             bool                       `json:"share_with_group_lock"`
+	RequireTwoFactorAuth           bool                       `json:"require_two_factor_authentication"`
+	TwoFactorGracePeriod           int                        `json:"two_factor_grace_period"`
+	ProjectCreationLevel           ProjectCreationLevelValue  `json:"project_creation_level"`
+	AutoDevopsEnabled              bool                       `json:"auto_devops_enabled"`
+	SubGroupCreationLevel          SubGroupCreationLevelValue `json:"subgroup_creation_level"`
+	EmailsDisabled                 bool                       `json:"emails_disabled"`
+	MentionsDisabled               bool                       `json:"mentions_disabled"`
+	RunnersToken                   string                     `json:"runners_token"`
+	SharedProjects                 []*Project                 `json:"shared_projects"`
+	LDAPCN                         string                     `json:"ldap_cn"`
+	LDAPAccess                     AccessLevelValue           `json:"ldap_access"`
+	LDAPGroupLinks                 []*LDAPGroupLink           `json:"ldap_group_links"`
+	SharedRunnersMinutesLimit      int                        `json:"shared_runners_minutes_limit"`
+	ExtraSharedRunnersMinutesLimit int                        `json:"extra_shared_runners_minutes_limit"`
+	MarkedForDeletionOn            *ISOTime                   `json:"marked_for_deletion_on"`
+	CreatedAt                      *time.Time                 `json:"created_at"`
 }
 
 type LDAPGroupLink struct {
@@ -398,7 +391,7 @@ func (s *GroupsService) ListGroupLDAPLinks(gid interface{}, options ...RequestOp
 type AddGroupLDAPLinkOptions struct {
 	CN          *string `url:"cn,omitempty" json:"cn,omitempty"`
 	GroupAccess *int    `url:"group_access,omitempty" json:"group_access,omitempty"`
-	Provider    *string `url:"provider,omitempty" json:"provider,omitempty"`
+	Provider    *string `url:"provider,omitempty" json:"provider,ommitempty"`
 }
 
 // AddGroupLDAPLink creates a new group LDAP link. Available only for users who
diff --git a/instance_clusters.go b/instance_clusters.go
index 4156854..9a62268 100644
--- a/instance_clusters.go
+++ b/instance_clusters.go
@@ -37,6 +37,7 @@ type InstanceCluster struct {
 	ID                 int                 `json:"id"`
 	Name               string              `json:"name"`
 	Domain             string              `json:"domain"`
+	Managed            bool                `json:"managed"`
 	CreatedAt          *time.Time          `json:"created_at"`
 	ProviderType       string              `json:"provider_type"`
 	PlatformType       string              `json:"platform_type"`
@@ -56,7 +57,7 @@ func (v InstanceCluster) String() string {
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/instance_clusters.html#list-instance-clusters
 func (s *InstanceClustersService) ListClusters(options ...RequestOptionFunc) ([]*InstanceCluster, *Response, error) {
-	u := "admin/clusters"
+	u := fmt.Sprintf("admin/clusters")
 
 	req, err := s.client.NewRequest("GET", u, nil, options)
 	if err != nil {
@@ -98,7 +99,7 @@ func (s *InstanceClustersService) GetCluster(cluster int, options ...RequestOpti
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/instance_clusters.html#add-existing-instance-cluster
 func (s *InstanceClustersService) AddCluster(opt *AddClusterOptions, options ...RequestOptionFunc) (*InstanceCluster, *Response, error) {
-	u := "admin/clusters/add"
+	u := fmt.Sprintf("admin/clusters/add")
 
 	req, err := s.client.NewRequest("POST", u, opt, options)
 	if err != nil {
diff --git a/instance_variables.go b/instance_variables.go
deleted file mode 100644
index 0d4006b..0000000
--- a/instance_variables.go
+++ /dev/null
@@ -1,179 +0,0 @@
-//
-// Copyright 2018, Patrick Webster
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package gitlab
-
-import (
-	"fmt"
-	"net/url"
-)
-
-// InstanceVariablesService handles communication with the
-// instance level CI variables related methods of the GitLab API.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html
-type InstanceVariablesService struct {
-	client *Client
-}
-
-// InstanceVariable represents a GitLab instance level CI Variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html
-type InstanceVariable struct {
-	Key          string            `json:"key"`
-	Value        string            `json:"value"`
-	VariableType VariableTypeValue `json:"variable_type"`
-	Protected    bool              `json:"protected"`
-	Masked       bool              `json:"masked"`
-}
-
-func (v InstanceVariable) String() string {
-	return Stringify(v)
-}
-
-// ListInstanceVariablesOptions represents the available options for listing variables
-// for an instance.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables
-type ListInstanceVariablesOptions ListOptions
-
-// ListVariables gets a list of all variables for an instance.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#list-all-instance-variables
-func (s *InstanceVariablesService) ListVariables(opt *ListInstanceVariablesOptions, options ...RequestOptionFunc) ([]*InstanceVariable, *Response, error) {
-	u := "admin/ci/variables"
-
-	req, err := s.client.NewRequest("GET", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var vs []*InstanceVariable
-	resp, err := s.client.Do(req, &vs)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return vs, resp, err
-}
-
-// GetVariable gets a variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#show-instance-variable-details
-func (s *InstanceVariablesService) GetVariable(key string, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
-	u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
-
-	req, err := s.client.NewRequest("GET", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	v := new(InstanceVariable)
-	resp, err := s.client.Do(req, v)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return v, resp, err
-}
-
-// CreateInstanceVariableOptions represents the available CreateVariable()
-// options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable
-type CreateInstanceVariableOptions struct {
-	Key          *string            `url:"key,omitempty" json:"key,omitempty"`
-	Value        *string            `url:"value,omitempty" json:"value,omitempty"`
-	VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
-	Protected    *bool              `url:"protected,omitempty" json:"protected,omitempty"`
-	Masked       *bool              `url:"masked,omitempty" json:"masked,omitempty"`
-}
-
-// CreateVariable creates a new instance level CI variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#create-instance-variable
-func (s *InstanceVariablesService) CreateVariable(opt *CreateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
-	u := "admin/ci/variables"
-
-	req, err := s.client.NewRequest("POST", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	v := new(InstanceVariable)
-	resp, err := s.client.Do(req, v)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return v, resp, err
-}
-
-// UpdateInstanceVariableOptions represents the available UpdateVariable()
-// options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable
-type UpdateInstanceVariableOptions struct {
-	Value        *string            `url:"value,omitempty" json:"value,omitempty"`
-	VariableType *VariableTypeValue `url:"variable_type,omitempty" json:"variable_type,omitempty"`
-	Protected    *bool              `url:"protected,omitempty" json:"protected,omitempty"`
-	Masked       *bool              `url:"masked,omitempty" json:"masked,omitempty"`
-}
-
-// UpdateVariable updates the position of an existing
-// instance level CI variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#update-instance-variable
-func (s *InstanceVariablesService) UpdateVariable(key string, opt *UpdateInstanceVariableOptions, options ...RequestOptionFunc) (*InstanceVariable, *Response, error) {
-	u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
-
-	req, err := s.client.NewRequest("PUT", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	v := new(InstanceVariable)
-	resp, err := s.client.Do(req, v)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return v, resp, err
-}
-
-// RemoveVariable removes an instance level CI variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/instance_level_ci_variables.html#remove-instance-variable
-func (s *InstanceVariablesService) RemoveVariable(key string, options ...RequestOptionFunc) (*Response, error) {
-	u := fmt.Sprintf("admin/ci/variables/%s", url.PathEscape(key))
-
-	req, err := s.client.NewRequest("DELETE", u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/issues.go b/issues.go
index 4670b3c..220aa77 100644
--- a/issues.go
+++ b/issues.go
@@ -17,7 +17,6 @@
 package gitlab
 
 import (
-	"bytes"
 	"encoding/json"
 	"fmt"
 	"net/url"
@@ -114,7 +113,6 @@ type Issue struct {
 	IssueLinkID          int              `json:"issue_link_id"`
 	MergeRequestCount    int              `json:"merge_requests_count"`
 	EpicIssueID          int              `json:"epic_issue_id"`
-	Epic                 *Epic            `json:"epic"`
 	TaskCompletionStatus struct {
 		Count          int `json:"count"`
 		CompletedCount int `json:"completed_count"`
@@ -164,21 +162,9 @@ type Labels []string
 
 // MarshalJSON implements the json.Marshaler interface.
 func (l *Labels) MarshalJSON() ([]byte, error) {
-	if *l == nil {
-		return []byte(`null`), nil
-	}
 	return json.Marshal(strings.Join(*l, ","))
 }
 
-// UnmarshalJSON implements the json.Unmarshaler interface.
-func (l *Labels) UnmarshalJSON(data []byte) error {
-	type alias Labels
-	if !bytes.HasPrefix(data, []byte("[")) {
-		data = []byte(fmt.Sprintf("[%s]", string(data)))
-	}
-	return json.Unmarshal(data, (*alias)(l))
-}
-
 // EncodeValues implements the query.EncodeValues interface
 func (l *Labels) EncodeValues(key string, v *url.Values) error {
 	v.Set(key, strings.Join(*l, ","))
@@ -200,29 +186,23 @@ type LabelDetails struct {
 // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues
 type ListIssuesOptions struct {
 	ListOptions
-	State              *string    `url:"state,omitempty" json:"state,omitempty"`
-	Labels             Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	NotLabels          Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
-	WithLabelDetails   *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
-	Milestone          *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
-	NotMilestone       *string    `url:"not[milestone],omitempty" json:"not[milestone],omitempty"`
-	Scope              *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID           *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	NotAuthorID        []int      `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
-	AssigneeID         *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	NotAssigneeID      []int      `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"`
-	AssigneeUsername   *string    `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji    *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	NotMyReactionEmoji []string   `url:"not[my_reaction_emoji],omitempty" json:"not[my_reaction_emoji],omitempty"`
-	IIDs               []int      `url:"iids[],omitempty" json:"iids,omitempty"`
-	OrderBy            *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Sort               *string    `url:"sort,omitempty" json:"sort,omitempty"`
-	Search             *string    `url:"search,omitempty" json:"search,omitempty"`
-	CreatedAfter       *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore      *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter       *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore      *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	Confidential       *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
+	State            *string    `url:"state,omitempty" json:"state,omitempty"`
+	Labels           Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	WithLabelDetails *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
+	Milestone        *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
+	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
+	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
+	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
+	IIDs             []int      `url:"iids[],omitempty" json:"iids,omitempty"`
+	OrderBy          *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort             *string    `url:"sort,omitempty" json:"sort,omitempty"`
+	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
+	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
+	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
+	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
+	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
+	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
 }
 
 // ListIssues gets all issues created by authenticated user. This function
@@ -249,30 +229,25 @@ func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...RequestOpt
 // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues
 type ListGroupIssuesOptions struct {
 	ListOptions
-	State              *string    `url:"state,omitempty" json:"state,omitempty"`
-	Labels             Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	NotLabels          Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
-	WithLabelDetails   *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
-	IIDs               []int      `url:"iids[],omitempty" json:"iids,omitempty"`
-	Milestone          *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
-	NotMilestone       *string    `url:"not[milestone],omitempty" json:"not[milestone],omitempty"`
-	Scope              *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID           *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	NotAuthorID        []int      `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
-	AuthorUsername     *string    `url:"author_username,omitempty" json:"author_username,omitempty"`
-	AssigneeID         *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	NotAssigneeID      []int      `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"`
-	AssigneeUsername   *string    `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji    *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	NotMyReactionEmoji []string   `url:"not[my_reaction_emoji],omitempty" json:"not[my_reaction_emoji],omitempty"`
-	OrderBy            *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Sort               *string    `url:"sort,omitempty" json:"sort,omitempty"`
-	Search             *string    `url:"search,omitempty" json:"search,omitempty"`
-	In                 *string    `url:"in,omitempty" json:"in,omitempty"`
-	CreatedAfter       *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore      *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter       *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore      *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
+	State            *string    `url:"state,omitempty" json:"state,omitempty"`
+	Labels           Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	WithLabelDetails *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
+	IIDs             []int      `url:"iids[],omitempty" json:"iids,omitempty"`
+	Milestone        *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
+	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
+	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
+	AuthorUsername   *string    `url:"author_username,omitempty" json:"author_username,omitempty"`
+	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	AssigneeUsername *string    `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
+	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
+	OrderBy          *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort             *string    `url:"sort,omitempty" json:"sort,omitempty"`
+	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
+	In               *string    `url:"in,omitempty" json:"in,omitempty"`
+	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
+	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
+	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
+	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
 }
 
 // ListGroupIssues gets a list of group issues. This function accepts
@@ -305,30 +280,24 @@ func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOpt
 // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues
 type ListProjectIssuesOptions struct {
 	ListOptions
-	IIDs               []int      `url:"iids[],omitempty" json:"iids,omitempty"`
-	State              *string    `url:"state,omitempty" json:"state,omitempty"`
-	Labels             Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	NotLabels          Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
-	WithLabelDetails   *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
-	Milestone          *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
-	NotMilestone       []string   `url:"not[milestone],omitempty" json:"not[milestone],omitempty"`
-	Scope              *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID           *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	NotAuthorID        []int      `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
-	AssigneeID         *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	NotAssigneeID      []int      `url:"not[assignee_id],omitempty" json:"not[assignee_id],omitempty"`
-	AssigneeUsername   *string    `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji    *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	NotMyReactionEmoji []string   `url:"not[my_reaction_emoji],omitempty" json:"not[my_reaction_emoji],omitempty"`
-	OrderBy            *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Sort               *string    `url:"sort,omitempty" json:"sort,omitempty"`
-	Search             *string    `url:"search,omitempty" json:"search,omitempty"`
-	In                 *string    `url:"in,omitempty" json:"in,omitempty"`
-	CreatedAfter       *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore      *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter       *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore      *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	Confidential       *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
+	IIDs             []int      `url:"iids[],omitempty" json:"iids,omitempty"`
+	State            *string    `url:"state,omitempty" json:"state,omitempty"`
+	Labels           Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	WithLabelDetails *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
+	Milestone        *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
+	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
+	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
+	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
+	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
+	OrderBy          *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort             *string    `url:"sort,omitempty" json:"sort,omitempty"`
+	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
+	In               *string    `url:"in,omitempty" json:"in,omitempty"`
+	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
+	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
+	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
+	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
+	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
 }
 
 // ListProjectIssues gets a list of project issues. This function accepts
@@ -390,7 +359,7 @@ type CreateIssueOptions struct {
 	Confidential                       *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
 	AssigneeIDs                        []int      `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
 	MilestoneID                        *int       `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
-	Labels                             Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	Labels                             *Labels    `url:"labels,comma,omitempty" json:"labels,omitempty"`
 	CreatedAt                          *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"`
 	DueDate                            *ISOTime   `url:"due_date,omitempty" json:"due_date,omitempty"`
 	MergeRequestToResolveDiscussionsOf *int       `url:"merge_request_to_resolve_discussions_of,omitempty" json:"merge_request_to_resolve_discussions_of,omitempty"`
@@ -431,9 +400,7 @@ type UpdateIssueOptions struct {
 	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
 	AssigneeIDs      []int      `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
 	MilestoneID      *int       `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
-	Labels           Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	AddLabels        Labels     `url:"add_labels,comma,omitempty" json:"add_labels,omitempty"`
-	RemoveLabels     Labels     `url:"remove_labels,comma,omitempty" json:"remove_labels,omitempty"`
+	Labels           *Labels    `url:"labels,comma,omitempty" json:"labels,omitempty"`
 	StateEvent       *string    `url:"state_event,omitempty" json:"state_event,omitempty"`
 	UpdatedAt        *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"`
 	DueDate          *ISOTime   `url:"due_date,omitempty" json:"due_date,omitempty"`
@@ -678,28 +645,3 @@ func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...Re
 func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...RequestOptionFunc) (*TimeStats, *Response, error) {
 	return s.timeStats.getTimeSpent(pid, "issues", issue, options...)
 }
-
-// GetParticipants gets a list of issue participants.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/issues.html#participants-on-issues
-func (s *IssuesService) GetParticipants(pid interface{}, issue int, options ...RequestOptionFunc) ([]*BasicUser, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/issues/%d/participants", pathEscape(project), issue)
-
-	req, err := s.client.NewRequest("GET", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var bu []*BasicUser
-	resp, err := s.client.Do(req, &bu)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return bu, resp, err
-}
diff --git a/issues_statistics.go b/issues_statistics.go
deleted file mode 100644
index 990544a..0000000
--- a/issues_statistics.go
+++ /dev/null
@@ -1,186 +0,0 @@
-//
-// Copyright 2017, Sander van Harmelen
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-package gitlab
-
-import (
-	"fmt"
-	"time"
-)
-
-// IssuesStatisticsService handles communication with the issues statistics
-// related methods of the GitLab API.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html
-type IssuesStatisticsService struct {
-	client *Client
-}
-
-// IssuesStatistics represents a GitLab issues statistic.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/issues_statistics.html
-type IssuesStatistics struct {
-	Statistics struct {
-		Counts struct {
-			All    int `json:"all"`
-			Closed int `json:"closed"`
-			Opened int `json:"opened"`
-		} `json:"counts"`
-	} `json:"statistics"`
-}
-
-func (n IssuesStatistics) String() string {
-	return Stringify(n)
-}
-
-// GetIssuesStatisticsOptions represents the available GetIssuesStatistics() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics
-type GetIssuesStatisticsOptions struct {
-	Labels           Labels     `url:"labels,omitempty" json:"labels,omitempty"`
-	Milestone        *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
-	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	AuthorUsername   *string    `url:"author_username,omitempty" json:"author_username,omitempty"`
-	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	AssigneeUsername []string   `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	IIDs             []int      `url:"iids,omitempty" json:"iids,omitempty"`
-	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
-	In               *string    `url:"in,omitempty" json:"in,omitempty"`
-	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
-}
-
-// GetIssuesStatistics gets issues statistics on all issues the authenticated
-// user has access to.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-issues-statistics
-func (s *IssuesStatisticsService) GetIssuesStatistics(opt *GetIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) {
-	req, err := s.client.NewRequest("GET", "issues_statistics", opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	is := new(IssuesStatistics)
-	resp, err := s.client.Do(req, is)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return is, resp, err
-}
-
-// GetGroupIssuesStatisticsOptions represents the available GetGroupIssuesStatistics()
-// options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics
-type GetGroupIssuesStatisticsOptions struct {
-	Labels           Labels     `url:"labels,omitempty" json:"labels,omitempty"`
-	IIDs             []int      `url:"iids,omitempty" json:"iids,omitempty"`
-	Milestone        *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"`
-	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	AuthorUsername   *string    `url:"author_username,omitempty" json:"author_username,omitempty"`
-	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	AssigneeUsername []string   `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
-	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
-}
-
-// GetGroupIssuesStatistics gets issues count statistics for given group.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-group-issues-statistics
-func (s *IssuesStatisticsService) GetGroupIssuesStatistics(gid interface{}, opt *GetGroupIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/issues_statistics", pathEscape(group))
-
-	req, err := s.client.NewRequest("GET", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	is := new(IssuesStatistics)
-	resp, err := s.client.Do(req, is)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return is, resp, err
-}
-
-// GetProjectIssuesStatisticsOptions represents the available
-// GetProjectIssuesStatistics() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics
-type GetProjectIssuesStatisticsOptions struct {
-	IIDs             []int      `url:"iids,omitempty" json:"iids,omitempty"`
-	Labels           Labels     `url:"labels,omitempty" json:"labels,omitempty"`
-	Milestone        *Milestone `url:"milestone,omitempty" json:"milestone,omitempty"`
-	Scope            *string    `url:"scope,omitempty" json:"scope,omitempty"`
-	AuthorID         *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
-	AuthorUsername   *string    `url:"author_username,omitempty" json:"author_username,omitempty"`
-	AssigneeID       *int       `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
-	AssigneeUsername []string   `url:"assignee_username,omitempty" json:"assignee_username,omitempty"`
-	MyReactionEmoji  *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
-	Search           *string    `url:"search,omitempty" json:"search,omitempty"`
-	CreatedAfter     *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore    *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
-	UpdatedAfter     *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore    *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	Confidential     *bool      `url:"confidential,omitempty" json:"confidential,omitempty"`
-}
-
-// GetProjectIssuesStatistics gets issues count statistics for given project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics
-func (s *IssuesStatisticsService) GetProjectIssuesStatistics(pid interface{}, opt *GetProjectIssuesStatisticsOptions, options ...RequestOptionFunc) (*IssuesStatistics, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/issues_statistics", pathEscape(project))
-
-	req, err := s.client.NewRequest("GET", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	is := new(IssuesStatistics)
-	resp, err := s.client.Do(req, is)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return is, resp, err
-}
diff --git a/merge_requests.go b/merge_requests.go
index 02e951d..bcd41d3 100644
--- a/merge_requests.go
+++ b/merge_requests.go
@@ -139,7 +139,6 @@ type ListMergeRequestsOptions struct {
 	Milestone       *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
 	View            *string    `url:"view,omitempty" json:"view,omitempty"`
 	Labels          Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	NotLabels       Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
 	CreatedAfter    *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
 	CreatedBefore   *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
 	UpdatedAfter    *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
@@ -189,8 +188,7 @@ type ListGroupMergeRequestsOptions struct {
 	Sort            *string    `url:"sort,omitempty" json:"sort,omitempty"`
 	Milestone       *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
 	View            *string    `url:"view,omitempty" json:"view,omitempty"`
-	Labels          Labels     `url:"labels,omitempty" json:"labels,omitempty"`
-	NotLabels       Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
+	Labels          *Labels    `url:"labels,omitempty" json:"labels,omitempty"`
 	CreatedAfter    *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
 	CreatedBefore   *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
 	UpdatedAfter    *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
@@ -242,8 +240,7 @@ type ListProjectMergeRequestsOptions struct {
 	Sort            *string    `url:"sort,omitempty" json:"sort,omitempty"`
 	Milestone       *string    `url:"milestone,omitempty" json:"milestone,omitempty"`
 	View            *string    `url:"view,omitempty" json:"view,omitempty"`
-	Labels          Labels     `url:"labels,comma,omitempty" json:"labels,omitempty"`
-	NotLabels       Labels     `url:"not[labels],comma,omitempty" json:"not[labels],omitempty"`
+	Labels          *Labels    `url:"labels,omitempty" json:"labels,omitempty"`
 	CreatedAfter    *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
 	CreatedBefore   *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
 	UpdatedAfter    *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
@@ -452,31 +449,6 @@ func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeR
 	return p, resp, err
 }
 
-// CreateMergeRequestPipeline creates a new pipeline for a merge request.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr-pipeline
-func (s *MergeRequestsService) CreateMergeRequestPipeline(pid interface{}, mergeRequest int, options ...RequestOptionFunc) (*PipelineInfo, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/merge_requests/%d/pipelines", pathEscape(project), mergeRequest)
-
-	req, err := s.client.NewRequest("POST", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	p := new(PipelineInfo)
-	resp, err := s.client.Do(req, p)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return p, resp, err
-}
-
 // GetIssuesClosedOnMergeOptions represents the available GetIssuesClosedOnMerge()
 // options.
 //
@@ -520,7 +492,7 @@ type CreateMergeRequestOptions struct {
 	Description        *string `url:"description,omitempty" json:"description,omitempty"`
 	SourceBranch       *string `url:"source_branch,omitempty" json:"source_branch,omitempty"`
 	TargetBranch       *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
-	Labels             Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	Labels             *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
 	AssigneeID         *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	AssigneeIDs        []int   `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
 	TargetProjectID    *int    `url:"target_project_id,omitempty" json:"target_project_id,omitempty"`
@@ -566,7 +538,7 @@ type UpdateMergeRequestOptions struct {
 	TargetBranch       *string `url:"target_branch,omitempty" json:"target_branch,omitempty"`
 	AssigneeID         *int    `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	AssigneeIDs        []int   `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"`
-	Labels             Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
+	Labels             *Labels `url:"labels,comma,omitempty" json:"labels,omitempty"`
 	MilestoneID        *int    `url:"milestone_id,omitempty" json:"milestone_id,omitempty"`
 	StateEvent         *string `url:"state_event,omitempty" json:"state_event,omitempty"`
 	RemoveSourceBranch *bool   `url:"remove_source_branch,omitempty" json:"remove_source_branch,omitempty"`
diff --git a/milestones.go b/milestones.go
index 3d881d5..eb3e3a3 100644
--- a/milestones.go
+++ b/milestones.go
@@ -44,7 +44,6 @@ type Milestone struct {
 	WebURL      string     `json:"web_url"`
 	UpdatedAt   *time.Time `json:"updated_at"`
 	CreatedAt   *time.Time `json:"created_at"`
-	Expired     *bool      `json:"expired"`
 }
 
 func (m Milestone) String() string {
diff --git a/pipeline_schedules.go b/pipeline_schedules.go
index b57adcf..b9eaa53 100644
--- a/pipeline_schedules.go
+++ b/pipeline_schedules.go
@@ -230,25 +230,6 @@ func (s *PipelineSchedulesService) DeletePipelineSchedule(pid interface{}, sched
 	return s.client.Do(req, nil)
 }
 
-// RunPipelineSchedule triggers a new scheduled pipeline to run immediately.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ce/api/pipeline_schedules.html#run-a-scheduled-pipeline-immediately
-func (s *PipelineSchedulesService) RunPipelineSchedule(pid interface{}, schedule int, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/play", pathEscape(project), schedule)
-
-	req, err := s.client.NewRequest("POST", u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
 // CreatePipelineScheduleVariableOptions represents the available
 // CreatePipelineScheduleVariable() options.
 //
diff --git a/project_members.go b/project_members.go
index 0a1b57f..0b41678 100644
--- a/project_members.go
+++ b/project_members.go
@@ -117,31 +117,6 @@ func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, opti
 	return pm, resp, err
 }
 
-// GetInheritedProjectMember gets a project team member, including inherited
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project-including-inherited-members
-func (s *ProjectMembersService) GetInheritedProjectMember(pid interface{}, user int, options ...RequestOptionFunc) (*ProjectMember, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/members/all/%d", pathEscape(project), user)
-
-	req, err := s.client.NewRequest("GET", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	pm := new(ProjectMember)
-	resp, err := s.client.Do(req, pm)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return pm, resp, err
-}
-
 // AddProjectMemberOptions represents the available AddProjectMember() options.
 //
 // GitLab API docs:
diff --git a/projects.go b/projects.go
index ff5d8fe..faaf54e 100644
--- a/projects.go
+++ b/projects.go
@@ -38,69 +38,57 @@ type ProjectsService struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html
 type Project struct {
-	ID                                        int                `json:"id"`
-	Description                               string             `json:"description"`
-	DefaultBranch                             string             `json:"default_branch"`
-	Public                                    bool               `json:"public"`
-	Visibility                                VisibilityValue    `json:"visibility"`
-	SSHURLToRepo                              string             `json:"ssh_url_to_repo"`
-	HTTPURLToRepo                             string             `json:"http_url_to_repo"`
-	WebURL                                    string             `json:"web_url"`
-	ReadmeURL                                 string             `json:"readme_url"`
-	TagList                                   []string           `json:"tag_list"`
-	Owner                                     *User              `json:"owner"`
-	Name                                      string             `json:"name"`
-	NameWithNamespace                         string             `json:"name_with_namespace"`
-	Path                                      string             `json:"path"`
-	PathWithNamespace                         string             `json:"path_with_namespace"`
-	IssuesEnabled                             bool               `json:"issues_enabled"`
-	OpenIssuesCount                           int                `json:"open_issues_count"`
-	MergeRequestsEnabled                      bool               `json:"merge_requests_enabled"`
-	ApprovalsBeforeMerge                      int                `json:"approvals_before_merge"`
-	JobsEnabled                               bool               `json:"jobs_enabled"`
-	WikiEnabled                               bool               `json:"wiki_enabled"`
-	SnippetsEnabled                           bool               `json:"snippets_enabled"`
-	ResolveOutdatedDiffDiscussions            bool               `json:"resolve_outdated_diff_discussions"`
-	ContainerRegistryEnabled                  bool               `json:"container_registry_enabled"`
-	CreatedAt                                 *time.Time         `json:"created_at,omitempty"`
-	LastActivityAt                            *time.Time         `json:"last_activity_at,omitempty"`
-	CreatorID                                 int                `json:"creator_id"`
-	Namespace                                 *ProjectNamespace  `json:"namespace"`
-	ImportStatus                              string             `json:"import_status"`
-	ImportError                               string             `json:"import_error"`
-	Permissions                               *Permissions       `json:"permissions"`
-	MarkedForDeletionAt                       *ISOTime           `json:"marked_for_deletion_at"`
-	Archived                                  bool               `json:"archived"`
-	AvatarURL                                 string             `json:"avatar_url"`
-	SharedRunnersEnabled                      bool               `json:"shared_runners_enabled"`
-	ForksCount                                int                `json:"forks_count"`
-	StarCount                                 int                `json:"star_count"`
-	RunnersToken                              string             `json:"runners_token"`
-	PublicBuilds                              bool               `json:"public_builds"`
-	OnlyAllowMergeIfPipelineSucceeds          bool               `json:"only_allow_merge_if_pipeline_succeeds"`
-	OnlyAllowMergeIfAllDiscussionsAreResolved bool               `json:"only_allow_merge_if_all_discussions_are_resolved"`
-	RemoveSourceBranchAfterMerge              bool               `json:"remove_source_branch_after_merge"`
-	LFSEnabled                                bool               `json:"lfs_enabled"`
-	RequestAccessEnabled                      bool               `json:"request_access_enabled"`
-	MergeMethod                               MergeMethodValue   `json:"merge_method"`
-	ForkedFromProject                         *ForkParent        `json:"forked_from_project"`
-	Mirror                                    bool               `json:"mirror"`
-	MirrorUserID                              int                `json:"mirror_user_id"`
-	MirrorTriggerBuilds                       bool               `json:"mirror_trigger_builds"`
-	OnlyMirrorProtectedBranches               bool               `json:"only_mirror_protected_branches"`
-	MirrorOverwritesDivergedBranches          bool               `json:"mirror_overwrites_diverged_branches"`
-	PackagesEnabled                           bool               `json:"packages_enabled"`
-	ServiceDeskEnabled                        bool               `json:"service_desk_enabled"`
-	ServiceDeskAddress                        string             `json:"service_desk_address"`
-	IssuesAccessLevel                         AccessControlValue `json:"issues_access_level"`
-	RepositoryAccessLevel                     AccessControlValue `json:"repository_access_level"`
-	MergeRequestsAccessLevel                  AccessControlValue `json:"merge_requests_access_level"`
-	ForkingAccessLevel                        AccessControlValue `json:"forking_access_level"`
-	WikiAccessLevel                           AccessControlValue `json:"wiki_access_level"`
-	BuildsAccessLevel                         AccessControlValue `json:"builds_access_level"`
-	SnippetsAccessLevel                       AccessControlValue `json:"snippets_access_level"`
-	PagesAccessLevel                          AccessControlValue `json:"pages_access_level"`
-	AutocloseReferencedIssues                 bool               `json:"autoclose_referenced_issues"`
+	ID                                        int               `json:"id"`
+	Description                               string            `json:"description"`
+	DefaultBranch                             string            `json:"default_branch"`
+	Public                                    bool              `json:"public"`
+	Visibility                                VisibilityValue   `json:"visibility"`
+	SSHURLToRepo                              string            `json:"ssh_url_to_repo"`
+	HTTPURLToRepo                             string            `json:"http_url_to_repo"`
+	WebURL                                    string            `json:"web_url"`
+	ReadmeURL                                 string            `json:"readme_url"`
+	TagList                                   []string          `json:"tag_list"`
+	Owner                                     *User             `json:"owner"`
+	Name                                      string            `json:"name"`
+	NameWithNamespace                         string            `json:"name_with_namespace"`
+	Path                                      string            `json:"path"`
+	PathWithNamespace                         string            `json:"path_with_namespace"`
+	IssuesEnabled                             bool              `json:"issues_enabled"`
+	OpenIssuesCount                           int               `json:"open_issues_count"`
+	MergeRequestsEnabled                      bool              `json:"merge_requests_enabled"`
+	ApprovalsBeforeMerge                      int               `json:"approvals_before_merge"`
+	JobsEnabled                               bool              `json:"jobs_enabled"`
+	WikiEnabled                               bool              `json:"wiki_enabled"`
+	SnippetsEnabled                           bool              `json:"snippets_enabled"`
+	ResolveOutdatedDiffDiscussions            bool              `json:"resolve_outdated_diff_discussions"`
+	ContainerRegistryEnabled                  bool              `json:"container_registry_enabled"`
+	CreatedAt                                 *time.Time        `json:"created_at,omitempty"`
+	LastActivityAt                            *time.Time        `json:"last_activity_at,omitempty"`
+	CreatorID                                 int               `json:"creator_id"`
+	Namespace                                 *ProjectNamespace `json:"namespace"`
+	ImportStatus                              string            `json:"import_status"`
+	ImportError                               string            `json:"import_error"`
+	Permissions                               *Permissions      `json:"permissions"`
+	MarkedForDeletionAt                       *ISOTime          `json:"marked_for_deletion_at"`
+	Archived                                  bool              `json:"archived"`
+	AvatarURL                                 string            `json:"avatar_url"`
+	SharedRunnersEnabled                      bool              `json:"shared_runners_enabled"`
+	ForksCount                                int               `json:"forks_count"`
+	StarCount                                 int               `json:"star_count"`
+	RunnersToken                              string            `json:"runners_token"`
+	PublicBuilds                              bool              `json:"public_builds"`
+	OnlyAllowMergeIfPipelineSucceeds          bool              `json:"only_allow_merge_if_pipeline_succeeds"`
+	OnlyAllowMergeIfAllDiscussionsAreResolved bool              `json:"only_allow_merge_if_all_discussions_are_resolved"`
+	RemoveSourceBranchAfterMerge              bool              `json:"remove_source_branch_after_merge"`
+	LFSEnabled                                bool              `json:"lfs_enabled"`
+	RequestAccessEnabled                      bool              `json:"request_access_enabled"`
+	MergeMethod                               MergeMethodValue  `json:"merge_method"`
+	ForkedFromProject                         *ForkParent       `json:"forked_from_project"`
+	Mirror                                    bool              `json:"mirror"`
+	MirrorUserID                              int               `json:"mirror_user_id"`
+	MirrorTriggerBuilds                       bool              `json:"mirror_trigger_builds"`
+	OnlyMirrorProtectedBranches               bool              `json:"only_mirror_protected_branches"`
+	MirrorOverwritesDivergedBranches          bool              `json:"mirror_overwrites_diverged_branches"`
 	SharedWithGroups                          []struct {
 		GroupID          int    `json:"group_id"`
 		GroupName        string `json:"group_name"`
@@ -504,12 +492,9 @@ type CreateProjectOptions struct {
 	MirrorTriggerBuilds                       *bool               `url:"mirror_trigger_builds,omitempty" json:"mirror_trigger_builds,omitempty"`
 	InitializeWithReadme                      *bool               `url:"initialize_with_readme,omitempty" json:"initialize_with_readme,omitempty"`
 	TemplateName                              *string             `url:"template_name,omitempty" json:"template_name,omitempty"`
-	TemplateProjectID                         *int                `url:"template_project_id,omitempty" json:"template_project_id,omitempty"`
 	UseCustomTemplate                         *bool               `url:"use_custom_template,omitempty" json:"use_custom_template,omitempty"`
 	GroupWithProjectTemplatesID               *int                `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"`
 	PackagesEnabled                           *bool               `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"`
-	ServiceDeskEnabled                        *bool               `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"`
-	AutocloseReferencedIssues                 *bool               `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"`
 
 	// Deprecated members
 	IssuesEnabled        *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
@@ -612,8 +597,6 @@ type EditProjectOptions struct {
 	OnlyMirrorProtectedBranches               *bool               `url:"only_mirror_protected_branches,omitempty" json:"only_mirror_protected_branches,omitempty"`
 	MirrorOverwritesDivergedBranches          *bool               `url:"mirror_overwrites_diverged_branches,omitempty" json:"mirror_overwrites_diverged_branches,omitempty"`
 	PackagesEnabled                           *bool               `url:"packages_enabled,omitempty" json:"packages_enabled,omitempty"`
-	ServiceDeskEnabled                        *bool               `url:"service_desk_enabled,omitempty" json:"service_desk_enabled,omitempty"`
-	AutocloseReferencedIssues                 *bool               `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"`
 
 	// Deprecated members
 	IssuesEnabled        *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"`
diff --git a/registry.go b/registry.go
index 8694cf9..57f4575 100644
--- a/registry.go
+++ b/registry.go
@@ -190,13 +190,9 @@ func (s *ContainerRegistryService) DeleteRegistryRepositoryTag(pid interface{},
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/container_registry.html#delete-repository-tags-in-bulk
 type DeleteRegistryRepositoryTagsOptions struct {
-	NameRegexpDelete *string `url:"name_regex_delete,omitempty" json:"name_regex_delete,omitempty"`
-	NameRegexpKeep   *string `url:"name_regex_keep,omitempty" json:"name_regex_keep,omitempty"`
-	KeepN            *int    `url:"keep_n,omitempty" json:"keep_n,omitempty"`
-	OlderThan        *string `url:"older_than,omitempty" json:"older_than,omitempty"`
-
-	// Deprecated members
 	NameRegexp *string `url:"name_regex,omitempty" json:"name_regex,omitempty"`
+	KeepN      *int    `url:"keep_n,omitempty" json:"keep_n,omitempty"`
+	OlderThan  *string `url:"older_than,omitempty" json:"older_than,omitempty"`
 }
 
 // DeleteRegistryRepositoryTags deletes repository tags in bulk based on
diff --git a/runners.go b/runners.go
index 96c2346..775c3e1 100644
--- a/runners.go
+++ b/runners.go
@@ -336,44 +336,6 @@ func (s *RunnersService) DisableProjectRunner(pid interface{}, runner int, optio
 	return s.client.Do(req, nil)
 }
 
-// ListGroupsRunnersOptions represents the available ListGroupsRunners() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners
-type ListGroupsRunnersOptions struct {
-	ListOptions
-	Type    *string  `url:"type,omitempty" json:"type,omitempty"`
-	Status  *string  `url:"status,omitempty" json:"status,omitempty"`
-	TagList []string `url:"tag_list,comma,omitempty" json:"tag_list,omitempty"`
-}
-
-// ListGroupsRunners lists all runners (specific and shared) available in the
-// group as well it’s ancestor groups. Shared runners are listed if at least one
-// shared runner is defined.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/runners.html#list-groups-runners
-func (s *RunnersService) ListGroupsRunners(gid interface{}, opt *ListGroupsRunnersOptions, options ...RequestOptionFunc) ([]*Runner, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/runners", pathEscape(group))
-
-	req, err := s.client.NewRequest("GET", u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var rs []*Runner
-	resp, err := s.client.Do(req, &rs)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return rs, resp, err
-}
-
 // RegisterNewRunnerOptions represents the available RegisterNewRunner()
 // options.
 //
diff --git a/services.go b/services.go
index 0f36c4e..fb646f5 100644
--- a/services.go
+++ b/services.go
@@ -54,30 +54,6 @@ type Service struct {
 	WikiPageEvents           bool       `json:"wiki_page_events"`
 }
 
-// ListServices gets a list of all active services.
-//
-// GitLab API docs: https://docs.gitlab.com/ce/api/services.html#list-all-active-services
-func (s *ServicesService) ListServices(pid interface{}, options ...RequestOptionFunc) ([]*Service, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/services", pathEscape(project))
-
-	req, err := s.client.NewRequest("GET", u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var svcs []*Service
-	resp, err := s.client.Do(req, &svcs)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return svcs, resp, err
-}
-
 // DroneCIService represents Drone CI service settings.
 //
 // GitLab API docs:
@@ -700,6 +676,7 @@ type MicrosoftTeamsServiceProperties struct {
 	ConfidentialNoteEvents    BoolValue `json:"confidential_note_events"`
 	PipelineEvents            BoolValue `json:"pipeline_events"`
 	WikiPageEvents            BoolValue `json:"wiki_page_events"`
+
 }
 
 // GetMicrosoftTeamsService gets MicrosoftTeams service settings for a project.
@@ -801,7 +778,6 @@ type PipelinesEmailProperties struct {
 	Recipients                string    `json:"recipients,omitempty"`
 	NotifyOnlyBrokenPipelines BoolValue `json:"notify_only_broken_pipelines,omitempty"`
 	NotifyOnlyDefaultBranch   BoolValue `json:"notify_only_default_branch,omitempty"`
-	BranchesToBeNotified      string    `json:"branches_to_be_notified,omitempty"`
 }
 
 // GetPipelinesEmailService gets Pipelines Email service settings for a project.
diff --git a/tags.go b/tags.go
index 32fdeb4..3c49dc2 100644
--- a/tags.go
+++ b/tags.go
@@ -58,7 +58,6 @@ func (t Tag) String() string {
 type ListTagsOptions struct {
 	ListOptions
 	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Search  *string `url:"search,omitempty" json:"search,omitempty"`
 	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
 }
 
diff --git a/types.go b/types.go
index bebb980..a78b80f 100644
--- a/types.go
+++ b/types.go
@@ -402,11 +402,8 @@ func Time(v time.Time) *time.Time {
 // BoolValue is a boolean value with advanced json unmarshaling features.
 type BoolValue bool
 
-// UnmarshalJSON allows 1, 0, "true", and "false" to be considered as boolean values
-// Needed for:
-// https://gitlab.com/gitlab-org/gitlab-ce/issues/50122
-// https://gitlab.com/gitlab-org/gitlab/-/issues/233941
-// https://github.com/gitlabhq/terraform-provider-gitlab/issues/348
+// UnmarshalJSON allows 1 and 0 to be considered as boolean values
+// Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/50122
 func (t *BoolValue) UnmarshalJSON(b []byte) error {
 	switch string(b) {
 	case `"1"`:
@@ -415,12 +412,6 @@ func (t *BoolValue) UnmarshalJSON(b []byte) error {
 	case `"0"`:
 		*t = false
 		return nil
-	case `"true"`:
-		*t = true
-		return nil
-	case `"false"`:
-		*t = false
-		return nil
 	default:
 		var v bool
 		err := json.Unmarshal(b, &v)
diff --git a/users.go b/users.go
index 9a220b8..2b5a992 100644
--- a/users.go
+++ b/users.go
@@ -59,7 +59,6 @@ type User struct {
 	Email                     string             `json:"email"`
 	Name                      string             `json:"name"`
 	State                     string             `json:"state"`
-	WebURL                    string             `json:"web_url"`
 	CreatedAt                 *time.Time         `json:"created_at"`
 	Bio                       string             `json:"bio"`
 	Location                  string             `json:"location"`


Test patch:
diff --git a/gitlab_test.go b/gitlab_test.go
index ee96093..c522d56 100644
--- a/gitlab_test.go
+++ b/gitlab_test.go
@@ -3,6 +3,7 @@ package gitlab
 import (
 	"bytes"
 	"context"
+	"encoding/json"
 	"errors"
 	"io"
 	"io/ioutil"
@@ -166,6 +167,43 @@ func TestRequestWithContext(t *testing.T) {
 	}
 }
 
+func TestBoolValue(t *testing.T) {
+	testCases := map[string]struct {
+		data     []byte
+		expected bool
+	}{
+		"should unmarshal true as true": {
+			data:     []byte("true"),
+			expected: true,
+		},
+		"should unmarshal false as true": {
+			data:     []byte("false"),
+			expected: false,
+		},
+		"should unmarshal \"1\" as true": {
+			data:     []byte(`"1"`),
+			expected: true,
+		},
+		"should unmarshal \"0\" as false": {
+			data:     []byte(`"0"`),
+			expected: false,
+		},
+	}
+
+	for name, testCase := range testCases {
+		t.Run(name, func(t *testing.T) {
+			var b BoolValue
+			if err := json.Unmarshal(testCase.data, &b); err != nil {
+				t.Fatalf("Unexpected error: %v", err)
+			}
+
+			if bool(b) != testCase.expected {
+				t.Fatalf("Expected %v but got %v", testCase.expected, b)
+			}
+		})
+	}
+}
+
 func loadFixture(filePath string) []byte {
 	content, err := ioutil.ReadFile(filePath)
 	if err != nil {
diff --git a/issues_statistics_test.go b/issues_statistics_test.go
deleted file mode 100644
index d44061e..0000000
--- a/issues_statistics_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package gitlab
-
-import (
-	"fmt"
-	"log"
-	"net/http"
-	"reflect"
-	"testing"
-)
-
-func TestGetIssuesStatistics(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/issues_statistics", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		testURL(t, r, "/api/v4/issues_statistics?assignee_id=1&author_id=1")
-		fmt.Fprint(w, `{"statistics": {"counts": {"all": 20,"closed": 5,"opened": 15}}}`)
-	})
-
-	opt := &GetIssuesStatisticsOptions{
-		AssigneeID: Int(1),
-		AuthorID:   Int(1),
-	}
-
-	issue, _, err := client.IssuesStatistics.GetIssuesStatistics(opt)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := &IssuesStatistics{
-		Statistics: struct {
-			Counts struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			} `json:"counts"`
-		}{
-			Counts: struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			}{
-				20, 5, 15,
-			},
-		},
-	}
-
-	if !reflect.DeepEqual(want, issue) {
-		t.Errorf("IssuesStatistics.GetIssuesStatistics returned %+v, want %+v", issue, want)
-	}
-}
-
-func TestGetGroupIssuesStatistics(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/issues_statistics", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		testURL(t, r, "/api/v4/groups/1/issues_statistics?assignee_id=1&author_id=1")
-		fmt.Fprint(w, `{"statistics": {"counts": {"all": 20,"closed": 5,"opened": 15}}}`)
-	})
-
-	opt := &GetGroupIssuesStatisticsOptions{
-		AssigneeID: Int(1),
-		AuthorID:   Int(1),
-	}
-
-	issue, _, err := client.IssuesStatistics.GetGroupIssuesStatistics(1, opt)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := &IssuesStatistics{
-		Statistics: struct {
-			Counts struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			} `json:"counts"`
-		}{
-			Counts: struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			}{
-				20, 5, 15,
-			},
-		},
-	}
-
-	if !reflect.DeepEqual(want, issue) {
-		t.Errorf("IssuesStatistics.GetGroupIssuesStatistics returned %+v, want %+v", issue, want)
-	}
-}
-
-func TestGetProjectIssuesStatistics(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/issues_statistics", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		testURL(t, r, "/api/v4/projects/1/issues_statistics?assignee_id=1&author_id=1")
-		fmt.Fprint(w, `{"statistics": {"counts": {"all": 20,"closed": 5,"opened": 15}}}`)
-	})
-
-	opt := &GetProjectIssuesStatisticsOptions{
-		AssigneeID: Int(1),
-		AuthorID:   Int(1),
-	}
-
-	issue, _, err := client.IssuesStatistics.GetProjectIssuesStatistics(1, opt)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := &IssuesStatistics{
-		Statistics: struct {
-			Counts struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			} `json:"counts"`
-		}{
-			Counts: struct {
-				All    int `json:"all"`
-				Closed int `json:"closed"`
-				Opened int `json:"opened"`
-			}{
-				20, 5, 15,
-			},
-		},
-	}
-
-	if !reflect.DeepEqual(want, issue) {
-		t.Errorf("IssuesStatistics.GetProjectIssuesStatistics returned %+v, want %+v", issue, want)
-	}
-}
diff --git a/issues_test.go b/issues_test.go
index 0b686c1..d89f879 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -548,28 +548,3 @@ func TestGetTimeSpent(t *testing.T) {
 		t.Errorf("Issues.GetTimeSpent returned %+v, want %+v", timeState, want)
 	}
 }
-
-func TestGetIssueParticipants(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/issues/5/participants", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		testURL(t, r, "/api/v4/projects/1/issues/5/participants")
-
-		fmt.Fprint(w, `[{"id":1,"name":"User1","username":"User1","state":"active","avatar_url":"","web_url":"https://localhost/User1"},
-		{"id":2,"name":"User2","username":"User2","state":"active","avatar_url":"https://localhost/uploads/-/system/user/avatar/2/avatar.png","web_url":"https://localhost/User2"}]`)
-	})
-
-	issueParticipants, _, err := client.Issues.GetParticipants("1", 5)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := []*BasicUser{{ID: 1, Name: "User1", Username: "User1", State: "active", AvatarURL: "", WebURL: "https://localhost/User1"},
-		{ID: 2, Name: "User2", Username: "User2", State: "active", AvatarURL: "https://localhost/uploads/-/system/user/avatar/2/avatar.png", WebURL: "https://localhost/User2"}}
-
-	if !reflect.DeepEqual(want, issueParticipants) {
-		t.Errorf("Issues.GetIssueParticipants returned %+v, want %+v", issueParticipants, want)
-	}
-}
diff --git a/merge_requests_test.go b/merge_requests_test.go
index 75e0ad0..65595b8 100644
--- a/merge_requests_test.go
+++ b/merge_requests_test.go
@@ -1,10 +1,7 @@
 package gitlab
 
 import (
-	"fmt"
-	"log"
 	"net/http"
-	"reflect"
 	"testing"
 	"time"
 
@@ -162,47 +159,3 @@ func TestListProjectMergeRequests(t *testing.T) {
 		assert.Equal(t, "", mr.DiffRefs.HeadSha)
 	}
 }
-
-func TestCreateMergeRequestPipeline(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/merge_requests/1/pipelines", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "POST")
-		fmt.Fprint(w, `{"id":1, "status":"pending"}`)
-	})
-
-	pipeline, _, err := client.MergeRequests.CreateMergeRequestPipeline(1, 1)
-
-	if err != nil {
-		t.Errorf("MergeRequests.CreateMergeRequestPipeline returned error: %v", err)
-	}
-
-	assert.Equal(t, 1, pipeline.ID)
-	assert.Equal(t, "pending", pipeline.Status)
-}
-
-func TestGetMergeRequestParticipants(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/merge_requests/5/participants", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		testURL(t, r, "/api/v4/projects/1/merge_requests/5/participants")
-
-		fmt.Fprint(w, `[{"id":1,"name":"User1","username":"User1","state":"active","avatar_url":"","web_url":"https://localhost/User1"},
-		{"id":2,"name":"User2","username":"User2","state":"active","avatar_url":"https://localhost/uploads/-/system/user/avatar/2/avatar.png","web_url":"https://localhost/User2"}]`)
-	})
-
-	mergeRequestParticipants, _, err := client.MergeRequests.GetMergeRequestParticipants("1", 5)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := []*BasicUser{{ID: 1, Name: "User1", Username: "User1", State: "active", AvatarURL: "", WebURL: "https://localhost/User1"},
-		{ID: 2, Name: "User2", Username: "User2", State: "active", AvatarURL: "https://localhost/uploads/-/system/user/avatar/2/avatar.png", WebURL: "https://localhost/User2"}}
-
-	if !reflect.DeepEqual(want, mergeRequestParticipants) {
-		t.Errorf("Issues.GetMergeRequestParticipants returned %+v, want %+v", mergeRequestParticipants, want)
-	}
-}
diff --git a/pipeline_schedules_test.go b/pipeline_schedules_test.go
deleted file mode 100644
index 2f2b6a5..0000000
--- a/pipeline_schedules_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package gitlab
-
-import (
-	"fmt"
-	"net/http"
-	"testing"
-)
-
-func TestRunPipelineSchedule(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/pipeline_schedules/1/play", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "POST")
-		w.WriteHeader(http.StatusCreated)
-		fmt.Fprint(w, `{"message": "201 Created"}`)
-	})
-
-	res, err := client.PipelineSchedules.RunPipelineSchedule(1, 1)
-
-	if err != nil {
-		t.Errorf("PipelineTriggers.RunPipelineTrigger returned error: %v", err)
-	}
-
-	if res.StatusCode != http.StatusCreated {
-		t.Errorf("PipelineSchedules.RunPipelineSchedule returned status %v, want %v", res.StatusCode, http.StatusCreated)
-	}
-}
diff --git a/projects_test.go b/projects_test.go
index 76d8cf5..5fc6496 100644
--- a/projects_test.go
+++ b/projects_test.go
@@ -190,9 +190,9 @@ func TestGetProjectByID(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/projects/1", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		fmt.Fprint(w, `{"id":1, "packages_enabled": false}`)
+		fmt.Fprint(w, `{"id":1}`)
 	})
-	want := &Project{ID: 1, PackagesEnabled: false}
+	want := &Project{ID: 1}
 
 	project, _, err := client.Projects.GetProject(1, nil)
 	if err != nil {
diff --git a/search_test.go b/search_test.go
index c8d67ff..80c1d1f 100644
--- a/search_test.go
+++ b/search_test.go
@@ -27,7 +27,6 @@ func TestSearchService_Users(t *testing.T) {
 		Name:      "John Doe1",
 		State:     "active",
 		AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
-		WebURL:    "http://localhost/user1",
 	}}
 	require.Equal(t, want, users)
 }
@@ -52,7 +51,6 @@ func TestSearchService_UsersByGroup(t *testing.T) {
 		Name:      "John Doe1",
 		State:     "active",
 		AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
-		WebURL:    "http://localhost/user1",
 	}}
 	require.Equal(t, want, users)
 }
@@ -77,7 +75,6 @@ func TestSearchService_UsersByProject(t *testing.T) {
 		Name:      "John Doe1",
 		State:     "active",
 		AvatarURL: "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon",
-		WebURL:    "http://localhost/user1",
 	}}
 	require.Equal(t, want, users)
 }
diff --git a/services_test.go b/services_test.go
index c23a990..9c25663 100644
--- a/services_test.go
+++ b/services_test.go
@@ -7,25 +7,6 @@ import (
 	"testing"
 )
 
-func TestListServices(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/services", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		fmt.Fprint(w, `[{"id":1},{"id":2}]`)
-	})
-	want := []*Service{{ID: 1}, {ID: 2}}
-
-	services, _, err := client.Services.ListServices(1)
-	if err != nil {
-		t.Fatalf("Services.ListServices returns an error: %v", err)
-	}
-	if !reflect.DeepEqual(want, services) {
-		t.Errorf("Services.ListServices returned %+v, want %+v", services, want)
-	}
-}
-
 func TestGetDroneCIService(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
diff --git a/testdata/webhooks/merge_request.json b/testdata/webhooks/merge_request.json
index 6678953..f7d051e 100644
--- a/testdata/webhooks/merge_request.json
+++ b/testdata/webhooks/merge_request.json
@@ -116,12 +116,6 @@
       "previous": "2017-09-15 16:50:55 UTC",
       "current": "2017-09-15 16:52:00 UTC"
     },
-    "changes": {
-      "state_id": {
-        "previous": 2,
-        "current": 1
-      }
-    },
     "labels": {
       "previous": [{
         "id": 206,
diff --git a/types_test.go b/types_test.go
deleted file mode 100644
index 6e14e7c..0000000
--- a/types_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package gitlab
-
-import (
-	"encoding/json"
-	"testing"
-)
-
-func TestBoolValue(t *testing.T) {
-	testCases := []struct {
-		name     string
-		data     []byte
-		expected bool
-	}{
-		{
-			name:     "should unmarshal true as true",
-			data:     []byte("true"),
-			expected: true,
-		},
-		{
-			name:     "should unmarshal false as false",
-			data:     []byte("false"),
-			expected: false,
-		},
-		{
-			name:     "should unmarshal true as true",
-			data:     []byte(`"true"`),
-			expected: true,
-		},
-		{
-			name:     "should unmarshal false as false",
-			data:     []byte(`"false"`),
-			expected: false,
-		},
-		{
-			name:     "should unmarshal \"1\" as true",
-			data:     []byte(`"1"`),
-			expected: true,
-		},
-		{
-			name:     "should unmarshal \"0\" as false",
-			data:     []byte(`"0"`),
-			expected: false,
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.name, func(t *testing.T) {
-			var b BoolValue
-			if err := json.Unmarshal(testCase.data, &b); err != nil {
-				t.Fatalf("Unexpected error: %v", err)
-			}
-
-			if bool(b) != testCase.expected {
-				t.Fatalf("Expected %v but got %v", testCase.expected, b)
-			}
-		})
-	}
-}