diff --git a/lib/config/index.js b/lib/config/index.js
index b5ee821b7dec9472f6d3c2ce0beebfd593f28330..27a05b485cc3b0e47197fc8ea97cfa345940e78d 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -8,8 +8,6 @@ const envParser = require('./env');
 const { resolveConfigPresets } = require('./presets');
 const { get, getLanguageList, getManagerList } = require('../manager');
 
-const hostRules = require('../util/host-rules');
-
 const clone = input => JSON.parse(JSON.stringify(input));
 
 exports.parseConfigs = parseConfigs;
@@ -81,53 +79,6 @@ async function parseConfigs(env, argv) {
   // Get global config
   logger.trace({ config }, 'Full config');
 
-  // Check platform and authentication
-  const { platform, username, password } = config;
-  const platformInfo = hostRules.defaults[platform];
-  if (!platformInfo) {
-    throw new Error(`Unsupported platform: ${config.platform}.`);
-  }
-  const endpoint = config.endpoint || platformInfo.endpoint;
-  let token = config.token;
-  if (username && password) {
-    logger.info('Using username and password to generate token');
-    const base64 = str => Buffer.from(str, 'binary').toString('base64');
-    token = base64(`${username}:${password}`);
-  }
-  if (!token) {
-    throw new Error(
-      `No authentication found for platform ${endpoint} (${platform})`
-    );
-  }
-  config.hostRules.push({
-    platform,
-    endpoint,
-    username,
-    password,
-    token,
-  });
-  config.hostRules.forEach(hostRules.update);
-  delete config.hostRules;
-  delete config.token;
-  delete config.username;
-  delete config.password;
-
-  const credentials = hostRules.find(
-    { platform },
-    {
-      platform,
-      endpoint: endpoint || platformInfo.endpoint,
-      token,
-    }
-  );
-
-  if (!global.appMode) {
-    hostRules.update({
-      ...credentials,
-      default: true,
-    });
-  }
-
   // Print config
   logger.trace({ config }, 'Global config');
   // Remove log file entries
diff --git a/lib/platform/azure/azure-got-wrapper.js b/lib/platform/azure/azure-got-wrapper.js
index 612ce8b7ee3f175eb45ca4c7a39da9c364808b56..10733e9978d433a73d7548cb5d4dc2836ae9f616 100644
--- a/lib/platform/azure/azure-got-wrapper.js
+++ b/lib/platform/azure/azure-got-wrapper.js
@@ -1,19 +1,23 @@
 const azure = require('azure-devops-node-api');
 const hostRules = require('../../util/host-rules');
 
+const platform = 'azure';
+let endpoint;
+
 module.exports = {
   azureObj,
   gitApi,
   getCoreApi,
+  setEndpoint,
 };
 
 function azureObj() {
-  const config = hostRules.find({ platform: 'azure' }, {});
-  if (!config.token) {
+  const config = hostRules.find({ platform, endpoint });
+  if (!(config && config.token)) {
     throw new Error(`No token found for azure`);
   }
   const authHandler = azure.getPersonalAccessTokenHandler(config.token);
-  return new azure.WebApi(config.endpoint, authHandler);
+  return new azure.WebApi(endpoint, authHandler);
 }
 
 function gitApi() {
@@ -23,3 +27,7 @@ function gitApi() {
 function getCoreApi() {
   return azureObj().getCoreApi();
 }
+
+function setEndpoint(e) {
+  endpoint = e;
+}
diff --git a/lib/platform/azure/index.js b/lib/platform/azure/index.js
index 743ef57e17bf30f1a59c506ec2e9e9539031e351..70dd1cc8b21c4ace39de80a1aa49e44b3d2c7e45 100644
--- a/lib/platform/azure/index.js
+++ b/lib/platform/azure/index.js
@@ -7,8 +7,13 @@ const GitStorage = require('../git/storage');
 
 let config = {};
 
+const defaults = {
+  platform: 'azure',
+};
+
 module.exports = {
   // Initialization
+  initPlatform,
   getRepos,
   cleanRepo,
   initRepo,
@@ -58,24 +63,31 @@ module.exports = {
   getVulnerabilityAlerts,
 };
 
-async function getRepos(token, endpoint) {
+function initPlatform({ endpoint, token }) {
+  if (!endpoint) {
+    throw new Error('Init: You must configure an Azure DevOps endpoint');
+  }
+  if (!token) {
+    throw new Error('Init: You must configure an Azure DevOps token');
+  }
+  // TODO: Add a connection check that endpoint/token combination are valid
+  const res = {
+    endpoint: endpoint.replace(/\/?$/, '/'), // always add a trailing slash
+  };
+  defaults.endpoint = res.endpoint;
+  azureApi.setEndpoint(res.endpoint);
+  return res;
+}
+
+async function getRepos() {
   logger.info('Autodiscovering Azure DevOps repositories');
-  logger.debug('getRepos(token, endpoint)');
-  const opts = hostRules.find({ platform: 'azure' }, { token, endpoint });
-  hostRules.update({ ...opts, platform: 'azure', default: true });
   const azureApiGit = await azureApi.gitApi();
   const repos = await azureApiGit.getRepositories();
   return repos.map(repo => `${repo.project.name}/${repo.name}`);
 }
 
-async function initRepo({ repository, endpoint, localDir, azureWorkItemId }) {
+async function initRepo({ repository, localDir, azureWorkItemId }) {
   logger.debug(`initRepo("${repository}")`);
-  const opts = hostRules.find({ platform: 'azure' }, { endpoint });
-  // istanbul ignore next
-  if (!opts.token) {
-    throw new Error('No token found for getRepos');
-  }
-  hostRules.update({ ...opts, platform: 'azure', default: true });
   config.repository = repository;
   config.fileList = null;
   config.prList = null;
@@ -134,8 +146,9 @@ async function initRepo({ repository, endpoint, localDir, azureWorkItemId }) {
   // Always gitFs
   config.storage = new GitStorage();
   const [projectName, repoName] = repository.split('/');
+  const opts = hostRules.find(defaults);
   const url =
-    endpoint.replace('https://', `https://token:${opts.token}@`) +
+    defaults.endpoint.replace('https://', `https://token:${opts.token}@`) +
     `${encodeURIComponent(projectName)}/_git/${encodeURIComponent(repoName)}`;
   await config.storage.initRepo({
     ...config,
diff --git a/lib/platform/bitbucket-server/bb-got-wrapper.js b/lib/platform/bitbucket-server/bb-got-wrapper.js
index 5aa97dcc6095b23a1491d716f5e6c25b5d05f5dd..f4b9bd44e748734f5f87c221c700848ed9c3ac8e 100644
--- a/lib/platform/bitbucket-server/bb-got-wrapper.js
+++ b/lib/platform/bitbucket-server/bb-got-wrapper.js
@@ -5,9 +5,10 @@ const hostRules = require('../../util/host-rules');
 let cache = {};
 
 const platform = 'bitbucket-server';
+let endpoint;
 
 async function get(path, options) {
-  const { host } = URL.parse(path);
+  const host = URL.parse(path).host || URL.parse(endpoint).host;
   const opts = {
     // TODO: Move to configurable host rules, or use utils/got
     timeout: 60 * 1000,
@@ -16,7 +17,7 @@ async function get(path, options) {
     ...hostRules.find({ platform, host }),
     ...options,
   };
-  const url = URL.resolve(opts.endpoint, path);
+  const url = URL.resolve(endpoint, path);
   const method = (opts.method || 'get').toLowerCase();
   const useCache = opts.useCache;
   if (method === 'get' && useCache !== false && cache[path]) {
@@ -49,4 +50,8 @@ get.reset = function reset() {
   cache = {};
 };
 
+get.setEndpoint = e => {
+  endpoint = e;
+};
+
 module.exports = get;
diff --git a/lib/platform/bitbucket-server/index.js b/lib/platform/bitbucket-server/index.js
index 086ffd763f22004f6b0b749696ef87e0e9cb7c38..a159d51a347a5c354768a288d2cb2737a97be023 100644
--- a/lib/platform/bitbucket-server/index.js
+++ b/lib/platform/bitbucket-server/index.js
@@ -10,7 +10,12 @@ const platform = 'bitbucket-server';
 
 let config = {};
 
+const defaults = {
+  platform: 'bitbucket-server',
+};
+
 module.exports = {
+  initPlatform,
   getRepos,
   cleanRepo,
   initRepo,
@@ -60,15 +65,27 @@ module.exports = {
   getVulnerabilityAlerts,
 };
 
-// Get all repositories that the user has access to
-async function getRepos(token, endpoint) {
-  logger.debug(`getRepos(${endpoint})`);
-  const opts = hostRules.find({ platform }, { token, endpoint });
-  // istanbul ignore next
-  if (!opts.token) {
-    throw new Error('No token found for getRepos');
+function initPlatform({ endpoint, username, password }) {
+  if (!endpoint) {
+    throw new Error('Init: You must configure a Bitbucket Server endpoint');
   }
-  hostRules.update({ ...opts, platform, default: true });
+  if (!(username && password)) {
+    throw new Error(
+      'Init: You must configure a Bitbucket Server username/password'
+    );
+  }
+  // TODO: Add a connection check that endpoint/username/password combination are valid
+  const res = {
+    endpoint: endpoint.replace(/\/?$/, '/'), // always add a trailing slash
+  };
+  api.setEndpoint(res.endpoint);
+  defaults.endpoint = res.endpoint;
+  return res;
+}
+
+// Get all repositories that the user has access to
+async function getRepos() {
+  logger.info('Autodiscovering Bitbucket Server repositories');
   try {
     const repos = await utils.accumulateValues(
       `./rest/api/1.0/repos?permission=REPO_WRITE&state=AVAILABLE`
@@ -108,17 +125,6 @@ async function initRepo({
     )}")`
   );
   const opts = hostRules.find({ platform }, { endpoint });
-  // istanbul ignore if
-  if (!(opts.username && opts.password)) {
-    throw new Error(
-      `No username/password found for Bitbucket repository ${repository}`
-    );
-  }
-  // istanbul ignore if
-  if (!opts.endpoint) {
-    throw new Error(`No endpoint found for Bitbucket Server`);
-  }
-  hostRules.update({ ...opts, platform, default: true });
   api.reset();
 
   const [projectKey, repositorySlug] = repository.split('/');
diff --git a/lib/platform/bitbucket/bb-got-wrapper.js b/lib/platform/bitbucket/bb-got-wrapper.js
index 8197f9282270a787ec524724612791646783c684..7a52ab5dae9b07d612b19203b397aa50bd7f2453 100644
--- a/lib/platform/bitbucket/bb-got-wrapper.js
+++ b/lib/platform/bitbucket/bb-got-wrapper.js
@@ -4,8 +4,10 @@ const hostRules = require('../../util/host-rules');
 
 let cache = {};
 
+const endpoint = 'https://api.bitbucket.org/';
+const host = 'api.bitbucket.org';
+
 async function get(path, options) {
-  const { host } = URL.parse(path);
   const opts = {
     // TODO: Move to configurable host rules, or use utils/got
     timeout: 60 * 1000,
@@ -14,7 +16,7 @@ async function get(path, options) {
     ...hostRules.find({ platform: 'bitbucket', host }),
     ...options,
   };
-  const url = URL.resolve(opts.endpoint, path);
+  const url = URL.resolve(endpoint, path);
   const method = (opts.method || 'get').toLowerCase();
   if (method === 'get' && cache[path]) {
     logger.trace({ path }, 'Returning cached result');
diff --git a/lib/platform/bitbucket/index.js b/lib/platform/bitbucket/index.js
index 8b54202cbd368c43bdad9c0180b41984b6073aaf..98da8f2ab433206122d2d2e6340ca43be922a823 100644
--- a/lib/platform/bitbucket/index.js
+++ b/lib/platform/bitbucket/index.js
@@ -9,6 +9,7 @@ let config = {};
 
 module.exports = {
   // Initialization
+  initPlatform,
   getRepos,
   cleanRepo,
   initRepo,
@@ -58,15 +59,28 @@ module.exports = {
   getVulnerabilityAlerts,
 };
 
-// Get all repositories that the user has access to
-async function getRepos(token, endpoint) {
-  logger.debug('getRepos(token, endpoint)');
-  const opts = hostRules.find({ platform: 'bitbucket' }, { token, endpoint });
-  // istanbul ignore next
-  if (!opts.token) {
-    throw new Error('No token found for getRepos');
+function initPlatform({ endpoint, username, password }) {
+  if (!(username && password)) {
+    throw new Error(
+      'Init: You must configure a Bitbucket username and password'
+    );
+  }
+  if (endpoint && endpoint !== 'https://api.bitbucket.org/') {
+    throw new Error(
+      'Init: Bitbucket Cloud endpoint can only be https://api.bitbucket.org/'
+    );
   }
-  hostRules.update({ ...opts, platform: 'bitbucket', default: true });
+  // TODO: Add a connection check that endpoint/username/password combination are valid
+  const res = {
+    endpoint: 'https://api.bitbucket.org/',
+  };
+  logger.info('Using default Bitbucket Cloud endpoint: ' + res.endpoint);
+  return res;
+}
+
+// Get all repositories that the user has access to
+async function getRepos() {
+  logger.info('Autodiscovering Bitbucket Cloud repositories');
   try {
     const repos = await utils.accumulateValues(
       `/2.0/repositories/?role=contributor`
@@ -79,16 +93,9 @@ async function getRepos(token, endpoint) {
 }
 
 // Initialize bitbucket by getting base branch and SHA
-async function initRepo({ repository, endpoint, localDir }) {
+async function initRepo({ repository, localDir }) {
   logger.debug(`initRepo("${repository}")`);
-  const opts = hostRules.find({ platform: 'bitbucket' }, { endpoint });
-  // istanbul ignore next
-  if (!(opts.username && opts.password)) {
-    throw new Error(
-      `No username/password found for Bitbucket repository ${repository}`
-    );
-  }
-  hostRules.update({ ...opts, platform: 'bitbucket', default: true });
+  const opts = hostRules.find({ platform: 'bitbucket' });
   api.reset();
   config = {};
   // TODO: get in touch with @rarkins about lifting up the caching into the app layer
diff --git a/lib/platform/git/storage.ts b/lib/platform/git/storage.ts
index 6b5d4cb7a3031807695df67c3459c759f69484d7..3b9149fc806ec4b5430929c83ae4ca8720aef6b2 100644
--- a/lib/platform/git/storage.ts
+++ b/lib/platform/git/storage.ts
@@ -48,6 +48,7 @@ class Storage {
   }
 
   async initRepo(args: IStorageConfig) {
+    debugger;
     this.cleanRepo();
     let config: ILocalConfig = (this._config = { ...args } as any);
     let cwd = (this._cwd = config.localDir);
@@ -105,6 +106,7 @@ class Storage {
         // clone only the default branch
         await this._git.clone(config.url, '.', ['--depth=2']);
       } catch (err) /* istanbul ignore next */ {
+        debugger;
         logger.debug({ err }, 'git clone error');
         throw new Error('platform-failure');
       }
diff --git a/lib/platform/github/gh-got-wrapper.js b/lib/platform/github/gh-got-wrapper.js
index 50222697834ec9ed928eff78ad0a0bc475f03984..64f33f85c4fb334031a5197a1c6b9de0bf65ebe4 100644
--- a/lib/platform/github/gh-got-wrapper.js
+++ b/lib/platform/github/gh-got-wrapper.js
@@ -10,21 +10,23 @@ const { maskToken } = require('../../util/mask');
 let cache = {};
 let stats = {};
 
+let endpoint = 'https://api.github.com/';
+
 async function get(path, options, retries = 5) {
-  const { host } = URL.parse(path);
+  const host = URL.parse(path).host || URL.parse(endpoint).host;
   const opts = {
     // TODO: Move to configurable host rules, or use utils/got
     timeout: 60 * 1000,
     ...hostRules.find({ platform: 'github', host }),
     ...options,
   };
-  opts.baseUrl = opts.endpoint;
   delete opts.endpoint;
   const method = opts.method || 'get';
   const useCache = opts.useCache || true;
+  let url = URL.resolve(endpoint, path);
   if (method.toLowerCase() === 'post' && path === 'graphql') {
     // GitHub Enterprise uses unversioned graphql path
-    opts.baseUrl = opts.baseUrl.replace(/\/v3\/?$/, '/');
+    url = url.replace('/v3/', '/');
   }
   if (method === 'get' && useCache && cache[path]) {
     logger.trace({ path }, 'Returning cached result');
@@ -51,7 +53,7 @@ async function get(path, options, retries = 5) {
         opts.headers.accept = `${appAccept}, ${opts.headers.accept}`;
       }
     }
-    const res = await ghGot(path, opts);
+    const res = await ghGot(url, opts);
     if (res && res.headers) {
       stats.rateLimit = res.headers['x-ratelimit-limit'];
       stats.rateLimitRemaining = res.headers['x-ratelimit-remaining'];
@@ -70,10 +72,14 @@ async function get(path, options, retries = 5) {
           (x, i) => i + 1
         ).slice(1);
         const queue = pageNumbers.map(page => () => {
-          const url = URL.parse(linkHeader.next.url, true);
-          delete url.search;
-          url.query.page = page;
-          return get(URL.format(url), { ...opts, paginate: false }, retries);
+          const nextUrl = URL.parse(linkHeader.next.url, true);
+          delete nextUrl.search;
+          nextUrl.query.page = page;
+          return get(
+            URL.format(nextUrl),
+            { ...opts, paginate: false },
+            retries
+          );
         });
         const pages = await pAll(queue, { concurrency: 5 });
         res.body = res.body.concat(
@@ -242,4 +248,8 @@ get.reset = function reset() {
   }
 };
 
+get.setEndpoint = e => {
+  endpoint = e;
+};
+
 module.exports = get;
diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js
index f1713448bed821d2c8091b6644761fc225d01f3c..e3373ecfcebe2153c972cbdd738aa672e82adc40 100644
--- a/lib/platform/github/index.js
+++ b/lib/platform/github/index.js
@@ -18,8 +18,14 @@ const defaultConfigFile = configFileNames[0];
 
 let config = {};
 
+const defaults = {
+  platform: 'github',
+  endpoint: 'https://api.github.com/',
+};
+
 module.exports = {
   // Initialization
+  initPlatform,
   getRepos,
   cleanRepo,
   initRepo,
@@ -69,30 +75,33 @@ module.exports = {
   getVulnerabilityAlerts,
 };
 
-// istanbul ignore next
-async function getRenovateUsername() {
-  if (!global.renovateUsername) {
-    try {
-      global.renovateUsername = (await get('user')).body.login;
-    } catch (err) {
-      if (err.message === 'integration-unauthorized') {
-        global.renovateUsername = 'renovate[bot]';
-      } else {
-        throw err;
-      }
-    }
+async function initPlatform({ endpoint, token }) {
+  if (!token) {
+    throw new Error('Init: You must configure a GitHub personal access token');
   }
-  return global.renovateUsername;
+  const res = {};
+  if (endpoint) {
+    defaults.endpoint = endpoint.replace(/\/?$/, '/'); // always add a trailing slash
+    get.setEndpoint(defaults.endpoint);
+  } else {
+    logger.info('Using default github endpoint: ' + res.endpoint);
+  }
+  res.endpoint = defaults.endpoint;
+  try {
+    res.renovateUsername = (await get(res.endpoint + 'user', {
+      token,
+    })).body.login;
+  } catch (err) {
+    logger.debug({ err }, 'Error authenticating with GitHub');
+    throw new Error('Init: Authentication failure');
+  }
+  logger.info('Authenticated as GitHub user: ' + res.renovateUsername);
+  return res;
 }
 
 // Get all repositories that the user has access to
-async function getRepos(token, endpoint) {
+async function getRepos() {
   logger.info('Autodiscovering GitHub repositories');
-  const opts = hostRules.find({ platform: 'github' }, { token, endpoint });
-  if (!opts.token) {
-    throw new Error('No token found for getRepos');
-  }
-  hostRules.update({ ...opts, platform: 'github', default: true });
   try {
     const res = await get('user/repos?per_page=100', { paginate: true });
     return res.body.map(repo => repo.full_name);
@@ -115,26 +124,25 @@ function cleanRepo() {
 // Initialize GitHub by getting base branch and SHA
 async function initRepo({
   repository,
-  token,
-  endpoint,
   forkMode,
   forkToken,
   gitPrivateKey,
   gitFs,
   localDir,
   includeForks,
+  renovateUsername,
 }) {
   logger.debug(`initRepo("${repository}")`);
-  const opts = hostRules.find({ platform: 'github' }, { token, endpoint });
-  if (!opts.token) {
-    throw new Error(`No token found for GitHub repository ${repository}`);
-  }
-  hostRules.update({ ...opts, platform: 'github', default: true });
-  logger.info('Authenticated as user: ' + (await getRenovateUsername()));
+  logger.info('Authenticated as user: ' + renovateUsername);
   logger.info('Using renovate version: ' + global.renovateVersion);
   // config is used by the platform api itself, not necessary for the app layer to know
   cleanRepo();
-  config.isGhe = endpoint && !endpoint.startsWith('https://api.github.com');
+  const opts = hostRules.find({
+    platform: 'github',
+  });
+  config.isGhe =
+    opts.endpoint && !opts.endpoint.startsWith('https://api.github.com');
+  config.renovateUsername = renovateUsername;
   config.localDir = localDir;
   config.platform = 'github';
   config.repository = repository;
@@ -597,10 +605,10 @@ async function setBranchStatus(
 async function getIssueList() {
   if (!config.issueList) {
     logger.debug('Retrieving issueList');
-    const renovateUsername = await getRenovateUsername();
     const res = await get(
-      `repos/${config.parentRepo ||
-        config.repository}/issues?creator=${renovateUsername}&state=all&per_page=100&sort=created&direction=asc`,
+      `repos/${config.parentRepo || config.repository}/issues?creator=${
+        config.renovateUsername
+      }&state=all&per_page=100&sort=created&direction=asc`,
       { paginate: 'all', useCache: false }
     );
     // istanbul ignore if
diff --git a/lib/platform/gitlab/gl-got-wrapper.js b/lib/platform/gitlab/gl-got-wrapper.js
index c6d159639dbde2e7bb57479775be0fd997abe91e..9d4a90add78a8aa7b726edd716f682a7fc407560 100644
--- a/lib/platform/gitlab/gl-got-wrapper.js
+++ b/lib/platform/gitlab/gl-got-wrapper.js
@@ -6,16 +6,17 @@ const parseLinkHeader = require('parse-link-header');
 const hostRules = require('../../util/host-rules');
 
 let cache = {};
+let endpoint = 'https://gitlab.com/api/v4/';
 
 async function get(path, options, retries = 5) {
-  const { host } = URL.parse(path);
+  const host = URL.parse(path).host || URL.parse(endpoint).host;
   const opts = {
     // TODO: Move to configurable host rules, or use utils/got
     timeout: 60 * 1000,
     ...hostRules.find({ platform: 'gitlab', host }),
     ...options,
   };
-  opts.baseUrl = opts.endpoint;
+  const url = URL.resolve(endpoint, path);
   delete opts.endpoint;
   const method = opts.method || 'get';
   const useCache = opts.useCache || true;
@@ -25,7 +26,7 @@ async function get(path, options, retries = 5) {
   }
   logger.debug({ path }, method.toUpperCase());
   try {
-    const res = await glGot(path, opts);
+    const res = await glGot(url, opts);
     if (opts.paginate) {
       // Check if result is paginated
       try {
@@ -68,4 +69,8 @@ get.reset = function reset() {
   cache = {};
 };
 
+get.setEndpoint = e => {
+  endpoint = e;
+};
+
 module.exports = get;
diff --git a/lib/platform/gitlab/index.js b/lib/platform/gitlab/index.js
index 1b1bf3edde4141ddabb237ebc32d87c3f5e6cd63..837efc11b080146ec21d58f9993ce8493f667971 100644
--- a/lib/platform/gitlab/index.js
+++ b/lib/platform/gitlab/index.js
@@ -6,8 +6,13 @@ const hostRules = require('../../util/host-rules');
 const GitStorage = require('../git/storage');
 
 let config = {};
+const defaults = {
+  platform: 'gitlab',
+  endpoint: 'https://gitlab.com/api/v4/',
+};
 
 module.exports = {
+  initPlatform,
   getRepos,
   cleanRepo,
   initRepo,
@@ -57,15 +62,26 @@ module.exports = {
   getVulnerabilityAlerts,
 };
 
+function initPlatform({ endpoint, token }) {
+  if (!token) {
+    throw new Error('Init: You must configure a GitLab personal access token');
+  }
+  const res = {};
+  if (endpoint) {
+    res.endpoint = endpoint.replace(/\/?$/, '/'); // always add a trailing slash
+    get.setEndpoint(res.endpoint);
+    defaults.endpoint = res.endpoint;
+  } else {
+    logger.info('Using default GitLab endpoint: ' + res.endpoint);
+    res.endpoint = defaults.endpoint;
+  }
+  // TODO: Add a connection check that endpoint/token combination are valid
+  return res;
+}
+
 // Get all repositories that the user has access to
-async function getRepos(token, endpoint) {
+async function getRepos() {
   logger.info('Autodiscovering GitLab repositories');
-  logger.debug('getRepos(token, endpoint)');
-  const opts = hostRules.find({ platform: 'gitlab' }, { token, endpoint });
-  if (!opts.token) {
-    throw new Error('No token found for getRepos');
-  }
-  hostRules.update({ ...opts, platform: 'gitlab', default: true });
   try {
     const url = `projects?membership=true&per_page=100`;
     const res = await get(url, { paginate: true });
@@ -92,12 +108,7 @@ function cleanRepo() {
 }
 
 // Initialize GitLab by getting base branch
-async function initRepo({ repository, token, endpoint, gitFs, localDir }) {
-  const opts = hostRules.find({ platform: 'gitlab' }, { token, endpoint });
-  if (!opts.token) {
-    throw new Error(`No token found for GitLab repository ${repository}`);
-  }
-  hostRules.update({ ...opts, platform: 'gitlab', default: true });
+async function initRepo({ repository, gitFs, localDir }) {
   config = {};
   get.reset();
   config.repository = urlEscape(repository);
@@ -126,14 +137,15 @@ async function initRepo({ repository, token, endpoint, gitFs, localDir }) {
     delete config.prList;
     // Always gitFs
     logger.debug('Enabling Git FS');
-    const { hostname, protocol } = URL.parse(
-      opts.endpoint || 'https://gitlab.com'
-    );
-    const detectedGitFs = protocol.substring(0, protocol.length - 1); // strip the trailing ':'
+    const { host, protocol } = URL.parse(defaults.endpoint);
+    const opts = hostRules.find({
+      platform: 'gitlab',
+      host,
+    });
     const url = GitStorage.getUrl({
-      gitFs: gitFs || detectedGitFs,
+      gitFs: protocol.slice(0, -1),
       auth: 'oauth2:' + opts.token,
-      hostname,
+      host,
       repository,
     });
     config.storage = new GitStorage();
diff --git a/lib/platform/index.js b/lib/platform/index.js
index 8789f40864635ed355edc74352f4aa6e631a86c1..aca02a1a3c1ff5ae813c5a16500c288cb01e90a4 100644
--- a/lib/platform/index.js
+++ b/lib/platform/index.js
@@ -1,22 +1,56 @@
+const hostRules = require('../util/host-rules');
+
 /* eslint-disable global-require */
 const platforms = new Map([
+  ['azure', require('./azure')],
   ['bitbucket', require('./bitbucket')],
   ['bitbucket-server', require('./bitbucket-server')],
   ['github', require('./github')],
   ['gitlab', require('./gitlab')],
-  ['azure', require('./azure')],
 ]);
 /* eslint-enable global-require */
 
-function getPlatformApi(platform) {
-  return platforms.get(platform);
+function setPlatformApi(platform) {
+  global.platform = platforms.get(platform);
 }
 
-function initPlatform(platform) {
-  global.platform = getPlatformApi(platform);
+async function initPlatform(config) {
+  setPlatformApi(config.platform);
+  if (!global.platform) {
+    const supportedPlatforms = [...platforms.keys()].join(', ');
+    throw new Error(
+      `Init: Platform "${
+        config.platform
+      }" not found. Must be one of: ${supportedPlatforms}`
+    );
+  }
+  const platformInfo = await global.platform.initPlatform(config);
+  const returnConfig = { ...config, ...platformInfo };
+  let token = config.token;
+  if (
+    config.platform.startsWith('bitbucket') &&
+    config.username &&
+    config.password
+  ) {
+    logger.debug('Generating Bitbucket token from username:password');
+    const base64 = str => Buffer.from(str, 'binary').toString('base64');
+    token = base64(`${config.username}:${config.password}`);
+  }
+  const platformRule = {
+    platform: returnConfig.platform,
+    endpoint: returnConfig.endpoint,
+    token,
+    username: returnConfig.username,
+    password: returnConfig.password,
+  };
+  hostRules.update(platformRule);
+  delete returnConfig.token;
+  delete returnConfig.username;
+  delete returnConfig.password;
+  return returnConfig;
 }
 
 module.exports = {
   initPlatform,
-  getPlatformApi,
+  setPlatformApi,
 };
diff --git a/lib/util/host-rules.ts b/lib/util/host-rules.ts
index 11140d7e85f84f81ab53b5f7b660dca02c3e562f..1438ae6f74d7ff6650a3555591e044cef3136dbb 100644
--- a/lib/util/host-rules.ts
+++ b/lib/util/host-rules.ts
@@ -1,13 +1,5 @@
 import URL from 'url';
 
-export const defaults: IDict<IPlatformConfig> = {
-  bitbucket: { name: 'Bitbucket', endpoint: 'https://api.bitbucket.org/' },
-  'bitbucket-server': { name: 'Bitbucket Server' },
-  github: { name: 'GitHub', endpoint: 'https://api.github.com/' },
-  gitlab: { name: 'GitLab', endpoint: 'https://gitlab.com/api/v4/' },
-  azure: { name: 'Azure DevOps' },
-};
-
 //TODO: add known properties
 interface IPlatformConfig {
   [prop: string]: any;
@@ -32,7 +24,7 @@ export function update(params: IPlatformConfig) {
       'Failed to set configuration: no platform or endpoint specified'
     );
   }
-  const config = { ...defaults[platform], ...params };
+  const config = { ...params };
   const { endpoint } = config;
   if (!endpoint) {
     // istanbul ignore if
@@ -56,11 +48,6 @@ export function update(params: IPlatformConfig) {
     );
   }
   platforms[platform] = { ...platforms[platform] };
-  if (config.default) {
-    for (const conf of Object.values(platforms[platform])) {
-      delete conf.default;
-    }
-  }
   logger.debug({ config }, 'Setting hostRule');
   platforms[platform][host] = { ...platforms[platform][host], ...config };
   return true;
@@ -96,8 +83,8 @@ export function find(
     return merge(platforms[platform][massagedHost], overrides);
   }
   const configs = Object.values(platforms[platform]);
-  let config = configs.find(c => c.default);
-  if (!config && configs.length === 1) {
+  let config;
+  if (configs.length === 1) {
     [config] = configs;
   }
   return merge(config, overrides);
diff --git a/lib/workers/global/autodiscover.js b/lib/workers/global/autodiscover.js
index 92eaf2d0208bc3664d27c40e40791e825cc4e136..a07796dac0c9f4baf0cd64a4b5dc0ebafcc73a63 100644
--- a/lib/workers/global/autodiscover.js
+++ b/lib/workers/global/autodiscover.js
@@ -1,7 +1,5 @@
 const is = require('@sindresorhus/is');
 const minimatch = require('minimatch');
-const { getPlatformApi } = require('../../platform');
-const hostRules = require('../../util/host-rules');
 
 module.exports = {
   autodiscoverRepositories,
@@ -11,12 +9,8 @@ async function autodiscoverRepositories(config) {
   if (!config.autodiscover) {
     return config;
   }
-  const credentials = hostRules.find(config, {});
   // Autodiscover list of repositories
-  let discovered = await getPlatformApi(config.platform).getRepos(
-    credentials.token,
-    credentials.endpoint
-  );
+  let discovered = await platform.getRepos();
   if (!(discovered && discovered.length)) {
     // Soft fail (no error thrown) if no accessible repositories
     logger.info(
diff --git a/lib/workers/global/index.js b/lib/workers/global/index.js
index 0f2517f9569e390c91df004df85b0ded86be3119..573518a0372c474397f1556afbf200422b2411e5 100644
--- a/lib/workers/global/index.js
+++ b/lib/workers/global/index.js
@@ -9,6 +9,7 @@ const cache = require('./cache');
 const { appName } = require('../../config/app-strings');
 const { autodiscoverRepositories } = require('./autodiscover');
 const { setMeta } = require('./meta');
+const { initPlatform } = require('../../platform');
 
 module.exports = {
   start,
@@ -20,6 +21,7 @@ async function start() {
   try {
     cache.init(os.tmpdir());
     let config = await configParser.parseConfigs(process.env, process.argv);
+    config = await initPlatform(config);
     config = await setDirectories(config);
     setMeta(config);
     config = await autodiscoverRepositories(config);
@@ -66,7 +68,11 @@ async function start() {
     logger.setMeta({});
     logger.info(`${appName} finished`);
   } catch (err) /* istanbul ignore next */ {
-    logger.fatal({ err }, `Fatal error: ${err.message}`);
+    if (err.message.startsWith('Init: ')) {
+      logger.fatal(err.message.substring(6));
+    } else {
+      logger.fatal({ err }, `Fatal error: ${err.message}`);
+    }
   }
 }
 
diff --git a/lib/workers/repository/init/apis.js b/lib/workers/repository/init/apis.js
index 2e06f5d85fd46cbe27c597a2d1327ec05b06868f..149cb6cf6b79a63e17a076f1a01485271954f21d 100644
--- a/lib/workers/repository/init/apis.js
+++ b/lib/workers/repository/init/apis.js
@@ -1,12 +1,5 @@
-const { initPlatform } = require('../../../platform');
 const npmApi = require('../../../datasource/npm');
 
-function assignPlatform(config) {
-  logger.trace('assignPlatform');
-  initPlatform(config.platform);
-  return config;
-}
-
 async function getPlatformConfig(config) {
   const platformConfig = await platform.initRepo(config);
   return {
@@ -17,7 +10,6 @@ async function getPlatformConfig(config) {
 
 async function initApis(input) {
   let config = { ...input };
-  config = await assignPlatform(config);
   config = await getPlatformConfig(config);
   npmApi.resetMemCache();
   npmApi.setNpmrc(config.npmrc);
diff --git a/test/config/index.spec.js b/test/config/index.spec.js
index e2a845480515a7efbea4f74d208c7a63da7e1657..dd31c9919ceee41cf85bc1dc4f66c4eb5a7c47c0 100644
--- a/test/config/index.spec.js
+++ b/test/config/index.spec.js
@@ -21,41 +21,6 @@ describe('config/index', () => {
       jest.mock('delay');
       require('delay').mockImplementation(() => Promise.resolve());
     });
-    it('throws for invalid platform', async () => {
-      const env = {};
-      defaultArgv.push('--platform=foo');
-      await expect(configParser.parseConfigs(env, defaultArgv)).rejects.toThrow(
-        Error('Unsupported platform: foo.')
-      );
-    });
-    it('throws for no GitHub token', async () => {
-      const env = { RENOVATE_CONFIG_FILE: '/tmp/does-not-exist' };
-      await expect(configParser.parseConfigs(env, defaultArgv)).rejects.toThrow(
-        Error(
-          'No authentication found for platform https://api.github.com/ (github)'
-        )
-      );
-    });
-    it('throws for no GitLab token', async () => {
-      const env = {
-        RENOVATE_CONFIG_FILE: '/tmp/does-not-exist',
-        RENOVATE_PLATFORM: 'gitlab',
-      };
-      await expect(configParser.parseConfigs(env, defaultArgv)).rejects.toThrow(
-        Error(
-          'No authentication found for platform https://gitlab.com/api/v4/ (gitlab)'
-        )
-      );
-    });
-    it('throws for no Azure DevOps token', async () => {
-      const env = {
-        RENOVATE_CONFIG_FILE: '/tmp/does-not-exist',
-        RENOVATE_PLATFORM: 'azure',
-      };
-      await expect(configParser.parseConfigs(env, defaultArgv)).rejects.toThrow(
-        Error('No authentication found for platform undefined (azure)')
-      );
-    });
     it('supports token in env', async () => {
       const env = { RENOVATE_TOKEN: 'abc' };
       await configParser.parseConfigs(env, defaultArgv);
diff --git a/test/globals.js b/test/globals.js
index f4d7f1205d407e54bd1dddc6aa8c9ac5bfe27946..c86469b8b22ce301d6793f8c553075f3e0ae22fb 100644
--- a/test/globals.js
+++ b/test/globals.js
@@ -9,7 +9,6 @@ const cache = require('../lib/workers/global/cache');
 global.platform = jest.genMockFromModule('../lib/platform/github');
 global.logger = require('./logger/_fixtures');
 
-global.renovateUsername = 'renovate-testing';
 global.repoCache = {};
 
 const tmpDir = process.env.RENOVATE_TMPDIR || process.env.TMPDIR || os.tmpdir();
diff --git a/test/platform/__snapshots__/index.spec.js.snap b/test/platform/__snapshots__/index.spec.js.snap
index 76d576aa4b801ca4a391a14a23d08d1b73a86cea..0eec1c8943c34ef3b54efb04e437f15c57e5d193 100644
--- a/test/platform/__snapshots__/index.spec.js.snap
+++ b/test/platform/__snapshots__/index.spec.js.snap
@@ -2,6 +2,7 @@
 
 exports[`platform has a list of supported methods for azure 1`] = `
 Array [
+  "initPlatform",
   "getRepos",
   "cleanRepo",
   "initRepo",
@@ -46,6 +47,7 @@ Array [
 
 exports[`platform has a list of supported methods for github 1`] = `
 Array [
+  "initPlatform",
   "getRepos",
   "cleanRepo",
   "initRepo",
@@ -90,6 +92,7 @@ Array [
 
 exports[`platform has a list of supported methods for gitlab 1`] = `
 Array [
+  "initPlatform",
   "getRepos",
   "cleanRepo",
   "initRepo",
@@ -131,3 +134,10 @@ Array [
   "getVulnerabilityAlerts",
 ]
 `;
+
+exports[`platform initializes 1`] = `
+Object {
+  "endpoint": "https://api.bitbucket.org/",
+  "platform": "bitbucket",
+}
+`;
diff --git a/test/platform/azure/__snapshots__/azure-got-wrapper.spec.js.snap b/test/platform/azure/__snapshots__/azure-got-wrapper.spec.js.snap
index 6dfbb9a3b3dba0a7907394e332747812b9d087e3..5a6987453c3f3f1a70136c46c1d4195db284cc34 100644
--- a/test/platform/azure/__snapshots__/azure-got-wrapper.spec.js.snap
+++ b/test/platform/azure/__snapshots__/azure-got-wrapper.spec.js.snap
@@ -3,7 +3,7 @@
 exports[`platform/azure/azure-got-wrapper gitApi should set token and endpoint 1`] = `
 WebApi {
   "authHandler": PersonalAccessTokenCredentialHandler {
-    "token": "myToken",
+    "token": "token",
   },
   "isNoProxyHost": [Function],
   "options": Object {
@@ -23,7 +23,7 @@ WebApi {
       "_socketTimeout": undefined,
       "handlers": Array [
         PersonalAccessTokenCredentialHandler {
-          "token": "myToken",
+          "token": "token",
         },
       ],
       "requestOptions": Object {
@@ -31,12 +31,12 @@ WebApi {
       },
     },
   },
-  "serverUrl": "myEndpoint/",
+  "serverUrl": "https://dev.azure.com/renovate12345",
   "vsoClient": VsoClient {
     "_initializationPromise": Promise {},
     "_locationsByAreaPromises": Object {},
-    "basePath": "myEndpoint/",
-    "baseUrl": "myEndpoint/",
+    "basePath": "/renovate12345",
+    "baseUrl": "https://dev.azure.com/renovate12345",
     "restClient": RestClient {
       "client": HttpClient {
         "_allowRedirects": true,
@@ -51,7 +51,7 @@ WebApi {
         "_socketTimeout": undefined,
         "handlers": Array [
           PersonalAccessTokenCredentialHandler {
-            "token": "myToken",
+            "token": "token",
           },
         ],
         "requestOptions": Object {
diff --git a/test/platform/azure/__snapshots__/index.spec.js.snap b/test/platform/azure/__snapshots__/index.spec.js.snap
index a900a51278ff2b6f1abdd23ca99d79b3eb66119a..22cc6cb3c6b2d74e258ff302c0ba008412ad7834 100644
--- a/test/platform/azure/__snapshots__/index.spec.js.snap
+++ b/test/platform/azure/__snapshots__/index.spec.js.snap
@@ -120,6 +120,12 @@ Array [
 ]
 `;
 
+exports[`platform/azure initPlatform() should init 1`] = `
+Object {
+  "endpoint": "https://dev.azure.com/renovate12345/",
+}
+`;
+
 exports[`platform/azure initRepo should initialise the config for a repo 1`] = `
 Array [
   Array [],
diff --git a/test/platform/azure/azure-got-wrapper.spec.js b/test/platform/azure/azure-got-wrapper.spec.js
index 7511e4444dcb33cf7f0cd7524f6233abe8588af7..6e414c202244e3c96cac0031447ae5262a2fb7a3 100644
--- a/test/platform/azure/azure-got-wrapper.spec.js
+++ b/test/platform/azure/azure-got-wrapper.spec.js
@@ -16,9 +16,10 @@ describe('platform/azure/azure-got-wrapper', () => {
     it('should set token and endpoint', async () => {
       hostRules.update({
         platform: 'azure',
-        token: 'myToken',
-        endpoint: 'myEndpoint',
+        token: 'token',
+        endpoint: 'https://dev.azure.com/renovate12345',
       });
+      azure.setEndpoint('https://dev.azure.com/renovate12345');
       const res = await azure.azureObj();
 
       delete res.rest.client.userAgent;
diff --git a/test/platform/azure/index.spec.js b/test/platform/azure/index.spec.js
index 5c8b113976299769a8aa5478bfaec3e71a4d4158..3e94594586686f321c2c393d5f69c97eb3735bac 100644
--- a/test/platform/azure/index.spec.js
+++ b/test/platform/azure/index.spec.js
@@ -10,6 +10,7 @@ describe('platform/azure', () => {
     jest.mock('../../../lib/platform/azure/azure-got-wrapper');
     jest.mock('../../../lib/platform/azure/azure-helper');
     jest.mock('../../../lib/platform/git/storage');
+    jest.mock('../../../lib/util/host-rules');
     hostRules = require('../../../lib/util/host-rules');
     azure = require('../../../lib/platform/azure');
     azureApi = require('../../../lib/platform/azure/azure-got-wrapper');
@@ -31,11 +32,11 @@ describe('platform/azure', () => {
       deleteBranch: jest.fn(),
       getRepoStatus: jest.fn(),
     }));
-
-    // clean up hostRules
-    hostRules.clear();
-    hostRules.update({
-      platform: 'azure',
+    hostRules.find.mockReturnValue({
+      endpoint: 'https://dev.azure.com/renovate12345',
+      token: 'token',
+    });
+    azure.initPlatform({
       endpoint: 'https://dev.azure.com/renovate12345',
       token: 'token',
     });
@@ -65,6 +66,27 @@ describe('platform/azure', () => {
     return azure.getRepos(token, endpoint);
   }
 
+  describe('initPlatform()', () => {
+    it('should throw if no endpoint', () => {
+      expect(() => {
+        azure.initPlatform({});
+      }).toThrow();
+    });
+    it('should throw if no token', () => {
+      expect(() => {
+        azure.initPlatform({ endpoint: 'https://dev.azure.com/renovate12345' });
+      }).toThrow();
+    });
+    it('should init', () => {
+      expect(
+        azure.initPlatform({
+          endpoint: 'https://dev.azure.com/renovate12345',
+          token: 'token',
+        })
+      ).toMatchSnapshot();
+    });
+  });
+
   describe('getRepos()', () => {
     it('should return an array of repos', async () => {
       const repos = await getRepos(
diff --git a/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap b/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
index 85a2d813778e4bac3e834293379dbc8becfbad98..5a01392c476ca178d2dc22df7a97bdfa192fed19 100644
--- a/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
+++ b/test/platform/bitbucket-server/__snapshots__/index.spec.js.snap
@@ -916,6 +916,12 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server endpoint with no path init function should init 1`] = `
+Object {
+  "endpoint": "https://stash.renovatebot.com/",
+}
+`;
+
 exports[`platform/bitbucket-server endpoint with no path initRepo() no author 1`] = `
 Object {
   "isFork": false,
@@ -2288,6 +2294,12 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket-server endpoint with path init function should init 1`] = `
+Object {
+  "endpoint": "https://stash.renovatebot.com/",
+}
+`;
+
 exports[`platform/bitbucket-server endpoint with path initRepo() no author 1`] = `
 Object {
   "isFork": false,
diff --git a/test/platform/bitbucket-server/index.spec.js b/test/platform/bitbucket-server/index.spec.js
index 4b6f806d7468a2976bcf6ff6e677d61ac6cf5cfc..8c4bf7cd7e07f9202d0634d4c1c3e6622f3d7678 100644
--- a/test/platform/bitbucket-server/index.spec.js
+++ b/test/platform/bitbucket-server/index.spec.js
@@ -23,6 +23,7 @@ describe('platform/bitbucket-server', () => {
           return Promise.resolve({ body });
         });
         jest.mock('../../../lib/platform/git/storage');
+        jest.mock('../../../lib/util/host-rules');
         hostRules = require('../../../lib/util/host-rules');
         api = require('../../../lib/platform/bitbucket-server/bb-got-wrapper');
         jest.spyOn(api, 'get');
@@ -50,15 +51,20 @@ describe('platform/bitbucket-server', () => {
             () => '0d9c7726c3d628b7e28af234595cfd20febdbf8e'
           ),
         }));
-
-        // clean up hostRules
-        hostRules.clear();
-        hostRules.update({
+        const endpoint =
+          scenarioName === 'endpoint with path'
+            ? 'https://stash.renovatebot.com/vcs/'
+            : 'https://stash.renovatebot.com';
+        hostRules.find.mockReturnValue({
           platform: 'bitbucket-server',
-          token: 'token',
-          username: 'username',
-          password: 'password',
-          endpoint: mockResponses.baseURL,
+          endpoint,
+          username: 'abc',
+          password: '123',
+        });
+        bitbucket.initPlatform({
+          endpoint,
+          username: 'abc',
+          password: '123',
         });
       });
 
@@ -73,6 +79,28 @@ describe('platform/bitbucket-server', () => {
         });
       }
 
+      describe('init function', () => {
+        it('should throw if no endpoint', () => {
+          expect(() => {
+            bitbucket.initPlatform({});
+          }).toThrow();
+        });
+        it('should throw if no username/password', () => {
+          expect(() => {
+            bitbucket.initPlatform({ endpoint: 'endpoint' });
+          }).toThrow();
+        });
+        it('should init', () => {
+          expect(
+            bitbucket.initPlatform({
+              endpoint: 'https://stash.renovatebot.com',
+              username: 'abc',
+              password: '123',
+            })
+          ).toMatchSnapshot();
+        });
+      });
+
       describe('getRepos()', () => {
         it('returns repos', async () => {
           expect.assertions(2);
diff --git a/test/platform/bitbucket/__snapshots__/index.spec.js.snap b/test/platform/bitbucket/__snapshots__/index.spec.js.snap
index 21421c6e37661517193f3fb4442b2ad1186208ee..ccd53af46f697368973883826496f8b39348129e 100644
--- a/test/platform/bitbucket/__snapshots__/index.spec.js.snap
+++ b/test/platform/bitbucket/__snapshots__/index.spec.js.snap
@@ -184,6 +184,12 @@ Array [
 ]
 `;
 
+exports[`platform/bitbucket initPlatform() should init 1`] = `
+Object {
+  "endpoint": "https://api.bitbucket.org/",
+}
+`;
+
 exports[`platform/bitbucket initRepo() works 1`] = `
 Object {
   "isFork": false,
diff --git a/test/platform/bitbucket/bb-got-wrapper.spec.js b/test/platform/bitbucket/bb-got-wrapper.spec.js
index 3a505f6ab65e417b8ac57d31958bfc501a79a81c..4ece1cfc8af06159a7ec1dd8f9884bcd6602db2d 100644
--- a/test/platform/bitbucket/bb-got-wrapper.spec.js
+++ b/test/platform/bitbucket/bb-got-wrapper.spec.js
@@ -14,6 +14,7 @@ describe('platform/gl-got-wrapper', () => {
     hostRules.clear();
     hostRules.update({
       platform: 'bitbucket',
+      endpoint: 'https://api.bitbucket.org',
       token: 'token',
     });
   });
diff --git a/test/platform/bitbucket/index.spec.js b/test/platform/bitbucket/index.spec.js
index 18f60675386b716089ca2e90af6c436d67b8ea4c..45fee17d180dcc4f2085665725f3613cf63ca7ac 100644
--- a/test/platform/bitbucket/index.spec.js
+++ b/test/platform/bitbucket/index.spec.js
@@ -11,6 +11,7 @@ describe('platform/bitbucket', () => {
     jest.resetModules();
     jest.mock('../../../lib/platform/bitbucket/bb-got-wrapper');
     jest.mock('../../../lib/platform/git/storage');
+    jest.mock('../../../lib/util/host-rules');
     hostRules = require('../../../lib/util/host-rules');
     api = require('../../../lib/platform/bitbucket/bb-got-wrapper');
     bitbucket = require('../../../lib/platform/bitbucket');
@@ -34,11 +35,11 @@ describe('platform/bitbucket', () => {
 
     // clean up hostRules
     hostRules.clear();
-    hostRules.update({
+    hostRules.find.mockReturnValue({
       platform: 'bitbucket',
-      token: 'token',
-      username: 'username',
-      password: 'password',
+      endpoint: 'https://bitbucket.org',
+      username: 'abc',
+      password: '123',
     });
   });
 
@@ -76,6 +77,31 @@ describe('platform/bitbucket', () => {
     );
   }
 
+  describe('initPlatform()', () => {
+    it('should throw if no username/password', () => {
+      expect(() => {
+        bitbucket.initPlatform({});
+      }).toThrow();
+    });
+    it('should throw if wrong endpoint', () => {
+      expect(() => {
+        bitbucket.initPlatform({
+          endpoint: 'endpoint',
+          username: 'abc',
+          password: '123',
+        });
+      }).toThrow();
+    });
+    it('should init', () => {
+      expect(
+        bitbucket.initPlatform({
+          username: 'abc',
+          password: '123',
+        })
+      ).toMatchSnapshot();
+    });
+  });
+
   describe('getRepos()', () => {
     it('returns repos', async () => {
       api.get.mockReturnValueOnce({
diff --git a/test/platform/github/__snapshots__/index.spec.js.snap b/test/platform/github/__snapshots__/index.spec.js.snap
index 7bc47397bbb348467b4f5ae7c3116cf8b6a2a74f..0b903b4eca8c0b24b5baff4b4da1fac47e00a6f1 100644
--- a/test/platform/github/__snapshots__/index.spec.js.snap
+++ b/test/platform/github/__snapshots__/index.spec.js.snap
@@ -471,70 +471,21 @@ Array [
 ]
 `;
 
-exports[`platform/github getRepos should support a custom endpoint 1`] = `
-Array [
-  Array [
-    "user/repos?per_page=100",
-    Object {
-      "paginate": true,
-    },
-  ],
-]
-`;
-
-exports[`platform/github getRepos should support a custom endpoint 2`] = `
-Array [
-  "a/b",
-  "c/d",
-]
-`;
-
-exports[`platform/github initRepo should forks when forkMode 1`] = `
+exports[`platform/github initPlatform() should support custom endpoint 1`] = `
 Object {
-  "isFork": false,
-  "privateRepo": false,
+  "endpoint": "https://ghe.renovatebot.com/",
+  "renovateUsername": "renovate-bot",
 }
 `;
 
-exports[`platform/github initRepo should initialise the config for the repo - 0 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-  ],
-]
-`;
-
-exports[`platform/github initRepo should initialise the config for the repo - 0 2`] = `
-Object {
-  "isFork": false,
-  "privateRepo": false,
-}
-`;
-
-exports[`platform/github initRepo should initialise the config for the repo - 1 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-  ],
-]
-`;
-
-exports[`platform/github initRepo should initialise the config for the repo - 1 2`] = `
+exports[`platform/github initPlatform() should support default endpoint 1`] = `
 Object {
-  "isFork": false,
-  "privateRepo": false,
+  "endpoint": "https://api.github.com/",
+  "renovateUsername": "renovate-bot",
 }
 `;
 
-exports[`platform/github initRepo should initialise the config for the repo - 2 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-  ],
-]
-`;
-
-exports[`platform/github initRepo should initialise the config for the repo - 2 2`] = `
+exports[`platform/github initRepo should forks when forkMode 1`] = `
 Object {
   "isFork": false,
   "privateRepo": false,
diff --git a/test/platform/github/gh-got-wrapper.spec.js b/test/platform/github/gh-got-wrapper.spec.js
index 09c7cc049dd01ee5e61e6d2dd92c8dbb2d7069de..85bf26650cd17a008f6c08c2bf98ae379803c451 100644
--- a/test/platform/github/gh-got-wrapper.spec.js
+++ b/test/platform/github/gh-got-wrapper.spec.js
@@ -24,13 +24,11 @@ describe('platform/gh-got-wrapper', () => {
     ghGot.mockImplementationOnce(() => ({
       body: '{"data":{',
     }));
+    get.setEndpoint('https://ghe.mycompany.com/api/v3/');
     await get.post('graphql', {
-      endpoint: 'https://ghe.mycompany.com/api/v3/',
       body: 'abc',
     });
-    expect(ghGot.mock.calls[0][1].baseUrl).toEqual(
-      'https://ghe.mycompany.com/api/'
-    );
+    expect(ghGot.mock.calls[0][0].includes('/v3')).toBe(false);
   });
   it('paginates', async () => {
     ghGot.mockReturnValueOnce({
diff --git a/test/platform/github/index.spec.js b/test/platform/github/index.spec.js
index bf1f3d1635f0c0de50ce1412ab1814707583ae04..76206b1133c53f0d3b412e476275b55cb2f50322 100644
--- a/test/platform/github/index.spec.js
+++ b/test/platform/github/index.spec.js
@@ -3,14 +3,22 @@ const fs = require('fs-extra');
 describe('platform/github', () => {
   let github;
   let get;
+  let hostRules;
   beforeEach(() => {
     // reset module
     jest.resetModules();
     jest.mock('delay');
     jest.mock('../../../lib/platform/github/gh-got-wrapper');
+    jest.mock('../../../lib/util/host-rules');
     get = require('../../../lib/platform/github/gh-got-wrapper');
     github = require('../../../lib/platform/github');
+    hostRules = require('../../../lib/util/host-rules');
     delete global.gitAuthor;
+    hostRules.find.mockReturnValue({
+      platform: 'github',
+      endpoint: 'https://api.github.com',
+      token: 'abc123',
+    });
   });
 
   const graphqlOpenPullRequests = fs.readFileSync(
@@ -37,19 +45,40 @@ describe('platform/github', () => {
     return github.getRepos(...args);
   }
 
-  describe('getRepos', () => {
-    it('should throw an error if no token is provided', async () => {
-      await expect(github.getRepos()).rejects.toThrow(
-        Error('No token found for getRepos')
-      );
+  describe('initPlatform()', () => {
+    it('should throw if no token', async () => {
+      await expect(github.initPlatform({})).rejects.toThrow();
     });
-    it('should return an array of repos', async () => {
-      const repos = await getRepos('sometoken');
-      expect(get.mock.calls).toMatchSnapshot();
-      expect(repos).toMatchSnapshot();
+    it('should throw if user failure', async () => {
+      get.mockImplementationOnce(() => ({}));
+      await expect(github.initPlatform({ token: 'abc123' })).rejects.toThrow();
+    });
+    it('should support default endpoint', async () => {
+      get.mockImplementationOnce(() => ({
+        body: {
+          login: 'renovate-bot',
+        },
+      }));
+      expect(await github.initPlatform({ token: 'abc123' })).toMatchSnapshot();
+    });
+    it('should support custom endpoint', async () => {
+      get.mockImplementationOnce(() => ({
+        body: {
+          login: 'renovate-bot',
+        },
+      }));
+      expect(
+        await github.initPlatform({
+          endpoint: 'https://ghe.renovatebot.com',
+          token: 'abc123',
+        })
+      ).toMatchSnapshot();
     });
-    it('should support a custom endpoint', async () => {
-      const repos = await getRepos('sometoken', 'someendpoint');
+  });
+
+  describe('getRepos', () => {
+    it('should return an array of repos', async () => {
+      const repos = await getRepos();
       expect(get.mock.calls).toMatchSnapshot();
       expect(repos).toMatchSnapshot();
     });
@@ -72,31 +101,6 @@ describe('platform/github', () => {
   }
 
   describe('initRepo', () => {
-    [
-      [undefined, 'mytoken', undefined],
-      [undefined, 'mytoken', 'https://my.custom.endpoint/'],
-      ['myenvtoken', 'myenvtoken', undefined],
-    ].forEach(([envToken, token, endpoint], i) => {
-      it(`should initialise the config for the repo - ${i}`, async () => {
-        if (envToken !== undefined) {
-          process.env.RENOVATE_TOKEN = envToken;
-        }
-        const config = await initRepo({
-          repository: 'some/repo',
-          token,
-          endpoint,
-        });
-        expect(get.mock.calls).toMatchSnapshot();
-        expect(config).toMatchSnapshot();
-      });
-    });
-    it('should throw an error if no token is provided', async () => {
-      await expect(
-        github.initRepo({ repository: 'some/repo' })
-      ).rejects.toThrow(
-        Error('No token found for GitHub repository some/repo')
-      );
-    });
     it('should rebase', async () => {
       function squashInitRepo(...args) {
         // repo info
@@ -115,7 +119,6 @@ describe('platform/github', () => {
       }
       const config = await squashInitRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       expect(config).toMatchSnapshot();
     });
@@ -153,8 +156,6 @@ describe('platform/github', () => {
       }
       const config = await forkInitRepo({
         repository: 'some/repo',
-        token: 'token',
-        endpoint: 'some-endpoint',
         forkMode: true,
       });
       expect(config).toMatchSnapshot();
@@ -197,8 +198,6 @@ describe('platform/github', () => {
       }
       const config = await forkInitRepo({
         repository: 'some/repo',
-        token: 'token',
-        endpoint: 'some-endpoint',
         forkMode: true,
       });
       expect(config).toMatchSnapshot();
@@ -221,7 +220,6 @@ describe('platform/github', () => {
       }
       const config = await mergeInitRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       expect(config).toMatchSnapshot();
     });
@@ -243,7 +241,6 @@ describe('platform/github', () => {
       }
       const config = await mergeInitRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       expect(config).toMatchSnapshot();
     });
@@ -262,7 +259,6 @@ describe('platform/github', () => {
       }
       const config = await mergeInitRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       expect(config).toMatchSnapshot();
     });
@@ -276,7 +272,6 @@ describe('platform/github', () => {
       await expect(
         github.initRepo({
           repository: 'some/repo',
-          token: 'token',
         })
       ).rejects.toThrow();
     });
@@ -289,7 +284,6 @@ describe('platform/github', () => {
       await expect(
         github.initRepo({
           repository: 'some/repo',
-          token: 'token',
         })
       ).rejects.toThrow();
     });
@@ -355,7 +349,6 @@ describe('platform/github', () => {
     it('sets the base branch', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -379,7 +372,6 @@ describe('platform/github', () => {
     beforeEach(async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
     });
     it('throws if error', async () => {
@@ -433,7 +425,6 @@ describe('platform/github', () => {
     it('should return true if the branch exists (one result)', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: [
@@ -450,7 +441,6 @@ describe('platform/github', () => {
     it('should return all renovate branches', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: [
@@ -473,7 +463,6 @@ describe('platform/github', () => {
     it('should return false if same SHA as master', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -505,7 +494,6 @@ describe('platform/github', () => {
     it('should return true if SHA different from master', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -539,7 +527,6 @@ describe('platform/github', () => {
     it('should return null if no PR exists', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: [],
@@ -550,7 +537,6 @@ describe('platform/github', () => {
     it('should return the PR object', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: [{ number: 91, head: {} }],
@@ -575,7 +561,6 @@ describe('platform/github', () => {
     it('returns success if requiredStatusChecks null', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       const res = await github.getBranchStatus('somebranch', null);
       expect(res).toEqual('success');
@@ -583,7 +568,6 @@ describe('platform/github', () => {
     it('return failed if unsupported requiredStatusChecks', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       const res = await github.getBranchStatus('somebranch', ['foo']);
       expect(res).toEqual('failed');
@@ -591,7 +575,6 @@ describe('platform/github', () => {
     it('should pass through success', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -604,7 +587,6 @@ describe('platform/github', () => {
     it('should pass through failed', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -617,7 +599,6 @@ describe('platform/github', () => {
     it('should fail if a check run has failed', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -650,7 +631,6 @@ describe('platform/github', () => {
     it('should suceed if no status and all passed check runs', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -683,7 +663,6 @@ describe('platform/github', () => {
     it('should fail if a check run has failed', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -717,7 +696,6 @@ describe('platform/github', () => {
     it('returns state if found', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -748,7 +726,6 @@ describe('platform/github', () => {
     it('returns null', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       // getBranchCommit
       get.mockImplementationOnce(() => ({
@@ -782,7 +759,6 @@ describe('platform/github', () => {
     it('returns if already set', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       // getBranchCommit
       get.mockImplementationOnce(() => ({
@@ -812,7 +788,6 @@ describe('platform/github', () => {
     it('sets branch status', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       // getBranchCommit
       get.mockImplementationOnce(() => ({
@@ -860,7 +835,6 @@ describe('platform/github', () => {
     it('should perform a branch merge', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -890,7 +864,6 @@ describe('platform/github', () => {
     it('should throw if branch merge throws', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -918,7 +891,6 @@ describe('platform/github', () => {
     it('should throw not ready', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       }); // getBranchCommit
       get.mockImplementationOnce(() => ({
         body: {
@@ -939,7 +911,6 @@ describe('platform/github', () => {
     it('should return a Date', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({
         body: [
@@ -958,7 +929,6 @@ describe('platform/github', () => {
     it('handles error', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({
         body: [],
@@ -1165,7 +1135,6 @@ describe('platform/github', () => {
     it('should delete the label', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       await github.deleteLabel(42, 'rebase');
       expect(get.delete.mock.calls).toMatchSnapshot();
@@ -1175,7 +1144,6 @@ describe('platform/github', () => {
     it('should add the given assignees to the issue', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       await github.addAssignees(42, ['someuser', 'someotheruser']);
       expect(get.post.mock.calls).toMatchSnapshot();
@@ -1185,7 +1153,6 @@ describe('platform/github', () => {
     it('should add the given reviewers to the PR', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.post.mockReturnValueOnce({});
       await github.addReviewers(42, ['someuser', 'someotheruser']);
@@ -1196,7 +1163,6 @@ describe('platform/github', () => {
     it('add comment if not found', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({ body: [] });
       await github.ensureComment(42, 'some-subject', 'some\ncontent');
@@ -1206,7 +1172,6 @@ describe('platform/github', () => {
     it('adds comment if found in closed PR list', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.post.mockImplementationOnce(() => ({
         body: graphqlClosedPullrequests,
@@ -1218,7 +1183,6 @@ describe('platform/github', () => {
     it('add updates comment if necessary', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({
         body: [{ id: 1234, body: '### some-subject\n\nblablabla' }],
@@ -1231,7 +1195,6 @@ describe('platform/github', () => {
     it('skips comment', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({
         body: [{ id: 1234, body: '### some-subject\n\nsome\ncontent' }],
@@ -1243,7 +1206,6 @@ describe('platform/github', () => {
     it('handles comment with no description', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockReturnValueOnce({ body: [{ id: 1234, body: '!merge' }] });
       await github.ensureComment(42, null, '!merge');
@@ -1376,7 +1338,6 @@ describe('platform/github', () => {
       };
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.post.mockImplementationOnce(() => ({
         body: graphqlOpenPullRequests,
@@ -1396,7 +1357,6 @@ describe('platform/github', () => {
     it('should return PR from closed graphql result', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.post.mockImplementationOnce(() => ({
         body: graphqlOpenPullRequests,
@@ -1568,7 +1528,6 @@ describe('platform/github', () => {
       };
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -1609,7 +1568,6 @@ describe('platform/github', () => {
       };
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
       get.mockImplementationOnce(() => ({
         body: {
@@ -1714,10 +1672,13 @@ describe('platform/github', () => {
       expect(github.getPrBody(input)).toMatchSnapshot();
     });
     it('returns not-updated pr body for GHE', async () => {
+      hostRules.find.mockReturnValue({
+        platform: 'github',
+        endpoint: 'https://github.company.com',
+        token: 'abc123',
+      });
       await initRepo({
         repository: 'some/repo',
-        token: 'some-token',
-        endpoint: 'https://github.company.com/api/v3/',
       });
       const input =
         'https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5)';
@@ -2031,7 +1992,6 @@ describe('platform/github', () => {
       };
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
       });
 
       // getBranchCommit
@@ -2160,7 +2120,6 @@ describe('platform/github', () => {
     it('returns commits messages', async () => {
       await initRepo({
         repository: 'some/repo',
-        token: 'token',
         gitAuthor: 'Renovate Bot <bot@renovatebot.com>',
       });
       get.mockReturnValueOnce({
diff --git a/test/platform/gitlab/__snapshots__/index.spec.js.snap b/test/platform/gitlab/__snapshots__/index.spec.js.snap
index 660f5722aa3b6040cf92b865e2133ee7a041b015..a1ecd052b401897b09aa0156b29b4f39ecd613ee 100644
--- a/test/platform/gitlab/__snapshots__/index.spec.js.snap
+++ b/test/platform/gitlab/__snapshots__/index.spec.js.snap
@@ -234,90 +234,22 @@ Array [
 ]
 `;
 
-exports[`platform/gitlab getRepos should support a custom endpoint 1`] = `
-Array [
-  Array [
-    "projects?membership=true&per_page=100",
-    Object {
-      "paginate": true,
-    },
-  ],
-]
-`;
-
-exports[`platform/gitlab getRepos should support a custom endpoint 2`] = `
-Array [
-  "a/b",
-  "c/d",
-]
-`;
-
-exports[`platform/gitlab initRepo should escape all forward slashes in project names 1`] = `
-Array [
-  Array [
-    "projects/some%2Frepo%2Fproject",
-  ],
-  Array [
-    "user",
-  ],
-]
-`;
-
-exports[`platform/gitlab initRepo should initialise the config for the repo - 0 1`] = `
-Array [
-  Array [
-    "projects/some%2Frepo",
-  ],
-  Array [
-    "user",
-  ],
-]
-`;
-
-exports[`platform/gitlab initRepo should initialise the config for the repo - 0 2`] = `
-Object {
-  "isFork": false,
-}
-`;
-
-exports[`platform/gitlab initRepo should initialise the config for the repo - 1 1`] = `
-Array [
-  Array [
-    "projects/some%2Frepo",
-  ],
-  Array [
-    "user",
-  ],
-]
-`;
-
-exports[`platform/gitlab initRepo should initialise the config for the repo - 1 2`] = `
+exports[`platform/gitlab initPlatform() should accept custom endpoint 1`] = `
 Object {
-  "isFork": false,
+  "endpoint": "https://gitlab.renovatebot.com/",
 }
 `;
 
-exports[`platform/gitlab initRepo should initialise the config for the repo - 2 1`] = `
-Array [
-  Array [
-    "projects/some%2Frepo",
-  ],
-  Array [
-    "user",
-  ],
-]
-`;
-
-exports[`platform/gitlab initRepo should initialise the config for the repo - 2 2`] = `
+exports[`platform/gitlab initPlatform() should default to gitlab.com 1`] = `
 Object {
-  "isFork": false,
+  "endpoint": "https://gitlab.com/api/v4/",
 }
 `;
 
-exports[`platform/gitlab initRepo should initialise the config for the repo - 3 1`] = `
+exports[`platform/gitlab initRepo should escape all forward slashes in project names 1`] = `
 Array [
   Array [
-    "projects/some%2Frepo",
+    "projects/some%2Frepo%2Fproject",
   ],
   Array [
     "user",
@@ -325,12 +257,6 @@ Array [
 ]
 `;
 
-exports[`platform/gitlab initRepo should initialise the config for the repo - 3 2`] = `
-Object {
-  "isFork": false,
-}
-`;
-
 exports[`platform/gitlab setBaseBranch(branchName) sets the base branch 1`] = `
 Array [
   Array [
diff --git a/test/platform/gitlab/gl-got-wrapper.spec.js b/test/platform/gitlab/gl-got-wrapper.spec.js
index 7a110d96c7268c6acff4a8a3c5a57b225be7b469..0941135bc5becdd5152e30e2630670b73e26ad9c 100644
--- a/test/platform/gitlab/gl-got-wrapper.spec.js
+++ b/test/platform/gitlab/gl-got-wrapper.spec.js
@@ -61,4 +61,7 @@ describe('platform/gl-got-wrapper', () => {
     const res2 = await get('projects/foo');
     expect(res1).toEqual(res2);
   });
+  it('sets endpoint', () => {
+    get.setEndpoint('https://gitlab.renovatebot.com/api/v4/');
+  });
 });
diff --git a/test/platform/gitlab/index.spec.js b/test/platform/gitlab/index.spec.js
index 45bc031f7350a279e5a9adedac1f126a717fec2a..d6cf7f3b105fb195d3f3e19c3e1e7231eedde445 100644
--- a/test/platform/gitlab/index.spec.js
+++ b/test/platform/gitlab/index.spec.js
@@ -1,18 +1,16 @@
-const hostRules = require('../../../lib/util/host-rules');
-
 describe('platform/gitlab', () => {
   let gitlab;
   let get;
+  let hostRules;
   let GitStorage;
   beforeEach(() => {
-    // clean up hostRules
-    hostRules.clear();
-
     // reset module
     jest.resetModules();
     jest.mock('../../../lib/platform/gitlab/gl-got-wrapper');
     gitlab = require('../../../lib/platform/gitlab');
     get = require('../../../lib/platform/gitlab/gl-got-wrapper');
+    jest.mock('../../../lib/util/host-rules');
+    hostRules = require('../../../lib/util/host-rules');
     jest.mock('../../../lib/platform/git/storage');
     GitStorage = require('../../../lib/platform/git/storage');
     GitStorage.mockImplementation(() => ({
@@ -34,12 +32,36 @@ describe('platform/gitlab', () => {
         () => '0d9c7726c3d628b7e28af234595cfd20febdbf8e'
       ),
     }));
+    hostRules.find.mockReturnValue({
+      platform: 'github',
+      endpoint: 'https://gitlab.com/v4/',
+      token: 'abc123',
+    });
   });
 
   afterEach(() => {
     gitlab.cleanRepo();
   });
 
+  describe('initPlatform()', () => {
+    it(`should throw if no token`, () => {
+      expect(() => {
+        gitlab.initPlatform({});
+      }).toThrow();
+    });
+    it(`should default to gitlab.com`, () => {
+      expect(gitlab.initPlatform({ token: 'some-token' })).toMatchSnapshot();
+    });
+    it(`should accept custom endpoint`, () => {
+      expect(
+        gitlab.initPlatform({
+          endpoint: 'https://gitlab.renovatebot.com',
+          token: 'some-token',
+        })
+      ).toMatchSnapshot();
+    });
+  });
+
   describe('getRepos', () => {
     function getRepos(...args) {
       // repo info
@@ -55,26 +77,14 @@ describe('platform/gitlab', () => {
       }));
       return gitlab.getRepos(...args);
     }
-    it('should throw an error if no token is provided', async () => {
-      await expect(gitlab.getRepos()).rejects.toThrow(
-        Error('No token found for getRepos')
-      );
-    });
     it('should throw an error if it receives an error', async () => {
       get.mockImplementation(() => {
         throw new Error('getRepos error');
       });
-      await expect(gitlab.getRepos('sometoken')).rejects.toThrow(
-        Error('getRepos error')
-      );
+      await expect(gitlab.getRepos()).rejects.toThrow(Error('getRepos error'));
     });
     it('should return an array of repos', async () => {
-      const repos = await getRepos('sometoken');
-      expect(get.mock.calls).toMatchSnapshot();
-      expect(repos).toMatchSnapshot();
-    });
-    it('should support a custom endpoint', async () => {
-      const repos = await getRepos('sometoken', 'someendpoint');
+      const repos = await getRepos();
       expect(get.mock.calls).toMatchSnapshot();
       expect(repos).toMatchSnapshot();
     });
@@ -124,39 +134,11 @@ describe('platform/gitlab', () => {
   }
 
   describe('initRepo', () => {
-    [
-      [undefined, 'mytoken', undefined],
-      [undefined, 'mytoken', 'https://my.custom.endpoint/'],
-      ['myenvtoken', 'myenvtoken', undefined],
-      [undefined, 'mytoken', undefined, 'Renovate Bot <bot@renovatebot.com>'],
-    ].forEach(([envToken, token, endpoint, gitAuthor], i) => {
-      it(`should initialise the config for the repo - ${i}`, async () => {
-        if (envToken !== undefined) {
-          process.env.RENOVATE_TOKEN = envToken;
-        }
-        get.mockReturnValue({ body: [] });
-        const config = await initRepo({
-          repository: 'some/repo',
-          token,
-          endpoint,
-          gitAuthor,
-        });
-        expect(get.mock.calls).toMatchSnapshot();
-        expect(config).toMatchSnapshot();
-      });
-    });
     it(`should escape all forward slashes in project names`, async () => {
       get.mockReturnValue({ body: [] });
       await initRepo({ repository: 'some/repo/project', token: 'some-token' });
       expect(get.mock.calls).toMatchSnapshot();
     });
-    it('should throw an error if no token is provided', async () => {
-      await expect(
-        gitlab.initRepo({ repository: 'some/repo' })
-      ).rejects.toThrow(
-        Error('No token found for GitLab repository some/repo')
-      );
-    });
     it('should throw an error if receiving an error', async () => {
       get.mockImplementation(() => {
         throw new Error('always error');
diff --git a/test/platform/index.spec.js b/test/platform/index.spec.js
index c64fc58ae063ab30135f959af8bfd9ff90d7264b..a0078fe096281c10f877587cd19ee09e05177466 100644
--- a/test/platform/index.spec.js
+++ b/test/platform/index.spec.js
@@ -4,7 +4,17 @@ const azure = require('../../lib/platform/azure');
 const bitbucket = require('../../lib/platform/bitbucket');
 const bitbucketServer = require('../../lib/platform/bitbucket-server');
 
+const platform = require('../../lib/platform');
+
 describe('platform', () => {
+  it('throws if wrong platform', async () => {
+    const config = { platform: 'wrong', username: 'abc', password: '123' };
+    await expect(platform.initPlatform(config)).rejects.toThrow();
+  });
+  it('initializes', async () => {
+    const config = { platform: 'bitbucket', username: 'abc', password: '123' };
+    expect(await platform.initPlatform(config)).toMatchSnapshot();
+  });
   it('has a list of supported methods for github', () => {
     const githubMethods = Object.keys(github);
     expect(githubMethods).toMatchSnapshot();
diff --git a/test/util/__snapshots__/host-rules.spec.js.snap b/test/util/__snapshots__/host-rules.spec.js.snap
index 6ba37df3be0fc4d3d253adff2aa407eef3fe9d76..03060ad866bc7e47e0d6bd1b49b0cf4ecfb81ef2 100644
--- a/test/util/__snapshots__/host-rules.spec.js.snap
+++ b/test/util/__snapshots__/host-rules.spec.js.snap
@@ -3,7 +3,6 @@
 exports[`util/host-rules find() allows overrides 1`] = `
 Object {
   "endpoint": "endpoint/",
-  "name": "GitHub",
   "other": "data",
   "platform": "github",
   "token": "secret",
@@ -59,23 +58,3 @@ Object {
   "username": "user1",
 }
 `;
-
-exports[`util/host-rules update() uses default endpoint 1`] = `
-Object {
-  "endpoint": "https://api.github.com/",
-  "name": "GitHub",
-  "other": "data",
-  "platform": "github",
-  "token": "token",
-}
-`;
-
-exports[`util/host-rules update() uses default endpoint 2`] = `
-Object {
-  "endpoint": "https://api.github.com/",
-  "name": "GitHub",
-  "other": "data",
-  "platform": "github",
-  "token": "token",
-}
-`;
diff --git a/test/util/host-rules.spec.js b/test/util/host-rules.spec.js
index eb3d772144cefb5e269c99c7da718a0b8b111ed4..1b9118711c588b3801c9504a39df6f9276abc27a 100644
--- a/test/util/host-rules.spec.js
+++ b/test/util/host-rules.spec.js
@@ -31,18 +31,6 @@ describe('util/host-rules', () => {
       });
       expect(find({ host: 'some.endpoint' })).toMatchSnapshot();
     });
-    it('uses default endpoint', () => {
-      update({
-        platform: 'github',
-        token: 'token',
-        other: 'data',
-      });
-      expect(find({ platform: 'github' })).toMatchSnapshot();
-      expect(
-        find({ platform: 'github', host: 'api.github.com' })
-      ).toMatchSnapshot();
-      expect(find({ platform: 'github', host: 'example.com' })).toBeNull();
-    });
   });
   describe('find()', () => {
     it('allows overrides', () => {
diff --git a/test/workers/global/autodiscover.spec.js b/test/workers/global/autodiscover.spec.js
index c123c2bca183ec52447df6c898d0e39b09930846..8d88e638a5fcfb05d18bbed2f942d70a7167d84d 100644
--- a/test/workers/global/autodiscover.spec.js
+++ b/test/workers/global/autodiscover.spec.js
@@ -1,15 +1,18 @@
 const {
   autodiscoverRepositories,
 } = require('../../../lib/workers/global/autodiscover');
-
+const platform = require('../../../lib/platform');
 const hostRules = require('../../../lib/util/host-rules');
 const ghApi = require('../../../lib/platform/github');
 
+jest.mock('../../../lib/platform/github');
+
 describe('lib/workers/global/autodiscover', () => {
   let config;
   beforeEach(() => {
     jest.resetAllMocks();
     config = {};
+    platform.initPlatform({ platform: 'github', token: 'abc123' });
   });
   it('returns if not autodiscovering', async () => {
     expect(await autodiscoverRepositories(config)).toEqual(config);
diff --git a/test/workers/global/index.spec.js b/test/workers/global/index.spec.js
index ee66a41dcdf5fcd0322fa35a5d7216fe455f7427..e98ff5868ff4f0b166d2a9197db87f6635b8d7f3 100644
--- a/test/workers/global/index.spec.js
+++ b/test/workers/global/index.spec.js
@@ -1,6 +1,9 @@
 const globalWorker = require('../../../lib/workers/global');
 const repositoryWorker = require('../../../lib/workers/repository');
 const configParser = require('../../../lib/config');
+const platform = require('../../../lib/platform');
+
+jest.mock('../../../lib/platform');
 
 describe('lib/workers/global', () => {
   beforeEach(() => {
@@ -8,6 +11,7 @@ describe('lib/workers/global', () => {
     configParser.parseConfigs = jest.fn();
     configParser.getRepositoryConfig = jest.fn();
     repositoryWorker.renovateRepository = jest.fn();
+    platform.initPlatform.mockImplementation(input => input);
   });
   it('handles config warnings and errors', async () => {
     configParser.parseConfigs.mockReturnValueOnce({