Add mergeRequestResolveConflicts GraphQL mutation

What does this MR do and why?

Dependencies

This MR now contains only the mergeRequestResolveConflicts GraphQL mutation itself. The shared gates and the read-side sections field it depends on split off into two other MRs:

  • !256973 (closed) moves the push-access, mergeability and resolvable-in-UI checks, the usage counter, and the error mapping into MergeRequests::Conflicts::ResolveService. This MR is stacked on it (retargeted onto its branch) because it needs the ServiceResponse the service returns there.
  • !256975 (closed) adds the sections field to MergeRequest.conflictFiles, which is where the sectionId values this mutation's input takes come from. This MR is not stacked on it. One request spec context that reads section ids from that field is left out here until it merges, and will be added back once this MR is rebased onto master.

Adds a mergeRequestResolveConflicts GraphQL mutation: the conflicts controller's resolve_conflicts action for API clients. MergeRequests::Conflicts::ResolveService (see !256973 (closed)) checks that the user can push to the source branch (ListService#can_be_resolved_by?), that the merge request is still unmergeable, and that its conflicts are resolvable in the UI (can_be_resolved_in_ui?), and returns a ServiceResponse that this mutation maps to payload errors. The service produces the same merge commit of the target branch into the source branch the web UI produces.

Per conflicting file the input takes either a side for each conflict section (HEAD = "our changes", ORIGIN = "their changes"), keyed by the section ids from MergeRequest.conflictFiles.sections (!256975 (closed)), or the file's full resolved content. An optional commit message defaults to the UI's Merge branch '…' into '…' message. Resolution and pre-receive errors come back in errors.

Until now conflicts could only be resolved through the web UI, which is session-authenticated. API clients, concretely the GitLab mobile app, which already reads MergeRequest.conflictFiles (added in 19.4 as an experiment) to show conflicts natively, were left with a browser hand-off for the resolution step. With this mutation the app resolves conflicts in place with the same semantics as the web page.

Both the mutation and the conflictFiles.sections field are experiments (milestone 19.5).

Related: MergeRequest.conflictFiles field (19.4 experiment). This is its write counterpart.

Screenshots or screen recordings

None (API-only).

How to set up and validate locally

  1. Create a merge request whose branches conflict (e.g. the spec fixture branches conflict-resolvable → conflict-start in the test repository).
  2. Fetch the sections and their ids:
{
  project(fullPath: "group/project") {
    mergeRequest(iid: "1") {
      conflictFiles {
        ourPath
        theirPath
        sections {
          sectionId
          conflict
          lines { type oldLine newLine text }
        }
      }
    }
  }
}
  1. Run the mutation with the returned sectionId values:
mutation {
  mergeRequestResolveConflicts(input: {
    projectPath: "group/project",
    iid: "1",
    commitMessage: "Resolve the conflicts",
    files: [
      { oldPath: "files/ruby/popen.rb", newPath: "files/ruby/popen.rb",
        sections: [{ sectionId: "<sectionId from step 2>", resolution: HEAD }] },
      { oldPath: "files/ruby/regex.rb", newPath: "files/ruby/regex.rb", content: "resolved\n" }
    ]
  }) { errors mergeRequest { id detailedMergeStatus } }
}
  1. The source branch gains a merge commit with both heads as parents; the MR becomes mergeable after the mergeability re-check.

MR acceptance checklist

Evaluated against the MR acceptance checklist.

  • Specs: spec/graphql/mutations/merge_requests/resolve_conflicts_spec.rb, spec/requests/api/graphql/mutations/merge_requests/resolve_conflicts_spec.rb.
  • Generated: GraphQL reference docs, introspection schemas, fine-grained token GraphQL docs.
Edited by Marcel van Remmerden

Merge request reports

Loading
Loading