Skip to content

GraphQL - expose full merge request diff stats

Problem

The current GraphQL interface doesn't expose enough information about what files have changed in an MR. This makes it unusable for representing the whole MR diff.

Example DiffStats response:

{
  "additions": 2,
  "deletions": 5,
  "path": "test.js"
}

From this response it's impossible to know whether the file has been moved, deleted or created. That is important when representing the diff. We can't show the old file in the diff without knowing its path.

Proposal

At the very least, we should add oldPath and newPath to the DiffStats model.

Detailed explanation

It's possible to ask for the DiffStats.

Query:

{
  project(fullPath:"viktomas/test-project"){
    mergeRequest(iid: "1"){
      diffStats{
        additions
        deletions
        path
      }
    }
  }
}

Response:

{
  "data": {
    "project": {
      "mergeRequest": {
        "diffStats": [
          {
            "additions": 0,
            "deletions": 0,
            "path": "README1.md"
          },
          {
            "additions": 2,
            "deletions": 5,
            "path": "test.js"
          }
        ]
      }
    }
  }
}

This is used for the left file tree in our web interface:

Update_test_js___1____Merge_Requests___Tomas_Vik___test_project___GitLab

Compare that with the REST API

curl -H "Authorization: Bearer $TOKEN" 'https://gitlab.com/api/v4/projects/20486274/merge_requests/1/versions/123390038' | jq

Response:

{
  ...
  "diffs": [
    {
      "old_path": "README.md",
      "new_path": "README1.md",
      "a_mode": "100644",
      "b_mode": "100644",
      "new_file": false,
      "renamed_file": true,
      "deleted_file": false,
      "diff": ""
    },
    {
      "old_path": "test.js",
      "new_path": "test.js",
      "a_mode": "100644",
      "b_mode": "100644",
      "new_file": false,
      "renamed_file": false,
      "deleted_file": false,
      "diff": "@@ -13,14 +13,11 @@\n function containingFunction(){\n     function subFunction(){\n         console.log(\"Some Output\");\n+        console.log(\"Some Output1\");\n     }\n     // Issue is not present when the line after the function name and opening { is empty\n     function subFunction(){\n \n-        console.log(\"OPutput\");\n+        console.log(\"Output\");\n     }\n }\n-\n-function anotherFunction(){\n-    console.log(\"Other Output\");\n-}\n"
    }
  ]
}