diff --git a/lib/platform/gh-got-wrapper.js b/lib/platform/github/gh-got-wrapper.js
similarity index 98%
rename from lib/platform/gh-got-wrapper.js
rename to lib/platform/github/gh-got-wrapper.js
index fba297867339533626fec085207a01107dc46b1f..80573a2e96ffd10b4d0ad5c6bf7243ffc6f8306f 100644
--- a/lib/platform/gh-got-wrapper.js
+++ b/lib/platform/github/gh-got-wrapper.js
@@ -1,4 +1,4 @@
-const logger = require('../logger');
+const logger = require('../../logger');
 const ghGot = require('gh-got');
 const parseLinkHeader = require('parse-link-header');
 
diff --git a/lib/platform/github.js b/lib/platform/github/index.js
similarity index 99%
rename from lib/platform/github.js
rename to lib/platform/github/index.js
index 3abf31392fb84280add0a0b4239f2d42bfe46666..d14faf9c30263706f3dd7098783f56635748a805 100644
--- a/lib/platform/github.js
+++ b/lib/platform/github/index.js
@@ -1,4 +1,4 @@
-let logger = require('../logger');
+let logger = require('../../logger');
 const get = require('./gh-got-wrapper');
 
 const config = {};
@@ -25,14 +25,9 @@ module.exports = {
   addAssignees,
   addReviewers,
   // Comments
-  getComments,
-  addComment,
-  editComment,
-  deleteComment,
   ensureComment,
   ensureCommentRemoval,
   // PR
-  getPrList,
   findPr,
   createPr,
   getPr,
@@ -46,8 +41,6 @@ module.exports = {
   getFileJson,
   // Commits
   getCommitMessages,
-  getBranchCommit,
-  getCommitDetails,
 };
 
 // Get all repositories that the user has access to
@@ -494,7 +487,7 @@ async function getPrList() {
 
 async function findPr(branchName, prTitle, state = 'all') {
   logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);
-  const prList = await module.exports.getPrList();
+  const prList = await getPrList();
   const pr = prList.filter(
     p =>
       p.branchName === branchName &&
diff --git a/lib/platform/gl-got-wrapper.js b/lib/platform/gitlab/gl-got-wrapper.js
similarity index 100%
rename from lib/platform/gl-got-wrapper.js
rename to lib/platform/gitlab/gl-got-wrapper.js
diff --git a/lib/platform/gitlab/helpers.js b/lib/platform/gitlab/helpers.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9c7336b0500610eb4e668378fdf6e83b5a3699a
--- /dev/null
+++ b/lib/platform/gitlab/helpers.js
@@ -0,0 +1,49 @@
+const get = require('./gl-got-wrapper');
+
+module.exports = {
+  createFile,
+  updateFile,
+};
+
+async function createFile(
+  repoName,
+  branchName,
+  filePath,
+  fileContents,
+  message
+) {
+  const opts = {};
+  const url = `projects/${repoName}/repository/files/${filePath.replace(
+    /\//g,
+    '%2F'
+  )}`;
+  opts.body = {
+    branch: branchName,
+    commit_message: message,
+    encoding: 'base64',
+    content: Buffer.from(fileContents).toString('base64'),
+  };
+  await get.post(url, opts);
+}
+
+async function updateFile(
+  repoName,
+  branchName,
+  filePath,
+  fileContents,
+  message
+) {
+  const opts = {};
+  const url = `projects/${repoName}/repository/files/${filePath.replace(
+    /\//g,
+    '%2F'
+  )}`;
+  opts.body = {
+    branch: branchName,
+    commit_message: message,
+    encoding: 'base64',
+    content: Buffer.from(fileContents).toString('base64'),
+  };
+
+  await get.put(url, opts);
+}
diff --git a/lib/platform/gitlab.js b/lib/platform/gitlab/index.js
similarity index 87%
rename from lib/platform/gitlab.js
rename to lib/platform/gitlab/index.js
index 55b0293cf92ec8294edb24bcc16b796109b21dc9..9898d1f610ba5d8652336b83fd14ee690e8bffcc 100644
--- a/lib/platform/gitlab.js
+++ b/lib/platform/gitlab/index.js
@@ -1,6 +1,8 @@
-let logger = require('../logger');
+let logger = require('../../logger');
 const get = require('./gl-got-wrapper');
 
+const { createFile, updateFile } = require('./helpers');
+
 const config = {};
 
 module.exports = {
@@ -11,13 +13,14 @@ module.exports = {
   getFileList,
   // Branch
   branchExists,
-  createBranch,
-  getBranch,
+  getAllRenovateBranches,
+  isBranchStale,
   getBranchPr,
   getBranchStatus,
   getBranchStatusCheck,
   setBranchStatus,
   deleteBranch,
+  mergeBranch,
   getBranchLastCommitTime,
   // issue
   addAssignees,
@@ -37,8 +40,6 @@ module.exports = {
   getFile,
   getFileContent,
   getFileJson,
-  createFile,
-  updateFile,
   // commits
   getCommitMessages,
 };
@@ -156,19 +157,14 @@ async function branchExists(branchName) {
   }
 }
 
-// Returns branch object
-async function getBranch(branchName) {
-  logger.debug(`getBranch(${branchName})`);
-  const url = `projects/${config.repoName}/repository/branches/${branchName.replace(
-    '/',
-    '%2F'
-  )}`;
-  try {
-    return (await get(url)).body;
-  } catch (err) {
-    logger.warn({ err }, `Failed to getBranch ${branchName}`);
-    return null;
-  }
+function getAllRenovateBranches() {
+  logger.warn('Unimplemented in GitLab: getAllRenovateBranches');
+  return [];
+}
+
+function isBranchStale() {
+  logger.warn('Unimplemented in GitLab: isBranchStale');
+  return false;
 }
 
 // Returns the Pull Request for a branch. Null if not exists.
@@ -287,6 +283,10 @@ async function deleteBranch(branchName) {
   );
 }
 
+function mergeBranch() {
+  logger.warn('Unimplemented in GitLab: mergeBranch');
+}
+
 async function getBranchLastCommitTime(branchName) {
   try {
     const res = await get(
@@ -392,8 +392,12 @@ async function getPr(prNo) {
   }
   // Check if the most recent branch commit is by us
   // If not then we don't allow it to be rebased, in case someone's changes would be lost
-  const branch = await getBranch(pr.source_branch);
-  if (branch && branch.commit.author_email === config.email) {
+  const branchUrl = `projects/${config.repoName}/repository/branches/${pr.source_branch.replace(
+    '/',
+    '%2F'
+  )}`;
+  const branch = (await get(branchUrl)).body;
+  if (branch && branch.commit && branch.commit.author_email === config.email) {
     pr.canRebase = true;
   }
   return pr;
@@ -454,37 +458,6 @@ async function getFileJson(filePath, branchName) {
   return JSON.parse(fileContent);
 }
 
-async function createFile(branchName, filePath, fileContents, message) {
-  const opts = {};
-  const url = `projects/${config.repoName}/repository/files/${filePath.replace(
-    /\//g,
-    '%2F'
-  )}`;
-  opts.body = {
-    branch: branchName,
-    commit_message: message,
-    encoding: 'base64',
-    content: Buffer.from(fileContents).toString('base64'),
-  };
-  await get.post(url, opts);
-}
-
-async function updateFile(branchName, filePath, fileContents, message) {
-  const opts = {};
-  const url = `projects/${config.repoName}/repository/files/${filePath.replace(
-    /\//g,
-    '%2F'
-  )}`;
-  opts.body = {
-    branch: branchName,
-    commit_message: message,
-    encoding: 'base64',
-    content: Buffer.from(fileContents).toString('base64'),
-  };
-
-  await get.put(url, opts);
-}
-
 async function getSubDirectories(path) {
   logger.trace(`getSubDirectories(path=${path})`);
   const res = await get(
@@ -515,17 +488,35 @@ async function commitFilesToBranch(
       logger.debug(`Branch ${branchName} already exists`);
     } else {
       logger.debug(`Creating branch ${branchName}`);
-      await createBranch(branchName);
+      const opts = {
+        body: {
+          branch: branchName,
+          ref: config.basBranch,
+        },
+      };
+      await get.post(`projects/${config.repoName}/repository/branches`, opts);
     }
   }
   for (const file of files) {
     const existingFile = await getFileContent(file.name, branchName);
     if (existingFile) {
       logger.debug(`${file.name} exists - updating it`);
-      await updateFile(branchName, file.name, file.contents, message);
+      await updateFile(
+        config.repoName,
+        branchName,
+        file.name,
+        file.contents,
+        message
+      );
     } else {
       logger.debug(`Creating file ${file.name}`);
-      await createFile(branchName, file.name, file.contents, message);
+      await createFile(
+        config.repoName,
+        branchName,
+        file.name,
+        file.contents,
+        message
+      );
     }
   }
 }
@@ -541,16 +532,3 @@ async function getCommitMessages() {
     return [];
   }
 }
-
-// Internal branch operations
-
-// Creates a new branch with provided commit
-async function createBranch(branchName, ref = config.baseBranch) {
-  const opts = {
-    body: {
-      branch: branchName,
-      ref,
-    },
-  };
-  await get.post(`projects/${config.repoName}/repository/branches`, opts);
-}
diff --git a/test/manager/__snapshots__/resolve.spec.js.snap b/test/manager/__snapshots__/resolve.spec.js.snap
index d34dda00420deae6a5069e3b2cff7647f4405ca1..bfcd09f61041bdadcb047830d2946c04820b39a1 100644
--- a/test/manager/__snapshots__/resolve.spec.js.snap
+++ b/test/manager/__snapshots__/resolve.spec.js.snap
@@ -4,32 +4,25 @@ exports[`manager/resolve resolvePackageFiles() deetect package.json and warns if
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -545,32 +538,25 @@ exports[`manager/resolve resolvePackageFiles() detects meteor and docker 1`] = `
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -1306,32 +1292,25 @@ exports[`manager/resolve resolvePackageFiles() detects package.json and parses j
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -1852,32 +1831,25 @@ exports[`manager/resolve resolvePackageFiles() downloads accompanying files 1`]
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -2399,32 +2371,25 @@ exports[`manager/resolve resolvePackageFiles() skips docker if no content or no
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -2935,32 +2900,25 @@ exports[`manager/resolve resolvePackageFiles() uses packageFiles if already conf
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
diff --git a/test/platform/__snapshots__/index.spec.js.snap b/test/platform/__snapshots__/index.spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dcd05f52756e6d50aba02e19fb85ccf0a277fa5d
--- /dev/null
+++ b/test/platform/__snapshots__/index.spec.js.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`platform has same API for github and gitlab 1`] = `
+Array [
+  "getRepos",
+  "initRepo",
+  "setBaseBranch",
+  "getFileList",
+  "branchExists",
+  "getAllRenovateBranches",
+  "isBranchStale",
+  "getBranchPr",
+  "getBranchStatus",
+  "getBranchStatusCheck",
+  "setBranchStatus",
+  "deleteBranch",
+  "mergeBranch",
+  "getBranchLastCommitTime",
+  "addAssignees",
+  "addReviewers",
+  "ensureComment",
+  "ensureCommentRemoval",
+  "findPr",
+  "createPr",
+  "getPr",
+  "updatePr",
+  "mergePr",
+  "getSubDirectories",
+  "commitFilesToBranch",
+  "getFile",
+  "getFileContent",
+  "getFileJson",
+  "getCommitMessages",
+]
+`;
+
+exports[`platform has same API for github and gitlab 2`] = `
+Array [
+  "getRepos",
+  "initRepo",
+  "setBaseBranch",
+  "getFileList",
+  "branchExists",
+  "getAllRenovateBranches",
+  "isBranchStale",
+  "getBranchPr",
+  "getBranchStatus",
+  "getBranchStatusCheck",
+  "setBranchStatus",
+  "deleteBranch",
+  "mergeBranch",
+  "getBranchLastCommitTime",
+  "addAssignees",
+  "addReviewers",
+  "ensureComment",
+  "ensureCommentRemoval",
+  "findPr",
+  "createPr",
+  "getPr",
+  "updatePr",
+  "mergePr",
+  "getSubDirectories",
+  "commitFilesToBranch",
+  "getFile",
+  "getFileContent",
+  "getFileJson",
+  "getCommitMessages",
+]
+`;
diff --git a/test/platform/__snapshots__/github.spec.js.snap b/test/platform/github/__snapshots__/index.spec.js.snap
similarity index 100%
rename from test/platform/__snapshots__/github.spec.js.snap
rename to test/platform/github/__snapshots__/index.spec.js.snap
diff --git a/test/platform/gh-got-wrapper.spec.js b/test/platform/github/gh-got-wrapper.spec.js
similarity index 98%
rename from test/platform/gh-got-wrapper.spec.js
rename to test/platform/github/gh-got-wrapper.spec.js
index 785c5b70a26f37da7ed769a43970ff5745c5f8d3..9f88a1f6e1e9968307e069e9175624fe2de3e6a0 100644
--- a/test/platform/gh-got-wrapper.spec.js
+++ b/test/platform/github/gh-got-wrapper.spec.js
@@ -1,4 +1,4 @@
-const get = require('../../lib/platform/gh-got-wrapper');
+const get = require('../../../lib/platform/github/gh-got-wrapper');
 const ghGot = require('gh-got');
 
 jest.mock('gh-got');
diff --git a/test/platform/github.spec.js b/test/platform/github/index.spec.js
similarity index 99%
rename from test/platform/github.spec.js
rename to test/platform/github/index.spec.js
index b6b3a2ed11b3e22a2d235307c084e9fa9dae5dd0..d0336d02d67d687eefd14fa8dfc5a89226b59c2d 100644
--- a/test/platform/github.spec.js
+++ b/test/platform/github/index.spec.js
@@ -1,4 +1,4 @@
-const logger = require('../_fixtures/logger');
+const logger = require('../../_fixtures/logger');
 
 describe('platform/github', () => {
   let github;
@@ -10,9 +10,9 @@ describe('platform/github', () => {
 
     // reset module
     jest.resetModules();
-    jest.mock('../../lib/platform/gh-got-wrapper');
-    get = require('../../lib/platform/gh-got-wrapper');
-    github = require('../../lib/platform/github');
+    jest.mock('../../../lib/platform/github/gh-got-wrapper');
+    get = require('../../../lib/platform/github/gh-got-wrapper');
+    github = require('../../../lib/platform/github');
   });
 
   function getRepos(...args) {
diff --git a/test/platform/gitlab/__snapshots__/helpers.spec.js.snap b/test/platform/gitlab/__snapshots__/helpers.spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1e218fb0f1288a836c152fd2497501bd1f89a3e3
--- /dev/null
+++ b/test/platform/gitlab/__snapshots__/helpers.spec.js.snap
@@ -0,0 +1,33 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`platform/gitlab/helpers createFile(branchName, filePath, fileContents, message) creates file 1`] = `
+Array [
+  Array [
+    "projects/some%2Frepo/repository/files/some-path",
+    Object {
+      "body": Object {
+        "branch": "some-branch",
+        "commit_message": "some-message",
+        "content": "c29tZS1jb250ZW50cw==",
+        "encoding": "base64",
+      },
+    },
+  ],
+]
+`;
+
+exports[`platform/gitlab/helpers updateFile(branchName, filePath, fileContents, message) updates file 1`] = `
+Array [
+  Array [
+    "projects/some%2Frepo/repository/files/some-path",
+    Object {
+      "body": Object {
+        "branch": "some-branch",
+        "commit_message": "some-message",
+        "content": "c29tZS1jb250ZW50cw==",
+        "encoding": "base64",
+      },
+    },
+  ],
+]
+`;
diff --git a/test/platform/__snapshots__/gitlab.spec.js.snap b/test/platform/gitlab/__snapshots__/index.spec.js.snap
similarity index 78%
rename from test/platform/__snapshots__/gitlab.spec.js.snap
rename to test/platform/gitlab/__snapshots__/index.spec.js.snap
index 954ef0ddb85c4195c5bc1a9ba3df8cf243235cb1..9234239bce6fec25797e81e229bb0c5cbc5b570d 100644
--- a/test/platform/__snapshots__/gitlab.spec.js.snap
+++ b/test/platform/gitlab/__snapshots__/index.spec.js.snap
@@ -16,72 +16,6 @@ Array [
 ]
 `;
 
-exports[`platform/gitlab createFile(branchName, filePath, fileContents, message) createBranch(branchName) creates branch 1`] = `
-Array [
-  Array [
-    "projects/undefined/repository/branches",
-    Object {
-      "body": Object {
-        "branch": "some-branch",
-        "ref": undefined,
-      },
-    },
-  ],
-]
-`;
-
-exports[`platform/gitlab createFile(branchName, filePath, fileContents, message) creates file 1`] = `
-Array [
-  Array [
-    "projects/undefined/repository/files/some-path",
-    Object {
-      "body": Object {
-        "branch": "some-branch",
-        "commit_message": "some-message",
-        "content": "c29tZS1jb250ZW50cw==",
-        "encoding": "base64",
-      },
-    },
-  ],
-]
-`;
-
-exports[`platform/gitlab createFile(branchName, filePath, fileContents, message) getSubDirectories(path) should return subdirectories 1`] = `
-Array [
-  Array [
-    "projects/some%2Frepo",
-  ],
-  Array [
-    "user",
-  ],
-  Array [
-    "projects/some%2Frepo/repository/tree?path=some-path",
-  ],
-]
-`;
-
-exports[`platform/gitlab createFile(branchName, filePath, fileContents, message) getSubDirectories(path) should return subdirectories 2`] = `
-Array [
-  "a",
-]
-`;
-
-exports[`platform/gitlab createFile(branchName, filePath, fileContents, message) updateFile(branchName, filePath, fileContents, message) updates file 1`] = `
-Array [
-  Array [
-    "projects/undefined/repository/files/some-path",
-    Object {
-      "body": Object {
-        "branch": "some-branch",
-        "commit_message": "some-message",
-        "content": "c29tZS1jb250ZW50cw==",
-        "encoding": "base64",
-      },
-    },
-  ],
-]
-`;
-
 exports[`platform/gitlab createPr(branchName, title, body) returns the PR 1`] = `
 Object {
   "displayNumber": "Merge Request #12345",
@@ -125,7 +59,7 @@ Array [
     Object {
       "body": Object {
         "description": "the-body",
-        "labels": null,
+        "labels": "",
         "remove_source_branch": true,
         "source_branch": "some-branch",
         "target_branch": undefined,
@@ -136,8 +70,6 @@ Array [
 ]
 `;
 
-exports[`platform/gitlab getBranch returns a branch 1`] = `"foo"`;
-
 exports[`platform/gitlab getBranchLastCommitTime should return a Date 1`] = `2012-09-20T08:50:22.000Z`;
 
 exports[`platform/gitlab getBranchPr(branchName) should return null if no PR exists 1`] = `
@@ -275,6 +207,26 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab getSubDirectories(path) should return subdirectories 1`] = `
+Array [
+  Array [
+    "projects/some%2Frepo",
+  ],
+  Array [
+    "user",
+  ],
+  Array [
+    "projects/some%2Frepo/repository/tree?path=some-path",
+  ],
+]
+`;
+
+exports[`platform/gitlab getSubDirectories(path) should return subdirectories 2`] = `
+Array [
+  "a",
+]
+`;
+
 exports[`platform/gitlab initRepo should initialise the config for the repo - 0 1`] = `
 Array [
   Array [
diff --git a/test/platform/gl-got-wrapper.spec.js b/test/platform/gitlab/gl-got-wrapper.spec.js
similarity index 96%
rename from test/platform/gl-got-wrapper.spec.js
rename to test/platform/gitlab/gl-got-wrapper.spec.js
index 0e2b632613ad45475b7014e80b83242b02359b1f..a531078e9d52bd6e13d34068625b759b1b747246 100644
--- a/test/platform/gl-got-wrapper.spec.js
+++ b/test/platform/gitlab/gl-got-wrapper.spec.js
@@ -1,4 +1,4 @@
-const get = require('../../lib/platform/gl-got-wrapper');
+const get = require('../../../lib/platform/gitlab/gl-got-wrapper');
 const glGot = require('gl-got');
 
 jest.mock('gl-got');
diff --git a/test/platform/gitlab/helpers.spec.js b/test/platform/gitlab/helpers.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..4822280f49e76acb2a086f5ce46e446db0c402c8
--- /dev/null
+++ b/test/platform/gitlab/helpers.spec.js
@@ -0,0 +1,33 @@
+const helpers = require('../../../lib/platform/gitlab/helpers');
+
+jest.mock('../../../lib/platform/gitlab/gl-got-wrapper');
+const get = require('../../../lib/platform/gitlab/gl-got-wrapper');
+
+describe('platform/gitlab/helpers', () => {
+  describe('createFile(branchName, filePath, fileContents, message)', () => {
+    it('creates file', async () => {
+      await helpers.createFile(
+        'some%2Frepo',
+        'some-branch',
+        'some-path',
+        'some-contents',
+        'some-message'
+      );
+      expect(get.post.mock.calls).toMatchSnapshot();
+      expect(get.post.mock.calls[0][1].body.file_path).not.toBeDefined();
+    });
+  });
+  describe('updateFile(branchName, filePath, fileContents, message)', () => {
+    it('updates file', async () => {
+      await helpers.updateFile(
+        'some%2Frepo',
+        'some-branch',
+        'some-path',
+        'some-contents',
+        'some-message'
+      );
+      expect(get.put.mock.calls).toMatchSnapshot();
+      expect(get.put.mock.calls[0][1].body.file_path).not.toBeDefined();
+    });
+  });
+});
diff --git a/test/platform/gitlab.spec.js b/test/platform/gitlab/index.spec.js
similarity index 84%
rename from test/platform/gitlab.spec.js
rename to test/platform/gitlab/index.spec.js
index efbf3f92792c8b5f404b766d5f0e1ef59d3aa1cf..5b37731e457bebfedcc0d80f734d02e3961916ea 100644
--- a/test/platform/gitlab.spec.js
+++ b/test/platform/gitlab/index.spec.js
@@ -1,4 +1,4 @@
-const logger = require('../_fixtures/logger');
+const logger = require('../../_fixtures/logger');
 
 describe('platform/gitlab', () => {
   let gitlab;
@@ -10,9 +10,10 @@ describe('platform/gitlab', () => {
 
     // reset module
     jest.resetModules();
-    jest.mock('../../lib/platform/gl-got-wrapper');
-    gitlab = require('../../lib/platform/gitlab');
-    get = require('../../lib/platform/gl-got-wrapper');
+    jest.mock('../../../lib/platform/gitlab/gl-got-wrapper');
+    jest.mock('../../../lib/platform/gitlab/helpers');
+    gitlab = require('../../../lib/platform/gitlab');
+    get = require('../../../lib/platform/gitlab/gl-got-wrapper');
   });
 
   describe('getRepos', () => {
@@ -229,18 +230,14 @@ describe('platform/gitlab', () => {
       expect(e.statusCode).toBe(500);
     });
   });
-  describe('getBranch', () => {
-    it('returns a branch', async () => {
-      get.mockReturnValueOnce({ body: 'foo' });
-      const branch = await gitlab.getBranch('branch-name');
-      expect(branch).toMatchSnapshot();
+  describe('getAllRenovateBranches()', () => {
+    it('exists', () => {
+      gitlab.getAllRenovateBranches();
     });
-    it('nulls on error', async () => {
-      get.mockImplementationOnce(() => {
-        throw new Error('not found');
-      });
-      const branch = await gitlab.getBranch('branch-name');
-      expect(branch).toBe(null);
+  });
+  describe('isBranchStale()', () => {
+    it('exists', () => {
+      gitlab.isBranchStale();
     });
   });
   describe('getBranchPr(branchName)', () => {
@@ -255,10 +252,10 @@ describe('platform/gitlab', () => {
     });
     it('should return the PR object', async () => {
       await initRepo('some/repo', 'token');
-      get.mockImplementationOnce(() => ({
+      get.mockReturnValueOnce({
         body: [{ number: 91, source_branch: 'somebranch' }],
-      }));
-      get.mockImplementationOnce(() => ({
+      });
+      get.mockReturnValueOnce({
         body: {
           iid: 91,
           additions: 1,
@@ -269,7 +266,8 @@ describe('platform/gitlab', () => {
             sha: '1234',
           },
         },
-      }));
+      });
+      get.mockReturnValueOnce({ body: 'foo' });
       const pr = await gitlab.getBranchPr('somebranch');
       expect(get.mock.calls).toMatchSnapshot();
       expect(pr).toMatchSnapshot();
@@ -397,6 +395,11 @@ describe('platform/gitlab', () => {
       expect(get.delete.mock.calls.length).toBe(1);
     });
   });
+  describe('mergeBranch()', () => {
+    it('exists', () => {
+      gitlab.mergeBranch();
+    });
+  });
   describe('getBranchLastCommitTime', () => {
     it('should return a Date', async () => {
       await initRepo('some/repo', 'token');
@@ -520,7 +523,12 @@ describe('platform/gitlab', () => {
           iid: 12345,
         },
       });
-      const pr = await gitlab.createPr('some-branch', 'some-title', 'the-body');
+      const pr = await gitlab.createPr(
+        'some-branch',
+        'some-title',
+        'the-body',
+        null
+      );
       expect(pr).toMatchSnapshot();
       expect(get.post.mock.calls).toMatchSnapshot();
     });
@@ -535,6 +543,7 @@ describe('platform/gitlab', () => {
         'some-branch',
         'some-title',
         'the-body',
+        [],
         true
       );
       expect(pr).toMatchSnapshot();
@@ -621,85 +630,54 @@ describe('platform/gitlab', () => {
       expect(res).toBe(null);
     });
   });
-  describe('createFile(branchName, filePath, fileContents, message)', () => {
-    it('creates file', async () => {
-      await gitlab.createFile(
-        'some-branch',
-        'some-path',
-        'some-contents',
-        'some-message'
-      );
-      expect(get.post.mock.calls).toMatchSnapshot();
-      expect(get.post.mock.calls[0][1].body.file_path).not.toBeDefined();
-    });
-    describe('updateFile(branchName, filePath, fileContents, message)', () => {
-      it('updates file', async () => {
-        await gitlab.updateFile(
-          'some-branch',
-          'some-path',
-          'some-contents',
-          'some-message'
-        );
-        expect(get.put.mock.calls).toMatchSnapshot();
-        expect(get.put.mock.calls[0][1].body.file_path).not.toBeDefined();
-      });
+  describe('getSubDirectories(path)', () => {
+    it('should return subdirectories', async () => {
+      await initRepo('some/repo', 'token');
+      get.mockImplementationOnce(() => ({
+        body: [{ type: 'tree', name: 'a' }, { type: 'file', name: 'b' }],
+      }));
+      const dirList = await gitlab.getSubDirectories('some-path');
+      expect(get.mock.calls).toMatchSnapshot();
+      expect(dirList).toHaveLength(1);
+      expect(dirList).toMatchSnapshot();
     });
-    describe('createBranch(branchName)', () => {
-      it('creates branch', async () => {
-        await gitlab.createBranch('some-branch');
-        expect(get.post.mock.calls).toMatchSnapshot();
-        expect(get.post.mock.calls[0][1].body.branch_name).not.toBeDefined();
-      });
+  });
+  describe('commitFilesToBranch(branchName, files, message, parentBranch)', () => {
+    it('creates branch', async () => {
+      get.mockReturnValueOnce({ statusCode: 404 });
+      await gitlab.commitFilesToBranch('some-branch', [], 'some-message');
     });
-    describe('getSubDirectories(path)', () => {
-      it('should return subdirectories', async () => {
-        await initRepo('some/repo', 'token');
-        get.mockImplementationOnce(() => ({
-          body: [{ type: 'tree', name: 'a' }, { type: 'file', name: 'b' }],
-        }));
-        const dirList = await gitlab.getSubDirectories('some-path');
-        expect(get.mock.calls).toMatchSnapshot();
-        expect(dirList).toHaveLength(1);
-        expect(dirList).toMatchSnapshot();
+    it('does not create branch and updates file', async () => {
+      get.mockReturnValueOnce({ statusCode: 200 });
+      get.mockReturnValueOnce({
+        body: {
+          content: 'hello',
+        },
       });
+      const file = {
+        name: 'foo',
+        contents: 'bar',
+      };
+      await gitlab.commitFilesToBranch(
+        'some-branch',
+        [file],
+        'some-message',
+        'parent-branch'
+      );
     });
-    describe('commitFilesToBranch(branchName, files, message, parentBranch)', () => {
-      it('creates branch', async () => {
-        get.mockReturnValueOnce({ statusCode: 404 });
-        await gitlab.commitFilesToBranch('some-branch', [], 'some-message');
-      });
-      it('does not create branch and updates file', async () => {
-        get.mockReturnValueOnce({ statusCode: 200 });
-        get.mockReturnValueOnce({
-          body: {
-            content: 'hello',
-          },
-        });
-        const file = {
-          name: 'foo',
-          contents: 'bar',
-        };
-        await gitlab.commitFilesToBranch(
-          'some-branch',
-          [file],
-          'some-message',
-          'parent-branch'
-        );
-      });
-      it('does not create branch and creates file', async () => {
-        get.mockReturnValueOnce({ statusCode: 200 });
-        get.mockReturnValueOnce(Promise.reject({ statusCode: 404 }));
-        const file = {
-          name: 'foo',
-          contents: 'bar',
-        };
-        await gitlab.commitFilesToBranch(
-          'some-branch',
-          [file],
-          'some-message',
-          'parent-branch'
-        );
-      });
+    it('does not create branch and creates file', async () => {
+      get.mockReturnValueOnce({ statusCode: 200 });
+      get.mockReturnValueOnce(Promise.reject({ statusCode: 404 }));
+      const file = {
+        name: 'foo',
+        contents: 'bar',
+      };
+      await gitlab.commitFilesToBranch(
+        'some-branch',
+        [file],
+        'some-message',
+        'parent-branch'
+      );
     });
   });
   describe('getCommitMessages()', () => {
diff --git a/test/platform/index.spec.js b/test/platform/index.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..46658e3996764d180b6f18458b02b6c150f0d88e
--- /dev/null
+++ b/test/platform/index.spec.js
@@ -0,0 +1,12 @@
+const github = require('../../lib/platform/github');
+const gitlab = require('../../lib/platform/gitlab');
+
+describe('platform', () => {
+  it('has same API for github and gitlab', () => {
+    const githubMethods = Object.keys(github);
+    const gitlabMethods = Object.keys(gitlab);
+    expect(githubMethods).toMatchSnapshot();
+    expect(gitlabMethods).toMatchSnapshot();
+    expect(githubMethods).toMatchObject(gitlabMethods);
+  });
+});
diff --git a/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap b/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap
index 0de4581bdffc6005ea36dcd528e26b8dd37a34c9..642f3c05342601c219b16a4c57226ca174bcb122 100644
--- a/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap
+++ b/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap
@@ -4,32 +4,25 @@ exports[`workers/repository/updates/branchify branchifyUpgrades() does not group
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -611,32 +604,25 @@ exports[`workers/repository/updates/branchify branchifyUpgrades() groups if same
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -1201,32 +1187,25 @@ exports[`workers/repository/updates/branchify branchifyUpgrades() groups if same
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -1797,32 +1776,25 @@ exports[`workers/repository/updates/branchify branchifyUpgrades() mixes errors a
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],
@@ -2388,32 +2360,25 @@ exports[`workers/repository/updates/branchify branchifyUpgrades() returns one br
 Object {
   "api": Object {
     "addAssignees": [Function],
-    "addComment": [Function],
     "addReviewers": [Function],
     "branchExists": [Function],
     "commitFilesToBranch": [Function],
     "createPr": [Function],
     "deleteBranch": [Function],
-    "deleteComment": [Function],
-    "editComment": [Function],
     "ensureComment": [Function],
     "ensureCommentRemoval": [Function],
     "findPr": [Function],
     "getAllRenovateBranches": [Function],
-    "getBranchCommit": [Function],
     "getBranchLastCommitTime": [Function],
     "getBranchPr": [Function],
     "getBranchStatus": [Function],
     "getBranchStatusCheck": [Function],
-    "getComments": [Function],
-    "getCommitDetails": [Function],
     "getCommitMessages": [Function],
     "getFile": [Function],
     "getFileContent": [Function],
     "getFileJson": [Function],
     "getFileList": [Function],
     "getPr": [Function],
-    "getPrList": [Function],
     "getRepos": [Function],
     "getSubDirectories": [Function],
     "initRepo": [Function],