Repository: xanzy/go-gitlab
Pull request #1821 (2023-10-11 16:56:24)

Added NotAuthorUsername to List*MergeRequestsOptions
Added NotAuthorUsername following pattern established before with NotLabels. Added unit tests validating both AuthorUsername and Not[AuthorUsername].


Patch:
diff --git a/merge_requests.go b/merge_requests.go
index f5b68fd..458255f 100644
--- a/merge_requests.go
+++ b/merge_requests.go
@@ -202,6 +202,7 @@ type ListMergeRequestsOptions struct {
 	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"`
 	AssigneeID             *AssigneeIDValue  `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	ApproverIDs            *ApproverIDsValue `url:"approver_ids,omitempty" json:"approver_ids,omitempty"`
 	ApprovedByIDs          *ApproverIDsValue `url:"approved_by_ids,omitempty" json:"approved_by_ids,omitempty"`
@@ -262,6 +263,7 @@ type ListProjectMergeRequestsOptions struct {
 	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"`
 	AssigneeID             *AssigneeIDValue  `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	ApproverIDs            *ApproverIDsValue `url:"approver_ids,omitempty" json:"approver_ids,omitempty"`
 	ApprovedByIDs          *ApproverIDsValue `url:"approved_by_ids,omitempty" json:"approved_by_ids,omitempty"`
@@ -323,6 +325,7 @@ type ListGroupMergeRequestsOptions struct {
 	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"`
 	AssigneeID             *AssigneeIDValue  `url:"assignee_id,omitempty" json:"assignee_id,omitempty"`
 	ApproverIDs            *ApproverIDsValue `url:"approver_ids,omitempty" json:"approver_ids,omitempty"`
 	ApprovedByIDs          *ApproverIDsValue `url:"approved_by_ids,omitempty" json:"approved_by_ids,omitempty"`


Test patch:
diff --git a/merge_requests_test.go b/merge_requests_test.go
index b7301ca..cfee816 100644
--- a/merge_requests_test.go
+++ b/merge_requests_test.go
@@ -202,6 +202,120 @@ func TestListProjectMergeRequests(t *testing.T) {
 	}
 }
 
