nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: fluxcd/flagger
Pull request #1145 (2022-03-16 18:36:01)

istio: Add destination port when port discovery and delegation are true
When we set `delegation: true` in an Istio canary, and we have PortDiscovery true, since having delegation results in having no gateways the destination route gets no port.
This small change makes the port to be added to the destination route when we have PortDiscovery and no gateways in the VirtualService due to having delegation.


Signed-off-by: Marco Amador <amador.marco@gmail.com>


Patch:
diff --git a/pkg/router/istio.go b/pkg/router/istio.go
index d6f7ce79..8183e4a0 100644
--- a/pkg/router/istio.go
+++ b/pkg/router/istio.go
@@ -488,8 +488,8 @@ func makeDestination(canary *flaggerv1.Canary, host string, weight int) istiov1a
 
 	// set destination port when an ingress gateway is specified
 	if canary.Spec.Service.PortDiscovery &&
-		len(canary.Spec.Service.Gateways) > 0 &&
-		canary.Spec.Service.Gateways[0] != "mesh" {
+		(len(canary.Spec.Service.Gateways) > 0 &&
+			canary.Spec.Service.Gateways[0] != "mesh" || canary.Spec.Service.Delegation) {
 		dest = istiov1alpha3.DestinationWeight{
 			Destination: istiov1alpha3.Destination{
 				Host: host,


Test patch:
diff --git a/pkg/router/istio_test.go b/pkg/router/istio_test.go
index 5ec52012..9b549846 100644
--- a/pkg/router/istio_test.go
+++ b/pkg/router/istio_test.go
@@ -372,6 +372,9 @@ func TestIstioRouter_Delegate(t *testing.T) {
 
 		assert.Equal(t, 0, len(vs.Spec.Hosts))
 		assert.Equal(t, 0, len(vs.Spec.Gateways))
+
+		port := vs.Spec.Http[0].Route[0].Destination.Port.Number
+		assert.Equal(t, uint32(mocks.canary.Spec.Service.Port), port)
 	})
 
 	t.Run("invalid", func(t *testing.T) {
Repository: xanzy/go-gitlab
Pull request #1976 (2024-07-25 22:03:30)

Adds `HookEventToken` helper function for X-Gitlab-Token
- `HookEventToken` works just like `HookEventType` . Keeps the header in a const. 
- adds a test to ensure it can fetch it


Patch:
diff --git a/event_parsing.go b/event_parsing.go
index 0c3f2ff..0f47421 100644
--- a/event_parsing.go
+++ b/event_parsing.go
@@ -72,6 +72,13 @@ type serviceEvent struct {
 	ObjectKind string `json:"object_kind"`
 }
 
+const eventTokenHeader = "X-Gitlab-Token"
+
+// HookEventToken returns the token for the given request.
+func HookEventToken(r *http.Request) string {
+	return r.Header.Get(eventTokenHeader)
+}
+
 const eventTypeHeader = "X-Gitlab-Event"
 
 // HookEventType returns the event type for the given request.


Test patch:
diff --git a/event_parsing_webhook_test.go b/event_parsing_webhook_test.go
index 9c860ab..da78ede 100644
--- a/event_parsing_webhook_test.go
+++ b/event_parsing_webhook_test.go
@@ -37,6 +37,19 @@ func TestWebhookEventType(t *testing.T) {
 	}
 }
 
+func TestWebhookEventToken(t *testing.T) {
+	req, err := http.NewRequest(http.MethodGet, "https://gitlab.com", nil)
+	if err != nil {
+		t.Errorf("Error creating HTTP request: %s", err)
+	}
+	req.Header.Set("X-Gitlab-Token", "798d3dd3-67f5-41df-ad19-7882cc6263bf")
+
+	actualToken := HookEventToken(req)
+	if actualToken != "798d3dd3-67f5-41df-ad19-7882cc6263bf" {
+		t.Errorf("WebhookEventToken is %q, want %q", actualToken, "798d3dd3-67f5-41df-ad19-7882cc6263bf")
+	}
+}
+
 func TestParseBuildHook(t *testing.T) {
 	raw := loadFixture("testdata/webhooks/build.json")
Repository: xanzy/go-gitlab
Pull request #1981 (2024-08-07 08:00:30)

Add field "is_auditor" in user


Patch:
diff --git a/users.go b/users.go
index 224dc42..f463952 100644
--- a/users.go
+++ b/users.go
@@ -88,6 +88,7 @@ type User struct {
 	LastActivityOn                 *ISOTime           `json:"last_activity_on"`
 	ColorSchemeID                  int                `json:"color_scheme_id"`
 	IsAdmin                        bool               `json:"is_admin"`
+	IsAuditor                      bool               `json:"is_auditor"`
 	AvatarURL                      string             `json:"avatar_url"`
 	CanCreateGroup                 bool               `json:"can_create_group"`
 	CanCreateProject               bool               `json:"can_create_project"`


Test patch:
diff --git a/users_test.go b/users_test.go
index 566c6e1..79cede7 100644
--- a/users_test.go
+++ b/users_test.go
@@ -103,6 +103,7 @@ func TestGetUserAdmin(t *testing.T) {
 		LastActivityOn:   &lastActivityOn,
 		ColorSchemeID:    2,
 		IsAdmin:          true,
+		IsAuditor:        true,
 		AvatarURL:        "http://localhost:3000/uploads/user/avatar/1/index.jpg",
 		CanCreateGroup:   true,
 		CanCreateProject: true,
Repository: xanzy/go-gitlab
Pull request #2010 (2024-09-08 09:11:32)

Breaking change: New options when calling DeleteProject
Allow passing options to the DeleteProject function for immediately deleting a project. Used in Premium/Ultimate tiers where delayed deletion is enabled by default. See API docs: https://docs.gitlab.com/ee/api/projects.html#delete-project

This is a breaking change. Closes https://github.com/xanzy/go-gitlab/issues/2008


Patch:
diff --git a/projects.go b/projects.go
index cc23f26..98c39f6 100644
--- a/projects.go
+++ b/projects.go
@@ -1159,18 +1159,28 @@ func (s *ProjectsService) UnarchiveProject(pid interface{}, options ...RequestOp
 	return p, resp, nil
 }
 
+// DeleteProjectOptions represents options to delete a project.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/projects.html#delete-project
+type DeleteProjectOptions struct {
+	FullPath          *string `url:"full_path" json:"full_path"`
+	PermanentlyRemove *bool   `url:"permanently_remove" json:"permanently_remove"`
+}
+
 // DeleteProject removes a project including all associated resources
 // (issues, merge requests etc.)
 //
-// GitLab API docs: https://docs.gitlab.com/ee/api/projects.html#delete-project
-func (s *ProjectsService) DeleteProject(pid interface{}, options ...RequestOptionFunc) (*Response, error) {
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/projects.html#delete-project
+func (s *ProjectsService) DeleteProject(pid interface{}, opt *DeleteProjectOptions, options ...RequestOptionFunc) (*Response, error) {
 	project, err := parseID(pid)
 	if err != nil {
 		return nil, err
 	}
 	u := fmt.Sprintf("projects/%s", PathEscape(project))
 
-	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
+	req, err := s.client.NewRequest(http.MethodDelete, u, opt, options)
 	if err != nil {
 		return nil, err
 	}


Test patch:
diff --git a/projects_test.go b/projects_test.go
index d268eea..905d693 100644
--- a/projects_test.go
+++ b/projects_test.go
@@ -647,6 +647,24 @@ func TestListProjectForks(t *testing.T) {
 	}
 }
 
+func TestDeleteProject(t *testing.T) {
+	mux, client := setup(t)
+
+	mux.HandleFunc("/api/v4/projects/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodDelete)
+	})
+
+	opt := &DeleteProjectOptions{
+		FullPath:          Ptr("group/project"),
+		PermanentlyRemove: Ptr(true),
+	}
+
+	_, err := client.Projects.DeleteProject(1, opt)
+	if err != nil {
+		t.Errorf("Projects.DeleteProject returned error: %v", err)
+	}
+}
+
 func TestShareProjectWithGroup(t *testing.T) {
 	mux, client := setup(t)
Repository: xanzy/go-gitlab
Pull request #2035 (2024-10-14 07:23:21)

missing protected_branches#deploy_key_id
Protected branches can now have a deploy_key_id allowed to push (since 16.0).
The field was present for the create/update methods, but not the read/list ones.


Patch:
diff --git a/protected_branches.go b/protected_branches.go
index d13f57a..7fd83be 100644
--- a/protected_branches.go
+++ b/protected_branches.go
@@ -56,6 +56,7 @@ type BranchAccessDescription struct {
 	AccessLevelDescription string           `json:"access_level_description"`
 	UserID                 int              `json:"user_id"`
 	GroupID                int              `json:"group_id"`
+	DeployKeyID            int              `json:"deploy_key_id"`
 }
 
 // ListProtectedBranchesOptions represents the available ListProtectedBranches()


Test patch:
diff --git a/protected_branches_test.go b/protected_branches_test.go
index 0aaecbe..7a22f03 100644
--- a/protected_branches_test.go
+++ b/protected_branches_test.go
@@ -35,12 +35,31 @@ func TestListProtectedBranches(t *testing.T) {
 		"push_access_levels":[{
 			"id":1,
 			"access_level":40,
-			"access_level_description":"Maintainers"
+			"access_level_description":"Maintainers",
+			"deploy_key_id":null,
+			"user_id":null,
+			"group_id":null
+		},{
+			"id":2,
+			"access_level":30,
+			"access_level_description":"User name",
+			"deploy_key_id":null,
+			"user_id":123,
+			"group_id":null
+		},{
+			"id":3,
+			"access_level":40,
+			"access_level_description":"deploy key",
+			"deploy_key_id":456,
+			"user_id":null,
+			"group_id":null
 		}],
 		"merge_access_levels":[{
 			"id":1,
 			"access_level":40,
-			"access_level_description":"Maintainers"
+			"access_level_description":"Maintainers",
+			"user_id":null,
+			"group_id":null
 		}],
 		"code_owner_approval_required":false
 	}
@@ -61,6 +80,18 @@ func TestListProtectedBranches(t *testing.T) {
 					AccessLevel:            40,
 					AccessLevelDescription: "Maintainers",
 				},
+				{
+					ID:                     2,
+					AccessLevel:            30,
+					AccessLevelDescription: "User name",
+					UserID:                 123,
+				},
+				{
+					ID:                     3,
+					AccessLevel:            40,
+					AccessLevelDescription: "deploy key",
+					DeployKeyID:            456,
+				},
 			},
 			MergeAccessLevels: []*BranchAccessDescription{
 				{
Repository: xanzy/go-gitlab
Pull request #2043 (2024-10-16 13:29:03)

support ListOptions for ListMembershipsForBillableGroupMember
Just realized, that there was no pagination-support for this function/endpoint.
Forgot to add it in my initial commit - my bad :-/



Patch:
diff --git a/group_members.go b/group_members.go
index c18b180..9c29c10 100644
--- a/group_members.go
+++ b/group_members.go
@@ -253,19 +253,25 @@ func (s *GroupsService) ListBillableGroupMembers(gid interface{}, opt *ListBilla
 	return bgm, resp, nil
 }
 
+// ListMembershipsForBillableGroupMemberOptions represents the available ListMembershipsForBillableGroupMember() options.
+//
+// GitLab API docs:
+// https://docs.gitlab.com/ee/api/members.html#list-memberships-for-a-billable-member-of-a-group
+type ListMembershipsForBillableGroupMemberOptions = ListOptions
+
 // ListMembershipsForBillableGroupMember Gets a list of memberships for a billable member of a group.
 // Lists all projects and groups a user is a member of. Only projects and groups within the group hierarchy are included.
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/members.html#list-memberships-for-a-billable-member-of-a-group
-func (s *GroupsService) ListMembershipsForBillableGroupMember(gid interface{}, user int, options ...RequestOptionFunc) ([]*BillableUserMembership, *Response, error) {
+func (s *GroupsService) ListMembershipsForBillableGroupMember(gid interface{}, user int, opt *ListMembershipsForBillableGroupMemberOptions, options ...RequestOptionFunc) ([]*BillableUserMembership, *Response, error) {
 	group, err := parseID(gid)
 	if err != nil {
 		return nil, nil, err
 	}
 	u := fmt.Sprintf("groups/%s/billable_members/%d/memberships", PathEscape(group), user)
 
-	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
+	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
 	if err != nil {
 		return nil, nil, err
 	}


Test patch:
diff --git a/group_members_test.go b/group_members_test.go
index 98fc0d2..ae19374 100644
--- a/group_members_test.go
+++ b/group_members_test.go
@@ -102,7 +102,7 @@ func TestListMembershipsForBillableGroupMember(t *testing.T) {
 				]`)
 		})
 
-	memberships, _, err := client.Groups.ListMembershipsForBillableGroupMember(1, 42)
+	memberships, _, err := client.Groups.ListMembershipsForBillableGroupMember(1, 42, &ListMembershipsForBillableGroupMemberOptions{})
 	if err != nil {
 		t.Errorf("Groups.ListMembershipsForBillableGroupMember returned error: %v", err)
 	}
Repository: xataio/pgstream
Pull request #109 (2025-01-16 17:09:16)

Support int32 as id column
Support int32 as id column for seach

github-actions[bot]: ### Merging this branch will **increase** overall coverage

| Impacted Packages | Coverage Δ | :robot: |
|-------------------|------------|---------|
| github.com/xataio/pgstream/pkg/wal/processor/search | 85.87% (**+0.04%**) | :thumbsup: |

---

<details>

<summary>Coverage by file</summary>

### Changed files (no unit tests)

| Changed File | Coverage Δ | Total | Covered | Missed | :robot: |
|--------------|------------|-------|---------|--------|---------|
| github.com/xataio/pgstream/pkg/wal/processor/search/search_adapter.go | 98.39% (**+0.01%**) | 124 (+1) | 122 (+1) | 2 | :thumbsup: |

_Please note that the "Total", "Covered", and "Missed" counts above refer to ***code statements*** instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code._

### Changed unit test files

- github.com/xataio/pgstream/pkg/wal/processor/search/search_adapter_test.go

</details>


Patch:
diff --git a/pkg/wal/processor/search/search_adapter.go b/pkg/wal/processor/search/search_adapter.go
index 84af34b..d5d3f88 100644
--- a/pkg/wal/processor/search/search_adapter.go
+++ b/pkg/wal/processor/search/search_adapter.go
@@ -255,6 +255,8 @@ func (a *adapter) parseIDColumns(tableName string, idColumns []wal.Column, doc *
 		switch v := col.Value.(type) {
 		case string:
 			addToID(v)
+		case int32:
+			addToID(strconv.FormatInt(int64(v), 10))
 		case int64:
 			addToID(strconv.FormatInt(v, 10))
 		case float64:


Test patch:
diff --git a/pkg/wal/processor/search/search_adapter_test.go b/pkg/wal/processor/search/search_adapter_test.go
index 4d46d6e..e269ab9 100644
--- a/pkg/wal/processor/search/search_adapter_test.go
+++ b/pkg/wal/processor/search/search_adapter_test.go
@@ -650,6 +650,14 @@ func TestAdapter_parseIDColumns(t *testing.T) {
 			wantDoc: newDoc(fmt.Sprintf("%s_id1", testTable)),
 			wantErr: nil,
 		},
+		{
+			name: "ok - int32",
+			idColumns: []wal.Column{
+				{Name: "id-1", Value: int32(1)},
+			},
+			wantDoc: newDoc(fmt.Sprintf("%s_1", testTable)),
+			wantErr: nil,
+		},
 		{
 			name: "ok - int64",
 			idColumns: []wal.Column{
@@ -672,13 +680,15 @@ func TestAdapter_parseIDColumns(t *testing.T) {
 				{ID: "col-1", Name: "id-1", Value: "id1"},
 				{ID: "col-2", Name: "id-2", Value: float64(2.0)},
 				{ID: "col-3", Name: "id-3", Value: int64(100)},
+				{ID: "col-4", Name: "id-4", Value: int32(101)},
 			},
 			wantDoc: &Document{
-				ID: fmt.Sprintf("%s_id1-2-100", testTable),
+				ID: fmt.Sprintf("%s_id1-2-100-101", testTable),
 				Data: map[string]any{
 					"col-1": "id1",
 					"col-2": float64(2.0),
 					"col-3": int64(100),
+					"col-4": int32(101),
 				},
 			},
 			wantErr: nil,
Repository: xataio/pgstream
Pull request #182 (2025-03-14 21:04:30)

Fix choice return type


Patch:
diff --git a/pkg/transformers/greenmask/greenmask_choice_transformer.go b/pkg/transformers/greenmask/greenmask_choice_transformer.go
index af2c908..dad2146 100644
--- a/pkg/transformers/greenmask/greenmask_choice_transformer.go
+++ b/pkg/transformers/greenmask/greenmask_choice_transformer.go
@@ -60,5 +60,6 @@ func (t *ChoiceTransformer) Transform(value any) (any, error) {
 	if err != nil {
 		return nil, err
 	}
-	return ret, nil
+
+	return ret.Data, nil
 }


Test patch:
diff --git a/pkg/transformers/greenmask/greenmask_choice_transformer_test.go b/pkg/transformers/greenmask/greenmask_choice_transformer_test.go
index 6409e8f..4dd16bd 100644
--- a/pkg/transformers/greenmask/greenmask_choice_transformer_test.go
+++ b/pkg/transformers/greenmask/greenmask_choice_transformer_test.go
@@ -114,9 +114,9 @@ func TestChoiceTransformer_Transform(t *testing.T) {
 
 			// check if the result is in the choices
 			require.NotNil(t, got)
-			val, ok := got.(*toolkit.RawValue)
+			val, ok := got.([]byte)
 			require.True(t, ok)
-			require.Contains(t, tt.params["choices"], string(val.Data))
+			require.Contains(t, tt.params["choices"], string(val))
 
 			// if deterministic, check if we get the same result again
 			if tt.generatorType == transformers.Deterministic {
Repository: xataio/pgstream
Pull request #313 (2025-04-29 14:59:28)

UUID Transformer: Do not parse string into uuid
Do not parse string into uuid, for uuid transformer, but directly use the bytes instead.

github-actions[bot]: ### Merging this branch will **decrease** overall coverage

| Impacted Packages | Coverage Δ | :robot: |
|-------------------|------------|---------|
| github.com/xataio/pgstream/pkg/transformers/greenmask | 86.56% (**-0.12%**) | :thumbsdown: |

---

<details>

<summary>Coverage by file</summary>

### Changed files (no unit tests)

| Changed File | Coverage Δ | Total | Covered | Missed | :robot: |
|--------------|------------|-------|---------|--------|---------|
| github.com/xataio/pgstream/pkg/transformers/greenmask/greenmask_uuid_transformer.go | 77.78% (**-3.17%**) | 18 (-3) | 14 (-3) | 4 | :thumbsdown: |

_Please note that the "Total", "Covered", and "Missed" counts above refer to ***code statements*** instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code._

### Changed unit test files

- github.com/xataio/pgstream/pkg/transformers/greenmask/greenmask_uuid_transformer_test.go

</details>


Patch:
diff --git a/pkg/transformers/greenmask/greenmask_uuid_transformer.go b/pkg/transformers/greenmask/greenmask_uuid_transformer.go
index 8b9dc77..86b430e 100644
--- a/pkg/transformers/greenmask/greenmask_uuid_transformer.go
+++ b/pkg/transformers/greenmask/greenmask_uuid_transformer.go
@@ -31,11 +31,7 @@ func (ut *UUIDTransformer) Transform(value transformers.Value) (any, error) {
 	var toTransform []byte
 	switch val := value.TransformValue.(type) {
 	case string:
-		parsed, err := uuid.Parse(val)
-		if err != nil {
-			return nil, err
-		}
-		toTransform = parsed[:]
+		toTransform = []byte(val)
 	case uuid.UUID:
 		toTransform = val[:]
 	case []byte:


Test patch:
diff --git a/pkg/transformers/greenmask/greenmask_uuid_transformer_test.go b/pkg/transformers/greenmask/greenmask_uuid_transformer_test.go
index 93ab85c..7302401 100644
--- a/pkg/transformers/greenmask/greenmask_uuid_transformer_test.go
+++ b/pkg/transformers/greenmask/greenmask_uuid_transformer_test.go
@@ -86,20 +86,20 @@ func Test_UUIDTransformer_Transform(t *testing.T) {
 			wantErr: nil,
 		},
 		{
-			name: "error - invalid input type",
+			name: "ok - can be any string",
 			params: transformers.Parameters{
-				"generator": random,
+				"generator": deterministic,
 			},
-			input:   123,
-			wantErr: transformers.ErrUnsupportedValueType,
+			input:   "this is not a uuid",
+			wantErr: nil,
 		},
 		{
-			name: "error - cannot parse string",
+			name: "error - invalid input type",
 			params: transformers.Parameters{
 				"generator": random,
 			},
-			input:   "123e45671e89b112d31a4561426655440000",
-			wantErr: errors.New("invalid UUID format"),
+			input:   123,
+			wantErr: transformers.ErrUnsupportedValueType,
 		},
 	}
 	for _, tc := range tests {
Repository: xanzy/go-gitlab
Pull request #1079 (2021-02-22 10:32:56)

Add moved_to_id as an issue attribute
This field references the global id for an issue that has been moved to another proejct. It is null for issues that have never been moved.


Patch:
diff --git a/issues.go b/issues.go
index f162000..22a4f02 100644
--- a/issues.go
+++ b/issues.go
@@ -98,6 +98,7 @@ type Issue struct {
 	ClosedBy             *IssueCloser     `json:"closed_by"`
 	Title                string           `json:"title"`
 	CreatedAt            *time.Time       `json:"created_at"`
+	MovedToID            int              `json:"moved_to_id"`
 	Labels               Labels           `json:"labels"`
 	LabelDetails         []*LabelDetails  `json:"label_details"`
 	Upvotes              int              `json:"upvotes"`


Test patch:
diff --git a/issues_test.go b/issues_test.go
index f5dec2f..c583ecd 100644
--- a/issues_test.go
+++ b/issues_test.go
@@ -86,10 +86,38 @@ func TestMoveIssue(t *testing.T) {
 		ID:        92,
 		IID:       11,
 		ProjectID: 5,
+		MovedToID: 0,
 	}
 
 	assert.Equal(t, want.IID, issue.IID)
 	assert.Equal(t, want.ProjectID, issue.ProjectID)
+
+	mux.HandleFunc("/api/v4/projects/1/issues/11", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodGet)
+		fmt.Fprint(w, `
+		{
+				"id": 1,
+				"iid": 11,
+				"project_id": 1,
+				"moved_to_id": 92
+		}`,
+		)
+	})
+	movedIssue, _, err := client.Issues.GetIssue("1", 11)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	wantedMovedIssue := &Issue{
+		ID:        1,
+		IID:       11,
+		ProjectID: 1,
+		MovedToID: 92,
+	}
+
+	if !reflect.DeepEqual(wantedMovedIssue, movedIssue) {
+		t.Errorf("Issues.GetIssue returned %+v, want %+v", issue, want)
+	}
 }
 
 func TestListIssues(t *testing.T) {
@@ -217,6 +245,7 @@ func TestListIssuesWithLabelDetails(t *testing.T) {
 		t.Errorf("Issues.ListIssues returned %+v, want %+v", issues, want)
 	}
 }
+
 func TestListIssuesSearchInTitle(t *testing.T) {
 	mux, server, client := setup(t)
 	defer teardown(server)
Repository: xanzy/go-gitlab
Pull request #1107 (2021-03-17 19:41:27)

Support Environment list parameters in ListOptions
Hey,

this PR adds the `name`, `search` and `states` parameters for the environments list API. See https://docs.gitlab.com/ee/api/environments.html#list-environments

btw, could I ask if I can do anything further to get #1082 possibly merged?

Thanks!


Patch:
diff --git a/environments.go b/environments.go
index 9dd7a1b..c5d66db 100644
--- a/environments.go
+++ b/environments.go
@@ -50,7 +50,12 @@ func (env Environment) String() string {
 //
 // GitLab API docs:
 // https://docs.gitlab.com/ee/api/environments.html#list-environments
-type ListEnvironmentsOptions ListOptions
+type ListEnvironmentsOptions struct {
+	ListOptions
+	Name   *string `url:"name,omitempty" json:"name,omitempty"`
+	Search *string `url:"search,omitempty" json:"search,omitempty"`
+	States *string `url:"states,omitempty" json:"states,omitempty"`
+}
 
 // ListEnvironments gets a list of environments from a project, sorted by name
 // alphabetically.


Test patch:
diff --git a/environments_test.go b/environments_test.go
index 0c04dc9..ebc76a9 100644
--- a/environments_test.go
+++ b/environments_test.go
@@ -33,11 +33,11 @@ func TestListEnvironments(t *testing.T) {
 
 	mux.HandleFunc("/api/v4/projects/1/environments", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, http.MethodGet)
-		testURL(t, r, "/api/v4/projects/1/environments?page=1&per_page=10")
+		testURL(t, r, "/api/v4/projects/1/environments?name=review%2Ffix-foo&page=1&per_page=10")
 		fmt.Fprint(w, `[{"id": 1,"name": "review/fix-foo", "slug": "review-fix-foo-dfjre3", "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com"}]`)
 	})
 
-	envs, _, err := client.Environments.ListEnvironments(1, &ListEnvironmentsOptions{Page: 1, PerPage: 10})
+	envs, _, err := client.Environments.ListEnvironments(1, &ListEnvironmentsOptions{Name: String("review/fix-foo"), ListOptions: ListOptions{Page: 1, PerPage: 10}})
 	if err != nil {
 		log.Fatal(err)
 	}