nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: nats-io/nats-server
Pull request #3925 (2023-03-01 02:13:13)

Updated LEAFZ names to use remoteServer name/id and added is_spoke
This is a followup on #3923 that improves LEAFZ names to use `ln.leaf.remoteServer` instead of the connection name.

I've also added `is_spoke` to the leafz LeafInfo struct so that we can easily tell if a leaf connection is a hub or spoke.



Patch:
diff --git a/server/leafnode.go b/server/leafnode.go
index 7f2e8dcf..6be7657e 100644
--- a/server/leafnode.go
+++ b/server/leafnode.go
@@ -888,13 +888,7 @@ func (s *Server) createLeafNode(conn net.Conn, rURL *url.URL, remote *leafNodeCf
 	}
 	now := time.Now().UTC()
 
-	var clientOpts = ClientOpts{
-		Name:     opts.ServerName,
-		Verbose:  defaultOpts.Verbose,
-		Pedantic: defaultOpts.Pedantic,
-		Echo:     defaultOpts.Echo,
-	}
-	c := &client{srv: s, nc: conn, kind: LEAF, opts: clientOpts, mpay: maxPay, msubs: maxSubs, start: now, last: now}
+	c := &client{srv: s, nc: conn, kind: LEAF, opts: defaultOpts, mpay: maxPay, msubs: maxSubs, start: now, last: now}
 	// Do not update the smap here, we need to do it in initLeafNodeSmapAndSendSubs
 	c.leaf = &leaf{}
 
