Repository: xanzy/go-gitlab
Pull request #1506 (2022-07-16 09:11:51)

Fully support project and group avatars
This change set adds support for project, group and user avatars in the
same fashion this is already implemented for topics.

Currently it's not possible to remove avatars from those API - I'm
exploring possible solutions
[here](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92604).

Nonetheless, I think this PR can already be merged.


Patch:
diff --git a/README.md b/README.md
index a7fd7cf..b1f2e26 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,6 @@ to add new and/or missing endpoints. Currently, the following services are suppo
 - [x] Project Members
 - [x] Project Milestones
 - [x] Project Snippets
-- [x] Project Vulnerabilities
 - [x] Project-Level Variables
 - [x] Projects (including setting Webhooks)
 - [x] Protected Branches
diff --git a/client_options.go b/client_options.go
index d2434b5..2ba5424 100644
--- a/client_options.go
+++ b/client_options.go
@@ -18,7 +18,6 @@ package gitlab
 
 import (
 	"net/http"
-	"time"
 
 	retryablehttp "github.com/hashicorp/go-retryablehttp"
 )
@@ -76,24 +75,6 @@ func WithCustomRetry(checkRetry retryablehttp.CheckRetry) ClientOptionFunc {
 	}
 }
 
-// WithCustomRetryMax can be used to configure a custom maximum number of retries.
-func WithCustomRetryMax(retryMax int) ClientOptionFunc {
-	return func(c *Client) error {
-		c.client.RetryMax = retryMax
-		return nil
-	}
-}
-
-// WithCustomRetryWaitMinMax can be used to configure a custom minimum and
-// maximum time to wait between retries.
-func WithCustomRetryWaitMinMax(waitMin, waitMax time.Duration) ClientOptionFunc {
-	return func(c *Client) error {
-		c.client.RetryWaitMin = waitMin
-		c.client.RetryWaitMax = waitMax
-		return nil
-	}
-}
-
 // WithHTTPClient can be used to configure a custom HTTP client.
 func WithHTTPClient(httpClient *http.Client) ClientOptionFunc {
 	return func(c *Client) error {
diff --git a/deployments_merge_requests.go b/deployments_merge_requests.go
deleted file mode 100644
index 4293478..0000000
--- a/deployments_merge_requests.go
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2022, Daniela Filipe Bento
-//
-// 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/http"
-)
-
-// DeploymentMergeRequestsService handles communication with the deployment's
-// merge requests related methods of the GitLab API.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/deployments.html#list-of-merge-requests-associated-with-a-deployment
-type DeploymentMergeRequestsService struct {
-	client *Client
-}
-
-// ListDeploymentMergeRequests get the merge requests associated with deployment.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/deployments.html#list-of-merge-requests-associated-with-a-deployment
-func (s *DeploymentMergeRequestsService) ListDeploymentMergeRequests(pid interface{}, deployment int, opts *ListMergeRequestsOptions, options ...RequestOptionFunc) ([]*MergeRequest, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/deployments/%d/merge_requests", PathEscape(project), deployment)
-
-	req, err := s.client.NewRequest(http.MethodGet, u, opts, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var mrs []*MergeRequest
-	resp, err := s.client.Do(req, &mrs)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return mrs, resp, err
-}
diff --git a/discussions.go b/discussions.go
index 0497c2f..c8f8668 100644
--- a/discussions.go
+++ b/discussions.go
@@ -917,12 +917,12 @@ type ListCommitDiscussionsOptions ListOptions
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#list-project-commit-discussion-items
-func (s *DiscussionsService) ListCommitDiscussions(pid interface{}, commit string, opt *ListCommitDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) {
+func (s *DiscussionsService) ListCommitDiscussions(pid interface{}, commit int, opt *ListCommitDiscussionsOptions, options ...RequestOptionFunc) ([]*Discussion, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions",
 		PathEscape(project),
 		commit,
 	)
@@ -946,12 +946,12 @@ func (s *DiscussionsService) ListCommitDiscussions(pid interface{}, commit strin
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#get-single-commit-discussion-item
-func (s *DiscussionsService) GetCommitDiscussion(pid interface{}, commit string, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) {
+func (s *DiscussionsService) GetCommitDiscussion(pid interface{}, commit int, discussion string, options ...RequestOptionFunc) (*Discussion, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions/%s",
 		PathEscape(project),
 		commit,
 		discussion,
@@ -986,12 +986,12 @@ type CreateCommitDiscussionOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#create-new-commit-thread
-func (s *DiscussionsService) CreateCommitDiscussion(pid interface{}, commit string, opt *CreateCommitDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) {
+func (s *DiscussionsService) CreateCommitDiscussion(pid interface{}, commit int, opt *CreateCommitDiscussionOptions, options ...RequestOptionFunc) (*Discussion, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions",
 		PathEscape(project),
 		commit,
 	)
@@ -1024,12 +1024,12 @@ type AddCommitDiscussionNoteOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#add-note-to-existing-commit-thread
-func (s *DiscussionsService) AddCommitDiscussionNote(pid interface{}, commit string, discussion string, opt *AddCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) {
+func (s *DiscussionsService) AddCommitDiscussionNote(pid interface{}, commit int, discussion string, opt *AddCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions/%s/notes",
 		PathEscape(project),
 		commit,
 		discussion,
@@ -1063,12 +1063,12 @@ type UpdateCommitDiscussionNoteOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#modify-an-existing-commit-thread-note
-func (s *DiscussionsService) UpdateCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, opt *UpdateCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) {
+func (s *DiscussionsService) UpdateCommitDiscussionNote(pid interface{}, commit int, discussion string, note int, opt *UpdateCommitDiscussionNoteOptions, options ...RequestOptionFunc) (*Note, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions/%s/notes/%d",
 		PathEscape(project),
 		commit,
 		discussion,
@@ -1093,12 +1093,12 @@ func (s *DiscussionsService) UpdateCommitDiscussionNote(pid interface{}, commit
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/discussions.html#delete-a-commit-thread-note
-func (s *DiscussionsService) DeleteCommitDiscussionNote(pid interface{}, commit string, discussion string, note int, options ...RequestOptionFunc) (*Response, error) {
+func (s *DiscussionsService) DeleteCommitDiscussionNote(pid interface{}, commit int, discussion string, note int, options ...RequestOptionFunc) (*Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, err
 	}
-	u := fmt.Sprintf("projects/%s/repository/commits/%s/discussions/%s/notes/%d",
+	u := fmt.Sprintf("projects/%s/repository/commits/%d/discussions/%s/notes/%d",
 		PathEscape(project),
 		commit,
 		discussion,
diff --git a/epics.go b/epics.go
index 27744b0..cbd6b11 100644
--- a/epics.go
+++ b/epics.go
@@ -211,7 +211,6 @@ func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, optio
 // GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
 type UpdateEpicOptions struct {
 	Title            *string  `url:"title,omitempty" json:"title,omitempty"`
-	Confidential     *bool    `url:"confidential,omitempty" json:"confidential,omitempty"`
 	Description      *string  `url:"description,omitempty" json:"description,omitempty"`
 	Labels           *Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
 	StartDateIsFixed *bool    `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
diff --git a/event_parsing.go b/event_parsing.go
index bd668b0..e17a0f1 100644
--- a/event_parsing.go
+++ b/event_parsing.go
@@ -33,7 +33,6 @@ const (
 	EventTypeDeployment    EventType = "Deployment Hook"
 	EventTypeIssue         EventType = "Issue Hook"
 	EventTypeJob           EventType = "Job Hook"
-	EventTypeMember        EventType = "Member Hook"
 	EventTypeMergeRequest  EventType = "Merge Request Hook"
 	EventTypeNote          EventType = "Note Hook"
 	EventTypePipeline      EventType = "Pipeline Hook"
@@ -81,19 +80,20 @@ func HookEventType(r *http.Request) EventType {
 //
 // Example usage:
 //
-//	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-//	    payload, err := ioutil.ReadAll(r.Body)
-//	    if err != nil { ... }
-//	    event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload)
-//	    if err != nil { ... }
-//	    switch event := event.(type) {
-//	    case *gitlab.PushEvent:
-//	        processPushEvent(event)
-//	    case *gitlab.MergeEvent:
-//	        processMergeEvent(event)
-//	    ...
-//	    }
-//	}
+// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+//     payload, err := ioutil.ReadAll(r.Body)
+//     if err != nil { ... }
+//     event, err := gitlab.ParseHook(gitlab.HookEventType(r), payload)
+//     if err != nil { ... }
+//     switch event := event.(type) {
+//     case *gitlab.PushEvent:
+//         processPushEvent(event)
+//     case *gitlab.MergeEvent:
+//         processMergeEvent(event)
+//     ...
+//     }
+// }
+//
 func ParseHook(eventType EventType, payload []byte) (event interface{}, err error) {
 	switch eventType {
 	case EventTypeSystemHook:
@@ -109,19 +109,20 @@ func ParseHook(eventType EventType, payload []byte) (event interface{}, err erro
 //
 // Example usage:
 //
-//	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-//	    payload, err := ioutil.ReadAll(r.Body)
-//	    if err != nil { ... }
-//	    event, err := gitlab.ParseSystemhook(payload)
-//	    if err != nil { ... }
-//	    switch event := event.(type) {
-//	    case *gitlab.PushSystemEvent:
-//	        processPushSystemEvent(event)
-//	    case *gitlab.MergeSystemEvent:
-//	        processMergeSystemEvent(event)
-//	    ...
-//	    }
-//	}
+// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+//     payload, err := ioutil.ReadAll(r.Body)
+//     if err != nil { ... }
+//     event, err := gitlab.ParseSystemhook(payload)
+//     if err != nil { ... }
+//     switch event := event.(type) {
+//     case *gitlab.PushSystemEvent:
+//         processPushSystemEvent(event)
+//     case *gitlab.MergeSystemEvent:
+//         processMergeSystemEvent(event)
+//     ...
+//     }
+// }
+//
 func ParseSystemhook(payload []byte) (event interface{}, err error) {
 	e := &systemHookEvent{}
 	err = json.Unmarshal(payload, e)
@@ -194,19 +195,20 @@ func WebhookEventType(r *http.Request) EventType {
 //
 // Example usage:
 //
-//	func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-//	    payload, err := ioutil.ReadAll(r.Body)
-//	    if err != nil { ... }
-//	    event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload)
-//	    if err != nil { ... }
-//	    switch event := event.(type) {
-//	    case *gitlab.PushEvent:
-//	        processPushEvent(event)
-//	    case *gitlab.MergeEvent:
-//	        processMergeEvent(event)
-//	    ...
-//	    }
-//	}
+// func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+//     payload, err := ioutil.ReadAll(r.Body)
+//     if err != nil { ... }
+//     event, err := gitlab.ParseWebhook(gitlab.HookEventType(r), payload)
+//     if err != nil { ... }
+//     switch event := event.(type) {
+//     case *gitlab.PushEvent:
+//         processPushEvent(event)
+//     case *gitlab.MergeEvent:
+//         processMergeEvent(event)
+//     ...
+//     }
+// }
+//
 func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err error) {
 	switch eventType {
 	case EventTypeBuild:
@@ -217,8 +219,6 @@ func ParseWebhook(eventType EventType, payload []byte) (event interface{}, err e
 		event = &IssueEvent{}
 	case EventTypeJob:
 		event = &JobEvent{}
-	case EventTypeMember:
-		event = &MemberEvent{}
 	case EventTypeMergeRequest:
 		event = &MergeEvent{}
 	case EventTypeNote, EventConfidentialNote:
diff --git a/event_webhook_types.go b/event_webhook_types.go
index e596213..c777ab0 100644
--- a/event_webhook_types.go
+++ b/event_webhook_types.go
@@ -23,7 +23,7 @@ import (
 	"time"
 )
 
-// BuildEvent represents a build event.
+//BuildEvent represents a build event
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/user/project/integrations/webhooks.html#build-events
@@ -151,7 +151,6 @@ type DeploymentEvent struct {
 		SSHURL            string  `json:"ssh_url"`
 		HTTPURL           string  `json:"http_url"`
 	} `json:"project"`
-	Ref         string     `json:"ref"`
 	ShortSHA    string     `json:"short_sha"`
 	User        *EventUser `json:"user"`
 	UserURL     string     `json:"user_url"`
@@ -195,7 +194,6 @@ type IssueCommentEvent struct {
 		Attachment   string  `json:"attachment"`
 		LineCode     string  `json:"line_code"`
 		CommitID     string  `json:"commit_id"`
-		DiscussionID string  `json:"discussion_id"`
 		NoteableID   int     `json:"noteable_id"`
 		System       bool    `json:"system"`
 		StDiff       []*Diff `json:"st_diff"`
@@ -306,7 +304,8 @@ type IssueEvent struct {
 // JobEvent represents a job event.
 //
 // GitLab API docs:
-// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#job-events
+// TODO: link to docs instead of src once they are published.
+// https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/data_builder/build.rb
 type JobEvent struct {
 	ObjectKind         string     `json:"object_kind"`
 	Ref                string     `json:"ref"`
@@ -347,26 +346,6 @@ type JobEvent struct {
 	} `json:"runner"`
 }
 
-// MemberEvent represents a member event.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#group-member-events
-type MemberEvent struct {
-	CreatedAt    *time.Time `json:"created_at"`
-	UpdatedAt    *time.Time `json:"updated_at"`
-	GroupName    string     `json:"group_name"`
-	GroupPath    string     `json:"group_path"`
-	GroupID      int        `json:"group_id"`
-	UserUsername string     `json:"user_username"`
-	UserName     string     `json:"user_name"`
-	UserEmail    string     `json:"user_email"`
-	UserID       int        `json:"user_id"`
-	GroupAccess  string     `json:"group_access"`
-	GroupPlan    string     `json:"group_plan"`
-	ExpiresAt    *time.Time `json:"expires_at"`
-	EventName    string     `json:"event_name"`
-}
-
 // MergeCommentEvent represents a comment on a merge event.
 //
 // GitLab API docs:
@@ -503,7 +482,6 @@ type MergeEvent struct {
 		AuthorID                 int          `json:"author_id"`
 		AssigneeID               int          `json:"assignee_id"`
 		AssigneeIDs              []int        `json:"assignee_ids"`
-		ReviewerIDs              []int        `json:"reviewer_ids"`
 		Title                    string       `json:"title"`
 		CreatedAt                string       `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468)
 		UpdatedAt                string       `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468)
@@ -542,27 +520,21 @@ type MergeEvent struct {
 				Email string `json:"email"`
 			} `json:"author"`
 		} `json:"last_commit"`
-		BlockingDiscussionsResolved bool       `json:"blocking_discussions_resolved"`
-		WorkInProgress              bool       `json:"work_in_progress"`
-		URL                         string     `json:"url"`
-		Action                      string     `json:"action"`
-		OldRev                      string     `json:"oldrev"`
-		Assignee                    *EventUser `json:"assignee"`
+		WorkInProgress bool       `json:"work_in_progress"`
+		URL            string     `json:"url"`
+		Action         string     `json:"action"`
+		OldRev         string     `json:"oldrev"`
+		Assignee       *EventUser `json:"assignee"`
 	} `json:"object_attributes"`
 	Repository *Repository  `json:"repository"`
 	Assignee   *EventUser   `json:"assignee"`
 	Assignees  []*EventUser `json:"assignees"`
-	Reviewers  []*EventUser `json:"reviewers"`
 	Labels     []*Label     `json:"labels"`
 	Changes    struct {
 		Assignees struct {
 			Previous []*EventUser `json:"previous"`
 			Current  []*EventUser `json:"current"`
 		} `json:"assignees"`
-		Reviewers struct {
-			Previous []*EventUser `json:"previous"`
-			Current  []*EventUser `json:"current"`
-		} `json:"reviewers"`
 		Description struct {
 			Previous string `json:"previous"`
 			Current  string `json:"current"`
diff --git a/examples/applications.go b/examples/applications.go
index c0b68e7..74be8d4 100644
--- a/examples/applications.go
+++ b/examples/applications.go
@@ -55,6 +55,5 @@ func applicationsExample() {
 	if err != nil {
 		log.Fatal(err)
 	}
-
 	log.Printf("Status code response : %d", resp.StatusCode)
 }
diff --git a/examples/cluster_agents.go b/examples/cluster_agents.go
index 9b4d925..5250095 100644
--- a/examples/cluster_agents.go
+++ b/examples/cluster_agents.go
@@ -17,6 +17,7 @@
 package main
 
 import (
+	"fmt"
 	"log"
 
 	"github.com/xanzy/go-gitlab"
@@ -29,23 +30,22 @@ func clusterAgentsExample() {
 	}
 
 	projectID := 33
-	opt := &gitlab.RegisterAgentOptions{
-		Name: gitlab.String("agent-2"),
-	}
 
 	// Register Cluster Agent
-	clusterAgent, _, err := git.ClusterAgents.RegisterAgent(projectID, opt)
+	clusterAgent, _, err := git.ClusterAgents.RegisterAgent(projectID, &gitlab.RegisterAgentOptions{
+		Name: gitlab.String("agent-2"),
+	})
 	if err != nil {
-		log.Fatal(err)
+		panic(err)
 	}
 
-	log.Printf("Cluster Agent: %+v\n", clusterAgent)
+	fmt.Printf("Cluster Agent: %+v\n", clusterAgent)
 
 	// List Cluster Agents
 	clusterAgents, _, err := git.ClusterAgents.ListAgents(projectID, nil)
 	if err != nil {
-		log.Fatal(err)
+		panic(err)
 	}
 
-	log.Printf("Cluster Agents: %+v", clusterAgents)
+	fmt.Printf("Cluster Agents: %+v\n", clusterAgents)
 }
diff --git a/examples/deployments_merge_requests.go b/examples/deployments_merge_requests.go
deleted file mode 100644
index 047b65b..0000000
--- a/examples/deployments_merge_requests.go
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright 2022, Daniela Filipe Bento
-//
-// 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 main
-
-import (
-	"log"
-
-	gitlab "github.com/xanzy/go-gitlab"
-)
-
-func deploymentExample() {
-	git, err := gitlab.NewClient("yourtokengoeshere")
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	opt := &gitlab.ListMergeRequestsOptions{}
-	mergeRequests, _, err := git.DeploymentMergeRequests.ListDeploymentMergeRequests(1, 1, opt)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	for _, mergeRequest := range mergeRequests {
-		log.Printf("Found merge request: %v\n", mergeRequest)
-	}
-}
diff --git a/examples/impersonation.go b/examples/impersonation.go
index c93f0b6..43215d3 100644
--- a/examples/impersonation.go
+++ b/examples/impersonation.go
@@ -36,11 +36,11 @@ func impersonationExample() {
 		&gitlab.GetAllImpersonationTokensOptions{State: gitlab.String("active")},
 	)
 	if err != nil {
-		log.Fatal(err)
+		panic(err)
 	}
 
 	for _, token := range tokens {
-		log.Printf("Found token: %s", token.Token)
+		log.Println(token.Token)
 	}
 
 	//create an impersonation token of an user
@@ -49,8 +49,8 @@ func impersonationExample() {
 		&gitlab.CreateImpersonationTokenOptions{Scopes: &[]string{"api"}},
 	)
 	if err != nil {
-		log.Fatal(err)
+		panic(err)
 	}
 
-	log.Printf("Created token: %s", token.Token)
+	log.Println(token.Token)
 }
diff --git a/examples/labels.go b/examples/labels.go
index bd76062..678d69f 100644
--- a/examples/labels.go
+++ b/examples/labels.go
@@ -29,11 +29,11 @@ func labelExample() {
 	}
 
 	// Create new label
-	opt := &gitlab.CreateLabelOptions{
+	l := &gitlab.CreateLabelOptions{
 		Name:  gitlab.String("My Label"),
 		Color: gitlab.String("#11FF22"),
 	}
-	label, _, err := git.Labels.CreateLabel("myname/myproject", opt)
+	label, _, err := git.Labels.CreateLabel("myname/myproject", l)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/examples/pagination.go b/examples/pagination.go
index 3d4d62f..9fc828d 100644
--- a/examples/pagination.go
+++ b/examples/pagination.go
@@ -17,6 +17,7 @@
 package main
 
 import (
+	"fmt"
 	"log"
 
 	"github.com/xanzy/go-gitlab"
@@ -44,7 +45,7 @@ func pagination() {
 
 		// List all the projects we've found so far.
 		for _, p := range ps {
-			log.Printf("Found project: %s", p.Name)
+			fmt.Printf("Found project: %s", p.Name)
 		}
 
 		// Exit the loop when we've seen all pages.
diff --git a/examples/personal_access_tokens.go b/examples/personal_access_tokens.go
index b4d93be..07cfa75 100644
--- a/examples/personal_access_tokens.go
+++ b/examples/personal_access_tokens.go
@@ -59,5 +59,5 @@ func patListExampleWithUserFilter() {
 		log.Fatal(err)
 	}
 
-	log.Printf("Found personal access tokens: %s", data)
+	fmt.Printf("%s\n", data)
 }
diff --git a/examples/topics.go b/examples/topics.go
index ffc5c52..ef4f09d 100644
--- a/examples/topics.go
+++ b/examples/topics.go
@@ -17,6 +17,7 @@
 package main
 
 import (
+	"fmt"
 	"log"
 	"os"
 
@@ -38,7 +39,7 @@ func topicExample() {
 		panic(err)
 	}
 
-	log.Printf("Topic: %+v\n", topic)
+	fmt.Printf("Topic: %+v\n", topic)
 
 	// Set topic avatar
 	avatarFile, err := os.Open("5746961_detect_direction_gps_location_map_icon.png")
@@ -54,7 +55,7 @@ func topicExample() {
 	if err != nil {
 		panic(err)
 	}
-	log.Printf("Topic with Avatar: %+v\n", topic)
+	fmt.Printf("Topic with Avatar: %+v\n", topic)
 
 	// Remove topic avatar
 	topic, _, err = git.Topics.UpdateTopic(topic.ID, &gitlab.UpdateTopicOptions{
@@ -64,5 +65,5 @@ func topicExample() {
 		panic(err)
 	}
 
-	log.Printf("Topic without Avatar: %+v\n", topic)
+	fmt.Printf("Topic without Avatar: %+v\n", topic)
 }
diff --git a/examples/webhook.go b/examples/webhook.go
index 471272c..655437e 100644
--- a/examples/webhook.go
+++ b/examples/webhook.go
@@ -39,14 +39,14 @@ func (hook webhook) ServeHTTP(writer http.ResponseWriter, request *http.Request)
 	event, err := hook.parse(request)
 	if err != nil {
 		writer.WriteHeader(500)
-		fmt.Fprintf(writer, "could parse the webhook event: %v", err)
+		writer.Write([]byte(fmt.Sprintf("could parse the webhook event: %v", err)))
 		return
 	}
 
 	// Handle the event before we return.
 	if err := hook.handle(event); err != nil {
 		writer.WriteHeader(500)
-		fmt.Fprintf(writer, "error handling the event: %v", err)
+		writer.Write([]byte(fmt.Sprintf("error handling the event: %v", err)))
 		return
 	}
 
diff --git a/external_status_checks.go b/external_status_checks.go
index cc2d667..b6d3092 100644
--- a/external_status_checks.go
+++ b/external_status_checks.go
@@ -64,36 +64,6 @@ func (s *ExternalStatusChecksService) ListMergeStatusChecks(pid interface{}, mr
 	return mscs, resp, err
 }
 
-// SetExternalStatusCheckStatusOptions represents the available
-// SetExternalStatusCheckStatus() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#set-status-of-an-external-status-check
-type SetExternalStatusCheckStatusOptions struct {
-	SHA                   *string `url:"sha,omitempty" json:"sha,omitempty"`
-	ExternalStatusCheckID *int    `url:"external_status_check_id,omitempty" json:"external_status_check_id,omitempty"`
-	Status                *string `url:"status,omitempty" json:"status,omitempty"`
-}
-
-// SetExternalStatusCheckStatus sets the status of an external status check.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#set-status-of-an-external-status-check
-func (s *ExternalStatusChecksService) SetExternalStatusCheckStatus(pid interface{}, mergeRequest int, opt *SetExternalStatusCheckStatusOptions, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/merge_requests/%d/status_check_responses", PathEscape(project), mergeRequest)
-
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
 // ListProjectStatusChecks lists the project external status checks.
 //
 // GitLab API docs:
@@ -118,82 +88,3 @@ func (s *ExternalStatusChecksService) ListProjectStatusChecks(pid interface{}, o
 
 	return pscs, resp, err
 }
-
-// CreateExternalStatusCheckOptions represents the available
-// CreateExternalStatusCheck() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#create-external-status-check
-type CreateExternalStatusCheckOptions struct {
-	Name               *string `url:"name,omitempty" json:"name,omitempty"`
-	ExternalURL        *string `url:"external_url,omitempty" json:"external_url,omitempty"`
-	ProtectedBranchIDs *[]int  `url:"protected_branch_ids,omitempty" json:"protected_branch_ids,omitempty"`
-}
-
-// CreateExternalStatusCheck creates an external status check.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#create-external-status-check
-func (s *ExternalStatusChecksService) CreateExternalStatusCheck(pid interface{}, opt *CreateExternalStatusCheckOptions, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/external_status_checks", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
-// DeleteExternalStatusCheck deletes an external status check.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#delete-external-status-check
-func (s *ExternalStatusChecksService) DeleteExternalStatusCheck(pid interface{}, check int, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/external_status_checks/%d", PathEscape(project), check)
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
-// UpdateExternalStatusCheckOptions represents the available
-// UpdateExternalStatusCheck() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#update-external-status-check
-type UpdateExternalStatusCheckOptions struct {
-	Name               *string `url:"name,omitempty" json:"name,omitempty"`
-	ExternalURL        *string `url:"external_url,omitempty" json:"external_url,omitempty"`
-	ProtectedBranchIDs *[]int  `url:"protected_branch_ids,omitempty" json:"protected_branch_ids,omitempty"`
-}
-
-// UpdateExternalStatusCheck updates an external status check.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/status_checks.html#update-external-status-check
-func (s *ExternalStatusChecksService) UpdateExternalStatusCheck(pid interface{}, check int, opt *UpdateExternalStatusCheckOptions, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/external_status_checks/%d", PathEscape(project), check)
-
-	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/gitlab.go b/gitlab.go
index 50e084c..234f58a 100644
--- a/gitlab.go
+++ b/gitlab.go
@@ -23,6 +23,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"math/rand"
 	"mime/multipart"
 	"net/http"
@@ -115,7 +116,6 @@ type Client struct {
 	CustomAttribute         *CustomAttributesService
 	DeployKeys              *DeployKeysService
 	DeployTokens            *DeployTokensService
-	DeploymentMergeRequests *DeploymentMergeRequestsService
 	Deployments             *DeploymentsService
 	Discussions             *DiscussionsService
 	Environments            *EnvironmentsService
@@ -171,7 +171,6 @@ type Client struct {
 	ProjectAccessTokens     *ProjectAccessTokensService
 	ProjectBadges           *ProjectBadgesService
 	ProjectCluster          *ProjectClustersService
-	ProjectFeatureFlags     *ProjectFeatureFlagService
 	ProjectImportExport     *ProjectImportExportService
 	ProjectIterations       *ProjectIterationsService
 	ProjectMembers          *ProjectMembersService
@@ -191,7 +190,6 @@ type Client struct {
 	ResourceLabelEvents     *ResourceLabelEventsService
 	ResourceMilestoneEvents *ResourceMilestoneEventsService
 	ResourceStateEvents     *ResourceStateEventsService
-	ResourceWeightEvents    *ResourceWeightEventsService
 	Runners                 *RunnersService
 	Search                  *SearchService
 	Services                *ServicesService
@@ -313,14 +311,13 @@ func newClient(options ...ClientOptionFunc) (*Client, error) {
 	c.Boards = &IssueBoardsService{client: c}
 	c.Branches = &BranchesService{client: c}
 	c.BroadcastMessage = &BroadcastMessagesService{client: c}
-	c.CIYMLTemplate = &CIYMLTemplatesService{client: c}
 	c.ClusterAgents = &ClusterAgentsService{client: c}
+	c.CIYMLTemplate = &CIYMLTemplatesService{client: c}
 	c.Commits = &CommitsService{client: c}
 	c.ContainerRegistry = &ContainerRegistryService{client: c}
 	c.CustomAttribute = &CustomAttributesService{client: c}
 	c.DeployKeys = &DeployKeysService{client: c}
 	c.DeployTokens = &DeployTokensService{client: c}
-	c.DeploymentMergeRequests = &DeploymentMergeRequestsService{client: c}
 	c.Deployments = &DeploymentsService{client: c}
 	c.Discussions = &DiscussionsService{client: c}
 	c.Environments = &EnvironmentsService{client: c}
@@ -373,10 +370,9 @@ func newClient(options ...ClientOptionFunc) (*Client, error) {
 	c.PipelineTriggers = &PipelineTriggersService{client: c}
 	c.Pipelines = &PipelinesService{client: c}
 	c.PlanLimits = &PlanLimitsService{client: c}
-	c.ProjectAccessTokens = &ProjectAccessTokensService{client: c}
 	c.ProjectBadges = &ProjectBadgesService{client: c}
+	c.ProjectAccessTokens = &ProjectAccessTokensService{client: c}
 	c.ProjectCluster = &ProjectClustersService{client: c}
-	c.ProjectFeatureFlags = &ProjectFeatureFlagService{client: c}
 	c.ProjectImportExport = &ProjectImportExportService{client: c}
 	c.ProjectIterations = &ProjectIterationsService{client: c}
 	c.ProjectMembers = &ProjectMembersService{client: c}
@@ -396,7 +392,6 @@ func newClient(options ...ClientOptionFunc) (*Client, error) {
 	c.ResourceLabelEvents = &ResourceLabelEventsService{client: c}
 	c.ResourceMilestoneEvents = &ResourceMilestoneEventsService{client: c}
 	c.ResourceStateEvents = &ResourceStateEventsService{client: c}
-	c.ResourceWeightEvents = &ResourceWeightEventsService{client: c}
 	c.Runners = &RunnersService{client: c}
 	c.Search = &SearchService{client: c}
 	c.Services = &ServicesService{client: c}
@@ -890,13 +885,13 @@ func CheckResponse(r *http.Response) error {
 	}
 
 	errorResponse := &ErrorResponse{Response: r}
-	data, err := io.ReadAll(r.Body)
+	data, err := ioutil.ReadAll(r.Body)
 	if err == nil && data != nil {
 		errorResponse.Body = data
 
 		var raw interface{}
 		if err := json.Unmarshal(data, &raw); err != nil {
-			errorResponse.Message = fmt.Sprintf("failed to parse unknown error format: %s", data)
+			errorResponse.Message = "failed to parse unknown error format"
 		} else {
 			errorResponse.Message = parseError(raw)
 		}
@@ -906,24 +901,23 @@ func CheckResponse(r *http.Response) error {
 }
 
 // Format:
-//
-//	{
-//	    "message": {
-//	        "<property-name>": [
-//	            "<error-message>",
-//	            "<error-message>",
-//	            ...
-//	        ],
-//	        "<embed-entity>": {
-//	            "<property-name>": [
-//	                "<error-message>",
-//	                "<error-message>",
-//	                ...
-//	            ],
-//	        }
-//	    },
-//	    "error": "<error-message>"
-//	}
+// {
+//     "message": {
+//         "<property-name>": [
+//             "<error-message>",
+//             "<error-message>",
+//             ...
+//         ],
+//         "<embed-entity>": {
+//             "<property-name>": [
+//                 "<error-message>",
+//                 "<error-message>",
+//                 ...
+//             ],
+//         }
+//     },
+//     "error": "<error-message>"
+// }
 func parseError(raw interface{}) string {
 	switch raw := raw.(type) {
 	case string:
diff --git a/go.mod b/go.mod
index b4847d0..e1a16fc 100644
--- a/go.mod
+++ b/go.mod
@@ -6,17 +6,17 @@ require (
 	github.com/google/go-querystring v1.1.0
 	github.com/hashicorp/go-cleanhttp v0.5.2
 	github.com/hashicorp/go-retryablehttp v0.7.1
-	github.com/stretchr/testify v1.8.0
-	golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
-	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
+	github.com/stretchr/testify v1.4.0
+	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
+	golang.org/x/time v0.0.0-20220411224347-583f2d630306
 )
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect
+	golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/protobuf v1.28.1 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
+	google.golang.org/protobuf v1.28.0 // indirect
+	gopkg.in/yaml.v2 v2.2.2 // indirect
 )
diff --git a/go.sum b/go.sum
index 550f421..e556cb6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,107 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
 github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
@@ -17,35 +109,288 @@ github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxC
 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
 github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
 github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 h1:N9Vc/rorQUDes6B9CNdIxAn5jODGj2wzfrei2x4wNj4=
-golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY=
-golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y=
+golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
+golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/group_hooks.go b/group_hooks.go
index 6e75d6a..acb51d9 100644
--- a/group_hooks.go
+++ b/group_hooks.go
@@ -47,22 +47,17 @@ type GroupHook struct {
 	CreatedAt                *time.Time `json:"created_at"`
 }
 
-// ListGroupHooksOptions represents the available ListGroupHooks() options.
-//
-// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
-type ListGroupHooksOptions ListOptions
-
 // ListGroupHooks gets a list of group hooks.
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
-func (s *GroupsService) ListGroupHooks(gid interface{}, opt *ListGroupHooksOptions, options ...RequestOptionFunc) ([]*GroupHook, *Response, error) {
+func (s *GroupsService) ListGroupHooks(gid interface{}, options ...RequestOptionFunc) ([]*GroupHook, *Response, error) {
 	group, err := parseID(gid)
 	if err != nil {
 		return nil, nil, err
 	}
 	u := fmt.Sprintf("groups/%s/hooks", PathEscape(group))
 
-	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
+	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/group_members.go b/group_members.go
index 16bcdeb..843f4d9 100644
--- a/group_members.go
+++ b/group_members.go
@@ -328,26 +328,18 @@ func (s *GroupMembersService) EditGroupMember(gid interface{}, user int, opt *Ed
 	return gm, resp, err
 }
 
-// RemoveGroupMemberOptions represents the available options to remove a group member.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/members.html#remove-a-member-from-a-group-or-project
-type RemoveGroupMemberOptions struct {
-	SkipSubresources  *bool `url:"skip_subresources,omitempty" json:"skip_subresources,omitempty"`
-	UnassignIssuables *bool `url:"unassign_issuables,omitempty" json:"unassign_issuables,omitempty"`
-}
-
 // RemoveGroupMember removes user from user team.
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project
-func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, opt *RemoveGroupMemberOptions, options ...RequestOptionFunc) (*Response, error) {
+func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, options ...RequestOptionFunc) (*Response, error) {
 	group, err := parseID(gid)
 	if err != nil {
 		return nil, err
 	}
 	u := fmt.Sprintf("groups/%s/members/%d", PathEscape(group), user)
 
-	req, err := s.client.NewRequest(http.MethodDelete, u, opt, options)
+	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
 	if err != nil {
 		return nil, err
 	}
diff --git a/groups.go b/groups.go
index 96a1e3a..ca85575 100644
--- a/groups.go
+++ b/groups.go
@@ -18,10 +18,13 @@ package gitlab
 
 import (
 	"bytes"
+	"encoding/json"
 	"fmt"
 	"io"
 	"net/http"
 	"time"
+
+	retryablehttp "github.com/hashicorp/go-retryablehttp"
 )
 
 // GroupsService handles communication with the group related methods of
@@ -52,7 +55,7 @@ type Group struct {
 	FileTemplateProjectID   int                        `json:"file_template_project_id"`
 	ParentID                int                        `json:"parent_id"`
 	Projects                []*Project                 `json:"projects"`
-	Statistics              *Statistics                `json:"statistics"`
+	Statistics              *StorageStatistics         `json:"statistics"`
 	CustomAttributes        []*CustomAttribute         `json:"custom_attributes"`
 	ShareWithGroupLock      bool                       `json:"share_with_group_lock"`
 	RequireTwoFactorAuth    bool                       `json:"require_two_factor_authentication"`
@@ -75,7 +78,6 @@ type Group struct {
 	LDAPCN                         string           `json:"ldap_cn"`
 	LDAPAccess                     AccessLevelValue `json:"ldap_access"`
 	LDAPGroupLinks                 []*LDAPGroupLink `json:"ldap_group_links"`
-	SAMLGroupLinks                 []*SAMLGroupLink `json:"saml_group_links"`
 	SharedRunnersMinutesLimit      int              `json:"shared_runners_minutes_limit"`
 	ExtraSharedRunnersMinutesLimit int              `json:"extra_shared_runners_minutes_limit"`
 	PreventForkingOutsideGroup     bool             `json:"prevent_forking_outside_group"`
@@ -91,6 +93,15 @@ type GroupAvatar struct {
 	Image    io.Reader
 }
 
+// MarshalJSON implements the json.Marshaler interface.
+func (a *GroupAvatar) MarshalJSON() ([]byte, error) {
+	if a.Filename == "" && a.Image == nil {
+		return []byte(`""`), nil
+	}
+	type alias GroupAvatar
+	return json.Marshal((*alias)(a))
+}
+
 // LDAPGroupLink represents a GitLab LDAP group link.
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#ldap-group-links
@@ -101,14 +112,6 @@ type LDAPGroupLink struct {
 	Provider    string           `json:"provider"`
 }
 
-// SAMLGroupLink represents a GitLab SAML group link.
-//
-// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#saml-group-links
-type SAMLGroupLink struct {
-	Name        string           `json:"name"`
-	AccessLevel AccessLevelValue `json:"access_level"`
-}
-
 // ListGroupsOptions represents the available ListGroups() options.
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups
@@ -321,6 +324,7 @@ func (s *GroupsService) DownloadAvatar(gid interface{}, options ...RequestOption
 type CreateGroupOptions struct {
 	Name                           *string                     `url:"name,omitempty" json:"name,omitempty"`
 	Path                           *string                     `url:"path,omitempty" json:"path,omitempty"`
+	Avatar                         *GroupAvatar                `url:"-" json:"-"`
 	Description                    *string                     `url:"description,omitempty" json:"description,omitempty"`
 	MembershipLock                 *bool                       `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
 	Visibility                     *VisibilityValue            `url:"visibility,omitempty" json:"visibility,omitempty"`
@@ -345,7 +349,22 @@ type CreateGroupOptions struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group
 func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...RequestOptionFunc) (*Group, *Response, error) {
-	req, err := s.client.NewRequest(http.MethodPost, "groups", opt, options)
+	var err error
+	var req *retryablehttp.Request
+
+	if opt.Avatar == nil {
+		req, err = s.client.NewRequest(http.MethodPost, "groups", opt, options)
+	} else {
+		req, err = s.client.UploadRequest(
+			http.MethodPost,
+			"groups",
+			opt.Avatar.Image,
+			opt.Avatar.Filename,
+			UploadAvatar,
+			opt,
+			options,
+		)
+	}
 	if err != nil {
 		return nil, nil, err
 	}
@@ -429,6 +448,7 @@ func (s *GroupsService) TransferSubGroup(gid interface{}, opt *TransferSubGroupO
 type UpdateGroupOptions struct {
 	Name                                 *string                     `url:"name,omitempty" json:"name,omitempty"`
 	Path                                 *string                     `url:"path,omitempty" json:"path,omitempty"`
+	Avatar                               *GroupAvatar                `url:"-" json:"avatar,omitempty"`
 	Description                          *string                     `url:"description,omitempty" json:"description,omitempty"`
 	MembershipLock                       *bool                       `url:"membership_lock,omitempty" json:"membership_lock,omitempty"`
 	Visibility                           *VisibilityValue            `url:"visibility,omitempty" json:"visibility,omitempty"`
@@ -462,7 +482,21 @@ func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, op
 	}
 	u := fmt.Sprintf("groups/%s", PathEscape(group))
 
-	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
+	var req *retryablehttp.Request
+
+	if opt.Avatar == nil || (opt.Avatar.Filename == "" && opt.Avatar.Image == nil) {
+		req, err = s.client.NewRequest(http.MethodPut, u, opt, options)
+	} else {
+		req, err = s.client.UploadRequest(
+			http.MethodPut,
+			u,
+			opt.Avatar.Image,
+			opt.Avatar.Filename,
+			UploadAvatar,
+			opt,
+			options,
+		)
+	}
 	if err != nil {
 		return nil, nil, err
 	}
@@ -753,113 +787,6 @@ func (s *GroupsService) DeleteGroupLDAPLinkForProvider(gid interface{}, provider
 	return s.client.Do(req, nil)
 }
 
-// ListGroupSAMLLinks lists the group's SAML links. Available only for users who
-// can edit groups.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/groups.html#list-saml-group-links
-func (s *GroupsService) ListGroupSAMLLinks(gid interface{}, options ...RequestOptionFunc) ([]*SAMLGroupLink, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/saml_group_links", PathEscape(group))
-
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var gl []*SAMLGroupLink
-	resp, err := s.client.Do(req, &gl)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return gl, resp, nil
-}
-
-// GetGroupSAMLLink get a specific group SAML link. Available only for users who
-// can edit groups.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/groups.html#get-saml-group-link
-func (s *GroupsService) GetGroupSAMLLink(gid interface{}, samlGroupName string, options ...RequestOptionFunc) (*SAMLGroupLink, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/saml_group_links/%s", PathEscape(group), PathEscape(samlGroupName))
-
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	gl := new(SAMLGroupLink)
-	resp, err := s.client.Do(req, &gl)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return gl, resp, nil
-}
-
-// AddGroupSAMLLinkOptions represents the available AddGroupSAMLLink() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/groups.html#add-saml-group-link
-type AddGroupSAMLLinkOptions struct {
-	SAMLGroupName *string           `url:"saml_group_name,omitempty" json:"saml_group_name,omitempty"`
-	AccessLevel   *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
-}
-
-// AddGroupSAMLLink creates a new group SAML link. Available only for users who
-// can edit groups.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/groups.html#add-saml-group-link
-func (s *GroupsService) AddGroupSAMLLink(gid interface{}, opt *AddGroupSAMLLinkOptions, options ...RequestOptionFunc) (*SAMLGroupLink, *Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("groups/%s/saml_group_links", PathEscape(group))
-
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	gl := new(SAMLGroupLink)
-	resp, err := s.client.Do(req, &gl)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return gl, resp, err
-}
-
-// DeleteGroupSAMLLink deletes a group SAML link. Available only for users who
-// can edit groups.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/groups.html#delete-saml-group-link
-func (s *GroupsService) DeleteGroupSAMLLink(gid interface{}, samlGroupName string, options ...RequestOptionFunc) (*Response, error) {
-	group, err := parseID(gid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("groups/%s/saml_group_links/%s", PathEscape(group), PathEscape(samlGroupName))
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
 // ShareGroupWithGroupOptions represents the available ShareGroupWithGroup() options.
 //
 // GitLab API docs:
diff --git a/invites.go b/invites.go
index 46c9c89..b5ae81c 100644
--- a/invites.go
+++ b/invites.go
@@ -111,7 +111,6 @@ func (s *InvitesService) ListPendingProjectInvitations(pid interface{}, opt *Lis
 type InvitesOptions struct {
 	ID          interface{}       `url:"id,omitempty" json:"id,omitempty"`
 	Email       *string           `url:"email,omitempty" json:"email,omitempty"`
-	UserID      interface{}       `url:"user_id,omitempty" json:"user_id,omitempty"`
 	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
 	ExpiresAt   *ISOTime          `url:"expires_at,omitempty" json:"expires_at,omitempty"`
 }
diff --git a/issue_links.go b/issue_links.go
index 0d4a29e..f40b65c 100644
--- a/issue_links.go
+++ b/issue_links.go
@@ -19,7 +19,6 @@ package gitlab
 import (
 	"fmt"
 	"net/http"
-	"time"
 )
 
 // IssueLinksService handles communication with the issue relations related methods
@@ -39,36 +38,6 @@ type IssueLink struct {
 	LinkType    string `json:"link_type"`
 }
 
-// IssueRelation gets a relation between two issues.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issue_links.html#list-issue-relations
-type IssueRelation struct {
-	ID             int              `json:"id"`
-	IID            int              `json:"iid"`
-	State          string           `json:"state"`
-	Description    string           `json:"description"`
-	Confidential   bool             `json:"confidential"`
-	Author         *IssueAuthor     `json:"author"`
-	Milestone      *Milestone       `json:"milestone"`
-	ProjectID      int              `json:"project_id"`
-	Assignees      []*IssueAssignee `json:"assignees"`
-	Assignee       *IssueAssignee   `json:"assignee"`
-	UpdatedAt      *time.Time       `json:"updated_at"`
-	Title          string           `json:"title"`
-	CreatedAt      *time.Time       `json:"created_at"`
-	Labels         Labels           `json:"labels"`
-	DueDate        *ISOTime         `json:"due_date"`
-	WebURL         string           `json:"web_url"`
-	References     *IssueReferences `json:"references"`
-	Weight         int              `json:"weight"`
-	UserNotesCount int              `json:"user_notes_count"`
-	IssueLinkID    int              `json:"issue_link_id"`
-	LinkType       string           `json:"link_type"`
-	LinkCreatedAt  *time.Time       `json:"link_created_at"`
-	LinkUpdatedAt  *time.Time       `json:"link_updated_at"`
-}
-
 // ListIssueRelations gets a list of related issues of a given issue,
 // sorted by the relationship creation datetime (ascending).
 //
@@ -76,19 +45,19 @@ type IssueRelation struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/issue_links.html#list-issue-relations
-func (s *IssueLinksService) ListIssueRelations(pid interface{}, issue int, options ...RequestOptionFunc) ([]*IssueRelation, *Response, error) {
+func (s *IssueLinksService) ListIssueRelations(pid interface{}, issueIID int, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/issues/%d/links", PathEscape(project), issue)
+	u := fmt.Sprintf("projects/%s/issues/%d/links", PathEscape(project), issueIID)
 
 	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	var is []*IssueRelation
+	var is []*Issue
 	resp, err := s.client.Do(req, &is)
 	if err != nil {
 		return nil, resp, err
@@ -97,31 +66,6 @@ func (s *IssueLinksService) ListIssueRelations(pid interface{}, issue int, optio
 	return is, resp, err
 }
 
-// GetIssueLink gets a specific issue link.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/issue_links.html#get-an-issue-link
-func (s *IssueLinksService) GetIssueLink(pid interface{}, issue, issueLink int, options ...RequestOptionFunc) (*IssueLink, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/issues/%d/links/%d", PathEscape(project), issue, issueLink)
-
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	il := new(IssueLink)
-	resp, err := s.client.Do(req, il)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return il, resp, err
-}
-
 // CreateIssueLinkOptions represents the available CreateIssueLink() options.
 //
 // GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html
@@ -136,12 +80,12 @@ type CreateIssueLinkOptions struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/issue_links.html#create-an-issue-link
-func (s *IssueLinksService) CreateIssueLink(pid interface{}, issue int, opt *CreateIssueLinkOptions, options ...RequestOptionFunc) (*IssueLink, *Response, error) {
+func (s *IssueLinksService) CreateIssueLink(pid interface{}, issueIID int, opt *CreateIssueLinkOptions, options ...RequestOptionFunc) (*IssueLink, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/issues/%d/links", PathEscape(project), issue)
+	u := fmt.Sprintf("projects/%s/issues/%d/links", PathEscape(project), issueIID)
 
 	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
 	if err != nil {
@@ -161,26 +105,26 @@ func (s *IssueLinksService) CreateIssueLink(pid interface{}, issue int, opt *Cre
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/issue_links.html#delete-an-issue-link
-func (s *IssueLinksService) DeleteIssueLink(pid interface{}, issue, issueLink int, options ...RequestOptionFunc) (*IssueLink, *Response, error) {
+func (s *IssueLinksService) DeleteIssueLink(pid interface{}, issueIID, issueLinkID int, options ...RequestOptionFunc) (*IssueLink, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
 	u := fmt.Sprintf("projects/%s/issues/%d/links/%d",
 		PathEscape(project),
-		issue,
-		issueLink)
+		issueIID,
+		issueLinkID)
 
 	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	il := new(IssueLink)
-	resp, err := s.client.Do(req, &il)
+	i := new(IssueLink)
+	resp, err := s.client.Do(req, &i)
 	if err != nil {
 		return nil, resp, err
 	}
 
-	return il, resp, err
+	return i, resp, err
 }
diff --git a/issues.go b/issues.go
index 31bb935..4d9e0b4 100644
--- a/issues.go
+++ b/issues.go
@@ -120,7 +120,6 @@ type Issue struct {
 	MergeRequestCount    int                    `json:"merge_requests_count"`
 	EpicIssueID          int                    `json:"epic_issue_id"`
 	Epic                 *Epic                  `json:"epic"`
-	Iteration            *GroupIteration        `json:"iteration"`
 	TaskCompletionStatus *TasksCompletionStatus `json:"task_completion_status"`
 }
 
@@ -207,38 +206,32 @@ 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"`
-	AuthorUsername      *string          `url:"author_username,omitempty" json:"author_username,omitempty"`
-	NotAuthorUsername   *string          `url:"not[author_username],omitempty" json:"not[author_username],omitempty"`
-	NotAuthorID         *[]int           `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
-	AssigneeID          *AssigneeIDValue `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"`
-	NotAssigneeUsername *string          `url:"not[assignee_username],omitempty" json:"not[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"`
-	In                  *string          `url:"in,omitempty" json:"in,omitempty"`
-	NotIn               *string          `url:"not[in],omitempty" json:"not[in],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"`
-	NotSearch           *string          `url:"not[search],omitempty" json:"not[search],omitempty"`
-	CreatedAfter        *time.Time       `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore       *time.Time       `url:"created_before,omitempty" json:"created_before,omitempty"`
-	DueDate             *string          `url:"due_date,omitempty" json:"due_date,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"`
-	IssueType           *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
-	IterationID         *int             `url:"iteration_id,omitempty" json:"iteration_id,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"`
+	AuthorUsername     *string          `url:"author_username,omitempty" json:"author_username,omitempty"`
+	NotAuthorID        *[]int           `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
+	AssigneeID         *AssigneeIDValue `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"`
+	In                 *string          `url:"in,omitempty" json:"in,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"`
+	IssueType          *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
 }
 
 // ListIssues gets all issues created by authenticated user. This function
@@ -265,38 +258,32 @@ 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"`
-	NotAuthorUsername *string `url:"not[author_username],omitempty" json:"not[author_username],omitempty"`
-
-	AssigneeID          *AssigneeIDValue `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"`
-	NotAssigneeUsername *string          `url:"not[assignee_username],omitempty" json:"not[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"`
-	NotSearch           *string          `url:"not[search],omitempty" json:"not[search],omitempty"`
-	In                  *string          `url:"in,omitempty" json:"in,omitempty"`
-	NotIn               *string          `url:"not[in],omitempty" json:"not[in],omitempty"`
-	CreatedAfter        *time.Time       `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore       *time.Time       `url:"created_before,omitempty" json:"created_before,omitempty"`
-	DueDate             *string          `url:"due_date,omitempty" json:"due_date,omitempty"`
-	UpdatedAfter        *time.Time       `url:"updated_after,omitempty" json:"updated_after,omitempty"`
-	UpdatedBefore       *time.Time       `url:"updated_before,omitempty" json:"updated_before,omitempty"`
-	IssueType           *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
-	IterationID         *int             `url:"iteration_id,omitempty" json:"iteration_id,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"`
+	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         *AssigneeIDValue `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"`
+	IssueType          *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
 }
 
 // ListGroupIssues gets a list of group issues. This function accepts
@@ -329,37 +316,33 @@ 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"`
-	AuthorUsername      *string          `url:"author_username,omitempty" json:"author_username,omitempty"`
-	NotAuthorUsername   *string          `url:"not[author_username],omitempty" json:"not[author_username],omitempty"`
-	NotAuthorID         *[]int           `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
-	AssigneeID          *AssigneeIDValue `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"`
-	NotAssigneeUsername *string          `url:"not[assignee_username],omitempty" json:"not[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"`
-	NotIn               *string          `url:"not[in],omitempty" json:"not[in],omitempty"`
-	CreatedAfter        *time.Time       `url:"created_after,omitempty" json:"created_after,omitempty"`
-	CreatedBefore       *time.Time       `url:"created_before,omitempty" json:"created_before,omitempty"`
-	DueDate             *string          `url:"due_date,omitempty" json:"due_date,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"`
-	IssueType           *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
-	IterationID         *int             `url:"iteration_id,omitempty" json:"iteration_id,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"`
+	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"`
+	AuthorUsername     *string          `url:"author_username,omitempty" json:"author_username,omitempty"`
+	NotAuthorID        *[]int           `url:"not[author_id],omitempty" json:"not[author_id],omitempty"`
+	AssigneeID         *AssigneeIDValue `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"`
+	DueDate            *string          `url:"due_date,omitempty" json:"due_date,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"`
+	IssueType          *string          `url:"issue_type,omitempty" json:"issue_type,omitempty"`
 }
 
 // ListProjectIssues gets a list of project issues. This function accepts
diff --git a/jobs.go b/jobs.go
index ec06009..b238fc8 100644
--- a/jobs.go
+++ b/jobs.go
@@ -48,11 +48,10 @@ type Job struct {
 	ID                int        `json:"id"`
 	Name              string     `json:"name"`
 	Pipeline          struct {
-		ID        int    `json:"id"`
-		ProjectID int    `json:"project_id"`
-		Ref       string `json:"ref"`
-		Sha       string `json:"sha"`
-		Status    string `json:"status"`
+		ID     int    `json:"id"`
+		Ref    string `json:"ref"`
+		Sha    string `json:"sha"`
+		Status string `json:"status"`
 	} `json:"pipeline"`
 	Ref       string `json:"ref"`
 	Artifacts []struct {
@@ -499,36 +498,18 @@ func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...Reque
 	return job, resp, err
 }
 
-// PlayJobOptions represents the available PlayJob() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/jobs.html#run-a-job
-type PlayJobOptions struct {
-	JobVariablesAttributes *[]*JobVariableOptions `url:"job_variables_attributes,omitempty" json:"job_variables_attributes,omitempty"`
-}
-
-// JobVariableOptions represents a single job variable.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/jobs.html#run-a-job
-type JobVariableOptions struct {
-	Key          *string `url:"key,omitempty" json:"key,omitempty"`
-	Value        *string `url:"value,omitempty" json:"value,omitempty"`
-	VariableType *string `url:"variable_type,omitempty" json:"variable_type,omitempty"`
-}
-
 // PlayJob triggers a manual action to start a job.
 //
 // GitLab API docs:
-// https://docs.gitlab.com/ce/api/jobs.html#run-a-job
-func (s *JobsService) PlayJob(pid interface{}, jobID int, opt *PlayJobOptions, options ...RequestOptionFunc) (*Job, *Response, error) {
+// https://docs.gitlab.com/ce/api/jobs.html#play-a-job
+func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
 	u := fmt.Sprintf("projects/%s/jobs/%d/play", PathEscape(project), jobID)
 
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
+	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -546,17 +527,23 @@ func (s *JobsService) PlayJob(pid interface{}, jobID int, opt *PlayJobOptions, o
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/job_artifacts.html#delete-artifacts
-func (s *JobsService) DeleteArtifacts(pid interface{}, jobID int, options ...RequestOptionFunc) (*Response, error) {
+func (s *JobsService) DeleteArtifacts(pid interface{}, jobID int, options ...RequestOptionFunc) (*Job, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", PathEscape(project), jobID)
 
 	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return s.client.Do(req, nil)
+	job := new(Job)
+	resp, err := s.client.Do(req, job)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return job, resp, err
 }
diff --git a/license.go b/license.go
index ddec3be..618fde6 100644
--- a/license.go
+++ b/license.go
@@ -70,8 +70,8 @@ func (l License) String() string {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/license.html#retrieve-information-about-the-current-license
-func (s *LicenseService) GetLicense(options ...RequestOptionFunc) (*License, *Response, error) {
-	req, err := s.client.NewRequest(http.MethodGet, "license", nil, options)
+func (s *LicenseService) GetLicense() (*License, *Response, error) {
+	req, err := s.client.NewRequest(http.MethodGet, "license", nil, nil)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/notes.go b/notes.go
index 5dae480..40e41d4 100644
--- a/notes.go
+++ b/notes.go
@@ -82,7 +82,7 @@ type NotePosition struct {
 	NewLine      int        `json:"new_line,omitempty"`
 	OldPath      string     `json:"old_path,omitempty"`
 	OldLine      int        `json:"old_line,omitempty"`
-	LineRange    *LineRange `json:"line_range,omitempty"`
+	LineRange    *LineRange `json:"line_range"`
 }
 
 // LineRange represents the range of a note.
diff --git a/packages.go b/packages.go
index d3e2be3..06a1937 100644
--- a/packages.go
+++ b/packages.go
@@ -224,22 +224,3 @@ func (s *PackagesService) DeleteProjectPackage(pid interface{}, pkg int, options
 
 	return s.client.Do(req, nil)
 }
-
-// DeletePackageFile deletes a file in project package
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/packages.html#delete-a-package-file
-func (s *PackagesService) DeletePackageFile(pid interface{}, pkg, file int, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/packages/%d/package_files/%d", PathEscape(project), pkg, file)
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/pipeline_schedules.go b/pipeline_schedules.go
index 1a8cb8c..12640e2 100644
--- a/pipeline_schedules.go
+++ b/pipeline_schedules.go
@@ -110,39 +110,6 @@ func (s *PipelineSchedulesService) GetPipelineSchedule(pid interface{}, schedule
 	return p, resp, err
 }
 
-// ListPipelinesTriggeredByScheduleOptions represents the available
-// ListPipelinesTriggeredBySchedule() options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/pipeline_schedules.html#get-all-pipelines-triggered-by-a-pipeline-schedule
-type ListPipelinesTriggeredByScheduleOptions ListOptions
-
-// ListPipelinesTriggeredBySchedule gets all pipelines triggered by a pipeline
-// schedule.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/pipeline_schedules.html#get-all-pipelines-triggered-by-a-pipeline-schedule
-func (s *PipelineSchedulesService) ListPipelinesTriggeredBySchedule(pid interface{}, schedule int, opt *ListPipelinesTriggeredByScheduleOptions, options ...RequestOptionFunc) ([]*Pipeline, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/pipelines", PathEscape(project), schedule)
-
-	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var p []*Pipeline
-	resp, err := s.client.Do(req, &p)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return p, resp, err
-}
-
 // CreatePipelineScheduleOptions represents the available
 // CreatePipelineSchedule() options.
 //
diff --git a/project_feature_flags.go b/project_feature_flags.go
deleted file mode 100644
index c01a17e..0000000
--- a/project_feature_flags.go
+++ /dev/null
@@ -1,239 +0,0 @@
-package gitlab
-
-import (
-	"fmt"
-	"net/http"
-	"time"
-)
-
-// ProjectFeatureFlagService handles operations on gitlab project feature
-// flags using the following api:
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/feature_flags.html
-type ProjectFeatureFlagService struct {
-	client *Client
-}
-
-// ProjectFeatureFlag represents a GitLab project iteration.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/feature_flags.html
-type ProjectFeatureFlag struct {
-	Name        string                        `json:"name"`
-	Description string                        `json:"description"`
-	Active      bool                          `json:"active"`
-	Version     string                        `json:"version"`
-	CreatedAt   *time.Time                    `json:"created_at"`
-	UpdatedAt   *time.Time                    `json:"updated_at"`
-	Scopes      []*ProjectFeatureFlagScope    `json:"scopes"`
-	Strategies  []*ProjectFeatureFlagStrategy `json:"strategies"`
-}
-
-// ProjectFeatureFlagScope defines the scopes of a feature flag
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/feature_flags.html
-type ProjectFeatureFlagScope struct {
-	ID               int    `json:"id"`
-	EnvironmentScope string `json:"environment_scope"`
-}
-
-// ProjectFeatureFlagStrategy defines the strategy used for a feature flag
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/feature_flags.html
-type ProjectFeatureFlagStrategy struct {
-	ID         int                                  `json:"id"`
-	Name       string                               `json:"name"`
-	Parameters *ProjectFeatureFlagStrategyParameter `json:"parameters"`
-	Scopes     []*ProjectFeatureFlagScope           `json:"scopes"`
-}
-
-// ProjectFeatureFlagStrategyParameter is used in updating and creating feature flags
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/feature_flags.html
-type ProjectFeatureFlagStrategyParameter struct {
-	GroupID    string `json:"groupId,omitempty"`
-	UserIDs    string `json:"userIds,omitempty"`
-	Percentage string `json:"percentage,omitempty"`
-}
-
-func (i ProjectFeatureFlag) String() string {
-	return Stringify(i)
-}
-
-// ListProjectFeatureFlagOptions contains the options for ListProjectFeatureFlags
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#list-feature-flags-for-a-project
-type ListProjectFeatureFlagOptions struct {
-	ListOptions
-	Scope *string `url:"scope,omitempty" json:"scope,omitempty"`
-}
-
-// ListProjectFeatureFlags returns a list with the feature flags of a project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#list-feature-flags-for-a-project
-func (s *ProjectFeatureFlagService) ListProjectFeatureFlags(pid interface{}, opt *ListProjectFeatureFlagOptions, options ...RequestOptionFunc) ([]*ProjectFeatureFlag, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/feature_flags", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var pffs []*ProjectFeatureFlag
-	resp, err := s.client.Do(req, &pffs)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return pffs, resp, err
-}
-
-// GetProjectFeatureFlag gets a single feature flag for the specified project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#get-a-single-feature-flag
-func (s *ProjectFeatureFlagService) GetProjectFeatureFlag(pid interface{}, name string, options ...RequestOptionFunc) (*ProjectFeatureFlag, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/feature_flags/%s", PathEscape(project), name)
-
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	flag := new(ProjectFeatureFlag)
-	resp, err := s.client.Do(req, flag)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return flag, resp, err
-}
-
-// CreateProjectFeatureFlagOptions represents the available
-// CreateProjectFeatureFlag() options.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#create-a-feature-flag
-type CreateProjectFeatureFlagOptions struct {
-	Name        *string                        `url:"name,omitempty" json:"name,omitempty"`
-	Description *string                        `url:"description,omitempty" json:"description,omitempty"`
-	Version     *string                        `url:"version,omitempty" json:"version,omitempty"`
-	Active      *bool                          `url:"active,omitempty" json:"active,omitempty"`
-	Strategies  *[]*FeatureFlagStrategyOptions `url:"strategies,omitempty" json:"strategies,omitempty"`
-}
-
-// FeatureFlagStrategyOptions represents the available feature flag strategy
-// options.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#create-a-feature-flag
-type FeatureFlagStrategyOptions struct {
-	Name       *string                              `url:"name,omitempty" json:"name,omitempty"`
-	Parameters *ProjectFeatureFlagStrategyParameter `url:"parameters,omitempty" json:"parameters,omitempty"`
-	Scopes     *[]*ProjectFeatureFlagScope          `url:"scopes,omitempty" json:"scopes,omitempty"`
-}
-
-// ProjectFeatureFlagScopeOptions represents the available feature flag scope
-// options.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#create-a-feature-flag
-type ProjectFeatureFlagScopeOptions struct {
-	ID               *int    `url:"id,omitempty" json:"id,omitempty"`
-	EnvironmentScope *string `url:"id,omitempty" json:"environment_scope,omitempty"`
-}
-
-// CreateProjectFeatureFlag creates a feature flag
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#create-a-feature-flag
-func (s *ProjectFeatureFlagService) CreateProjectFeatureFlag(pid interface{}, opt *CreateProjectFeatureFlagOptions, options ...RequestOptionFunc) (*ProjectFeatureFlag, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/feature_flags",
-		PathEscape(project),
-	)
-
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	flag := new(ProjectFeatureFlag)
-	resp, err := s.client.Do(req, flag)
-	if err != nil {
-		return flag, resp, err
-	}
-
-	return flag, resp, err
-}
-
-// UpdateProjectFeatureFlagOptions represents the available
-// UpdateProjectFeatureFlag() options.
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#update-a-feature-flag
-type UpdateProjectFeatureFlagOptions struct {
-	Name        *string                        `url:"name,omitempty" json:"name,omitempty"`
-	Description *string                        `url:"description,omitempty" json:"description,omitempty"`
-	Active      *bool                          `url:"active,omitempty" json:"active,omitempty"`
-	Strategies  *[]*FeatureFlagStrategyOptions `url:"strategies,omitempty" json:"strategies,omitempty"`
-}
-
-// UpdateProjectFeatureFlag updates a feature flag
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#update-a-feature-flag
-func (s *ProjectFeatureFlagService) UpdateProjectFeatureFlag(pid interface{}, name string, opt *UpdateProjectFeatureFlagOptions, options ...RequestOptionFunc) (*ProjectFeatureFlag, *Response, error) {
-	group, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/feature_flags/%s",
-		PathEscape(group),
-		name,
-	)
-
-	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	flag := new(ProjectFeatureFlag)
-	resp, err := s.client.Do(req, flag)
-	if err != nil {
-		return flag, resp, err
-	}
-
-	return flag, resp, err
-}
-
-// DeleteProjectFeatureFlag deletes a feature flag
-//
-// Gitlab API docs:
-// https://docs.gitlab.com/ee/api/feature_flags.html#delete-a-feature-flag
-func (s *ProjectFeatureFlagService) DeleteProjectFeatureFlag(pid interface{}, name string, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/feature_flags/%s", PathEscape(project), name)
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/projects.go b/projects.go
index 151d0a6..1bef75f 100644
--- a/projects.go
+++ b/projects.go
@@ -17,6 +17,7 @@
 package gitlab
 
 import (
+	"encoding/json"
 	"fmt"
 	"io"
 	"net/http"
@@ -82,7 +83,7 @@ type Project struct {
 	ForksCount                                int                        `json:"forks_count"`
 	StarCount                                 int                        `json:"star_count"`
 	RunnersToken                              string                     `json:"runners_token"`
-	PublicJobs                                bool                       `json:"public_jobs"`
+	PublicBuilds                              bool                       `json:"public_builds"`
 	AllowMergeOnSkippedPipeline               bool                       `json:"allow_merge_on_skipped_pipeline"`
 	OnlyAllowMergeIfPipelineSucceeds          bool                       `json:"only_allow_merge_if_pipeline_succeeds"`
 	OnlyAllowMergeIfAllDiscussionsAreResolved bool                       `json:"only_allow_merge_if_all_discussions_are_resolved"`
@@ -116,18 +117,15 @@ type Project struct {
 	AutoCancelPendingPipelines                string                     `json:"auto_cancel_pending_pipelines"`
 	CIForwardDeploymentEnabled                bool                       `json:"ci_forward_deployment_enabled"`
 	SquashOption                              SquashOptionValue          `json:"squash_option"`
-	EnforceAuthChecksOnUploads                bool                       `json:"enforce_auth_checks_on_uploads,omitempty"`
 	SharedWithGroups                          []struct {
 		GroupID          int    `json:"group_id"`
 		GroupName        string `json:"group_name"`
-		GroupFullPath    string `json:"group_full_path"`
 		GroupAccessLevel int    `json:"group_access_level"`
 	} `json:"shared_with_groups"`
-	Statistics                               *Statistics        `json:"statistics"`
+	Statistics                               *ProjectStatistics `json:"statistics"`
 	Links                                    *Links             `json:"_links,omitempty"`
 	CIConfigPath                             string             `json:"ci_config_path"`
 	CIDefaultGitDepth                        int                `json:"ci_default_git_depth"`
-	CISeperateCache                          bool               `json:"ci_separated_caches"`
 	CustomAttributes                         []*CustomAttribute `json:"custom_attributes"`
 	ComplianceFrameworks                     []string           `json:"compliance_frameworks"`
 	BuildCoverageRegex                       string             `json:"build_coverage_regex"`
@@ -147,9 +145,6 @@ type Project struct {
 	ExternalAuthorizationClassificationLabel string             `json:"external_authorization_classification_label"`
 	RequirementsAccessLevel                  AccessControlValue `json:"requirements_access_level"`
 	SecurityAndComplianceAccessLevel         AccessControlValue `json:"security_and_compliance_access_level"`
-
-	// Deprecated members
-	PublicBuilds bool `json:"public_builds"`
 }
 
 // BasicProject included in other service responses (such as todos).
@@ -236,6 +231,12 @@ type ProjectNamespace struct {
 	WebURL    string `json:"web_url"`
 }
 
+// ProjectStatistics represents a statistics record for a project.
+type ProjectStatistics struct {
+	StorageStatistics
+	CommitCount int `json:"commit_count"`
+}
+
 // Repository represents a repository.
 type Repository struct {
 	Name              string          `json:"name"`
@@ -254,18 +255,12 @@ type Repository struct {
 	HTTPURL           string          `json:"http_url"`
 }
 
-// Statistics represents a statistics record for a group or project.
-type Statistics struct {
-	CommitCount           int64 `json:"commit_count"`
-	StorageSize           int64 `json:"storage_size"`
-	RepositorySize        int64 `json:"repository_size"`
-	WikiSize              int64 `json:"wiki_size"`
-	LFSObjectsSize        int64 `json:"lfs_objects_size"`
-	JobArtifactsSize      int64 `json:"job_artifacts_size"`
-	PipelineArtifactsSize int64 `json:"pipeline_artifacts_size"`
-	PackagesSize          int64 `json:"packages_size"`
-	SnippetsSize          int64 `json:"snippets_size"`
-	UploadsSize           int64 `json:"uploads_size"`
+// StorageStatistics represents a statistics record for a group or project.
+type StorageStatistics struct {
+	StorageSize      int64 `json:"storage_size"`
+	RepositorySize   int64 `json:"repository_size"`
+	LfsObjectsSize   int64 `json:"lfs_objects_size"`
+	JobArtifactsSize int64 `json:"job_artifacts_size"`
 }
 
 func (s Project) String() string {
@@ -628,7 +623,6 @@ type CreateProjectOptions struct {
 	DefaultBranch                             *string                              `url:"default_branch,omitempty" json:"default_branch,omitempty"`
 	Description                               *string                              `url:"description,omitempty" json:"description,omitempty"`
 	EmailsDisabled                            *bool                                `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
-	EnforceAuthChecksOnUploads                *bool                                `url:"enforce_auth_checks_on_uploads,omitempty" json:"enforce_auth_checks_on_uploads,omitempty"`
 	ExternalAuthorizationClassificationLabel  *string                              `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"`
 	ForkingAccessLevel                        *AccessControlValue                  `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"`
 	GroupWithProjectTemplatesID               *int                                 `url:"group_with_project_templates_id,omitempty" json:"group_with_project_templates_id,omitempty"`
@@ -711,6 +705,15 @@ type ProjectAvatar struct {
 	Image    io.Reader
 }
 
+// MarshalJSON implements the json.Marshaler interface.
+func (a *ProjectAvatar) MarshalJSON() ([]byte, error) {
+	if a.Filename == "" && a.Image == nil {
+		return []byte(`""`), nil
+	}
+	type alias ProjectAvatar
+	return json.Marshal((*alias)(a))
+}
+
 // CreateProject creates a new project owned by the authenticated user.
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project
@@ -812,20 +815,18 @@ type EditProjectOptions struct {
 	AutoDevopsDeployStrategy                  *string                              `url:"auto_devops_deploy_strategy,omitempty" json:"auto_devops_deploy_strategy,omitempty"`
 	AutoDevopsEnabled                         *bool                                `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
 	AutocloseReferencedIssues                 *bool                                `url:"autoclose_referenced_issues,omitempty" json:"autoclose_referenced_issues,omitempty"`
-	Avatar                                    *ProjectAvatar                       `url:"-" json:"-"`
+	Avatar                                    *ProjectAvatar                       `url:"-" json:"avatar,omitempty"`
 	BuildCoverageRegex                        *string                              `url:"build_coverage_regex,omitempty" json:"build_coverage_regex,omitempty"`
 	BuildGitStrategy                          *string                              `url:"build_git_strategy,omitempty" json:"build_git_strategy,omitempty"`
 	BuildTimeout                              *int                                 `url:"build_timeout,omitempty" json:"build_timeout,omitempty"`
 	BuildsAccessLevel                         *AccessControlValue                  `url:"builds_access_level,omitempty" json:"builds_access_level,omitempty"`
 	CIConfigPath                              *string                              `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"`
 	CIDefaultGitDepth                         *int                                 `url:"ci_default_git_depth,omitempty" json:"ci_default_git_depth,omitempty"`
-	CISeperateCache                           *bool                                `url:"ci_separated_caches,omitempty" json:"ci_separated_caches,omitempty"`
 	ContainerExpirationPolicyAttributes       *ContainerExpirationPolicyAttributes `url:"container_expiration_policy_attributes,omitempty" json:"container_expiration_policy_attributes,omitempty"`
 	ContainerRegistryAccessLevel              *AccessControlValue                  `url:"container_registry_access_level,omitempty" json:"container_registry_access_level,omitempty"`
 	DefaultBranch                             *string                              `url:"default_branch,omitempty" json:"default_branch,omitempty"`
 	Description                               *string                              `url:"description,omitempty" json:"description,omitempty"`
 	EmailsDisabled                            *bool                                `url:"emails_disabled,omitempty" json:"emails_disabled,omitempty"`
-	EnforceAuthChecksOnUploads                *bool                                `url:"enforce_auth_checks_on_uploads,omitempty" json:"enforce_auth_checks_on_uploads,omitempty"`
 	ExternalAuthorizationClassificationLabel  *string                              `url:"external_authorization_classification_label,omitempty" json:"external_authorization_classification_label,omitempty"`
 	ForkingAccessLevel                        *AccessControlValue                  `url:"forking_access_level,omitempty" json:"forking_access_level,omitempty"`
 	ImportURL                                 *string                              `url:"import_url,omitempty" json:"import_url,omitempty"`
@@ -902,11 +903,11 @@ func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions,
 
 	var req *retryablehttp.Request
 
-	if opt.Avatar == nil {
+	if opt.Avatar == nil || (opt.Avatar.Filename == "" && opt.Avatar.Image == nil) {
 		req, err = s.client.NewRequest(http.MethodPut, u, opt, options)
 	} else {
 		req, err = s.client.UploadRequest(
-			http.MethodPost,
+			http.MethodPut,
 			u,
 			opt.Avatar.Image,
 			opt.Avatar.Filename,
diff --git a/protected_tags.go b/protected_tags.go
index 4f8fb4e..f53c989 100644
--- a/protected_tags.go
+++ b/protected_tags.go
@@ -44,8 +44,6 @@ type ProtectedTag struct {
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/protected_tags.html
 type TagAccessDescription struct {
-	UserID                 int              `json:"user_id"`
-	GroupID                int              `json:"group_id"`
 	AccessLevel            AccessLevelValue `json:"access_level"`
 	AccessLevelDescription string           `json:"access_level_description"`
 }
@@ -113,19 +111,8 @@ func (s *ProtectedTagsService) GetProtectedTag(pid interface{}, tag string, opti
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags
 type ProtectRepositoryTagsOptions struct {
-	Name              *string                   `url:"name,omitempty" json:"name,omitempty"`
-	CreateAccessLevel *AccessLevelValue         `url:"create_access_level,omitempty" json:"create_access_level,omitempty"`
-	AllowedToCreate   *[]*TagsPermissionOptions `url:"allowed_to_create,omitempty" json:"allowed_to_create,omitempty"`
-}
-
-// TagsPermissionOptions represents a protected tag permission option.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/protected_tags.html#protect-repository-tags
-type TagsPermissionOptions struct {
-	UserID      *int              `url:"user_id,omitempty" json:"user_id,omitempty"`
-	GroupID     *int              `url:"group_id,omitempty" json:"group_id,omitempty"`
-	AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"`
+	Name              *string           `url:"name" json:"name"`
+	CreateAccessLevel *AccessLevelValue `url:"create_access_level,omitempty" json:"create_access_level,omitempty"`
 }
 
 // ProtectRepositoryTags protects a single repository tag or several project
diff --git a/releases.go b/releases.go
index 7a7a555..f7876d2 100644
--- a/releases.go
+++ b/releases.go
@@ -67,12 +67,7 @@ type Release struct {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/releases/index.html#list-releases
-type ListReleasesOptions struct {
-	ListOptions
-	OrderBy                *string `url:"order_by,omitempty" json:"order_by,omitempty"`
-	Sort                   *string `url:"sort,omitempty" json:"sort,omitempty"`
-	IncludeHTMLDescription *bool   `url:"include_html_description,omitempty" json:"include_html_description,omitempty"`	
-}
+type ListReleasesOptions ListOptions
 
 // ListReleases gets a pagenated of releases accessible by the authenticated user.
 //
diff --git a/resource_weight_events.go b/resource_weight_events.go
deleted file mode 100644
index e1a4bf5..0000000
--- a/resource_weight_events.go
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2021, Matthias Simon
-//
-// 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/http"
-	"time"
-)
-
-// ResourceWeightEventsService handles communication with the event related
-// methods of the GitLab API.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/resource_weight_events.html
-type ResourceWeightEventsService struct {
-	client *Client
-}
-
-// WeightEvent represents a resource weight event.
-//
-// GitLab API docs: https://docs.gitlab.com/ee/api/resource_weight_events.html
-type WeightEvent struct {
-	ID           int            `json:"id"`
-	User         *BasicUser     `json:"user"`
-	CreatedAt    *time.Time     `json:"created_at"`
-	ResourceType string         `json:"resource_type"`
-	ResourceID   int            `json:"resource_id"`
-	State        EventTypeValue `json:"state"`
-	IssueID      int            `json:"issue_id"`
-	Weight       int            `json:"weight"`
-}
-
-// ListWeightEventsOptions represents the options for all resource weight events
-// list methods.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/resource_weight_events.html#list-project-issue-weight-events
-type ListWeightEventsOptions struct {
-	ListOptions
-}
-
-// ListIssueWeightEvents retrieves resource weight events for the specified
-// project and issue.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/resource_weight_events.html#list-project-issue-weight-events
-func (s *ResourceWeightEventsService) ListIssueWeightEvents(pid interface{}, issue int, opt *ListWeightEventsOptions, options ...RequestOptionFunc) ([]*WeightEvent, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/issues/%d/resource_weight_events", PathEscape(project), issue)
-
-	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var wes []*WeightEvent
-	resp, err := s.client.Do(req, &wes)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return wes, resp, err
-}
diff --git a/services.go b/services.go
index c470d56..99688da 100644
--- a/services.go
+++ b/services.go
@@ -270,105 +270,6 @@ func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...Reque
 	return s.client.Do(req, nil)
 }
 
-// EmailsOnPushService represents Emails on Push service settings.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#emails-on-push
-type EmailsOnPushService struct {
-	Service
-	Properties *EmailsOnPushServiceProperties `json:"properties"`
-}
-
-// EmailsOnPushServiceProperties represents Emails on Push specific properties.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#emails-on-push
-type EmailsOnPushServiceProperties struct {
-	Recipients             string `json:"recipients"`
-	DisableDiffs           bool   `json:"disable_diffs"`
-	SendFromCommitterEmail bool   `json:"send_from_committer_email"`
-	PushEvents             bool   `json:"push_events"`
-	TagPushEvents          bool   `json:"tag_push_events"`
-	BranchesToBeNotified   string `json:"branches_to_be_notified"`
-}
-
-// GetEmailsOnPushService gets Emails on Push service settings for a project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#get-emails-on-push-integration-settings
-func (s *ServicesService) GetEmailsOnPushService(pid interface{}, options ...RequestOptionFunc) (*EmailsOnPushService, *Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, nil, err
-	}
-	u := fmt.Sprintf("projects/%s/integrations/emails-on-push", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	svc := new(EmailsOnPushService)
-	resp, err := s.client.Do(req, svc)
-	if err != nil {
-		return nil, resp, err
-	}
-
-	return svc, resp, err
-}
-
-// SetEmailsOnPushServiceOptions represents the available SetEmailsOnPushService()
-// options.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#createedit-emails-on-push-integration
-type SetEmailsOnPushServiceOptions struct {
-	Recipients             *string `url:"recipients,omitempty" json:"recipients,omitempty"`
-	DisableDiffs           *bool   `url:"disable_diffs,omitempty" json:"disable_diffs,omitempty"`
-	SendFromCommitterEmail *bool   `url:"send_from_committer_email,omitempty" json:"send_from_committer_email,omitempty"`
-	PushEvents             *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
-	TagPushEvents          *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
-	BranchesToBeNotified   *string `url:"branches_to_be_notified,omitempty" json:"branches_to_be_notified,omitempty"`
-}
-
-// SetEmailsOnPushService sets Emails on Push service for a project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#createedit-emails-on-push-integration
-func (s *ServicesService) SetEmailsOnPushService(pid interface{}, opt *SetEmailsOnPushServiceOptions, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/integrations/emails-on-push", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
-// DeleteEmailsOnPushService deletes Emails on Push service settings for a project.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/integrations.html#disable-emails-on-push-integration
-func (s *ServicesService) DeleteEmailsOnPushService(pid interface{}, options ...RequestOptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/integrations/emails-on-push", PathEscape(project))
-
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
-
 // ExternalWikiService represents External Wiki service settings.
 //
 // GitLab API docs:
diff --git a/settings.go b/settings.go
index 5905307..4e0006b 100644
--- a/settings.go
+++ b/settings.go
@@ -58,13 +58,11 @@ type Settings struct {
 	AssetProxyAllowlist                                   []string          `json:"asset_proxy_allowlist"`
 	AssetProxyEnabled                                     bool              `json:"asset_proxy_enabled"`
 	AssetProxyURL                                         string            `json:"asset_proxy_url"`
-	AssetProxySecretKey                                   string            `json:"asset_proxy_secret_key"`
 	AssetProxyWhitelist                                   []string          `json:"asset_proxy_whitelist"` // deprecated
 	AuthorizedKeysEnabled                                 bool              `json:"authorized_keys_enabled"`
 	AutoDevOpsDomain                                      string            `json:"auto_devops_domain"`
 	AutoDevOpsEnabled                                     bool              `json:"auto_devops_enabled"`
 	AutomaticPurchasedStorageAllocation                   bool              `json:"automatic_purchased_storage_allocation"`
-	CanCreateGroup                                        bool              `json:"can_create_group"`
 	CheckNamespacePlan                                    bool              `json:"check_namespace_plan"`
 	CommitEmailHostname                                   string            `json:"commit_email_hostname"`
 	ContainerExpirationPoliciesEnableHistoricEntries      bool              `json:"container_expiration_policies_enable_historic_entries"`
@@ -94,9 +92,7 @@ type Settings struct {
 	DefaultProjectVisibility                              VisibilityValue   `json:"default_project_visibility"`
 	DefaultProjectsLimit                                  int               `json:"default_projects_limit"`
 	DefaultSnippetVisibility                              VisibilityValue   `json:"default_snippet_visibility"`
-	DelayedGroupDeletion                                  bool              `json:"delayed_group_deletion"`
 	DelayedProjectDeletion                                bool              `json:"delayed_project_deletion"`
-	DeleteInactiveProjects                                bool              `json:"delete_inactive_projects"`
 	DeletionAdjournedPeriod                               int               `json:"deletion_adjourned_period"`
 	DiffMaxFiles                                          int               `json:"diff_max_files"`
 	DiffMaxLines                                          int               `json:"diff_max_lines"`
@@ -112,13 +108,11 @@ type Settings struct {
 	EKSAccessKeyID                                        string            `json:"eks_access_key_id"`
 	EKSAccountID                                          string            `json:"eks_account_id"`
 	EKSIntegrationEnabled                                 bool              `json:"eks_integration_enabled"`
-	EKSSecretAccessKey                                    string            `json:"eks_secret_access_key"`
 	Ed25519KeyRestriction                                 int               `json:"ed25519_key_restriction"`
 	Ed25519SKKeyRestriction                               int               `json:"ed25519_sk_key_restriction"`
 	ElasticsearchAWS                                      bool              `json:"elasticsearch_aws"`
 	ElasticsearchAWSAccessKey                             string            `json:"elasticsearch_aws_access_key"`
 	ElasticsearchAWSRegion                                string            `json:"elasticsearch_aws_region"`
-	ElasticsearchAWSSecretAccessKey                       string            `json:"elasticsearch_aws_secret_access_key"`
 	ElasticsearchAnalyzersKuromojiEnabled                 bool              `json:"elasticsearch_analyzers_kuromoji_enabled"`
 	ElasticsearchAnalyzersKuromojiSearch                  bool              `json:"elasticsearch_analyzers_kuromoji_search"`
 	ElasticsearchAnalyzersSmartCNEnabled                  bool              `json:"elasticsearch_analyzers_smartcn_enabled"`
@@ -169,7 +163,6 @@ type Settings struct {
 	GitalyTimeoutMedium                                   int               `json:"gitaly_timeout_medium"`
 	GitpodEnabled                                         bool              `json:"gitpod_enabled"`
 	GitpodURL                                             string            `json:"gitpod_url"`
-	GitRateLimitUsersAllowlist                            []string          `json:"git_rate_limit_users_allowlist"`
 	GrafanaEnabled                                        bool              `json:"grafana_enabled"`
 	GrafanaURL                                            string            `json:"grafana_url"`
 	GravatarEnabled                                       bool              `json:"gravatar_enabled"`
@@ -193,9 +186,6 @@ type Settings struct {
 	HousekeepingGcPeriod                                  int               `json:"housekeeping_gc_period"`
 	HousekeepingIncrementalRepackPeriod                   int               `json:"housekeeping_incremental_repack_period"`
 	ImportSources                                         []string          `json:"import_sources"`
-	InactiveProjectsDeleteAfterMonths                     int               `json:"inactive_projects_delete_after_months"`
-	InactiveProjectsMinSizeMB                             int               `json:"inactive_projects_min_size_mb"`
-	InactiveProjectsSendWarningEmailAfterMonths           int               `json:"inactive_projects_send_warning_email_after_months"`
 	InProductMarketingEmailsEnabled                       bool              `json:"in_product_marketing_emails_enabled"`
 	InvisibleCaptchaEnabled                               bool              `json:"invisible_captcha_enabled"`
 	IssuesCreateLimit                                     int               `json:"issues_create_limit"`
@@ -212,10 +202,7 @@ type Settings struct {
 	MaintenanceModeMessage                                string            `json:"maintenance_mode_message"`
 	MaxArtifactsSize                                      int               `json:"max_artifacts_size"`
 	MaxAttachmentSize                                     int               `json:"max_attachment_size"`
-	MaxExportSize                                         int               `json:"max_export_size"`
 	MaxImportSize                                         int               `json:"max_import_size"`
-	MaxNumberOfRepositoryDownloads                        int               `json:"max_number_of_repository_downloads"`
-	MaxNumberOfRepositoryDownloadsWithinTimePeriod        int               `json:"max_number_of_repository_downloads_within_time_period"`
 	MaxPagesSize                                          int               `json:"max_pages_size"`
 	MaxPersonalAccessTokenLifetime                        int               `json:"max_personal_access_token_lifetime"`
 	MaxSSHKeyLifetime                                     int               `json:"max_ssh_key_lifetime"`
@@ -231,20 +218,13 @@ type Settings struct {
 	NotesCreateLimit                                      int               `json:"notes_create_limit"`
 	NotifyOnUnknownSignIn                                 bool              `json:"notify_on_unknown_sign_in"`
 	OutboundLocalRequestsAllowlistRaw                     string            `json:"outbound_local_requests_allowlist_raw"`
-	OutboundLocalRequestsWhitelist                        []string          `json:"outbound_local_requests_whitelist"`
-	PackageRegistryCleanupPoliciesWorkerCapacity          int               `json:"package_registry_cleanup_policies_worker_capacity"`
 	PagesDomainVerificationEnabled                        bool              `json:"pages_domain_verification_enabled"`
 	PasswordAuthenticationEnabledForGit                   bool              `json:"password_authentication_enabled_for_git"`
 	PasswordAuthenticationEnabledForWeb                   bool              `json:"password_authentication_enabled_for_web"`
-	PasswordNumberRequired                                bool              `json:"password_number_required"`
-	PasswordSymbolRequired                                bool              `json:"password_symbol_required"`
-	PasswordUppercaseRequired                             bool              `json:"password_uppercase_required"`
-	PasswordLowercaseRequired                             bool              `json:"password_lowercase_required"`
 	PerformanceBarAllowedGroupID                          string            `json:"performance_bar_allowed_group_id"`
 	PerformanceBarAllowedGroupPath                        string            `json:"performance_bar_allowed_group_path"`
 	PerformanceBarEnabled                                 bool              `json:"performance_bar_enabled"`
 	PersonalAccessTokenPrefix                             string            `json:"personal_access_token_prefix"`
-	PipelineLimitPerProjectUserSha                        int               `json:"pipeline_limit_per_project_user_sha"`
 	PlantumlEnabled                                       bool              `json:"plantuml_enabled"`
 	PlantumlURL                                           string            `json:"plantuml_url"`
 	PollingIntervalMultiplier                             float64           `json:"polling_interval_multiplier,string"`
@@ -270,7 +250,6 @@ type Settings struct {
 	ReceiveMaxInputSize                                   int               `json:"receive_max_input_size"`
 	RepositoryChecksEnabled                               bool              `json:"repository_checks_enabled"`
 	RepositorySizeLimit                                   int               `json:"repository_size_limit"`
-	RepositoryStorages                                    []string          `json:"repository_storages"`
 	RepositoryStoragesWeighted                            map[string]int    `json:"repository_storages_weighted"`
 	RequireAdminApprovalAfterUserSignup                   bool              `json:"require_admin_approval_after_user_signup"`
 	RequireTwoFactorAuthentication                        bool              `json:"require_two_factor_authentication"`
@@ -299,7 +278,6 @@ type Settings struct {
 	SlackAppEnabled                                       bool              `json:"slack_app_enabled"`
 	SlackAppID                                            string            `json:"slack_app_id"`
 	SlackAppSecret                                        string            `json:"slack_app_secret"`
-	SlackAppSigningSecret                                 string            `json:"slack_app_signing_secret"`
 	SlackAppVerificationToken                             string            `json:"slack_app_verification_token"`
 	SnippetSizeLimit                                      int               `json:"snippet_size_limit"`
 	SnowplowAppID                                         string            `json:"snowplow_app_id"`
@@ -432,7 +410,6 @@ type UpdateSettingsOptions struct {
 	AutoDevOpsDomain                                      *string            `url:"auto_devops_domain,omitempty" json:"auto_devops_domain,omitempty"`
 	AutoDevOpsEnabled                                     *bool              `url:"auto_devops_enabled,omitempty" json:"auto_devops_enabled,omitempty"`
 	AutomaticPurchasedStorageAllocation                   *bool              `url:"automatic_purchased_storage_allocation,omitempty" json:"automatic_purchased_storage_allocation,omitempty"`
-	CanCreateGroup                                        *bool              `url:"can_create_group,omitempty" json:"can_create_group,omitempty"`
 	CheckNamespacePlan                                    *bool              `url:"check_namespace_plan,omitempty" json:"check_namespace_plan,omitempty"`
 	CommitEmailHostname                                   *string            `url:"commit_email_hostname,omitempty" json:"commit_email_hostname,omitempty"`
 	ContainerExpirationPoliciesEnableHistoricEntries      *bool              `url:"container_expiration_policies_enable_historic_entries,omitempty" json:"container_expiration_policies_enable_historic_entries,omitempty"`
@@ -461,9 +438,7 @@ type UpdateSettingsOptions struct {
 	DefaultProjectVisibility                              *VisibilityValue   `url:"default_project_visibility,omitempty" json:"default_project_visibility,omitempty"`
 	DefaultProjectsLimit                                  *int               `url:"default_projects_limit,omitempty" json:"default_projects_limit,omitempty"`
 	DefaultSnippetVisibility                              *VisibilityValue   `url:"default_snippet_visibility,omitempty" json:"default_snippet_visibility,omitempty"`
-	DelayedGroupDeletion                                  *bool              `url:"delayed_group_deletion,omitempty" json:"delayed_group_deletion,omitempty"`
 	DelayedProjectDeletion                                *bool              `url:"delayed_project_deletion,omitempty" json:"delayed_project_deletion,omitempty"`
-	DeleteInactiveProjects                                *bool              `url:"delete_inactive_projects,omitempty" json:"delete_inactive_projects,omitempty"`
 	DeletionAdjournedPeriod                               *int               `url:"deletion_adjourned_period,omitempty" json:"deletion_adjourned_period,omitempty"`
 	DiffMaxFiles                                          *int               `url:"diff_max_files,omitempty" json:"diff_max_files,omitempty"`
 	DiffMaxLines                                          *int               `url:"diff_max_lines,omitempty" json:"diff_max_lines,omitempty"`
@@ -536,7 +511,6 @@ type UpdateSettingsOptions struct {
 	GitalyTimeoutMedium                                   *int               `url:"gitaly_timeout_medium,omitempty" json:"gitaly_timeout_medium,omitempty"`
 	GitpodEnabled                                         *bool              `url:"gitpod_enabled,omitempty" json:"gitpod_enabled,omitempty"`
 	GitpodURL                                             *string            `url:"gitpod_url,omitempty" json:"gitpod_url,omitempty"`
-	GitRateLimitUsersAllowlist                            *[]string          `url:"git_rate_limit_users_allowlist,omitempty" json:"git_rate_limit_users_allowlist,omitempty"`
 	GrafanaEnabled                                        *bool              `url:"grafana_enabled,omitempty" json:"grafana_enabled,omitempty"`
 	GrafanaURL                                            *string            `url:"grafana_url,omitempty" json:"grafana_url,omitempty"`
 	GravatarEnabled                                       *bool              `url:"gravatar_enabled,omitempty" json:"gravatar_enabled,omitempty"`
@@ -560,9 +534,6 @@ type UpdateSettingsOptions struct {
 	HousekeepingGcPeriod                                  *int               `url:"housekeeping_gc_period,omitempty" json:"housekeeping_gc_period,omitempty"`
 	HousekeepingIncrementalRepackPeriod                   *int               `url:"housekeeping_incremental_repack_period,omitempty" json:"housekeeping_incremental_repack_period,omitempty"`
 	ImportSources                                         *[]string          `url:"import_sources,omitempty" json:"import_sources,omitempty"`
-	InactiveProjectsDeleteAfterMonths                     *int               `url:"inactive_projects_delete_after_months,omitempty" json:"inactive_projects_delete_after_months,omitempty"`
-	InactiveProjectsMinSizeMB                             *int               `url:"inactive_projects_min_size_mb,omitempty" json:"inactive_projects_min_size_mb,omitempty"`
-	InactiveProjectsSendWarningEmailAfterMonths           *int               `url:"inactive_projects_send_warning_email_after_months,omitempty" json:"inactive_projects_send_warning_email_after_months,omitempty"`
 	InProductMarketingEmailsEnabled                       *bool              `url:"in_product_marketing_emails_enabled,omitempty" json:"in_product_marketing_emails_enabled,omitempty"`
 	InvisibleCaptchaEnabled                               *bool              `url:"invisible_captcha_enabled,omitempty" json:"invisible_captcha_enabled,omitempty"`
 	IssuesCreateLimit                                     *int               `url:"issues_create_limit,omitempty" json:"issues_create_limit,omitempty"`
@@ -579,10 +550,7 @@ type UpdateSettingsOptions struct {
 	MaintenanceModeMessage                                *string            `url:"maintenance_mode_message,omitempty" json:"maintenance_mode_message,omitempty"`
 	MaxArtifactsSize                                      *int               `url:"max_artifacts_size,omitempty" json:"max_artifacts_size,omitempty"`
 	MaxAttachmentSize                                     *int               `url:"max_attachment_size,omitempty" json:"max_attachment_size,omitempty"`
-	MaxExportSize                                         *int               `url:"max_export_size,omitempty" json:"max_export_size,omitempty"`
 	MaxImportSize                                         *int               `url:"max_import_size,omitempty" json:"max_import_size,omitempty"`
-	MaxNumberOfRepositoryDownloads                        *int               `url:"max_number_of_repository_downloads,omitempty" json:"max_number_of_repository_downloads,omitempty"`
-	MaxNumberOfRepositoryDownloadsWithinTimePeriod        *int               `url:"max_number_of_repository_downloads_within_time_period,omitempty" json:"max_number_of_repository_downloads_within_time_period,omitempty"`
 	MaxPagesSize                                          *int               `url:"max_pages_size,omitempty" json:"max_pages_size,omitempty"`
 	MaxPersonalAccessTokenLifetime                        *int               `url:"max_personal_access_token_lifetime,omitempty" json:"max_personal_access_token_lifetime,omitempty"`
 	MaxSSHKeyLifetime                                     *int               `url:"max_ssh_key_lifetime,omitempty" json:"max_ssh_key_lifetime,omitempty"`
@@ -598,22 +566,15 @@ type UpdateSettingsOptions struct {
 	NotesCreateLimit                                      *int               `url:"notes_create_limit,omitempty" json:"notes_create_limit,omitempty"`
 	NotifyOnUnknownSignIn                                 *bool              `url:"notify_on_unknown_sign_in,omitempty" json:"notify_on_unknown_sign_in,omitempty"`
 	OutboundLocalRequestsAllowlistRaw                     *string            `url:"outbound_local_requests_allowlist_raw,omitempty" json:"outbound_local_requests_allowlist_raw,omitempty"`
-	OutboundLocalRequestsWhitelist                        *[]string          `url:"outbound_local_requests_whitelist,omitempty" json:"outbound_local_requests_whitelist,omitempty"`
-	PackageRegistryCleanupPoliciesWorkerCapacity          *int               `url:"package_registry_cleanup_policies_worker_capacity,omitempty" json:"package_registry_cleanup_policies_worker_capacity,omitempty"`
 	PagesDomainVerificationEnabled                        *bool              `url:"pages_domain_verification_enabled,omitempty" json:"pages_domain_verification_enabled,omitempty"`
 	PasswordAuthenticationEnabledForGit                   *bool              `url:"password_authentication_enabled_for_git,omitempty" json:"password_authentication_enabled_for_git,omitempty"`
 	PasswordAuthenticationEnabledForWeb                   *bool              `url:"password_authentication_enabled_for_web,omitempty" json:"password_authentication_enabled_for_web,omitempty"`
-	PasswordNumberRequired                                *bool              `url:"password_number_required,omitempty" json:"password_number_required,omitempty"`
-	PasswordSymbolRequired                                *bool              `url:"password_symbol_required,omitempty" json:"password_symbol_required,omitempty"`
-	PasswordUppercaseRequired                             *bool              `url:"password_uppercase_required,omitempty" json:"password_uppercase_required,omitempty"`
-	PasswordLowercaseRequired                             *bool              `url:"password_lowercase_required,omitempty" json:"password_lowercase_required,omitempty"`
 	PerformanceBarAllowedGroupID                          *string            `url:"performance_bar_allowed_group_id,omitempty" json:"performance_bar_allowed_group_id,omitempty"`
 	PerformanceBarAllowedGroupPath                        *string            `url:"performance_bar_allowed_group_path,omitempty" json:"performance_bar_allowed_group_path,omitempty"`
 	PerformanceBarEnabled                                 *bool              `url:"performance_bar_enabled,omitempty" json:"performance_bar_enabled,omitempty"`
 	PersonalAccessTokenPrefix                             *string            `url:"personal_access_token_prefix,omitempty" json:"personal_access_token_prefix,omitempty"`
 	PlantumlEnabled                                       *bool              `url:"plantuml_enabled,omitempty" json:"plantuml_enabled,omitempty"`
 	PlantumlURL                                           *string            `url:"plantuml_url,omitempty" json:"plantuml_url,omitempty"`
-	PipelineLimitPerProjectUserSha                        *int               `url:"pipeline_limit_per_project_user_sha,omitempty" json:"pipeline_limit_per_project_user_sha,omitempty"`
 	PollingIntervalMultiplier                             *float64           `url:"polling_interval_multiplier,omitempty" json:"polling_interval_multiplier,omitempty"`
 	PreventMergeRequestsAuthorApproval                    *bool              `url:"prevent_merge_requests_author_approval,omitempty" json:"prevent_merge_requests_author_approval,omitempty"`
 	PreventMergeRequestsCommittersApproval                *bool              `url:"prevent_merge_requests_committers_approval,omitempty" json:"prevent_merge_requests_committers_approval,omitempty"`
@@ -637,7 +598,6 @@ type UpdateSettingsOptions struct {
 	ReceiveMaxInputSize                                   *int               `url:"receive_max_input_size,omitempty" json:"receive_max_input_size,omitempty"`
 	RepositoryChecksEnabled                               *bool              `url:"repository_checks_enabled,omitempty" json:"repository_checks_enabled,omitempty"`
 	RepositorySizeLimit                                   *int               `url:"repository_size_limit,omitempty" json:"repository_size_limit,omitempty"`
-	RepositoryStorages                                    *[]string          `url:"repository_storages,omitempty" json:"repository_storages,omitempty"`
 	RepositoryStoragesWeighted                            *map[string]int    `url:"repository_storages_weighted,omitempty" json:"repository_storages_weighted,omitempty"`
 	RequireAdminApprovalAfterUserSignup                   *bool              `url:"require_admin_approval_after_user_signup,omitempty" json:"require_admin_approval_after_user_signup,omitempty"`
 	RequireTwoFactorAuthentication                        *bool              `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"`
@@ -666,7 +626,6 @@ type UpdateSettingsOptions struct {
 	SlackAppEnabled                                       *bool              `url:"slack_app_enabled,omitempty" json:"slack_app_enabled,omitempty"`
 	SlackAppID                                            *string            `url:"slack_app_id,omitempty" json:"slack_app_id,omitempty"`
 	SlackAppSecret                                        *string            `url:"slack_app_secret,omitempty" json:"slack_app_secret,omitempty"`
-	SlackAppSigningSecret                                 *string            `url:"slack_app_signing_secret,omitempty" json:"slack_app_signing_secret,omitempty"`
 	SlackAppVerificationToken                             *string            `url:"slack_app_verification_token,omitempty" json:"slack_app_verification_token,omitempty"`
 	SnippetSizeLimit                                      *int               `url:"snippet_size_limit,omitempty" json:"snippet_size_limit,omitempty"`
 	SnowplowAppID                                         *string            `url:"snowplow_app_id,omitempty" json:"snowplow_app_id,omitempty"`
diff --git a/users.go b/users.go
index f04acfb..bbe535a 100644
--- a/users.go
+++ b/users.go
@@ -26,16 +26,14 @@ import (
 
 // List a couple of standard errors.
 var (
-	ErrUserActivatePrevented         = errors.New("Cannot activate a user that is blocked by admin or by LDAP synchronization")
-	ErrUserApprovePrevented          = errors.New("Cannot approve a user that is blocked by admin or by LDAP synchronization")
-	ErrUserBlockPrevented            = errors.New("Cannot block a user that is already blocked by LDAP synchronization")
-	ErrUserConflict                  = errors.New("User does not have a pending request")
-	ErrUserDeactivatePrevented       = errors.New("Cannot deactivate a user that is blocked by admin or by LDAP synchronization")
-	ErrUserDisableTwoFactorPrevented = errors.New("Cannot disable two factor authentication if not authenticated as administrator")
-	ErrUserNotFound                  = errors.New("User does not exist")
-	ErrUserRejectPrevented           = errors.New("Cannot reject a user if not authenticated as administrator")
-	ErrUserTwoFactorNotEnabled       = errors.New("Cannot disable two factor authentication if not enabled")
-	ErrUserUnblockPrevented          = errors.New("Cannot unblock a user that is blocked by LDAP synchronization")
+	ErrUserActivatePrevented   = errors.New("Cannot activate a user that is blocked by admin or by LDAP synchronization")
+	ErrUserApprovePrevented    = errors.New("Cannot approve a user that is blocked by admin or by LDAP synchronization")
+	ErrUserBlockPrevented      = errors.New("Cannot block a user that is already blocked by LDAP synchronization")
+	ErrUserConflict            = errors.New("User does not have a pending request")
+	ErrUserDeactivatePrevented = errors.New("Cannot deactivate a user that is blocked by admin or by LDAP synchronization")
+	ErrUserNotFound            = errors.New("User does not exist")
+	ErrUserRejectPrevented     = errors.New("Cannot reject a user if not authenticated as administrator")
+	ErrUserUnblockPrevented    = errors.New("Cannot unblock a user that is blocked by LDAP synchronization")
 )
 
 // UsersService handles communication with the user related methods of
@@ -119,7 +117,6 @@ type ListUsersOptions struct {
 	Active          *bool `url:"active,omitempty" json:"active,omitempty"`
 	Blocked         *bool `url:"blocked,omitempty" json:"blocked,omitempty"`
 	ExcludeInternal *bool `url:"exclude_internal,omitempty" json:"exclude_internal,omitempty"`
-	ExcludeExternal *bool `url:"exclude_external,omitempty" json:"exclude_external,omitempty"`
 
 	// The options below are only available for admins.
 	Search               *string    `url:"search,omitempty" json:"search,omitempty"`
@@ -609,7 +606,7 @@ func (s *UsersService) ListGPGKeys(options ...RequestOptionFunc) ([]*GPGKey, *Re
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#get-a-specific-gpg-key
 func (s *UsersService) GetGPGKey(key int, options ...RequestOptionFunc) (*GPGKey, *Response, error) {
-	u := fmt.Sprintf("user/gpg_keys/%d", key)
+	u := fmt.Sprintf("users/gpg_keys/%d", key)
 
 	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
 	if err != nil {
@@ -654,7 +651,7 @@ func (s *UsersService) AddGPGKey(opt *AddGPGKeyOptions, options ...RequestOption
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/users.html#delete-a-gpg-key
 func (s *UsersService) DeleteGPGKey(key int, options ...RequestOptionFunc) (*Response, error) {
-	u := fmt.Sprintf("user/gpg_keys/%d", key)
+	u := fmt.Sprintf("users/gpg_keys/%d", key)
 
 	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
 	if err != nil {
@@ -709,10 +706,10 @@ func (s *UsersService) GetGPGKeyForUser(user, key int, options ...RequestOptionF
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/users.html#add-a-gpg-key-for-a-given-user
-func (s *UsersService) AddGPGKeyForUser(user int, opt *AddGPGKeyOptions, options ...RequestOptionFunc) (*GPGKey, *Response, error) {
+func (s *UsersService) AddGPGKeyForUser(user int, options ...RequestOptionFunc) (*GPGKey, *Response, error) {
 	u := fmt.Sprintf("users/%d/gpg_keys", user)
 
-	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
+	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -1340,34 +1337,3 @@ func (s *UsersService) GetUserMemberships(user int, opt *GetUserMembershipOption
 
 	return m, resp, err
 }
-
-// DisableTwoFactor disables two factor authentication for the specified user.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ee/api/users.html#disable-two-factor-authentication
-func (s *UsersService) DisableTwoFactor(user int, options ...RequestOptionFunc) error {
-	u := fmt.Sprintf("users/%d/disable_two_factor", user)
-
-	req, err := s.client.NewRequest(http.MethodPatch, u, nil, options)
-	if err != nil {
-		return err
-	}
-
-	resp, err := s.client.Do(req, nil)
-	if err != nil && resp == nil {
-		return err
-	}
-
-	switch resp.StatusCode {
-	case 204:
-		return nil
-	case 400:
-		return ErrUserTwoFactorNotEnabled
-	case 403:
-		return ErrUserDisableTwoFactorPrevented
-	case 404:
-		return ErrUserNotFound
-	default:
-		return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode)
-	}
-}


Test patch:
diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml
index 7c4cefa..6b7a3f5 100644
--- a/.github/workflows/lint_and_test.yml
+++ b/.github/workflows/lint_and_test.yml
@@ -5,19 +5,12 @@ on:
   push:
     branches: [master]
 
-permissions:
-  contents: read
-
 jobs:
   lint_and_test:
-    permissions:
-      contents: read
-      pull-requests: read
-
     name: Lint and Test - ${{ matrix.go-version }}
     strategy:
       matrix:
-        go-version: [1.18.x, 1.19.x, 1.x]
+        go-version: [1.16.x, 1.17.x, 1.x]
         platform: [ubuntu-latest]
     runs-on: ${{ matrix.platform }}
     steps:
diff --git a/commits_test.go b/commits_test.go
index 7c08ec8..7f022b2 100644
--- a/commits_test.go
+++ b/commits_test.go
@@ -19,7 +19,7 @@ package gitlab
 import (
 	"encoding/json"
 	"fmt"
-	"io"
+	"io/ioutil"
 	"net/http"
 	"reflect"
 	"testing"
@@ -108,7 +108,7 @@ func TestSetCommitStatus(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/projects/1/statuses/b0b3a907f41409829b307a28b82fdbd552ee5a27", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodPost)
-		body, err := io.ReadAll(r.Body)
+		body, err := ioutil.ReadAll(r.Body)
 		require.NoError(t, err)
 
 		var content SetCommitStatusOptions
diff --git a/deployments_merge_requests_test.go b/deployments_merge_requests_test.go
deleted file mode 100644
index bb9338c..0000000
--- a/deployments_merge_requests_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package gitlab
-
-import (
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestDeploymentMergeRequestsService_ListDeploymentMergeRequests(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/278964/deployments/2/merge_requests", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		testParams(t, r, "assignee_id=Any&with_labels_details=true&with_merge_status_recheck=true")
-		mustWriteHTTPResponse(t, w, "testdata/get_merge_requests.json")
-	})
-
-	opts := ListMergeRequestsOptions{
-		AssigneeID:             AssigneeID(UserIDAny),
-		WithLabelsDetails:      Bool(true),
-		WithMergeStatusRecheck: Bool(true),
-	}
-
-	mergeRequests, _, err := client.DeploymentMergeRequests.ListDeploymentMergeRequests(278964, 2, &opts)
-	require.NoError(t, err)
-	require.Equal(t, 20, len(mergeRequests))
-
-	validStates := []string{"opened", "closed", "locked", "merged"}
-	mergeStatuses := []string{"can_be_merged", "cannot_be_merged"}
-	allCreatedBefore := time.Date(2019, 8, 21, 0, 0, 0, 0, time.UTC)
-	allCreatedAfter := time.Date(2019, 8, 17, 0, 0, 0, 0, time.UTC)
-
-	for _, mr := range mergeRequests {
-		require.Equal(t, 278964, mr.ProjectID)
-		require.Contains(t, validStates, mr.State)
-		assert.Less(t, mr.CreatedAt.Unix(), allCreatedBefore.Unix())
-		assert.Greater(t, mr.CreatedAt.Unix(), allCreatedAfter.Unix())
-		assert.LessOrEqual(t, mr.CreatedAt.Unix(), mr.UpdatedAt.Unix())
-		assert.LessOrEqual(t, mr.TaskCompletionStatus.CompletedCount, mr.TaskCompletionStatus.Count)
-		require.Contains(t, mergeStatuses, mr.MergeStatus)
-
-		// list requests do not provide these fields:
-		assert.Nil(t, mr.Pipeline)
-		assert.Nil(t, mr.HeadPipeline)
-		assert.Equal(t, "", mr.DiffRefs.HeadSha)
-	}
-}
diff --git a/discussions_test.go b/discussions_test.go
index 81c4e4c..bb4214d 100644
--- a/discussions_test.go
+++ b/discussions_test.go
@@ -2245,7 +2245,7 @@ func TestDiscussionsService_ListCommitDiscussions(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
 		fmt.Fprintf(w, `
 			[
@@ -2327,22 +2327,22 @@ func TestDiscussionsService_ListCommitDiscussions(t *testing.T) {
 		}},
 	}}
 
-	ds, resp, err := client.Discussions.ListCommitDiscussions(5, "abc123", nil, nil)
+	ds, resp, err := client.Discussions.ListCommitDiscussions(5, 11, nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 	require.Equal(t, want, ds)
 
-	ds, resp, err = client.Discussions.ListCommitDiscussions(5.01, "abc123", nil, nil)
+	ds, resp, err = client.Discussions.ListCommitDiscussions(5.01, 11, nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 	require.Nil(t, ds)
 
-	ds, resp, err = client.Discussions.ListCommitDiscussions(5, "abc123", nil, nil, errorOption)
+	ds, resp, err = client.Discussions.ListCommitDiscussions(5, 11, nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 	require.Nil(t, ds)
 
-	ds, resp, err = client.Discussions.ListCommitDiscussions(3, "abc123", nil, nil)
+	ds, resp, err = client.Discussions.ListCommitDiscussions(3, 11, nil, nil)
 	require.Error(t, err)
 	require.Nil(t, ds)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -2352,7 +2352,7 @@ func TestDiscussionsService_GetCommitDiscussion(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
 		fmt.Fprintf(w, `
 		  {
@@ -2432,22 +2432,22 @@ func TestDiscussionsService_GetCommitDiscussion(t *testing.T) {
 		}},
 	}
 
-	d, resp, err := client.Discussions.GetCommitDiscussion(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	d, resp, err := client.Discussions.GetCommitDiscussion(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 	require.Equal(t, want, d)
 
-	d, resp, err = client.Discussions.GetCommitDiscussion(5.01, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	d, resp, err = client.Discussions.GetCommitDiscussion(5.01, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 	require.Nil(t, d)
 
-	d, resp, err = client.Discussions.GetCommitDiscussion(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil, errorOption)
+	d, resp, err = client.Discussions.GetCommitDiscussion(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 	require.Nil(t, d)
 
-	d, resp, err = client.Discussions.GetCommitDiscussion(3, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	d, resp, err = client.Discussions.GetCommitDiscussion(3, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.Error(t, err)
 	require.Nil(t, d)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -2457,7 +2457,7 @@ func TestDiscussionsService_CreateCommitDiscussion(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodPost)
 		fmt.Fprintf(w, `
 		  {
@@ -2537,22 +2537,22 @@ func TestDiscussionsService_CreateCommitDiscussion(t *testing.T) {
 		}},
 	}
 
-	d, resp, err := client.Discussions.CreateCommitDiscussion(5, "abc123", nil, nil)
+	d, resp, err := client.Discussions.CreateCommitDiscussion(5, 11, nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 	require.Equal(t, want, d)
 
-	d, resp, err = client.Discussions.CreateCommitDiscussion(5.01, "abc123", nil, nil)
+	d, resp, err = client.Discussions.CreateCommitDiscussion(5.01, 11, nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 	require.Nil(t, d)
 
-	d, resp, err = client.Discussions.CreateCommitDiscussion(5, "abc123", nil, nil, errorOption)
+	d, resp, err = client.Discussions.CreateCommitDiscussion(5, 11, nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 	require.Nil(t, d)
 
-	d, resp, err = client.Discussions.CreateCommitDiscussion(3, "abc123", nil, nil)
+	d, resp, err = client.Discussions.CreateCommitDiscussion(3, 11, nil, nil)
 	require.Error(t, err)
 	require.Nil(t, d)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -2562,7 +2562,7 @@ func TestDiscussionsService_AddCommitDiscussionNote(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodPost)
 		fmt.Fprintf(w, `
 		  {
@@ -2632,22 +2632,22 @@ func TestDiscussionsService_AddCommitDiscussionNote(t *testing.T) {
 		NoteableIID: 377,
 	}
 
-	n, resp, err := client.Discussions.AddCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	n, resp, err := client.Discussions.AddCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 	require.Equal(t, want, n)
 
-	n, resp, err = client.Discussions.AddCommitDiscussionNote(5.01, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	n, resp, err = client.Discussions.AddCommitDiscussionNote(5.01, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 	require.Nil(t, n)
 
-	n, resp, err = client.Discussions.AddCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil, errorOption)
+	n, resp, err = client.Discussions.AddCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 	require.Nil(t, n)
 
-	n, resp, err = client.Discussions.AddCommitDiscussionNote(3, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
+	n, resp, err = client.Discussions.AddCommitDiscussionNote(3, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", nil, nil)
 	require.Error(t, err)
 	require.Nil(t, n)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -2657,7 +2657,7 @@ func TestDiscussionsService_UpdateCommitDiscussionNote(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/302", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/302", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodPut)
 		fmt.Fprintf(w, `
 		  {
@@ -2727,22 +2727,22 @@ func TestDiscussionsService_UpdateCommitDiscussionNote(t *testing.T) {
 		NoteableIID: 377,
 	}
 
-	n, resp, err := client.Discussions.UpdateCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	n, resp, err := client.Discussions.UpdateCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 	require.Equal(t, want, n)
 
-	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(5.01, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(5.01, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 	require.Nil(t, n)
 
-	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil, errorOption)
+	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 	require.Nil(t, n)
 
-	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(3, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	n, resp, err = client.Discussions.UpdateCommitDiscussionNote(3, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.Error(t, err)
 	require.Nil(t, n)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
@@ -2752,23 +2752,23 @@ func TestDiscussionsService_DeleteCommitDiscussionNote(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	mux.HandleFunc("/api/v4/projects/5/repository/commits/abc123/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/302", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/api/v4/projects/5/repository/commits/11/discussions/6a9c1750b37d513a43987b574953fceb50b03ce7/notes/302", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodDelete)
 	})
 
-	resp, err := client.Discussions.DeleteCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	resp, err := client.Discussions.DeleteCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.NoError(t, err)
 	require.NotNil(t, resp)
 
-	resp, err = client.Discussions.DeleteCommitDiscussionNote(5.01, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	resp, err = client.Discussions.DeleteCommitDiscussionNote(5.01, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.EqualError(t, err, "invalid ID type 5.01, the ID must be an int or a string")
 	require.Nil(t, resp)
 
-	resp, err = client.Discussions.DeleteCommitDiscussionNote(5, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil, errorOption)
+	resp, err = client.Discussions.DeleteCommitDiscussionNote(5, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil, errorOption)
 	require.EqualError(t, err, "RequestOptionFunc returns an error")
 	require.Nil(t, resp)
 
-	resp, err = client.Discussions.DeleteCommitDiscussionNote(3, "abc123", "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
+	resp, err = client.Discussions.DeleteCommitDiscussionNote(3, 11, "6a9c1750b37d513a43987b574953fceb50b03ce7", 302, nil, nil)
 	require.Error(t, err)
 	require.Equal(t, http.StatusNotFound, resp.StatusCode)
 }
diff --git a/event_parsing_webhook_test.go b/event_parsing_webhook_test.go
index f63db48..373200b 100644
--- a/event_parsing_webhook_test.go
+++ b/event_parsing_webhook_test.go
@@ -218,24 +218,6 @@ func TestParseMergeRequestCommentHook(t *testing.T) {
 	}
 }
 
-func TestParseMemberHook(t *testing.T) {
-	raw := loadFixture("testdata/webhooks/member.json")
-
-	parsedEvent, err := ParseWebhook("Member Hook", raw)
-	if err != nil {
-		t.Errorf("Error parsing member hook: %s", err)
-	}
-
-	event, ok := parsedEvent.(*MemberEvent)
-	if !ok {
-		t.Errorf("Expected MemberEvent, but parsing produced %T", parsedEvent)
-	}
-
-	if event.EventName != "user_add_to_group" {
-		t.Errorf("EventName is %v, want %v", event.EventName, "user_add_to_group")
-	}
-}
-
 func TestParseMergeRequestHook(t *testing.T) {
 	raw := loadFixture("testdata/webhooks/merge_request.json")
 
diff --git a/event_webhook_types_test.go b/event_webhook_types_test.go
index e01ff40..1a75e29 100644
--- a/event_webhook_types_test.go
+++ b/event_webhook_types_test.go
@@ -23,13 +23,11 @@ import (
 )
 
 const (
-	ExpectedGroup     = "webhook-test"
-	excpectedAvatar   = "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
-	expectedEmail     = "user1@example.com"
-	expectedEventName = "user_add_to_group"
-	expectedID        = 1
-	expectedName      = "User1"
-	expectedUsername  = "user1"
+	expectedID       = 1
+	expectedName     = "User1"
+	expectedUsername = "user1"
+	excpectedAvatar  = "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+	expectedEmail    = "test.user1@example.com"
 )
 
 func TestBuildEventUnmarshal(t *testing.T) {
@@ -92,10 +90,6 @@ func TestDeploymentEventUnmarshal(t *testing.T) {
 	if event.CommitTitle != "Add new file" {
 		t.Errorf("CommitTitle is %s, want %s", event.CommitTitle, "Add new file")
 	}
-
-	if event.Ref != "1.0.0" {
-		t.Errorf("Ref is %s, want %s", event.Ref, "1.0.0")
-	}
 }
 
 func TestIssueCommentEventUnmarshal(t *testing.T) {
@@ -189,24 +183,24 @@ func TestMergeEventUnmarshal(t *testing.T) {
 	if event.ObjectAttributes.LastCommit.ID != "da1560886d4f094c3e6c9ef40349f7d38b5d27d7" {
 		t.Errorf("ObjectAttributes.LastCommit.ID is %v, want %s", event.ObjectAttributes.LastCommit.ID, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
 	}
-	if event.Assignees[0].Name != expectedName {
-		t.Errorf("Assignee.Name is %v, want %v", event.Assignees[0].Name, expectedName)
+	if event.ObjectAttributes.Assignee.Name != expectedName {
+		t.Errorf("Assignee.Name is %v, want %v", event.ObjectAttributes.Assignee.Name, expectedName)
 	}
 
-	if event.Assignees[0].Username != expectedUsername {
-		t.Errorf("ObjectAttributes is %v, want %v", event.Assignees[0].Username, expectedUsername)
+	if event.ObjectAttributes.Assignee.Username != expectedUsername {
+		t.Errorf("ObjectAttributes is %v, want %v", event.ObjectAttributes.Assignee.Username, expectedUsername)
 	}
 
-	if event.User.ID != expectedID {
-		t.Errorf("User ID is %d, want %d", event.User.ID, expectedID)
+	if event.User.ID != 42 {
+		t.Errorf("User ID is %d, want %d", event.User.ID, 42)
 	}
 
 	if event.User.Name != expectedName {
 		t.Errorf("Username is %s, want %s", event.User.Name, expectedName)
 	}
 
-	if event.User.Email != expectedEmail {
-		t.Errorf("User email is %s, want %s", event.User.Email, expectedEmail)
+	if event.User.Email != "user1@example.com" {
+		t.Errorf("User email is %s, want %s", event.User.Email, "user1@example.com")
 	}
 
 	if event.ObjectAttributes.LastCommit.Timestamp == nil {
@@ -217,10 +211,6 @@ func TestMergeEventUnmarshal(t *testing.T) {
 		t.Errorf("Commit Username is %s, want %s", name, "GitLab dev user")
 	}
 
-	if event.ObjectAttributes.BlockingDiscussionsResolved != true {
-		t.Errorf("BlockingDiscussionsResolved isn't true")
-	}
-
 	if event.Assignees[0].ID != expectedID {
 		t.Errorf("Assignees[0].ID is %v, want %v", event.Assignees[0].ID, expectedID)
 	}
@@ -234,93 +224,11 @@ func TestMergeEventUnmarshal(t *testing.T) {
 	}
 
 	if event.Assignees[0].AvatarURL != excpectedAvatar {
-		t.Errorf("Assignees[0].AvatarURL is %v, want %v", event.Assignees[0].AvatarURL, excpectedAvatar)
-	}
-
-	if len(event.Reviewers) < 1 {
-		t.Errorf("Reviewers length is %d, want %d", len(event.Reviewers), 1)
-	}
-
-	if event.Reviewers[0].Name != expectedName {
-		t.Errorf("Reviewers[0].Name is %v, want %v", event.Reviewers[0].Name, expectedName)
-	}
-
-	if event.Reviewers[0].Username != expectedUsername {
-		t.Errorf("Reviewer[0].Username is %v, want %v", event.Reviewers[0].Username, expectedUsername)
-	}
-
-	if event.Reviewers[0].AvatarURL != excpectedAvatar {
-		t.Errorf("Reviewers[0].AvatarURL is %v, want %v", event.Reviewers[0].AvatarURL, excpectedAvatar)
-	}
-}
-
-func TestMemberEventUnmarshal(t *testing.T) {
-	jsonObject := loadFixture("testdata/webhooks/member.json")
-
-	var event *MemberEvent
-	err := json.Unmarshal(jsonObject, &event)
-
-	if err != nil {
-		t.Errorf("Member Event can not unmarshaled: %v\n ", err.Error())
-	}
-
-	if event == nil {
-		t.Errorf("Member Event is null")
-	}
-
-	if event.GroupName != ExpectedGroup {
-		t.Errorf("Name is %v, want %v", event.GroupName, ExpectedGroup)
-	}
-
-	if event.GroupPath != ExpectedGroup {
-		t.Errorf("GroupPath is %v, want %v", event.GroupPath, ExpectedGroup)
-	}
-
-	if event.GroupID != 100 {
-		t.Errorf(
-			"GroupID is %v, want %v", event.GroupID, 100)
-	}
-
-	if event.UserUsername != expectedUsername {
-		t.Errorf(
-			"UserUsername is %v, want %v", event.UserUsername, expectedUsername)
-	}
-
-	if event.UserName != expectedName {
-		t.Errorf(
-			"UserName is %v, want %v", event.UserName, expectedName)
-	}
-
-	if event.UserEmail != "testuser@webhooktest.com" {
-		t.Errorf(
-			"UserEmail is %v, want %v", event.UserEmail, "testuser@webhooktest.com")
-	}
-
-	if event.UserID != 64 {
-		t.Errorf(
-			"UserID is %v, want %v", event.UserID, 64)
-	}
-
-	if event.GroupAccess != "Guest" {
-		t.Errorf(
-			"GroupAccess is %v, want %v", event.GroupAccess, "Guest")
-	}
-
-	if event.EventName != expectedEventName {
-		t.Errorf(
-			"EventName is %v, want %v", event.EventName, expectedEventName)
-	}
-
-	if event.CreatedAt.Format(time.RFC3339) != "2020-12-11T04:57:22Z" {
-		t.Errorf("CreatedAt is %v, want %v", event.CreatedAt.Format(time.RFC3339), "2020-12-11T04:57:22Z")
-	}
-
-	if event.UpdatedAt.Format(time.RFC3339) != "2020-12-11T04:57:22Z" {
-		t.Errorf("UpdatedAt is %v, want %v", event.UpdatedAt.Format(time.RFC3339), "2020-12-11T04:57:22Z")
+		t.Errorf("Assignees[0].Email is %v, want %v", event.Assignees[0].AvatarURL, excpectedAvatar)
 	}
 
-	if event.ExpiresAt.Format(time.RFC3339) != "2020-12-14T00:00:00Z" {
-		t.Errorf("ExpiresAt is %v, want %v", event.ExpiresAt.Format(time.RFC3339), "2020-12-14T00:00:00Z")
+	if event.Assignees[0].Email != expectedEmail {
+		t.Errorf("Assignees[0].Email is %v, want %v", event.Assignees[0].Email, expectedEmail)
 	}
 }
 
diff --git a/examples/pipelinestestreport.go b/examples/pipelinestestreport.go
index 1c7e6c3..a97a908 100644
--- a/examples/pipelinestestreport.go
+++ b/examples/pipelinestestreport.go
@@ -43,7 +43,7 @@ func pipelineTestReportExample() {
 		if err != nil {
 			log.Fatal(err)
 		}
-
 		log.Printf("Found test report: %v", report)
+
 	}
 }
diff --git a/gitlab_test.go b/gitlab_test.go
index 496fd6a..666739f 100644
--- a/gitlab_test.go
+++ b/gitlab_test.go
@@ -21,6 +21,7 @@ import (
 	"context"
 	"errors"
 	"io"
+	"io/ioutil"
 	"log"
 	"net/http"
 	"net/http/httptest"
@@ -134,7 +135,7 @@ func TestCheckResponse(t *testing.T) {
 	resp := &http.Response{
 		Request:    req.Request,
 		StatusCode: http.StatusBadRequest,
-		Body: io.NopCloser(strings.NewReader(`
+		Body: ioutil.NopCloser(strings.NewReader(`
 		{
 			"message": {
 				"prop1": [
@@ -172,35 +173,6 @@ func TestCheckResponse(t *testing.T) {
 	}
 }
 
-func TestCheckResponseOnUnknownErrorFormat(t *testing.T) {
-	c, err := NewClient("")
-	if err != nil {
-		t.Fatalf("Failed to create client: %v", err)
-	}
-
-	req, err := c.NewRequest(http.MethodGet, "test", nil, nil)
-	if err != nil {
-		t.Fatalf("Failed to create request: %v", err)
-	}
-
-	resp := &http.Response{
-		Request:    req.Request,
-		StatusCode: http.StatusBadRequest,
-		Body:       io.NopCloser(strings.NewReader("some error message but not JSON")),
-	}
-
-	errResp := CheckResponse(resp)
-	if errResp == nil {
-		t.Fatal("Expected error response.")
-	}
-
-	want := "GET https://gitlab.com/api/v4/test: 400 failed to parse unknown error format: some error message but not JSON"
-
-	if errResp.Error() != want {
-		t.Errorf("Expected error: %s, got %s", want, errResp.Error())
-	}
-}
-
 func TestRequestWithContext(t *testing.T) {
 	c, err := NewClient("")
 	if err != nil {
@@ -220,7 +192,7 @@ func TestRequestWithContext(t *testing.T) {
 }
 
 func loadFixture(filePath string) []byte {
-	content, err := os.ReadFile(filePath)
+	content, err := ioutil.ReadFile(filePath)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/group_hooks_test.go b/group_hooks_test.go
index 6834231..07775c8 100644
--- a/group_hooks_test.go
+++ b/group_hooks_test.go
@@ -55,7 +55,7 @@ func TestListGroupHooks(t *testing.T) {
 ]`)
 	})
 
-	groupHooks, _, err := client.Groups.ListGroupHooks(1, nil)
+	groupHooks, _, err := client.Groups.ListGroupHooks(1)
 	if err != nil {
 		t.Error(err)
 	}
diff --git a/group_import_export_test.go b/group_import_export_test.go
index 96454ef..d1c5db0 100644
--- a/group_import_export_test.go
+++ b/group_import_export_test.go
@@ -2,7 +2,7 @@ package gitlab
 
 import (
 	"fmt"
-	"io"
+	"io/ioutil"
 	"log"
 	"net/http"
 	"os"
@@ -42,7 +42,7 @@ func TestGroupExportDownload(t *testing.T) {
 		t.Errorf("GroupImportExport.ExportDownload returned error: %v", err)
 	}
 
-	data, err := io.ReadAll(export)
+	data, err := ioutil.ReadAll(export)
 	if err != nil {
 		t.Errorf("Error reading export: %v", err)
 	}
@@ -58,7 +58,7 @@ func TestGroupImport(t *testing.T) {
 	defer teardown(server)
 
 	content := []byte("temporary file's content")
-	tmpfile, err := os.CreateTemp(os.TempDir(), "example.*.tar.gz")
+	tmpfile, err := ioutil.TempFile("", "example.*.tar.gz")
 	if err != nil {
 		tmpfile.Close()
 		log.Fatal(err)
diff --git a/groups_test.go b/groups_test.go
index 0ab7b6b..8a37a43 100644
--- a/groups_test.go
+++ b/groups_test.go
@@ -364,106 +364,6 @@ func TestAddGroupLDAPLinkFilter(t *testing.T) {
 	}
 }
 
-func TestListGroupSAMLLinks(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/saml_group_links",
-		func(w http.ResponseWriter, r *http.Request) {
-			testMethod(t, r, http.MethodGet)
-			fmt.Fprint(w, `[
-	{
-		"access_level":30,
-		"name":"gitlab_group_example_developer"
-	},
-	{
-		"access_level":40,
-		"name":"gitlab_group_example_maintainer"
-	}
-]`)
-		})
-
-	links, _, err := client.Groups.ListGroupSAMLLinks(1)
-	if err != nil {
-		t.Errorf("Groups.ListGroupSAMLLinks returned error: %v", err)
-	}
-
-	want := []*SAMLGroupLink{
-		{
-			AccessLevel: DeveloperPermissions,
-			Name:        "gitlab_group_example_developer",
-		},
-		{
-			AccessLevel: MaintainerPermissions,
-			Name:        "gitlab_group_example_maintainer",
-		},
-	}
-	if !reflect.DeepEqual(want, links) {
-		t.Errorf("Groups.ListGroupSAMLLinks returned %+v, want %+v", links, want)
-	}
-}
-
-func TestGetGroupSAMLLink(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/saml_group_links/gitlab_group_example_developer",
-		func(w http.ResponseWriter, r *http.Request) {
-			testMethod(t, r, http.MethodGet)
-			fmt.Fprint(w, `
-{
-	"access_level":30,
-	"name":"gitlab_group_example_developer"
-}`)
-		})
-
-	links, _, err := client.Groups.GetGroupSAMLLink(1, "gitlab_group_example_developer")
-	if err != nil {
-		t.Errorf("Groups.GetGroupSAMLLinks returned error: %v", err)
-	}
-
-	want := &SAMLGroupLink{
-		AccessLevel: DeveloperPermissions,
-		Name:        "gitlab_group_example_developer",
-	}
-	if !reflect.DeepEqual(want, links) {
-		t.Errorf("Groups.GetGroupSAMLLink returned %+v, want %+v", links, want)
-	}
-}
-
-func TestAddGroupSAMLLink(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/saml_group_links",
-		func(w http.ResponseWriter, r *http.Request) {
-			testMethod(t, r, http.MethodPost)
-			fmt.Fprint(w, `
-{
-	"access_level":30,
-	"name":"gitlab_group_example_developer"
-}`)
-		})
-
-	opt := &AddGroupSAMLLinkOptions{
-		SAMLGroupName: String("gitlab_group_example_developer"),
-		AccessLevel:   AccessLevel(DeveloperPermissions),
-	}
-
-	link, _, err := client.Groups.AddGroupSAMLLink(1, opt)
-	if err != nil {
-		t.Errorf("Groups.AddGroupSAMLLink returned error: %v", err)
-	}
-
-	want := &SAMLGroupLink{
-		AccessLevel: DeveloperPermissions,
-		Name:        "gitlab_group_example_developer",
-	}
-	if !reflect.DeepEqual(want, link) {
-		t.Errorf("Groups.AddGroupSAMLLink returned %+v, want %+v", link, want)
-	}
-}
-
 func TestRestoreGroup(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
diff --git a/issue_links_test.go b/issue_links_test.go
index 6823312..dcad1be 100644
--- a/issue_links_test.go
+++ b/issue_links_test.go
@@ -19,7 +19,6 @@ func TestIssueLinksService_ListIssueRelations(t *testing.T) {
 			  {
 				"id" : 84,
 				"iid" : 14,
-				"confidential": false,
 				"issue_link_id": 1,
 				"project_id" : 4,
 				"title" : "Issues with auth",
@@ -50,30 +49,35 @@ func TestIssueLinksService_ListIssueRelations(t *testing.T) {
 		`)
 	})
 
-	want := []*IssueRelation{{
-		ID:           84,
-		IID:          14,
-		State:        "opened",
-		Description:  "",
-		Confidential: false,
+	want := []*Issue{{
+		ID:          84,
+		IID:         14,
+		ExternalID:  "",
+		State:       "opened",
+		Description: "",
 		Author: &IssueAuthor{
 			ID:        18,
 			State:     "active",
 			WebURL:    "https://gitlab.example.com/eileen.lowe",
 			Name:      "Venkatesh Thalluri",
 			AvatarURL: "",
-			Username:  "venkatesh.thalluri",
-		},
-		Milestone:   nil,
-		ProjectID:   4,
-		Assignees:   []*IssueAssignee{},
-		Assignee:    nil,
-		Title:       "Issues with auth",
-		Labels:      []string{"bug"},
-		WebURL:      "http://example.com/example/example/issues/14",
-		Weight:      0,
-		IssueLinkID: 1,
-		LinkType:    "relates_to",
+			Username:  "venkatesh.thalluri"},
+		ProjectID:         4,
+		Assignees:         []*IssueAssignee{},
+		Title:             "Issues with auth",
+		MovedToID:         0,
+		Labels:            []string{"bug"},
+		Upvotes:           0,
+		Downvotes:         0,
+		WebURL:            "http://example.com/example/example/issues/14",
+		Confidential:      false,
+		Weight:            0,
+		DiscussionLocked:  false,
+		Subscribed:        false,
+		UserNotesCount:    0,
+		IssueLinkID:       1,
+		MergeRequestCount: 0,
+		EpicIssueID:       0,
 	}}
 
 	is, resp, err := client.IssueLinks.ListIssueRelations(4, 14, nil)
diff --git a/issues_test.go b/issues_test.go
index 1b29f42..4e47c95 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -324,62 +324,6 @@ func TestListIssuesSearchInDescription(t *testing.T) {
 		t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want)
 	}
 }
-
-func TestListIssuesSearchByIterationID(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/issues", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		testURL(t, r, "/api/v4/issues?iteration_id=90")
-		fmt.Fprint(w, `
-			[
-				{
-					"id": 1,
-					"title": "A Test Issue Title",
-					"description": "This is the description for the issue",
-					"iteration": {
-						"id":90,
-						"iid":4,
-						"sequence":2,
-						"group_id":162,
-						"state":2,
-						"web_url":"https://gitlab.com/groups/my-group/-/iterations/90"
-					}
-				}
-			]`,
-		)
-	})
-
-	listProjectIssue := &ListIssuesOptions{
-		IterationID: Int(90),
-	}
-
-	issues, _, err := client.Issues.ListIssues(listProjectIssue)
-
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := []*Issue{{
-		ID:          1,
-		Title:       "A Test Issue Title",
-		Description: "This is the description for the issue",
-		Iteration: &GroupIteration{
-			ID:       90,
-			IID:      4,
-			Sequence: 2,
-			GroupID:  162,
-			State:    2,
-			WebURL:   "https://gitlab.com/groups/my-group/-/iterations/90",
-		},
-	}}
-
-	if !reflect.DeepEqual(want, issues) {
-		t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want)
-	}
- }
-
 func TestListProjectIssues(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
@@ -411,61 +355,6 @@ func TestListProjectIssues(t *testing.T) {
 	}
 }
 
-func TestListProjectIssuesSearchByIterationID(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/issues", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		testURL(t, r, "/api/v4/projects/1/issues?iteration_id=90")
-		fmt.Fprint(w, `
-			[
-				{
-					"id": 1,
-					"title": "A Test Issue Title",
-					"description": "This is the description for the issue",
-					"iteration": {
-						"id":90,
-						"iid":4,
-						"sequence":2,
-						"group_id":162,
-						"state":2,
-						"web_url":"https://gitlab.com/groups/my-group/-/iterations/90"
-					}
-				}
-			]`,
-		)
-	})
-
-	listProjectIssue := &ListProjectIssuesOptions{
-		IterationID: Int(90),
-	}
-
-	issues, _, err := client.Issues.ListProjectIssues(1 ,listProjectIssue)
-
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := []*Issue{{
-		ID:          1,
-		Title:       "A Test Issue Title",
-		Description: "This is the description for the issue",
-		Iteration: &GroupIteration{
-			ID:       90,
-			IID:      4,
-			Sequence: 2,
-			GroupID:  162,
-			State:    2,
-			WebURL:   "https://gitlab.com/groups/my-group/-/iterations/90",
-		},
-	}}
-
-	if !reflect.DeepEqual(want, issues) {
-		t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want)
-	}
- }
-
 func TestListGroupIssues(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
@@ -499,61 +388,6 @@ func TestListGroupIssues(t *testing.T) {
 	}
 }
 
-func TestListGroupIssuesSearchByIterationID(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/issues", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		testURL(t, r, "/api/v4/groups/1/issues?iteration_id=90")
-		fmt.Fprint(w, `
-			[
-				{
-					"id": 1,
-					"title": "A Test Issue Title",
-					"description": "This is the description for the issue",
-					"iteration": {
-						"id":90,
-						"iid":4,
-						"sequence":2,
-						"group_id":162,
-						"state":2,
-						"web_url":"https://gitlab.com/groups/my-group/-/iterations/90"
-					}
-				}
-			]`,
-		)
-	})
-
-	listProjectIssue := &ListGroupIssuesOptions{
-		IterationID: Int(90),
-	}
-
-	issues, _, err := client.Issues.ListGroupIssues(1, listProjectIssue)
-
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	want := []*Issue{{
-		ID:          1,
-		Title:       "A Test Issue Title",
-		Description: "This is the description for the issue",
-		Iteration: &GroupIteration{
-			ID:       90,
-			IID:      4,
-			Sequence: 2,
-			GroupID:  162,
-			State:    2,
-			WebURL:   "https://gitlab.com/groups/my-group/-/iterations/90",
-		},
-	}}
-
-	if !reflect.DeepEqual(want, issues) {
-		t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want)
-	}
- }
-
 func TestCreateIssue(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
diff --git a/jobs_test.go b/jobs_test.go
index 8a171a8..0abe9b0 100644
--- a/jobs_test.go
+++ b/jobs_test.go
@@ -18,7 +18,7 @@ package gitlab
 
 import (
 	"fmt"
-	"io"
+	"io/ioutil"
 	"net/http"
 	"reflect"
 	"testing"
@@ -70,7 +70,6 @@ func TestJobsService_ListProjectJobs(t *testing.T) {
     "name": "teaspoon",
     "pipeline": {
       "id": 6,
-      "project_id": 1,
       "ref": "master",
       "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
       "status": "pending"
@@ -101,7 +100,6 @@ func TestJobsService_ListProjectJobs(t *testing.T) {
     "name": "rspec:other",
     "pipeline": {
       "id": 6,
-      "project_id": 1,
       "ref": "master",
       "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
       "status": "pending"
@@ -135,17 +133,15 @@ func TestJobsService_ListProjectJobs(t *testing.T) {
 			Name:         "teaspoon",
 			TagList:      []string{"docker runner", "ubuntu18"},
 			Pipeline: struct {
-				ID        int    `json:"id"`
-				ProjectID int    `json:"project_id"`
-				Ref       string `json:"ref"`
-				Sha       string `json:"sha"`
-				Status    string `json:"status"`
+				ID     int    `json:"id"`
+				Ref    string `json:"ref"`
+				Sha    string `json:"sha"`
+				Status string `json:"status"`
 			}{
-				ID:        6,
-				ProjectID: 1,
-				Ref:       "master",
-				Sha:       "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
-				Status:    "pending",
+				ID:     6,
+				Ref:    "master",
+				Sha:    "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+				Status: "pending",
 			},
 			Ref:           "master",
 			Stage:         "test",
@@ -169,17 +165,15 @@ func TestJobsService_ListProjectJobs(t *testing.T) {
 			Name:         "rspec:other",
 			TagList:      []string{"docker runner", "win10-2004"},
 			Pipeline: struct {
-				ID        int    `json:"id"`
-				ProjectID int    `json:"project_id"`
-				Ref       string `json:"ref"`
-				Sha       string `json:"sha"`
-				Status    string `json:"status"`
+				ID     int    `json:"id"`
+				Ref    string `json:"ref"`
+				Sha    string `json:"sha"`
+				Status string `json:"status"`
 			}{
-				ID:        6,
-				ProjectID: 1,
-				Ref:       "master",
-				Sha:       "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
-				Status:    "pending",
+				ID:     6,
+				Ref:    "master",
+				Sha:    "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
+				Status: "pending",
 			},
 			Ref:    "master",
 			Stage:  "test",
@@ -208,7 +202,7 @@ func TestDownloadSingleArtifactsFileByTagOrBranch(t *testing.T) {
 		t.Fatalf("Jobs.DownloadSingleArtifactsFileByTagOrBranch returns an error: %v", err)
 	}
 
-	content, err := io.ReadAll(reader)
+	content, err := ioutil.ReadAll(reader)
 	if err != nil {
 		t.Fatalf("Jobs.DownloadSingleArtifactsFileByTagOrBranch error reading: %v", err)
 	}
diff --git a/project_feature_flags_test.go b/project_feature_flags_test.go
deleted file mode 100644
index ffbdc1b..0000000
--- a/project_feature_flags_test.go
+++ /dev/null
@@ -1,241 +0,0 @@
-package gitlab
-
-import (
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestListProjectFeatureFlags(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/333/feature_flags",
-		func(w http.ResponseWriter, r *http.Request) {
-			testMethod(t, r, http.MethodGet)
-			mustWriteHTTPResponse(t, w, "testdata/list_project_feature_flags.json")
-		})
-
-	actual, _, err := client.ProjectFeatureFlags.ListProjectFeatureFlags(333, &ListProjectFeatureFlagOptions{})
-	if err != nil {
-		t.Errorf("ProjectFeatureFlags.ListProjectFeatureFlags returned error: %v", err)
-		return
-	}
-
-	createdAt1 := time.Date(2019, 11, 4, 8, 13, 51, 0, time.UTC)
-	updatedAt1 := time.Date(2019, 11, 4, 8, 13, 11, 0, time.UTC)
-
-	createdAt2 := time.Date(2019, 11, 4, 8, 13, 10, 0, time.UTC)
-	updatedAt2 := time.Date(2019, 11, 4, 8, 13, 10, 0, time.UTC)
-
-	expected := []*ProjectFeatureFlag{
-		{
-			Name:        "merge_train",
-			Description: "This feature is about merge train",
-			Active:      true,
-			Version:     "new_version_flag",
-			CreatedAt:   &createdAt1,
-			UpdatedAt:   &updatedAt1,
-			Scopes:      []*ProjectFeatureFlagScope{},
-			Strategies: []*ProjectFeatureFlagStrategy{
-				{
-					ID:   1,
-					Name: "userWithId",
-					Parameters: &ProjectFeatureFlagStrategyParameter{
-						UserIDs: "user1",
-					},
-					Scopes: []*ProjectFeatureFlagScope{
-						{
-							ID:               1,
-							EnvironmentScope: "production",
-						},
-					},
-				},
-			},
-		},
-		{
-			Name:        "new_live_trace",
-			Description: "This is a new live trace feature",
-			Active:      true,
-			Version:     "new_version_flag",
-			CreatedAt:   &createdAt2,
-			UpdatedAt:   &updatedAt2,
-			Scopes:      []*ProjectFeatureFlagScope{},
-			Strategies: []*ProjectFeatureFlagStrategy{
-				{
-					ID:         2,
-					Name:       "default",
-					Parameters: &ProjectFeatureFlagStrategyParameter{},
-					Scopes: []*ProjectFeatureFlagScope{
-						{
-							ID:               2,
-							EnvironmentScope: "staging",
-						},
-					},
-				},
-			},
-		},
-	}
-
-	assert.Equal(t, len(expected), len(actual))
-	for i := range expected {
-		assert.Equal(t, expected[i], actual[i])
-	}
-}
-
-func TestGetProjectFeatureFlag(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		mustWriteHTTPResponse(t, w, "testdata/get_project_feature_flag.json")
-	})
-
-	actual, resp, err := client.ProjectFeatureFlags.GetProjectFeatureFlag(1, "testing")
-	if err != nil {
-		t.Fatalf("ProjectFeatureFlags.GetProjectFeatureFlag returned error: %v, response %v", err, resp)
-	}
-
-	date := time.Date(2020, 05, 13, 19, 56, 33, 0, time.UTC)
-	expected := &ProjectFeatureFlag{
-		Name:      "awesome_feature",
-		Active:    true,
-		Version:   "new_version_flag",
-		CreatedAt: &date,
-		UpdatedAt: &date,
-		Scopes:    []*ProjectFeatureFlagScope{},
-		Strategies: []*ProjectFeatureFlagStrategy{
-			{
-				ID:         36,
-				Name:       "default",
-				Parameters: &ProjectFeatureFlagStrategyParameter{},
-				Scopes: []*ProjectFeatureFlagScope{
-					{
-						ID:               37,
-						EnvironmentScope: "production",
-					},
-				},
-			},
-		},
-	}
-
-	assert.Equal(t, expected, actual)
-}
-
-func TestCreateProjectFeatureFlag(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodPut)
-		mustWriteHTTPResponse(t, w, "testdata/create_project_feature_flag.json")
-	})
-
-	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", &UpdateProjectFeatureFlagOptions{})
-	if err != nil {
-		t.Errorf("ProjectFeatureFlags.UpdateProjectFeatureFlag returned error: %v", err)
-		return
-	}
-
-	createdAt := time.Date(2020, 5, 13, 19, 56, 33, 0, time.UTC)
-	updatedAt := time.Date(2020, 5, 13, 19, 56, 33, 0, time.UTC)
-
-	expected := &ProjectFeatureFlag{
-		Name:      "awesome_feature",
-		Active:    true,
-		Version:   "new_version_flag",
-		CreatedAt: &createdAt,
-		UpdatedAt: &updatedAt,
-		Scopes:    []*ProjectFeatureFlagScope{},
-		Strategies: []*ProjectFeatureFlagStrategy{
-			{
-				ID:         36,
-				Name:       "default",
-				Parameters: &ProjectFeatureFlagStrategyParameter{},
-				Scopes: []*ProjectFeatureFlagScope{
-					{
-						ID:               37,
-						EnvironmentScope: "production",
-					},
-				},
-			},
-		},
-	}
-
-	assert.Equal(t, expected, actual)
-}
-
-func TestUpdateProjectFeatureFlag(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodPut)
-		mustWriteHTTPResponse(t, w, "testdata/update_project_feature_flag.json")
-	})
-
-	actual, _, err := client.ProjectFeatureFlags.UpdateProjectFeatureFlag(1, "testing", &UpdateProjectFeatureFlagOptions{})
-	if err != nil {
-		t.Errorf("ProjectFeatureFlags.UpdateProjectFeatureFlag returned error: %v", err)
-		return
-	}
-
-	createdAt := time.Date(2020, 5, 13, 20, 10, 32, 0, time.UTC)
-	updatedAt := time.Date(2020, 5, 13, 20, 10, 32, 0, time.UTC)
-
-	expected := &ProjectFeatureFlag{
-		Name:      "awesome_feature",
-		Active:    true,
-		Version:   "new_version_flag",
-		CreatedAt: &createdAt,
-		UpdatedAt: &updatedAt,
-		Scopes:    []*ProjectFeatureFlagScope{},
-		Strategies: []*ProjectFeatureFlagStrategy{
-			{
-				ID:   38,
-				Name: "gradualRolloutUserId",
-				Parameters: &ProjectFeatureFlagStrategyParameter{
-					GroupID:    "default",
-					Percentage: "25",
-				},
-				Scopes: []*ProjectFeatureFlagScope{
-					{
-						ID:               40,
-						EnvironmentScope: "staging",
-					},
-				},
-			},
-			{
-				ID:         37,
-				Name:       "default",
-				Parameters: &ProjectFeatureFlagStrategyParameter{},
-				Scopes: []*ProjectFeatureFlagScope{
-					{
-						ID:               39,
-						EnvironmentScope: "production",
-					},
-				},
-			},
-		},
-	}
-
-	assert.Equal(t, expected, actual)
-}
-
-func TestDeleteProjectFeatureFlag(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/feature_flags/testing", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodDelete)
-	})
-
-	_, err := client.ProjectFeatureFlags.DeleteProjectFeatureFlag(1, "testing")
-	if err != nil {
-		t.Errorf("ProjectFeatureFlags.DeleteProjectFeatureFlag returned error: %v", err)
-		return
-	}
-}
diff --git a/projects_test.go b/projects_test.go
index 6000741..f495b3f 100644
--- a/projects_test.go
+++ b/projects_test.go
@@ -19,6 +19,7 @@ package gitlab
 import (
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"net/http"
 	"os"
 	"reflect"
@@ -361,26 +362,18 @@ func TestGetProjectWithOptions(t *testing.T) {
 				"commit_count": 37,
 				"storage_size": 1038090,
 				"repository_size": 1038090,
-				"wiki_size": 10,
 				"lfs_objects_size": 0,
-				"job_artifacts_size": 0,
-				"pipeline_artifacts_size": 0,
-				"packages_size": 238906167,
-				"snippets_size": 146800,
-				"uploads_size": 6523619
+				"job_artifacts_size": 0
 			}}`)
 	})
-	want := &Project{ID: 1, Statistics: &Statistics{
-		CommitCount:           37,
-		StorageSize:           1038090,
-		RepositorySize:        1038090,
-		WikiSize:              10,
-		LFSObjectsSize:        0,
-		JobArtifactsSize:      0,
-		PipelineArtifactsSize: 0,
-		PackagesSize:          238906167,
-		SnippetsSize:          146800,
-		UploadsSize:           6523619,
+	want := &Project{ID: 1, Statistics: &ProjectStatistics{
+		CommitCount: 37,
+		StorageStatistics: StorageStatistics{
+			StorageSize:      1038090,
+			RepositorySize:   1038090,
+			LfsObjectsSize:   0,
+			JobArtifactsSize: 0,
+		},
 	}}
 
 	project, _, err := client.Projects.GetProject(1, &GetProjectOptions{Statistics: Bool(true)})
@@ -459,7 +452,7 @@ func TestUploadFile_Retry(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
 
-	tf, _ := os.CreateTemp(os.TempDir(), "test")
+	tf, _ := ioutil.TempFile(os.TempDir(), "test")
 	defer os.Remove(tf.Name())
 
 	isFirstRequest := true
diff --git a/protected_tags_test.go b/protected_tags_test.go
index 94c7a1a..66337fa 100644
--- a/protected_tags_test.go
+++ b/protected_tags_test.go
@@ -68,7 +68,7 @@ func TestGetProtectedTag(t *testing.T) {
 
 	mux.HandleFunc(fmt.Sprintf("/api/v4/projects/1/protected_tags/%s", tagName), func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
-		fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"},{"access_level": 40, "access_level_description": "Sample Group", "group_id": 300}]}`)
+		fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`)
 	})
 
 	expected := &ProtectedTag{
@@ -78,11 +78,6 @@ func TestGetProtectedTag(t *testing.T) {
 				AccessLevel:            30,
 				AccessLevelDescription: "Developers + Maintainers",
 			},
-			{
-				AccessLevel:            40,
-				GroupID:                300,
-				AccessLevelDescription: "Sample Group",
-			},
 		},
 	}
 
@@ -98,7 +93,7 @@ func TestProtectRepositoryTags(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/projects/1/protected_tags", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodPost)
-		fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"},{"access_level": 40, "access_level_description": "Sample Group", "group_id": 300}]}`)
+		fmt.Fprint(w, `{"name":"my-awesome-tag", "create_access_levels": [{"access_level": 30, "access_level_description": "Developers + Maintainers"}]}`)
 	})
 
 	expected := &ProtectedTag{
@@ -108,23 +103,10 @@ func TestProtectRepositoryTags(t *testing.T) {
 				AccessLevel:            30,
 				AccessLevelDescription: "Developers + Maintainers",
 			},
-			{
-				AccessLevel:            40,
-				GroupID:                300,
-				AccessLevelDescription: "Sample Group",
-			},
 		},
 	}
 
-	opt := &ProtectRepositoryTagsOptions{
-		Name:              String("my-awesome-tag"),
-		CreateAccessLevel: AccessLevel(30),
-		AllowedToCreate: &[]*TagsPermissionOptions{
-			{
-				GroupID: Int(300),
-			},
-		},
-	}
+	opt := &ProtectRepositoryTagsOptions{Name: String("my-awesome-tag"), CreateAccessLevel: AccessLevel(30)}
 	tag, _, err := client.ProtectedTags.ProtectRepositoryTags(1, opt)
 
 	assert.NoError(t, err, "failed to get response")
diff --git a/releases_test.go b/releases_test.go
index c02891f..0d0fcd8 100644
--- a/releases_test.go
+++ b/releases_test.go
@@ -18,7 +18,7 @@ package gitlab
 
 import (
 	"fmt"
-	"io"
+	"io/ioutil"
 	"net/http"
 	"strings"
 	"testing"
@@ -71,7 +71,7 @@ func TestReleasesService_CreateRelease(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPost)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -116,7 +116,7 @@ func TestReleasesService_CreateReleaseWithAsset(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPost)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -166,7 +166,7 @@ func TestReleasesService_CreateReleaseWithAssetAndNameMetadata(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPost)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -216,7 +216,7 @@ func TestReleasesService_CreateReleaseWithMilestones(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPost)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -262,7 +262,7 @@ func TestReleasesService_CreateReleaseWithReleasedAt(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPost)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -308,7 +308,7 @@ func TestReleasesService_UpdateRelease(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases/v0.1",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPut)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -344,7 +344,7 @@ func TestReleasesService_UpdateReleaseWithMilestones(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases/v0.1",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPut)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
@@ -381,7 +381,7 @@ func TestReleasesService_UpdateReleaseWithReleasedAt(t *testing.T) {
 	mux.HandleFunc("/api/v4/projects/1/releases/v0.1",
 		func(w http.ResponseWriter, r *http.Request) {
 			testMethod(t, r, http.MethodPut)
-			b, err := io.ReadAll(r.Body)
+			b, err := ioutil.ReadAll(r.Body)
 			if err != nil {
 				t.Fatalf("unable to read request body")
 			}
diff --git a/resource_weight_events_test.go b/resource_weight_events_test.go
deleted file mode 100644
index 41ac3ca..0000000
--- a/resource_weight_events_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package gitlab
-
-import (
-	"fmt"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/require"
-)
-
-func TestResourceWeightEventsService_ListIssueWightEvents(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/5/issues/11/resource_weight_events", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		fmt.Fprintf(w, `[
-			{
-			  "id": 142,
-			  "user": {
-				"id": 1,
-				"name": "Administrator",
-				"username": "root",
-				"state": "active",
-				"avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
-				"web_url": "http://gitlab.example.com/root"
-			  },
-			  "created_at": "2018-08-20T13:38:20.077Z",
-			  "issue_id": 253,
-			  "weight": 3
-			}
-		]`)
-	})
-
-	opt := &ListWeightEventsOptions{ListOptions{Page: 1, PerPage: 10}}
-
-	wes, _, err := client.ResourceWeightEvents.ListIssueWeightEvents(5, 11, opt)
-	require.NoError(t, err)
-
-	want := []*WeightEvent{{
-		ID: 142,
-		User: &BasicUser{
-			ID:        1,
-			Username:  "root",
-			Name:      "Administrator",
-			State:     "active",
-			AvatarURL: "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
-			WebURL:    "http://gitlab.example.com/root",
-		},
-		CreatedAt: Time(time.Date(2018, time.August, 20, 13, 38, 20, 77000000, time.UTC)),
-		IssueID:   253,
-		Weight:    3,
-	}}
-	require.Equal(t, want, wes)
-}
diff --git a/runners_test.go b/runners_test.go
index ee8cfed..27faf18 100644
--- a/runners_test.go
+++ b/runners_test.go
@@ -56,17 +56,15 @@ func TestListRunnersJobs(t *testing.T) {
 	}
 
 	pipeline := struct {
-		ID        int    `json:"id"`
-		ProjectID int    `json:"project_id"`
-		Ref       string `json:"ref"`
-		Sha       string `json:"sha"`
-		Status    string `json:"status"`
+		ID     int    `json:"id"`
+		Ref    string `json:"ref"`
+		Sha    string `json:"sha"`
+		Status string `json:"status"`
 	}{
-		ID:        8777,
-		ProjectID: 3252,
-		Ref:       "master",
-		Sha:       "6c016b801a88f4bd31f927fc045b5c746a6f823e",
-		Status:    "failed",
+		ID:     8777,
+		Ref:    "master",
+		Sha:    "6c016b801a88f4bd31f927fc045b5c746a6f823e",
+		Status: "failed",
 	}
 
 	want := []*Job{
diff --git a/services_test.go b/services_test.go
index c514c57..864964a 100644
--- a/services_test.go
+++ b/services_test.go
@@ -158,55 +158,6 @@ func TestDeleteDroneCIService(t *testing.T) {
 	}
 }
 
-func TestGetEmailsOnPushService(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/integrations/emails-on-push", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodGet)
-		fmt.Fprint(w, `{"id":1}`)
-	})
-	want := &EmailsOnPushService{Service: Service{ID: 1}}
-
-	service, _, err := client.Services.GetEmailsOnPushService(1)
-	if err != nil {
-		t.Fatalf("Services.GetEmailsOnPushService returns an error: %v", err)
-	}
-	if !reflect.DeepEqual(want, service) {
-		t.Errorf("Services.GetEmailsOnPushService returned %+v, want %+v", service, want)
-	}
-}
-
-func TestSetEmailsOnPushService(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/integrations/emails-on-push", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodPut)
-	})
-
-	opt := &SetEmailsOnPushServiceOptions{String("t"), Bool(true), Bool(true), Bool(true), Bool(true), String("t")}
-
-	_, err := client.Services.SetEmailsOnPushService(1, opt)
-	if err != nil {
-		t.Fatalf("Services.SetEmailsOnPushService returns an error: %v", err)
-	}
-}
-
-func TestDeleteEmailsOnPushService(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/integrations/emails-on-push", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodDelete)
-	})
-
-	_, err := client.Services.DeleteEmailsOnPushService(1)
-	if err != nil {
-		t.Fatalf("Services.DeleteEmailsOnPushService returns an error: %v", err)
-	}
-}
-
 func TestGetJiraService(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
diff --git a/testdata/create_project_feature_flag.json b/testdata/create_project_feature_flag.json
deleted file mode 100644
index e460627..0000000
--- a/testdata/create_project_feature_flag.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "name": "awesome_feature",
-  "description": null,
-  "active": true,
-  "version": "new_version_flag",
-  "created_at": "2020-05-13T19:56:33Z",
-  "updated_at": "2020-05-13T19:56:33Z",
-  "scopes": [],
-  "strategies": [
-    {
-      "id": 36,
-      "name": "default",
-      "parameters": {},
-      "scopes": [
-        {
-          "id": 37,
-          "environment_scope": "production"
-        }
-      ]
-    }
-  ]
-}
diff --git a/testdata/get_project_feature_flag.json b/testdata/get_project_feature_flag.json
deleted file mode 100644
index e460627..0000000
--- a/testdata/get_project_feature_flag.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "name": "awesome_feature",
-  "description": null,
-  "active": true,
-  "version": "new_version_flag",
-  "created_at": "2020-05-13T19:56:33Z",
-  "updated_at": "2020-05-13T19:56:33Z",
-  "scopes": [],
-  "strategies": [
-    {
-      "id": 36,
-      "name": "default",
-      "parameters": {},
-      "scopes": [
-        {
-          "id": 37,
-          "environment_scope": "production"
-        }
-      ]
-    }
-  ]
-}
diff --git a/testdata/list_project_feature_flags.json b/testdata/list_project_feature_flags.json
deleted file mode 100644
index 660fd2f..0000000
--- a/testdata/list_project_feature_flags.json
+++ /dev/null
@@ -1,48 +0,0 @@
-[
-  {
-    "name":"merge_train",
-    "description":"This feature is about merge train",
-    "active": true,
-    "version": "new_version_flag",
-    "created_at":"2019-11-04T08:13:51Z",
-    "updated_at":"2019-11-04T08:13:11Z",
-    "scopes":[],
-    "strategies": [
-      {
-        "id": 1,
-        "name": "userWithId",
-        "parameters": {
-          "userIds": "user1"
-        },
-        "scopes": [
-          {
-            "id": 1,
-            "environment_scope": "production"
-          }
-        ]
-      }
-    ]
-  },
-  {
-    "name":"new_live_trace",
-    "description":"This is a new live trace feature",
-    "active": true,
-    "version": "new_version_flag",
-    "created_at":"2019-11-04T08:13:10Z",
-    "updated_at":"2019-11-04T08:13:10Z",
-    "scopes":[],
-    "strategies": [
-      {
-        "id": 2,
-        "name": "default",
-        "parameters": {},
-        "scopes": [
-          {
-            "id": 2,
-            "environment_scope": "staging"
-          }
-        ]
-      }
-    ]
-  }
-]
diff --git a/testdata/update_project_feature_flag.json b/testdata/update_project_feature_flag.json
deleted file mode 100644
index f66b51a..0000000
--- a/testdata/update_project_feature_flag.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "name": "awesome_feature",
-  "description": null,
-  "active": true,
-  "version": "new_version_flag",
-  "created_at": "2020-05-13T20:10:32Z",
-  "updated_at": "2020-05-13T20:10:32Z",
-  "scopes": [],
-  "strategies": [
-    {
-      "id": 38,
-      "name": "gradualRolloutUserId",
-      "parameters": {
-        "groupId": "default",
-        "percentage": "25"
-      },
-      "scopes": [
-        {
-          "id": 40,
-          "environment_scope": "staging"
-        }
-      ]
-    },
-    {
-      "id": 37,
-      "name": "default",
-      "parameters": {},
-      "scopes": [
-        {
-          "id": 39,
-          "environment_scope": "production"
-        }
-      ]
-    }
-  ]
-}
diff --git a/testdata/webhooks/deployment.json b/testdata/webhooks/deployment.json
index ce3c131..3ab09fd 100644
--- a/testdata/webhooks/deployment.json
+++ b/testdata/webhooks/deployment.json
@@ -32,6 +32,5 @@
   },
   "user_url": "http://10.126.0.2:3000/root",
   "commit_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/commit/279484c09fbe69ededfced8c1bb6e6d24616b468",
-  "commit_title": "Add new file",
-  "ref": "1.0.0"
+  "commit_title": "Add new file"
 }
diff --git a/testdata/webhooks/member.json b/testdata/webhooks/member.json
deleted file mode 100644
index 4924d41..0000000
--- a/testdata/webhooks/member.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "created_at": "2020-12-11T04:57:22Z",
-  "updated_at": "2020-12-11T04:57:22Z",
-  "group_name": "webhook-test",
-  "group_path": "webhook-test",
-  "group_id": 100,
-  "user_username": "user1",
-  "user_name": "User1",
-  "user_email": "testuser@webhooktest.com",
-  "user_id": 64,
-  "group_access": "Guest",
-  "group_plan": null,
-  "expires_at": "2020-12-14T00:00:00Z",
-  "event_name": "user_add_to_group"
-}
diff --git a/testdata/webhooks/merge_request.json b/testdata/webhooks/merge_request.json
index c7b5754..2bc8406 100644
--- a/testdata/webhooks/merge_request.json
+++ b/testdata/webhooks/merge_request.json
@@ -1,12 +1,11 @@
 {
   "object_kind": "merge_request",
-  "event_type": "merge_request",
   "user": {
-    "id": 1,
+    "id": 42,
     "name": "User1",
     "username": "user1",
-    "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon",
-    "email": "user1@example.com"
+    "email": "user1@example.com",
+    "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
   },
   "project": {
     "id": 1,
@@ -33,26 +32,20 @@
   },
   "object_attributes": {
     "id": 99,
-    "iid": 1,
     "target_branch": "master",
     "source_branch": "ms-viewport",
     "source_project_id": 14,
     "author_id": 51,
-    "assignee_ids": [1],
-    "assignee_id": 1,
-    "reviewer_ids": [1],
+    "assignee_id": 6,
     "title": "MS-Viewport",
     "created_at": "2013-12-03T17:23:34Z",
     "updated_at": "2013-12-03T17:23:34Z",
     "milestone_id": null,
     "state": "opened",
-    "blocking_discussions_resolved": true,
-    "work_in_progress": false,
-    "first_contribution": true,
     "merge_status": "unchecked",
     "target_project_id": 14,
+    "iid": 1,
     "description": "",
-    "url": "http://example.com/diaspora/merge_requests/1",
     "source": {
       "name":"Awesome Project",
       "description":"Aut reprehenderit ut est.",
@@ -95,20 +88,24 @@
         "email": "gitlabdev@dv6700.(none)"
       }
     },
-    "labels": [{
-      "id": 206,
-      "title": "API",
-      "color": "#ffffff",
-      "project_id": 14,
-      "created_at": "2013-12-03T17:15:43Z",
-      "updated_at": "2013-12-03T17:15:43Z",
-      "template": false,
-      "description": "API related issues",
-      "type": "ProjectLabel",
-      "group_id": 41
-    }],
-    "action": "open"
+    "work_in_progress": false,
+    "url": "http://example.com/diaspora/merge_requests/1",
+    "action": "open",
+    "assignee": {
+      "name": "User1",
+      "username": "user1",
+      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+    }
   },
+  "assignees": [
+    {
+      "id": 1,
+      "name": "User1",
+      "username": "user1",
+      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon",
+      "email": "test.user1@example.com"
+    }
+  ],
   "labels": [{
     "id": 206,
     "title": "API",
@@ -128,7 +125,13 @@
     },
     "updated_at": {
       "previous": "2017-09-15 16:50:55 UTC",
-      "current":"2017-09-15 16:52:00 UTC"
+      "current": "2017-09-15 16:52:00 UTC"
+    },
+    "changes": {
+      "state_id": {
+        "previous": 2,
+        "current": 1
+      }
     },
     "labels": {
       "previous": [{
@@ -156,21 +159,5 @@
         "group_id": 41
       }]
     }
-  },
-  "assignees": [
-    {
-      "id": 1,
-      "name": "User1",
-      "username": "user1",
-      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
-    }
-  ],
-  "reviewers": [
-    {
-      "id": 1,
-      "name": "User1",
-      "username": "user1",
-      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
-    }
-  ]
+  }
 }
diff --git a/users_test.go b/users_test.go
index 380255b..3a388e0 100644
--- a/users_test.go
+++ b/users_test.go
@@ -649,19 +649,3 @@ func TestGetSingleSSHKeyForUser(t *testing.T) {
 		t.Errorf("Users.GetSSHKeyForUser returned %+v, want %+v", sshKey, want)
 	}
 }
-
-func TestDisableUser2FA(t *testing.T) {
-	mux, server, client := setup(t)
-	defer teardown(server)
-
-	path := fmt.Sprintf("/%susers/1/disable_two_factor", apiVersionPath)
-	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, http.MethodPatch)
-		w.WriteHeader(http.StatusNoContent)
-	})
-
-	err := client.Users.DisableTwoFactor(1)
-	if err != nil {
-		t.Errorf("Users.DisableTwoFactor returned error: %v", err)
-	}
-}