Add mergeRequestsCsvExport GraphQL mutation
What does this MR do and why?
Adds an experimental GraphQL mutation, mergeRequestsCsvExport (milestone 19.6), that takes a project path and the same filter arguments as the project mergeRequests connection, then enqueues the existing CSV export. Nothing changes for users yet.
This is the backend for fixing the merge request list "Export as CSV" ignoring filters. The list writes filters like merge_user and target_branches[] to the URL, but the REST export only accepts the finder names (merge_user_username, target_branch), so those filters are dropped. !261946 (merged) switches the export modal to this mutation behind a feature flag, and !261956 removes the REST export after the rollout.
Merge request stack
These merge requests fix #583992 together. Merge them in this order; same-numbered MRs are independent.
| Order | MR | What | Depends on |
|---|---|---|---|
| 1 | !262241 (merged) | Extract the merge request filter arguments into a shared concern (no schema change) | None |
| 1 | !262242 (merged) | Accept the subscribed filter as a string in IssuableFinder |
None |
| 2 | !261924 (merged) (this MR) | Add the mergeRequestsCsvExport GraphQL mutation |
!262241 (merged), !262242 (merged) |
| 3 | !261946 (merged) | Switch the MR list export to the mutation behind merge_requests_csv_export_graphql |
!261924 (merged) |
| 4 | !261956 | Remove the REST export and the flag after the rollout in #633656 (not before 2026-11-16) | !261946 (merged) |
Implementation details
- Stacked on !262241 (merged), which extracts
MergeRequests::SharedFilterArguments. This mutation includes that concern, so it accepts the list's filters and translates them to finder params the same way. - Depends on !262242 (merged) (
IssuableFinder#by_subscribedaccepting the string form job arguments arrive in), so thesubscribedfilter survives the worker. - Follows the
workItemsCsvExportpattern and enqueuesIssuableExportCsvWorker. - The project is exposed as
resource_parent, soSearchArgumentssetsattempt_project_search_optimizationslike the list resolver does. Without it, search terms under 3 characters were dropped or matched exactly, and the export returned different MRs from the list. - Authorization:
authorize :read_merge_requestandauthorize_granular_token permissions: :read_merge_request, boundary_type: :project. This matches what the REST export requires today. Anonymous users can't run any mutation (GlobalPolicypreventsexecute_graphql_mutation), and the spec covers that. - Schema: additions only.
Verification:
spec/requests/api/graphql/mutations/merge_requests/csv/export_spec.rb: filter mapping to finder names,closedAftervalidation, search parity with the list forUI,fix abandRefactor(the first two fail without theresource_parentchange), non-member and anonymous access errors, and the granular token shared example.ee/spec/requests/api/graphql/mutations/merge_requests/csv/export_spec.rb:approver.- Customer workaround (posted on the issue): add
merge_user_usernameandtarget_branchparams to the URL before exporting.
References
- Related to #583992
- Stacked on !262241 (merged), depends on !262242 (merged).
Screenshots or screen recordings
Not applicable: backend only.
How to set up and validate locally
- Run the request specs:
bundle exec rspec spec/requests/api/graphql/mutations/merge_requests/csv/export_spec.rb bundle exec rspec ee/spec/requests/api/graphql/mutations/merge_requests/csv/export_spec.rb - Or run
mutation { mergeRequestsCsvExport(input: { projectPath: "group/project", targetBranches: ["main"] }) { message errors } }in GraphiQL and confirmmessageis returned with noerrors.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.