diff --git a/server/monitor.go b/server/monitor.go
index d4365f60..6c2ead7c 100644
--- a/server/monitor.go
+++ b/server/monitor.go
@@ -2095,6 +2095,7 @@ type LeafzOptions struct {
 // LeafInfo has detailed information on each remote leafnode connection.
 type LeafInfo struct {
 	Name     string   `json:"name"`
+	IsSpoke  bool     `json:"is_spoke"`
 	Account  string   `json:"account"`
 	IP       string   `json:"ip"`
 	Port     int      `json:"port"`
@@ -2134,7 +2135,8 @@ func (s *Server) Leafz(opts *LeafzOptions) (*Leafz, error) {
 		for _, ln := range lconns {
 			ln.mu.Lock()
 			lni := &LeafInfo{
-				Name:     ln.opts.Name,
+				Name:     ln.leaf.remoteServer,
+				IsSpoke:  ln.isSpokeLeafNode(),
 				Account:  ln.acc.Name,
 				IP:       ln.host,
 				Port:     int(ln.port),


Test patch:
diff --git a/server/monitor_test.go b/server/monitor_test.go
index 8096ce22..00c81c52 100644
--- a/server/monitor_test.go
+++ b/server/monitor_test.go
@@ -3678,6 +3678,7 @@ func TestMonitorOpJWT(t *testing.T) {
 
 func TestMonitorLeafz(t *testing.T) {
 	content := `
+	server_name: "hub"
 	listen: "127.0.0.1:-1"
 	http: "127.0.0.1:-1"
 	operator = "../test/configs/nkeys/op.jwt"
@@ -3817,8 +3818,11 @@ func TestMonitorLeafz(t *testing.T) {
 			} else {
 				t.Fatalf("Expected account to be %q or %q, got %q", acc1.Name, acc2.Name, ln.Account)
 			}
-			if ln.Name != leafName {
-				t.Fatalf("Expected name to be %q, got %q", leafName, ln.Name)
+			if ln.Name != "hub" {
+				t.Fatalf("Expected name to be %q, got %q", "hub", ln.Name)
+			}
+			if !ln.IsSpoke {
+				t.Fatal("Expected leafnode connection to be spoke")
 			}
 			if ln.RTT == "" {
 				t.Fatalf("RTT not tracked?")
@@ -3911,6 +3915,9 @@ func TestMonitorLeafz(t *testing.T) {
 			if ln.Name != leafName {
 				t.Fatalf("Expected name to be %q, got %q", leafName, ln.Name)
 			}
+			if ln.IsSpoke {
+				t.Fatal("Expected leafnode connection to be hub")
+			}
 			if ln.RTT == "" {
 				t.Fatalf("RTT not tracked?")
 			}
Repository: nats-io/nats-server
Pull request #4042 (2023-04-12 08:48:37)

Fix FirstSeq not being updated with filestore when purging subject
Resolves https://github.com/nats-io/nats-server/issues/4041

Keeps `firstSeqNeedsUpdate` set if set previously, to ensure the FirstSeq gets updated.


Patch:
diff --git a/server/filestore.go b/server/filestore.go
index 211857e9..7ba7e2eb 100644
--- a/server/filestore.go
+++ b/server/filestore.go
@@ -5098,7 +5098,8 @@ func (fs *fileStore) PurgeEx(subject string, sequence, keep uint64) (purged uint
 					if mb.isEmpty() {
 						fs.removeMsgBlock(mb)
 						i--
-						firstSeqNeedsUpdate = seq == fs.state.FirstSeq
+						// keep flag set, if set previously
+						firstSeqNeedsUpdate = firstSeqNeedsUpdate || seq == fs.state.FirstSeq
 					} else if seq == fs.state.FirstSeq {
 						fs.state.FirstSeq = mb.first.seq // new one.
 						fs.state.FirstTime = time.Unix(0, mb.first.ts).UTC()


Test patch:
diff --git a/server/filestore_test.go b/server/filestore_test.go
index e3050018..984ff671 100644
--- a/server/filestore_test.go
+++ b/server/filestore_test.go
@@ -4020,6 +4020,7 @@ func TestFileStorePurgeExWithSubject(t *testing.T) {
 		require_True(t, int(p) == total)
 		require_True(t, int(p) == total)
 		require_True(t, fs.State().Msgs == 1)
+		require_True(t, fs.State().FirstSeq == 201)
 	})
 }
Repository: xanzy/go-gitlab
Pull request #545 (2019-01-11 18:39:50)

Update service jira: fix JiraIssueTransitionID type from string to int
Hi there,

This is a tiny fix for the JIRA service.

JiraIssueTransitionID parameter is currently a string when it should be an int, as mentioned in the [doc](https://docs.gitlab.com/ce/api/services.html#jira).

This currently creates error when unmarshalling the Json into the Go struct:
`json: cannot unmarshal number into Go struct field JiraServiceProperties.jira_issue_transition_id of type string`

Thanks,


Patch:
diff --git a/services.go b/services.go
index 890e5a3..313568f 100644
--- a/services.go
+++ b/services.go
@@ -393,7 +393,7 @@ type JiraServiceProperties struct {
 	ProjectKey            *string `url:"project_key,omitempty" json:"project_key,omitempty" `
 	Username              *string `url:"username,omitempty" json:"username,omitempty" `
 	Password              *string `url:"password,omitempty" json:"password,omitempty" `
-	JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"`
+	JiraIssueTransitionID *int    `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"`
 }
 
 // GetJiraService gets Jira service settings for a project.


Test patch:
diff --git a/services_test.go b/services_test.go
index 1e23ee3..853b5d1 100644
--- a/services_test.go
+++ b/services_test.go
@@ -141,7 +141,7 @@ func TestSetJiraService(t *testing.T) {
 		ProjectKey:            String("as"),
 		Username:              String("aas"),
 		Password:              String("asd"),
-		JiraIssueTransitionID: String("asd"),
+		JiraIssueTransitionID: Int(2),
 	}
 
 	_, err := client.Services.SetJiraService(1, opt)
Repository: xanzy/go-gitlab
Pull request #570 (2019-02-23 15:47:13)

Fix type for ApprovalsBeforeMerge
ApprovalsBeforeMerge denotes the number of approvals required before
merging and will never have the type `bool`. This change updates the
type for the field and adds test coverage for the type.


Patch:
diff --git a/todos.go b/todos.go
index b563daa..812181d 100644
--- a/todos.go
+++ b/todos.go
@@ -67,7 +67,7 @@ type TodoTarget struct {
 	Weight       int    `json:"weight"`
 
 	// Only available for type MergeRequest
-	ApprovalsBeforeMerge      bool   `json:"approvals_before_merge"`
+	ApprovalsBeforeMerge      int    `json:"approvals_before_merge"`
 	ForceRemoveSourceBranch   bool   `json:"force_remove_source_branch"`
 	MergeCommitSHA            string `json:"merge_commit_sha"`
 	MergeWhenPipelineSucceeds bool   `json:"merge_when_pipeline_succeeds"`


Test patch:
diff --git a/todos_test.go b/todos_test.go
index 3c06686..2068f51 100644
--- a/todos_test.go
+++ b/todos_test.go
@@ -13,7 +13,7 @@ func TestListTodos(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/todos", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		fmt.Fprint(w, `[{"id":1,"state": "pending"},{"id":2,"state":"pending"}]`)
+		fmt.Fprint(w, `[{"id":1,"state": "pending","target":{"id":1,"approvals_before_merge":2}},{"id":2,"state":"pending","target":{"id":2,"approvals_before_merge":null}}]`)
 	})
 
 	opts := &ListTodosOptions{}
@@ -23,7 +23,7 @@ func TestListTodos(t *testing.T) {
 		t.Errorf("Todos.ListTodos returned error: %v", err)
 	}
 
-	want := []*Todo{{ID: 1, State: "pending"}, {ID: 2, State: "pending"}}
+	want := []*Todo{{ID: 1, State: "pending", Target: TodoTarget{ID: 1, ApprovalsBeforeMerge: 2}}, {ID: 2, State: "pending", Target: TodoTarget{ID: 2}}}
 	if !reflect.DeepEqual(want, todos) {
 		t.Errorf("Todos.ListTodos returned %+v, want %+v", todos, want)
 	}
Repository: xanzy/go-gitlab
Pull request #581 (2019-03-13 10:56:11)

add ListMergeRequestsRelatedToIssue func
Add the gitlab api route "List merge requests related to issue":

https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue


Patch:
diff --git a/issues.go b/issues.go
index 7574b1d..7627d1a 100644
--- a/issues.go
+++ b/issues.go
@@ -452,6 +452,42 @@ func (s *IssuesService) ListMergeRequestsClosingIssue(pid interface{}, issue int
 	return m, resp, err
 }
 
+// ListMergeRequestsRelatedToIssueOptions represents the available
+// ListMergeRequestsRelatedToIssue() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue
+type ListMergeRequestsRelatedToIssueOptions ListOptions
+
+// ListMergeRequestsRelatedToIssue gets all the merge requests that are
+// related to the issue
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ce/api/issues.html#list-merge-requests-related-to-issue
+func (s *IssuesService) ListMergeRequestsRelatedToIssue(pid interface{}, issue int, opt *ListMergeRequestsRelatedToIssueOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, nil, err
+	}
+	u := fmt.Sprintf("/projects/%s/issues/%d/related_merge_requests",
+		url.QueryEscape(project),
+		issue,
+	)
+
+	req, err := s.client.NewRequest("GET", u, opt, options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var m []*MergeRequest
+	resp, err := s.client.Do(req, &m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, err
+}
+
 // SetTimeEstimate sets the time estimate for a single project issue.
 //
 // GitLab API docs:


Test patch:
diff --git a/issues_test.go b/issues_test.go
index 98dde53..d3b049a 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -293,6 +293,33 @@ func TestListMergeRequestsClosingIssue(t *testing.T) {
 	}
 }
 
+func TestListMergeRequestsRelatedToIssue(t *testing.T) {
+	mux, server, client := setup()
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/projects/1/issues/5/related_merge_requests", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testURL(t, r, "/api/v4/projects/1/issues/5/related_merge_requests?page=1&per_page=10")
+
+		fmt.Fprint(w, `[{"id":1, "title" : "test merge one"},{"id":2, "title" : "test merge two"}]`)
+	})
+
+	listMergeRequestsRelatedToIssueOpt := &ListMergeRequestsRelatedToIssueOptions{
+		Page:    1,
+		PerPage: 10,
+	}
+	mergeRequest, _, err := client.Issues.ListMergeRequestsRelatedToIssue("1", 5, listMergeRequestsRelatedToIssueOpt)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	want := []*MergeRequest{{ID: 1, Title: "test merge one"}, {ID: 2, Title: "test merge two"}}
+
+	if !reflect.DeepEqual(want, mergeRequest) {
+		t.Errorf("Issues.ListMergeRequestsClosingIssue returned %+v, want %+v", mergeRequest, want)
+	}
+}
+
 func TestSetTimeEstimate(t *testing.T) {
 	mux, server, client := setup()
 	defer teardown(server)
Repository: xanzy/go-gitlab
Pull request #584 (2019-03-19 14:19:24)

Adding DeletePipeline API call and test
Hi, I needed the DeletePipeline functionality and added it. Would be great to have it included upstream.


Patch:
diff --git a/pipelines.go b/pipelines.go
index 8466eac..598e8e0 100644
--- a/pipelines.go
+++ b/pipelines.go
@@ -229,3 +229,23 @@ func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipelineID int,
 
 	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{}, pipelineID int, options ...OptionFunc) (*Response, error) {
+	project, err := parseID(pid)
+	if err != nil {
+		return nil, err
+	}
+
+	u := fmt.Sprintf("projects/%s/pipelines/%d", url.QueryEscape(project), pipelineID)
+
+	req, err := s.client.NewRequest("DELETE", u, nil, options)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(req, nil)
+}


Test patch:
diff --git a/pipelines_test.go b/pipelines_test.go
index a34a84b..c1e7f0c 100644
--- a/pipelines_test.go
+++ b/pipelines_test.go
@@ -109,3 +109,19 @@ 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)
+	}
+
+}
Repository: xanzy/go-gitlab
Pull request #594 (2019-03-27 11:05:17)

add fields to IssueEvent and update basic tests


Patch:
diff --git a/.travis.yml b/.travis.yml
index 09075b6..556aec7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,7 @@ go:
   - 1.9.x
   - 1.10.x
   - 1.11.x
+  - 1.12.x
   - master
 
 stages:
diff --git a/event_types.go b/event_types.go
index b2aa1bd..b9cf37a 100644
--- a/event_types.go
+++ b/event_types.go
@@ -161,6 +161,14 @@ type IssueEvent struct {
 		Username  string `json:"username"`
 		AvatarURL string `json:"avatar_url"`
 	} `json:"assignee"`
+	Labels []Label `json:"labels"`
+	Changes struct {
+		Labels struct {
+			Previous []Label `json:"previous"`
+			Current  []Label `json:"current"`
+		} `json:"labels"`
+		UpdatedByID []int `json:"updated_by_id"`
+	} `json:"changes"`
 }
 
 // JobEvent represents a job event.
