Exporting Merge Requests by CSV ignores some filters
## Summary CSV export of merge requests returns significantly more results than displayed in the UI when using filters on the "merged" tab (specifically `merged_by`, `target_branch`, and `deployed_after`). Seemingly some filters are ignored when exporting the CSV and it results in a mismatch between the amount being filtered and the amount actually in the CSV. ## Steps to reproduce 1. Navigate to a project's merge requests page 2. Apply a mix of the following filters on the "merged" tab: - Sort: `created_asc` - State: `merged` - Merged by: specific user (e.g., `cleveland`) - Target branch: `main` - Deployed after: `2025-01-01` 3. Note the count displayed in the UI (e.g., 933 entries) 4. Click the three-vertical-dot menu and select "Export as CSV" 5. Check the received CSV file **Example URL:** ``` https://gitlab.example.com/project/-/merge_requests/?sort=created_asc&state=merged&merge_user=cleveland&target_branches%5B%5D=main&deployed_after=2025-01-01&first_page_size=20 ``` ## Expected behavior The CSV export should contain the same number of merge requests as displayed in the UI. ## Actual behavior The CSV export contains significantly more entries than shown in the UI (2000+ entries in the example, more than double the expected count). ## Relevant logs and/or screenshots Note in my example, I have two of my own users to test with. In the UI, I am filtering by one user and should have 3 MRs, but the CSV contains 4, one of which is my other user which was not filtered out. ![SCR-20251212-knxr.png](/uploads/e2b60bce79a2851b87cd52fffdae1a91/SCR-20251212-knxr.png) ![SCR-20251212-knub.png](/uploads/f9300d77d6fca5cc3627f89227cb8457/SCR-20251212-knub.png){width=900 height=463} ## Environment - **GitLab version:** Reported in GitLab SM 18.2.1 (replicated on GitLab.com) ## Root Cause Analysis (Duo Assisted) The issue stems from three filters in `MergeRequestsFinder` that don't properly respect the `state` parameter constraint when joining related tables: ### 1. `by_merge_user` filter (MergeUserFilter) - Joins to `merge_request_metrics` table without re-applying state constraint - Returns MRs with matching metrics regardless of actual merge state ### 2. `by_merged_at` filter (MergedAtFilter) - Similar issue with `merge_request_metrics` join - Doesn't verify state after applying date filters ### 3. `by_deployments` filter - Joins to `deployment_merge_requests` without state verification - Can return non-merged MRs if deployment records exist **Code references:** - https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/finders/concerns/merge_user_filter.rb - https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/finders/concerns/merged_at_filter.rb - https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/finders/merge_requests_finder.rb#L265-L283 - https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/merge_requests/export_csv_service.rb ## Possible fixes The filters should re-apply the state constraint after joining to related tables, or the join scopes should include state verification in their WHERE clauses. ## Workaround Use GraphQL API to query merge requests with proper filtering: ```graphql query { project(fullPath: "group/project") { mergeRequests( state: merged mergedBy: "username" deployedAfter: "2025-01-01T00:00:00Z" first: 100 ) { pageInfo { hasNextPage endCursor } edges { node { id iid title state targetBranch sourceBranch mergeUser { username } createdAt mergedAt } } } } } ```
issue