+func TestListProjectMergeRequestsAuthorUsername(t *testing.T) {
+	mux, client := setup(t)
+
+	path := "/api/v4/projects/278964/merge_requests"
+
+	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		testParams(t, r, "assignee_id=Any&author_username=hfyngvason&with_labels_details=true&with_merge_status_recheck=true")
+		mustWriteHTTPResponse(t, w, "testdata/get_merge_requests_author_username.json")
+	})
+
+	opts := ListProjectMergeRequestsOptions{
+		AssigneeID:             AssigneeID(UserIDAny),
+		AuthorUsername:         String("hfyngvason"),
+		WithLabelsDetails:      Bool(true),
+		WithMergeStatusRecheck: Bool(true),
+	}
+
+	mergeRequests, _, err := client.MergeRequests.ListProjectMergeRequests(278964, &opts)
+
+	require.NoError(t, err)
+	require.Equal(t, 1, len(mergeRequests))
+
+	validStates := []string{"opened", "closed", "locked", "merged"}
+	detailedMergeStatuses := []string{
+		"blocked_status",
+		"broken_status",
+		"checking",
+		"ci_must_pass",
+		"ci_still_running",
+		"discussions_not_resolved",
+		"draft_status",
+		"external_status_checks",
+		"mergeable",
+		"not_approved",
+		"not_open",
+		"policies_denied",
+		"unchecked",
+	}
+	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, detailedMergeStatuses, mr.DetailedMergeStatus)
+		// list requests do not provide these fields:
+		assert.Nil(t, mr.Pipeline)
+		assert.Nil(t, mr.HeadPipeline)
+		assert.Equal(t, "", mr.DiffRefs.HeadSha)
+	}
+}
+
+func TestListProjectMergeRequestsNotAuthorUsername(t *testing.T) {
+	mux, client := setup(t)
+
+	path := "/api/v4/projects/278964/merge_requests"
+
+	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		testParams(t, r, "assignee_id=Any&not%5Bauthor_username%5D=hfyngvason&with_labels_details=true&with_merge_status_recheck=true")
+		mustWriteHTTPResponse(t, w, "testdata/get_merge_requests_not_author_username.json")
+	})
+
+	opts := ListProjectMergeRequestsOptions{
+		AssigneeID:             AssigneeID(UserIDAny),
+		NotAuthorUsername:      String("hfyngvason"),
+		WithLabelsDetails:      Bool(true),
+		WithMergeStatusRecheck: Bool(true),
+	}
+
+	mergeRequests, _, err := client.MergeRequests.ListProjectMergeRequests(278964, &opts)
+
+	require.NoError(t, err)
+	require.Equal(t, 2, len(mergeRequests))
+
+	validStates := []string{"opened", "closed", "locked", "merged"}
+	detailedMergeStatuses := []string{
+		"blocked_status",
+		"broken_status",
+		"checking",
+		"ci_must_pass",
+		"ci_still_running",
+		"discussions_not_resolved",
+		"draft_status",
+		"external_status_checks",
+		"mergeable",
+		"not_approved",
+		"not_open",
+		"policies_denied",
+		"unchecked",
+	}
+	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, detailedMergeStatuses, mr.DetailedMergeStatus)
+		// list requests do not provide these fields:
+		assert.Nil(t, mr.Pipeline)
+		assert.Nil(t, mr.HeadPipeline)
+		assert.Equal(t, "", mr.DiffRefs.HeadSha)
+	}
+}
+
 func TestCreateMergeRequestPipeline(t *testing.T) {
 	mux, client := setup(t)
 
diff --git a/testdata/get_merge_requests_author_username.json b/testdata/get_merge_requests_author_username.json
new file mode 100644
index 0000000..898528a
--- /dev/null
+++ b/testdata/get_merge_requests_author_username.json
@@ -0,0 +1,89 @@
+[
+  {
+    "id": 35385049,
+    "iid": 15442,
+    "project_id": 278964,
+    "title": "Draft: Use structured logging for DB load balancer",
+    "description": "## What does this MR do?",
+    "state": "opened",
+    "created_at": "2019-08-20T10:58:54.413Z",
+    "updated_at": "2019-08-20T12:01:49.849Z",
+    "merged_by": null,
+    "merged_at": null,
+    "closed_by": null,
+    "closed_at": null,
+    "target_branch": "master",
+    "source_branch": "use-structured-logging-for-db-load-balancer",
+    "user_notes_count": 1,
+    "upvotes": 0,
+    "downvotes": 0,
+    "assignee": {
+      "id": 4088036,
+      "name": "Hordur Freyr Yngvason",
+      "username": "hfyngvason",
+      "state": "active",
+      "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
+      "web_url": "https://gitlab.com/hfyngvason"
+    },
+    "author": {
+      "id": 4088036,
+      "name": "Hordur Freyr Yngvason",
+      "username": "hfyngvason",
+      "state": "active",
+      "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
+      "web_url": "https://gitlab.com/hfyngvason"
+    },
+    "assignees": [
+      {
+        "id": 4088036,
+        "name": "Hordur Freyr Yngvason",
+        "username": "hfyngvason",
+        "state": "active",
+        "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4088036/avatar.png",
+        "web_url": "https://gitlab.com/hfyngvason"
+      }
+    ],
+    "reviewers": [
+      {
+        "id": 2535118,
+        "name": "Thong Kuah",
+        "username": "tkuah",
+        "state": "active",
+        "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon",
+        "web_url": "https://gitlab.com/tkuah"
+      }
+    ],
+    "source_project_id": 278964,
+    "target_project_id": 278964,
+    "labels": [
+      "backend",
+      "backstage",
+      "database",
+      "database::review pending",
+      "group::autodevops and kubernetes"
+    ],
+    "work_in_progress": true,
+    "milestone": null,
+    "merge_when_pipeline_succeeds": false,
+    "detailed_merge_status": "mergeable",
+    "sha": "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7",
+    "merge_commit_sha": null,
+    "discussion_locked": null,
+    "should_remove_source_branch": null,
+    "force_remove_source_branch": true,
+    "reference": "!15442",
+    "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15442",
+    "time_stats": {
+      "time_estimate": 0,
+      "total_time_spent": 0,
+      "human_time_estimate": null,
+      "human_total_time_spent": null
+    },
+    "squash": true,
+    "task_completion_status": {
+      "count": 12,
+      "completed_count": 0
+    },
+    "approvals_before_merge": 1
+  }
+]
diff --git a/testdata/get_merge_requests_not_author_username.json b/testdata/get_merge_requests_not_author_username.json
new file mode 100644
index 0000000..97c83d9
--- /dev/null
+++ b/testdata/get_merge_requests_not_author_username.json
@@ -0,0 +1,201 @@
+[
+  {
+    "id": 35384461,
+    "iid": 15441,
+    "project_id": 278964,
+    "title": "Draft: Implement public MR-level approval rules API",
+    "description": "## What does this MR do?",
+    "state": "opened",
+    "created_at": "2019-08-20T10:51:56.806Z",
+    "updated_at": "2019-08-20T11:00:25.244Z",
+    "merged_by": null,
+    "merged_at": null,
+    "closed_by": null,
+    "closed_at": null,
+    "target_branch": "master",
+    "source_branch": "12055-public-mr-approval-rules-api",
+    "user_notes_count": 1,
+    "upvotes": 0,
+    "downvotes": 0,
+    "assignee": {
+      "id": 1884221,
+      "name": "Patrick Bajao",
+      "username": "patrickbajao",
+      "state": "active",
+      "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png",
+      "web_url": "https://gitlab.com/patrickbajao"
+    },
+    "author": {
+      "id": 1884221,
+      "name": "Patrick Bajao",
+      "username": "patrickbajao",
+      "state": "active",
+      "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png",
+      "web_url": "https://gitlab.com/patrickbajao"
+    },
+    "assignees": [
+      {
+        "id": 1884221,
+        "name": "Patrick Bajao",
+        "username": "patrickbajao",
+        "state": "active",
+        "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/1884221/avatar.png",
+        "web_url": "https://gitlab.com/patrickbajao"
+      }
+    ],
+    "source_project_id": 278964,
+    "target_project_id": 278964,
+    "labels": [
+      "Create [DEPRECATED]",
+      "Deliverable",
+      "GitLab Enterprise Edition",
+      "GitLab Starter",
+      "api",
+      "approvals",
+      "backend",
+      "devops::create",
+      "feature",
+      "group::source code",
+      "workflow::In dev"
+    ],
+    "work_in_progress": true,
+    "milestone": {
+      "id": 731038,
+      "iid": 37,
+      "group_id": 9970,
+      "title": "12.3",
+      "description": "",
+      "state": "active",
+      "created_at": "2018-12-07T12:40:55.400Z",
+      "updated_at": "2019-01-16T19:50:20.313Z",
+      "due_date": "2019-09-22",
+      "start_date": "2019-08-08",
+      "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37"
+    },
+    "merge_when_pipeline_succeeds": false,
+    "detailed_merge_status": "mergeable",
+    "sha": "dbb2b82236b86328f44a1754c9188c0991e707e5",
+    "merge_commit_sha": null,
+    "discussion_locked": null,
+    "should_remove_source_branch": null,
+    "force_remove_source_branch": false,
+    "reference": "!15441",
+    "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15441",
+    "time_stats": {
+      "time_estimate": 0,
+      "total_time_spent": 0,
+      "human_time_estimate": null,
+      "human_total_time_spent": null
+    },
+    "squash": false,
+    "task_completion_status": {
+      "count": 8,
+      "completed_count": 1
+    },
+    "approvals_before_merge": 1
+  },
+  {
+    "id": 35368820,
+    "iid": 15440,
+    "project_id": 278964,
+    "title": "Log in Prometheus current number of host and index",
+    "description": "## What does this MR do?",
+    "state": "opened",
+    "created_at": "2019-08-20T10:20:51.687Z",
+    "updated_at": "2019-08-20T11:06:40.659Z",
+    "merged_by": null,
+    "merged_at": null,
+    "closed_by": null,
+    "closed_at": null,
+    "target_branch": "master",
+    "source_branch": "load-balancing-prometheus",
+    "user_notes_count": 2,
+    "upvotes": 0,
+    "downvotes": 0,
+    "assignee": {
+      "id": 4059128,
+      "name": "Avielle Wolfe",
+      "username": "avielle",
+      "state": "active",
+      "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4059128/avatar.png",
+      "web_url": "https://gitlab.com/avielle"
+    },
+    "author": {
+      "id": 2535118,
+      "name": "Thong Kuah",
+      "username": "tkuah",
+      "state": "active",
+      "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon",
+      "web_url": "https://gitlab.com/tkuah"
+    },
+    "assignees": [
+      {
+        "id": 4059128,
+        "name": "Avielle Wolfe",
+        "username": "avielle",
+        "state": "active",
+        "avatar_url": "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4059128/avatar.png",
+        "web_url": "https://gitlab.com/avielle"
+      },
+      {
+        "id": 2535118,
+        "name": "Thong Kuah",
+        "username": "tkuah",
+        "state": "active",
+        "avatar_url": "https://secure.gravatar.com/avatar/f7b51bdd49a4914d29504d7ff4c3f7b9?s=80&d=identicon",
+        "web_url": "https://gitlab.com/tkuah"
+      }
+    ],
+    "source_project_id": 278964,
+    "target_project_id": 278964,
+    "labels": [
+      "Configure [DEPRECATED]",
+      "Observability",
+      "P1",
+      "backend",
+      "backstage",
+      "database",
+      "database::review pending",
+      "devops::configure",
+      "gitlab.com",
+      "group::autodevops and kubernetes",
+      "infradev",
+      "workflow::In dev"
+    ],
+    "work_in_progress": false,
+    "milestone": {
+      "id": 731038,
+      "iid": 37,
+      "group_id": 9970,
+      "title": "12.3",
+      "description": "",
+      "state": "active",
+      "created_at": "2018-12-07T12:40:55.400Z",
+      "updated_at": "2019-01-16T19:50:20.313Z",
+      "due_date": "2019-09-22",
+      "start_date": "2019-08-08",
+      "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/37"
+    },
+    "merge_when_pipeline_succeeds": false,
+    "detailed_merge_status": "mergeable",
+    "sha": "eae31acf34d2df2aba2ea469e432cab1c6a05b53",
+    "merge_commit_sha": null,
+    "discussion_locked": null,
+    "should_remove_source_branch": null,
+    "force_remove_source_branch": false,
+    "reference": "!15440",
+    "web_url": "https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/15440",
+    "time_stats": {
+      "time_estimate": 0,
+      "total_time_spent": 0,
+      "human_time_estimate": null,
+      "human_total_time_spent": null
+    },
+    "squash": false,
+    "task_completion_status": {
+      "count": 12,
+      "completed_count": 1
+    },
+    "approvals_before_merge": 1
+  }
+]