@@ -532,6 +540,7 @@ type MergeEvent struct {
 		Username  string `json:"username"`
 		AvatarURL string `json:"avatar_url"`
 	} `json:"assignee"`
+	Labels []Label `json:"labels"`
 	Changes struct {
 		AssigneeID struct {
 			Previous int `json:"previous"`


Test patch:
diff --git a/event_parsing_test.go b/event_parsing_test.go
index 62391f2..786ccf9 100644
--- a/event_parsing_test.go
+++ b/event_parsing_test.go
@@ -3,6 +3,7 @@ package gitlab
 import (
 	"net/http"
 	"testing"
+	"github.com/stretchr/testify/assert"
 )
 
 func TestWebhookEventType(t *testing.T) {
@@ -315,6 +316,10 @@ func TestParseIssueHook(t *testing.T) {
 	if event.Assignee.Username != "user1" {
 		t.Errorf("Assignee username is %v, want %v", event.Assignee.Username, "user1")
 	}
+	assert.Equal(t, 1, len(event.Labels))
+	assert.Equal(t, []int{0, 1}, event.Changes.UpdatedByID)
+	assert.Equal(t, 1, len(event.Changes.Labels.Previous))
+	assert.Equal(t, 1, len(event.Changes.Labels.Current))
 }
 
 func TestParseCommitCommentHook(t *testing.T) {
@@ -906,6 +911,10 @@ func TestParseMergeRequestHook(t *testing.T) {
 	if event.ObjectAttributes.WorkInProgress {
 		t.Errorf("WorkInProgress is %v, want %v", event.ObjectAttributes.WorkInProgress, false)
 	}
+	assert.Equal(t, 1, len(event.Labels))
+	assert.Equal(t, []int{0, 1}, event.Changes.UpdatedByID)
+	assert.Equal(t, 1, len(event.Changes.Labels.Previous))
+	assert.Equal(t, 1, len(event.Changes.Labels.Current))
 }
 
 func TestParseWikiPageHook(t *testing.T) {
Repository: xanzy/go-gitlab
Pull request #611 (2019-04-18 15:27:42)

Add ApprovalsBeforeMerge attribute


Patch:
diff --git a/merge_requests.go b/merge_requests.go
index 3b61e26..3050edc 100644
--- a/merge_requests.go
+++ b/merge_requests.go
@@ -118,6 +118,7 @@ type MergeRequest struct {
 	} `json:"diff_refs"`
 	DivergedCommitsCount int  `json:"diverged_commits_count"`
 	RebaseInProgress     bool `json:"rebase_in_progress"`
+	ApprovalsBeforeMerge int  `json:"approvals_before_merge"`
 }
 
 func (m MergeRequest) String() string {


Test patch:
diff --git a/merge_request_test.go b/merge_request_test.go
new file mode 100644
index 0000000..1de2682
--- /dev/null
+++ b/merge_request_test.go
@@ -0,0 +1,61 @@
+package gitlab
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestListMergeRequestsNullApprovals(t *testing.T) {
+	mux, server, client := setup()
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/merge_requests", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `[{"id":1, "title": "some title", "approvals_before_merge": null}]`)
+	})
+
+	mr, _, err := client.MergeRequests.ListMergeRequests(nil)
+
+	if err != nil {
+		t.Errorf("MergeRequests.ListMergeRequests returned error: %v", err)
+	}
+
+	want := []*MergeRequest{{ID: 1, Title: "some title", ApprovalsBeforeMerge: 0}}
+	if !reflect.DeepEqual(want, mr) {
+		t.Errorf("MergeRequests.ListMergeRequests returned %+v, want %+v", mr, want)
+	}
+}
+
+func TestListMergeRequests2Approvals(t *testing.T) {
+	mux, server, client := setup()
+	defer teardown(server)
+
+	mux.HandleFunc("/api/v4/merge_requests", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `[{"id":1, "title": "some title", "approvals_before_merge": 2}]`)
+	})
+
+	mr, _, err := client.MergeRequests.ListMergeRequests(nil)
+
+	if err != nil {
+		t.Errorf("MergeRequests.ListMergeRequests returned error: %v", err)
+	}
+
+	want := []*MergeRequest{{ID: 1, Title: "some title", ApprovalsBeforeMerge: 2}}
+	if !reflect.DeepEqual(want, mr) {
+		t.Errorf("MergeRequests.ListMergeRequests returned %+v, want %+v", mr, want)
+	}
+}
+
+func TestListMergeRequestsError(t *testing.T) {
+	_, server, client := setup()
+	defer teardown(server)
+
+	_, _, err := client.MergeRequests.ListMergeRequests(nil)
+
+	if err == nil {
+		t.Errorf("MergeRequests.ListMergeRequests expected to receive error, but returned nil")
+	}
+}
Repository: xanzy/go-gitlab
Pull request #617 (2019-05-02 22:00:53)

Add API URL to the JIRA service integration
I needed the ability to set the API URL.

https://docs.gitlab.com/ce/api/services.html#createedit-jira-service


Patch:
diff --git a/services.go b/services.go
index 2d9269b..2ee8450 100644
--- a/services.go
+++ b/services.go
@@ -389,6 +389,7 @@ type JiraService struct {
 // https://docs.gitlab.com/ce/api/services.html#jira
 type JiraServiceProperties struct {
 	URL                   *string `url:"url,omitempty" json:"url,omitempty"`
+	APIURL                *string `url:"api_url,omitempty" json:"api_url,omitempty"`
 	ProjectKey            *string `url:"project_key,omitempty" json:"project_key,omitempty" `
 	Username              *string `url:"username,omitempty" json:"username,omitempty" `
 	Password              *string `url:"password,omitempty" json:"password,omitempty" `


Test patch:
diff --git a/services_test.go b/services_test.go
index 853b5d1..1af67c1 100644
--- a/services_test.go
+++ b/services_test.go
@@ -138,6 +138,7 @@ func TestSetJiraService(t *testing.T) {
 
 	opt := &SetJiraServiceOptions{
 		URL:                   String("asd"),
+		APIURL:                String("asd"),
 		ProjectKey:            String("as"),
 		Username:              String("aas"),
 		Password:              String("asd"),
Repository: xanzy/go-gitlab
Pull request #625 (2019-05-18 20:13:23)

Add Fork Project Options
With the current implementation, it's impossible to set a namespace, a name, or a path.

These attributes are supported by the API, but there's no way to set them, and the implementation of the OptionFun forces everything to be a JSON payload, thus it doesn't work.

With this change, we can set the attributes using a `ForkProjectOptions` symmetrical to the rest of the methods all around.


Patch:
diff --git a/projects.go b/projects.go
index 5297e43..8bd4f3f 100644
--- a/projects.go
+++ b/projects.go
@@ -557,18 +557,27 @@ func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions,
 	return p, resp, err
 }
 
+// ForkProjectOptions represents the available ForkProject() options.
+//
+// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project
+type ForkProjectOptions struct {
+	Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"`
+	Name      *string `url:"name,omitempty" json:"name,omitempty" `
+	Path      *string `url:"path,omitempty" json:"path,omitempty"`
+}
+
 // ForkProject forks a project into the user namespace of the authenticated
 // user.
 //
 // GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project
-func (s *ProjectsService) ForkProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) {
+func (s *ProjectsService) ForkProject(pid interface{}, opt *ForkProjectOptions, options ...OptionFunc) (*Project, *Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, nil, err
 	}
 	u := fmt.Sprintf("projects/%s/fork", pathEscape(project))
 
-	req, err := s.client.NewRequest("POST", u, nil, options)
+	req, err := s.client.NewRequest("POST", u, opt, options)
 	if err != nil {
 		return nil, nil, err
 	}


Test patch:
diff --git a/projects_test.go b/projects_test.go
index 3a72c26..8b69d06 100644
--- a/projects_test.go
+++ b/projects_test.go
@@ -522,3 +522,32 @@ func TestChangeAllowedApprovers(t *testing.T) {
 		t.Errorf("Projects.ChangeAllowedApprovers returned %+v, want %+v", approvals, want)
 	}
 }
+
+func TestForkProject(t *testing.T) {
+	mux, server, client := setup()
+	defer teardown(server)
+
+	namespace := "mynamespace"
+	name := "myreponame"
+	path := "myrepopath"
+
+	mux.HandleFunc("/api/v4/projects/1/fork", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		testBody(t, r, fmt.Sprintf(`{"namespace":"%s","name":"%s","path":"%s"}`, namespace, name, path))
+		fmt.Fprint(w, `{"id":2}`)
+	})
+
+	project, _, err := client.Projects.ForkProject(1, &ForkProjectOptions{
+		Namespace: &namespace,
+		Name:      &name,
+		Path:      &path,
+	})
+	if err != nil {
+		t.Errorf("Projects.ForkProject returned error: %v", err)
+	}
+
+	want := &Project{ID: 2}
+	if !reflect.DeepEqual(want, project) {
+		t.Errorf("Projects.ForProject returned %+v, want %+v", project, want)
+	}
+}