Repository: xanzy/go-gitlab
Pull request #591 (2019-03-24 12:30:40)

Support for comments on Epics
Epics were not yet supported to have their notes manipulated. With this
change, notes can be listed, created, updated, and deleted. The
conventions are followed that are set by Snippets, Merge Reqeuests, and
Issues.


Patch:
diff --git a/group_members.go b/group_members.go
index fc9ffa7..62d968a 100644
--- a/group_members.go
+++ b/group_members.go
@@ -54,7 +54,7 @@ type ListGroupMembersOptions struct {
 }
 
 // ListGroupMembers get a list of group members viewable by the authenticated
-// user. Inherited members through ancestor groups are not included.
+// user. Returns a list including inherited members through ancestor groups.
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project
diff --git a/issues.go b/issues.go
index e7610e0..7627d1a 100644
--- a/issues.go
+++ b/issues.go
@@ -65,33 +65,32 @@ type IssueLinks struct {
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/issues.html
 type Issue struct {
-	ID                int              `json:"id"`
-	IID               int              `json:"iid"`
-	ProjectID         int              `json:"project_id"`
-	Milestone         *Milestone       `json:"milestone"`
-	Author            *IssueAuthor     `json:"author"`
-	Description       string           `json:"description"`
-	State             string           `json:"state"`
-	Assignees         []*IssueAssignee `json:"assignees"`
-	Assignee          *IssueAssignee   `json:"assignee"`
-	Upvotes           int              `json:"upvotes"`
-	Downvotes         int              `json:"downvotes"`
-	Labels            []string         `json:"labels"`
-	Title             string           `json:"title"`
-	UpdatedAt         *time.Time       `json:"updated_at"`
-	CreatedAt         *time.Time       `json:"created_at"`
-	ClosedAt          *time.Time       `json:"closed_at"`
-	Subscribed        bool             `json:"subscribed"`
-	UserNotesCount    int              `json:"user_notes_count"`
-	DueDate           *ISOTime         `json:"due_date"`
-	WebURL            string           `json:"web_url"`
-	TimeStats         *TimeStats       `json:"time_stats"`
-	Confidential      bool             `json:"confidential"`
-	Weight            int              `json:"weight"`
-	DiscussionLocked  bool             `json:"discussion_locked"`
-	Links             *IssueLinks      `json:"_links"`
-	IssueLinkID       int              `json:"issue_link_id"`
-	MergeRequestCount int              `json:"merge_requests_count"`
+	ID               int              `json:"id"`
+	IID              int              `json:"iid"`
+	ProjectID        int              `json:"project_id"`
+	Milestone        *Milestone       `json:"milestone"`
+	Author           *IssueAuthor     `json:"author"`
+	Description      string           `json:"description"`
+	State            string           `json:"state"`
+	Assignees        []*IssueAssignee `json:"assignees"`
+	Assignee         *IssueAssignee   `json:"assignee"`
+	Upvotes          int              `json:"upvotes"`
+	Downvotes        int              `json:"downvotes"`
+	Labels           []string         `json:"labels"`
+	Title            string           `json:"title"`
+	UpdatedAt        *time.Time       `json:"updated_at"`
+	CreatedAt        *time.Time       `json:"created_at"`
+	ClosedAt         *time.Time       `json:"closed_at"`
+	Subscribed       bool             `json:"subscribed"`
+	UserNotesCount   int              `json:"user_notes_count"`
+	DueDate          *ISOTime         `json:"due_date"`
+	WebURL           string           `json:"web_url"`
+	TimeStats        *TimeStats       `json:"time_stats"`
+	Confidential     bool             `json:"confidential"`
+	Weight           int              `json:"weight"`
+	DiscussionLocked bool             `json:"discussion_locked"`
+	Links            *IssueLinks      `json:"_links"`
+	IssueLinkID      int              `json:"issue_link_id"`
 }
 
 func (i Issue) String() string {
diff --git a/notes.go b/notes.go
index cba77bc..dd0e890 100644
--- a/notes.go
+++ b/notes.go
@@ -194,6 +194,7 @@ type UpdateIssueNoteOptions struct {
 
 // UpdateIssueNote modifies existing note of an issue.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note
 func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *UpdateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
 	project, err := parseID(pid)
@@ -218,6 +219,7 @@ func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *Up
 
 // DeleteIssueNote deletes an existing note of an issue.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#delete-an-issue-note
 func (s *NotesService) DeleteIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Response, error) {
 	project, err := parseID(pid)
@@ -341,6 +343,7 @@ type UpdateSnippetNoteOptions struct {
 
 // UpdateSnippetNote modifies existing note of a snippet.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note
 func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt *UpdateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
 	project, err := parseID(pid)
@@ -365,6 +368,7 @@ func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt
 
 // DeleteSnippetNote deletes an existing note of a snippet.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#delete-a-snippet-note
 func (s *NotesService) DeleteSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Response, error) {
 	project, err := parseID(pid)
@@ -487,6 +491,7 @@ type UpdateMergeRequestNoteOptions struct {
 
 // UpdateMergeRequestNote modifies existing note of a merge request.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note
 func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, note int, opt *UpdateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
 	project, err := parseID(pid)
@@ -511,6 +516,7 @@ func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, not
 
 // DeleteMergeRequestNote deletes an existing note of a merge request.
 //
+// GitLab API docs:
 // https://docs.gitlab.com/ce/api/notes.html#delete-a-merge-request-note
 func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Response, error) {
 	project, err := parseID(pid)
@@ -527,3 +533,146 @@ func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, not
 
 	return s.client.Do(req, nil)
 }
+
+// ListEpicNotesOptions represents the available ListEpicNotes() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes
+type ListEpicNotesOptions struct {
+	ListOptions
+	OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"`
+	Sort    *string `url:"sort,omitempty" json:"sort,omitempty"`
+}
+
+// ListEpicNotes gets a list of all notes for a single epic.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#list-all-epic-notes
+func (s *NotesService) ListEpicNotes(gid interface{}, epic int, opt *ListEpicNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/epics/%d/notes", url.QueryEscape(group), epic)
+
+	req, err := s.client.NewRequest("GET", u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var n []*Note
+	resp, err := s.client.Do(req, &n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// GetEpicNote returns a single note for an epic.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#get-single-epic-note
+func (s *NotesService) GetEpicNote(gid interface{}, epic, note int, options ...OptionFunc) (*Note, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", url.QueryEscape(group), epic, note)
+
+	req, err := s.client.NewRequest("GET", u, nil, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// CreateEpicNoteOptions represents the available CreateEpicNote() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note
+type CreateEpicNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// CreateEpicNote creates a new note for a single merge request.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#create-new-epic-note
+func (s *NotesService) CreateEpicNote(gid interface{}, epic int, opt *CreateEpicNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/epics/%d/notes", url.QueryEscape(group), epic)
+
+	req, err := s.client.NewRequest("POST", u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// UpdateEpicNoteOptions represents the available UpdateEpicNote() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note
+type UpdateEpicNoteOptions struct {
+	Body *string `url:"body,omitempty" json:"body,omitempty"`
+}
+
+// UpdateEpicNote modifies existing note of an epic.
+//
+// https://docs.gitlab.com/ee/api/notes.html#modify-existing-epic-note
+func (s *NotesService) UpdateEpicNote(gid interface{}, epic, note int, opt *UpdateEpicNoteOptions, options ...OptionFunc) (*Note, *Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", url.QueryEscape(group), epic, note)
+
+	req, err := s.client.NewRequest("PUT", u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	n := new(Note)
+	resp, err := s.client.Do(req, n)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return n, resp, err
+}
+
+// DeleteEpicNote deletes an existing note of a merge request.
+//
+// https://docs.gitlab.com/ee/api/notes.html#delete-an-epic-note
+func (s *NotesService) DeleteEpicNote(gid interface{}, epic, note int, options ...OptionFunc) (*Response, error) {
+	group, err := parseID(gid)
+	if err != nil {
+		return nil, err
+	}
+	u := fmt.Sprintf("groups/%s/epics/%d/notes/%d", url.QueryEscape(group), epic, note)
+
+	req, err := s.client.NewRequest("DELETE", u, nil, options)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}
diff --git a/pipelines.go b/pipelines.go
index e08625e..8466eac 100644
--- a/pipelines.go
+++ b/pipelines.go
@@ -79,7 +79,6 @@ type PipelineList []struct {
 	Status string `json:"status"`
 	Ref    string `json:"ref"`
 	SHA    string `json:"sha"`
-	WebURL string `json:"web_url"`
 }
 
 func (i PipelineList) String() string {
@@ -185,12 +184,12 @@ func (s *PipelinesService) CreatePipeline(pid interface{}, opt *CreatePipelineOp
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/pipelines.html#retry-failed-builds-in-a-pipeline
-func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) {
+func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipelineID int, options ...OptionFunc) (*Pipeline, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/pipelines/%d/retry", project, pipeline)
+	u := fmt.Sprintf("projects/%s/pipelines/%d/retry", project, pipelineID)
 
 	req, err := s.client.NewRequest("POST", u, nil, options)
 	if err != nil {
@@ -210,12 +209,12 @@ func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipeline int, opt
 //
 // GitLab API docs:
 //https://docs.gitlab.com/ce/api/pipelines.html#cancel-a-pipelines-builds
-func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) {
+func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipelineID int, options ...OptionFunc) (*Pipeline, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
-	u := fmt.Sprintf("projects/%s/pipelines/%d/cancel", project, pipeline)
+	u := fmt.Sprintf("projects/%s/pipelines/%d/cancel", project, pipelineID)
 
 	req, err := s.client.NewRequest("POST", u, nil, options)
 	if err != nil {
@@ -230,22 +229,3 @@ func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipeline int, op
 
 	return p, resp, err
 }
-
-// DeletePipeline deletes an existing pipeline.
-//
-// GitLab API docs:
-// https://docs.gitlab.com/ce/api/pipelines.html#delete-a-pipeline
-func (s *PipelinesService) DeletePipeline(pid interface{}, pipeline int, options ...OptionFunc) (*Response, error) {
-	project, err := parseID(pid)
-	if err != nil {
-		return nil, err
-	}
-	u := fmt.Sprintf("projects/%s/pipelines/%d", project, pipeline)
-
-	req, err := s.client.NewRequest("DELETE", u, nil, options)
-	if err != nil {
-		return nil, err
-	}
-
-	return s.client.Do(req, nil)
-}
diff --git a/repositories.go b/repositories.go
index 75ab705..451f4c7 100644
--- a/repositories.go
+++ b/repositories.go
@@ -137,8 +137,7 @@ func (s *RepositoriesService) RawBlobContent(pid interface{}, sha string, option
 // GitLab API docs:
 // https://docs.gitlab.com/ce/api/repositories.html#get-file-archive
 type ArchiveOptions struct {
-	Format *string `url:"-" json:"-"`
-	SHA    *string `url:"sha,omitempty" json:"sha,omitempty"`
+	SHA *string `url:"sha,omitempty" json:"sha,omitempty"`
 }
 
 // Archive gets an archive of the repository.
@@ -152,11 +151,6 @@ func (s *RepositoriesService) Archive(pid interface{}, opt *ArchiveOptions, opti
 	}
 	u := fmt.Sprintf("projects/%s/repository/archive", url.QueryEscape(project))
 
-	// Set an optional format for the archive.
-	if opt != nil && opt.Format != nil {
-		u = fmt.Sprintf("%s.%s", u, *opt.Format)
-	}
-
 	req, err := s.client.NewRequest("GET", u, opt, options)
 	if err != nil {
 		return nil, nil, err


Test patch:
diff --git a/access_requests_test.go b/access_requests_test.go
deleted file mode 100644
index 3f89901..0000000
--- a/access_requests_test.go
+++ /dev/null
@@ -1,401 +0,0 @@
-package gitlab
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestListProjectAccessRequests(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/access_requests", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		fmt.Fprintf(w, `[
-			{
-			  "id": 1,
-			  "username": "raymond_smith",
-			  "name": "Raymond Smith",
-			  "state": "active",
-			  "created_at": "2012-10-22T14:13:35Z",
-			  "requested_at": "2012-10-22T14:13:35Z"
-			},
-			{
-			  "id": 2,
-			  "username": "john_doe",
-			  "name": "John Doe",
-			  "state": "active",
-			  "created_at": "2012-10-22T14:13:35Z",
-			  "requested_at": "2012-10-22T14:13:35Z"
-			}
-		]`)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := []*AccessRequest{
-		&AccessRequest{
-			ID:          1,
-			Username:    "raymond_smith",
-			Name:        "Raymond Smith",
-			State:       "active",
-			CreatedAt:   &created,
-			RequestedAt: &created,
-		},
-		&AccessRequest{
-			ID:          2,
-			Username:    "john_doe",
-			Name:        "John Doe",
-			State:       "active",
-			CreatedAt:   &created,
-			RequestedAt: &created,
-		},
-	}
-
-	requests, resp, err := client.AccessRequests.ListProjectAccessRequests(1, nil)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, requests)
-
-	requests, resp, err = client.AccessRequests.ListProjectAccessRequests(1.5, nil)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, requests)
-	assert.Nil(t, resp)
-
-	requests, resp, err = client.AccessRequests.ListProjectAccessRequests(2, nil)
-	assert.Error(t, err)
-	assert.Nil(t, requests)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	requests, resp, err = client.AccessRequests.ListProjectAccessRequests(1, nil, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, requests)
-	assert.Nil(t, resp)
-}
-
-func TestListGroupAccessRequests(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/access_requests", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "GET")
-		fmt.Fprintf(w, `[
-			{
-			  "id": 1,
-			  "username": "raymond_smith",
-			  "name": "Raymond Smith",
-			  "state": "active",
-			  "created_at": "2012-10-22T14:13:35Z",
-			  "requested_at": "2012-10-22T14:13:35Z"
-			},
-			{
-			  "id": 2,
-			  "username": "john_doe",
-			  "name": "John Doe",
-			  "state": "active",
-			  "created_at": "2012-10-22T14:13:35Z",
-			  "requested_at": "2012-10-22T14:13:35Z"
-			}
-		]`)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := []*AccessRequest{
-		&AccessRequest{
-			ID:          1,
-			Username:    "raymond_smith",
-			Name:        "Raymond Smith",
-			State:       "active",
-			CreatedAt:   &created,
-			RequestedAt: &created,
-		},
-		&AccessRequest{
-			ID:          2,
-			Username:    "john_doe",
-			Name:        "John Doe",
-			State:       "active",
-			CreatedAt:   &created,
-			RequestedAt: &created,
-		},
-	}
-
-	requests, resp, err := client.AccessRequests.ListGroupAccessRequests(1, nil)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, requests)
-
-	requests, resp, err = client.AccessRequests.ListGroupAccessRequests(1.5, nil)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, requests)
-	assert.Nil(t, resp)
-
-	requests, resp, err = client.AccessRequests.ListGroupAccessRequests(2, nil)
-	assert.Error(t, err)
-	assert.Nil(t, requests)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	requests, resp, err = client.AccessRequests.ListGroupAccessRequests(1, nil, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, requests)
-	assert.Nil(t, resp)
-}
-
-func TestRequestProjectAccess(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/access_requests", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "POST")
-		fmt.Fprintf(w, `{
-				"id": 1,
-				"username": "raymond_smith",
-				"name": "Raymond Smith",
-				"state": "active",
-				"created_at": "2012-10-22T14:13:35Z",
-				"requested_at": "2012-10-22T14:13:35Z"
-			}`)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := &AccessRequest{
-		ID:          1,
-		Username:    "raymond_smith",
-		Name:        "Raymond Smith",
-		State:       "active",
-		CreatedAt:   &created,
-		RequestedAt: &created,
-	}
-
-	accessRequest, resp, err := client.AccessRequests.RequestProjectAccess(1, nil)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, accessRequest)
-
-	accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(1.5, nil)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, accessRequest)
-	assert.Nil(t, resp)
-
-	accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(2, nil)
-	assert.Error(t, err)
-	assert.Nil(t, accessRequest)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	accessRequest, resp, err = client.AccessRequests.RequestProjectAccess(1, nil, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, accessRequest)
-	assert.Nil(t, resp)
-}
-
-func TestRequestGroupAccess(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/access_requests", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "POST")
-		fmt.Fprintf(w, `{
-				"id": 1,
-				"username": "raymond_smith",
-				"name": "Raymond Smith",
-				"state": "active",
-				"created_at": "2012-10-22T14:13:35Z",
-				"requested_at": "2012-10-22T14:13:35Z"
-			}`)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := &AccessRequest{
-		ID:          1,
-		Username:    "raymond_smith",
-		Name:        "Raymond Smith",
-		State:       "active",
-		CreatedAt:   &created,
-		RequestedAt: &created,
-	}
-
-	accessRequest, resp, err := client.AccessRequests.RequestGroupAccess(1, nil)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, accessRequest)
-
-	accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(1.5, nil)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, accessRequest)
-	assert.Nil(t, resp)
-
-	accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(2, nil)
-	assert.Error(t, err)
-	assert.Nil(t, accessRequest)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	accessRequest, resp, err = client.AccessRequests.RequestGroupAccess(1, nil, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, accessRequest)
-	assert.Nil(t, resp)
-}
-
-func TestApproveProjectAccessRequest(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/access_requests/10/approve", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "PUT")
-
-		var opt ApproveAccessRequestOptions
-		err := json.NewDecoder(r.Body).Decode(&opt)
-		assert.NoError(t, err)
-		defer r.Body.Close()
-
-		fmt.Fprintf(w, `{
-				"id": 10,
-				"username": "raymond_smith",
-				"name": "Raymond Smith",
-				"state": "active",
-				"created_at": "2012-10-22T14:13:35Z",
-				"requested_at": "2012-10-22T14:13:35Z",
-				"access_level": %d
-			}`,
-			*opt.AccessLevel)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := &AccessRequest{
-		ID:          10,
-		Username:    "raymond_smith",
-		Name:        "Raymond Smith",
-		State:       "active",
-		CreatedAt:   &created,
-		RequestedAt: &created,
-		AccessLevel: DeveloperPermissions,
-	}
-
-	opt := &ApproveAccessRequestOptions{
-		AccessLevel: AccessLevel(DeveloperPermissions),
-	}
-
-	request, resp, err := client.AccessRequests.ApproveProjectAccessRequest(1, 10, opt)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, request)
-
-	request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(1.5, 10, opt)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, request)
-	assert.Nil(t, resp)
-
-	request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(2, 10, opt)
-	assert.Error(t, err)
-	assert.Nil(t, request)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	request, resp, err = client.AccessRequests.ApproveProjectAccessRequest(1, 10, opt, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, request)
-	assert.Nil(t, resp)
-}
-
-func TestApproveGroupAccessRequest(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/access_requests/10/approve", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "PUT")
-
-		var opt ApproveAccessRequestOptions
-		err := json.NewDecoder(r.Body).Decode(&opt)
-		assert.NoError(t, err)
-		defer r.Body.Close()
-
-		fmt.Fprintf(w, `{
-				"id": 10,
-				"username": "raymond_smith",
-				"name": "Raymond Smith",
-				"state": "active",
-				"created_at": "2012-10-22T14:13:35Z",
-				"requested_at": "2012-10-22T14:13:35Z",
-				"access_level": %d
-			}`,
-			*opt.AccessLevel)
-	})
-
-	created := time.Date(2012, 10, 22, 14, 13, 35, 0, time.UTC)
-	expected := &AccessRequest{
-		ID:          10,
-		Username:    "raymond_smith",
-		Name:        "Raymond Smith",
-		State:       "active",
-		CreatedAt:   &created,
-		RequestedAt: &created,
-		AccessLevel: DeveloperPermissions,
-	}
-
-	opt := &ApproveAccessRequestOptions{
-		AccessLevel: AccessLevel(DeveloperPermissions),
-	}
-
-	request, resp, err := client.AccessRequests.ApproveGroupAccessRequest(1, 10, opt)
-	assert.NoError(t, err)
-	assert.Equal(t, expected, request)
-
-	request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(1.5, 10, opt)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, request)
-	assert.Nil(t, resp)
-
-	request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(2, 10, opt)
-	assert.Error(t, err)
-	assert.Nil(t, request)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	request, resp, err = client.AccessRequests.ApproveGroupAccessRequest(1, 10, opt, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, request)
-	assert.Nil(t, resp)
-}
-
-func TestDenyProjectAccessRequest(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/access_requests/10", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "DELETE")
-	})
-
-	resp, err := client.AccessRequests.DenyProjectAccessRequest(1, 10)
-	assert.NoError(t, err)
-
-	resp, err = client.AccessRequests.DenyProjectAccessRequest(1.5, 10)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, resp)
-
-	resp, err = client.AccessRequests.DenyProjectAccessRequest(2, 10)
-	assert.Error(t, err)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	resp, err = client.AccessRequests.DenyProjectAccessRequest(1, 10, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, resp)
-}
-
-func TestDenyGroupAccessRequest(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/groups/1/access_requests/10", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "DELETE")
-	})
-
-	resp, err := client.AccessRequests.DenyGroupAccessRequest(1, 10)
-	assert.NoError(t, err)
-
-	resp, err = client.AccessRequests.DenyGroupAccessRequest(1.5, 10)
-	assert.EqualError(t, err, "invalid ID type 1.5, the ID must be an int or a string")
-	assert.Nil(t, resp)
-
-	resp, err = client.AccessRequests.DenyGroupAccessRequest(2, 10)
-	assert.Error(t, err)
-	assert.Equal(t, http.StatusNotFound, resp.StatusCode)
-
-	resp, err = client.AccessRequests.DenyGroupAccessRequest(1, 10, errorOption)
-	assert.EqualError(t, err, "OptionFunc returns an error")
-	assert.Nil(t, resp)
-}
diff --git a/gitlab_test.go b/gitlab_test.go
index a93450d..dde0905 100644
--- a/gitlab_test.go
+++ b/gitlab_test.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
-	"errors"
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
@@ -59,10 +58,6 @@ func testBody(t *testing.T, r *http.Request, want string) {
 	}
 }
 
-func errorOption(*http.Request) error {
-	return errors.New("OptionFunc returns an error")
-}
-
 func TestNewClient(t *testing.T) {
 	c := NewClient(nil, "")
 	expectedBaseURL := defaultBaseURL + apiVersionPath
diff --git a/groups_test.go b/groups_test.go
index 8c8a180..99c00b9 100644
--- a/groups_test.go
+++ b/groups_test.go
@@ -111,6 +111,7 @@ func TestDeleteGroup(t *testing.T) {
 	if err != nil {
 		t.Errorf("Groups.DeleteGroup returned error: %v", err)
 	}
+	fmt.Println(resp.StatusCode)
 
 	want := http.StatusAccepted
 	got := resp.StatusCode
diff --git a/issues_test.go b/issues_test.go
index 1e79994..d3b049a 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -14,7 +14,7 @@ func TestGetIssue(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/projects/1/issues/5", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		fmt.Fprint(w, `{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}],"merge_requests_count": 1}`)
+		fmt.Fprint(w, `{"id":1, "description": "This is test project", "author" : {"id" : 1, "name": "snehal"}, "assignees":[{"id":1}]}`)
 	})
 
 	issue, _, err := client.Issues.GetIssue("1", 5)
@@ -23,11 +23,10 @@ func TestGetIssue(t *testing.T) {
 	}
 
 	want := &Issue{
-		ID:                1,
-		Description:       "This is test project",
-		Author:            &IssueAuthor{ID: 1, Name: "snehal"},
-		Assignees:         []*IssueAssignee{{ID: 1}},
-		MergeRequestCount: 1,
+		ID:          1,
+		Description: "This is test project",
+		Author:      &IssueAuthor{ID: 1, Name: "snehal"},
+		Assignees:   []*IssueAssignee{{ID: 1}},
 	}
 
 	if !reflect.DeepEqual(want, issue) {
diff --git a/notes_test.go b/notes_test.go
new file mode 100644
index 0000000..e614ff2
--- /dev/null
+++ b/notes_test.go
@@ -0,0 +1,38 @@
+package gitlab
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestGetEpicNote(t *testing.T) {
+	mux, server, client := setup()
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/groups/1/epics/4329/notes/3", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{"id":3,"type":null,"body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`)
+	})
+
+	note, _, err := client.Notes.GetEpicNote("1", 4329, 3, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := &Note{
+		ID:           3,
+		Body:         "foo bar",
+		Attachment:   "",
+		Title:        "",
+		FileName:     "",
+		System:       false,
+		NoteableID:   4392,
+		NoteableType: "Epic",
+	}
+
+	if !reflect.DeepEqual(note, want) {
+		t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want)
+	}
+}
diff --git a/pipelines_test.go b/pipelines_test.go
index c1e7f0c..a34a84b 100644
--- a/pipelines_test.go
+++ b/pipelines_test.go
@@ -109,19 +109,3 @@ func TestCancelPipelineBuild(t *testing.T) {
 		t.Errorf("Pipelines.CancelPipelineBuild returned %+v, want %+v", pipeline, want)
 	}
 }
-
-func TestDeletePipeline(t *testing.T) {
-	mux, server, client := setup()
-	defer teardown(server)
-
-	mux.HandleFunc("/api/v4/projects/1/pipelines/5949167", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "DELETE")
-	})
-
-	_, err := client.Pipelines.DeletePipeline("1", 5949167)
-
-	if err != nil {
-		t.Errorf("Pipelines.DeletePipeline returned error: %v", err)
-	}
-
-}
diff --git a/releases_test.go b/releases_test.go
index 03b7454..2d7c537 100644
--- a/releases_test.go
+++ b/releases_test.go
@@ -251,6 +251,7 @@ func TestReleasesService_CreateReleaseWithAsset(t *testing.T) {
 				t.Errorf("expected request body to have assets, got %s",
 					string(b))
 			}
+			fmt.Println(string(b))
 			fmt.Fprint(w, exampleReleaseRsp)
 		})