diff --git a/lib/api/github.js b/lib/api/github.js
index 7fba3274cf65ddf1a655dc817cef49a28a7e0f2b..e78039155f41e9aeb38958c8f02ca53d596b8cfc 100644
--- a/lib/api/github.js
+++ b/lib/api/github.js
@@ -185,7 +185,6 @@ async function branchExists(branchName) {
       `repos/${config.repoName}/git/refs/heads/${branchName}`
     );
     if (res.statusCode === 200) {
-      logger.debug(JSON.stringify(res.body));
       if (Array.isArray(res.body)) {
         // This seems to happen if GitHub has partial matches, so we check ref
         const matchedBranch = res.body.some(
diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index 74ae5c47b761d8f039448cf3fcdee06eaaa8f476..66fffab66a59465f42c5d2b98ff0a92e8f0e5d83 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -105,6 +105,22 @@ const options = [
     type: 'list',
     default: ['dependencies', 'devDependencies', 'optionalDependencies'],
   },
+  // depType
+  {
+    name: 'ignoreDeps',
+    description: 'Dependencies to ignore',
+    type: 'list',
+    level: 'depType',
+  },
+  {
+    name: 'packages',
+    description: 'Package Rules',
+    type: 'list',
+    level: 'depType',
+    cli: false,
+    env: false,
+    onboarding: false,
+  },
   // Version behaviour
   {
     name: 'pinVersions',
@@ -117,11 +133,6 @@ const options = [
       'If set to false, it will upgrade dependencies to latest release only, and not separate major/minor branches',
     type: 'boolean',
   },
-  {
-    name: 'ignoreDeps',
-    description: 'Dependencies to ignore',
-    type: 'list',
-  },
   {
     name: 'ignoreFuture',
     description: 'Ignore versions tagged as "future"',
diff --git a/lib/config/index.js b/lib/config/index.js
index a6a04ed1cb6ee34da6353306d6fdbb35b604f41e..dc8c3368a5194502a9e388f3548f6b57df092203 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -13,8 +13,7 @@ const githubAppHelper = require('../helpers/github-app');
 
 module.exports = {
   parseConfigs,
-  getRepositoryConfig,
-  getPackageFileConfig,
+  filterConfig,
 };
 
 async function parseConfigs(env, argv) {
@@ -117,47 +116,21 @@ async function parseConfigs(env, argv) {
   return config;
 }
 
-function getRepositoryConfig(globalConfig, index) {
-  let repository = globalConfig.repositories[index];
-  if (typeof repository === 'string') {
-    repository = { repository };
-  }
-  const repoConfig = Object.assign({}, globalConfig, repository);
-  for (const option of definitions.getOptions()) {
-    if (option.level === 'global') {
-      delete repoConfig[option.name];
-    }
-  }
-  repoConfig.logger = logger.child({
-    repository: repoConfig.repository,
-  });
-  return repoConfig;
-}
-
-function getPackageFileConfig(repoConfig, index) {
-  let packageFile = repoConfig.packageFiles[index];
-  if (typeof packageFile === 'string') {
-    packageFile = { packageFile };
-  } else if (packageFile.fileName) {
-    // Retained deprecated 'fileName' for backwards compatibility
-    // TODO: Remove in renovate 9
-    packageFile.packageFile = packageFile.fileName;
-    delete packageFile.fileName;
-  }
-  const packageFileConfig = Object.assign({}, repoConfig, packageFile);
+function filterConfig(inputConfig, filterLevel) {
+  const outputConfig = Object.assign({}, inputConfig);
+  const levelScores = {
+    package: 10,
+    depType: 20,
+    packageFile: 30,
+    repository: 40,
+    global: 50,
+  };
+  const threshold = levelScores[filterLevel];
   for (const option of definitions.getOptions()) {
-    if (option.level === 'repository') {
-      delete packageFileConfig[option.name];
+    const optionScore = levelScores[option.level] || 0;
+    if (optionScore > threshold) {
+      delete outputConfig[option.name];
     }
   }
-  repoConfig.logger.trace({ config: repoConfig }, 'repoConfig');
-  packageFileConfig.logger = logger.child({
-    repository: packageFileConfig.repository,
-    packageFile: packageFileConfig.packageFile,
-  });
-  packageFileConfig.logger.trace(
-    { config: packageFileConfig },
-    'packageFileConfig'
-  );
-  return packageFileConfig;
+  return outputConfig;
 }
diff --git a/lib/helpers/github-app.js b/lib/helpers/github-app.js
index a03a83518d9c7ececbf9e18c5be6fcf2247c42bb..aedfa32110f168f3dd1166ac192828557fc8ede0 100644
--- a/lib/helpers/github-app.js
+++ b/lib/helpers/github-app.js
@@ -52,7 +52,7 @@ async function getRepositories(config) {
     const installations = await ghApi.getInstallations(appToken);
     logger.info(`Found installations for ${installations.length} users`);
     for (const installation of installations) {
-      logger.debug(JSON.stringify(installation));
+      logger.debug(`installation=${JSON.stringify(installation)}`);
       let installationRepos = await module.exports.getUserRepositories(
         appToken,
         installation.id
diff --git a/lib/helpers/logger/pretty-stdout.js b/lib/helpers/logger/pretty-stdout.js
index 9679d1bb2d722b611844e76798a17a891f4c970d..7fad24e171d25116af6d6c16bd9bc4998ebfc6ea 100644
--- a/lib/helpers/logger/pretty-stdout.js
+++ b/lib/helpers/logger/pretty-stdout.js
@@ -27,6 +27,7 @@ function getMeta(rec) {
   const metaFields = [
     'repository',
     'packageFile',
+    'depType',
     'dependency',
     'branch',
   ].filter(elem => rec[elem]);
diff --git a/lib/helpers/package-json.js b/lib/helpers/package-json.js
index a4ad33dc5eb929b6405782c77c56748e55ff4ff3..c9f1711edb5e2ce902b3fefe4cd7363932c4a407 100644
--- a/lib/helpers/package-json.js
+++ b/lib/helpers/package-json.js
@@ -1,28 +1,9 @@
 const _ = require('lodash');
 
 module.exports = {
-  extractDependencies,
   setNewValue,
 };
 
-// Returns an array of current dependencies
-function extractDependencies(packageJson, sections) {
-  // loop through dependency types
-  return sections.reduce((allDeps, depType) => {
-    // loop through each dependency within a type
-    const depNames = packageJson[depType]
-      ? Object.keys(packageJson[depType])
-      : [];
-    return allDeps.concat(
-      depNames.map(depName => ({
-        depType,
-        depName,
-        currentVersion: packageJson[depType][depName].trim(),
-      }))
-    );
-  }, []);
-}
-
 function setNewValue(currentFileContent, depType, depName, newVersion, logger) {
   logger.debug(`setNewValue: ${depType}.${depName} = ${newVersion}`);
   const parsedContents = JSON.parse(currentFileContent);
diff --git a/lib/workers/branch.js b/lib/workers/branch.js
index 691d0c1a27b59761310bd763f01fca3fb5ad93af..bd5cf53138820fe3201145bde84cbd12d1591c44 100644
--- a/lib/workers/branch.js
+++ b/lib/workers/branch.js
@@ -15,10 +15,10 @@ module.exports = {
 async function getParentBranch(branchName, config) {
   // Check if branch exists
   if ((await config.api.branchExists(branchName)) === false) {
-    logger.info(`Branch ${branchName} needs creating`);
+    logger.info(`Branch needs creating`);
     return undefined;
   }
-  logger.info(`Branch ${branchName} already exists`);
+  logger.info(`Branch already exists`);
   // Check if needs rebasing
   if (
     config.rebaseStalePrs ||
@@ -26,7 +26,7 @@ async function getParentBranch(branchName, config) {
   ) {
     const isBranchStale = await config.api.isBranchStale(branchName);
     if (isBranchStale) {
-      logger.info(`Branch ${branchName} is stale and needs rebasing`);
+      logger.info(`Branch is stale and needs rebasing`);
       return undefined;
     }
   }
@@ -35,7 +35,7 @@ async function getParentBranch(branchName, config) {
   const pr = await config.api.getBranchPr(branchName);
   // Decide if we need to rebase
   if (!pr) {
-    logger.debug(`No PR found for ${branchName}`);
+    logger.debug(`No PR found`);
     // We can't tell if this branch can be rebased so better not
     return branchName;
   }
@@ -53,9 +53,9 @@ async function getParentBranch(branchName, config) {
       }
     }
     // Don't do anything different, but warn
-    logger.warn(`Branch ${branchName} is not mergeable but can't be rebased`);
+    logger.warn(`Branch is not mergeable but can't be rebased`);
   }
-  logger.debug(`Branch ${branchName} does not need rebasing`);
+  logger.debug(`Branch does not need rebasing`);
   return branchName;
 }
 
@@ -158,7 +158,7 @@ async function ensureBranch(upgrades) {
     }
   }
   if (commitFiles.length) {
-    logger.debug(`Commit ${commitFiles.length} files to branch ${branchName}`);
+    logger.debug(`${commitFiles.length} file(s) to commit`);
     // API will know whether to create new branch or not
     await api.commitFilesToBranch(
       branchName,
@@ -167,7 +167,7 @@ async function ensureBranch(upgrades) {
       parentBranch
     );
   } else {
-    logger.debug(`No files to commit to branch ${branchName}`);
+    logger.debug(`No files to commit`);
   }
   if (!api.branchExists(branchName)) {
     // Return now if no branch exists
@@ -181,18 +181,16 @@ async function ensureBranch(upgrades) {
   logger.debug('Checking if we can automerge branch');
   const branchStatus = await api.getBranchStatus(branchName);
   if (branchStatus === 'success') {
-    logger.info(`Automerging branch ${branchName}`);
+    logger.info(`Automerging branch`);
     try {
       await api.mergeBranch(branchName, config.automergeType);
     } catch (err) {
-      logger.error(`Failed to automerge branch ${branchName}`);
+      logger.error(`Failed to automerge branch`);
       logger.debug(JSON.stringify(err));
       throw err;
     }
   } else {
-    logger.debug(
-      `Branch status is "${branchStatus}" - skipping branch automerge`
-    );
+    logger.debug(`Branch status is "${branchStatus}" - skipping automerge`);
   }
   // Return true as branch exists
   return true;
@@ -211,7 +209,7 @@ async function updateBranch(upgrades) {
   });
 
   logger.info(
-    `Branch '${branchName}' has ${upgrades.length} upgrade(s): ${upgrades.map(
+    `Branch has ${upgrades.length} upgrade(s): ${upgrades.map(
       upgrade => upgrade.depName
     )}`
   );
@@ -223,9 +221,7 @@ async function updateBranch(upgrades) {
       !upgrade0.recreateClosed &&
       (await upgrade0.api.checkForClosedPr(branchName, prTitle))
     ) {
-      logger.info(
-        `Skipping ${branchName} upgrade as matching closed PR already existed`
-      );
+      logger.info(`Skipping branch as matching closed PR already existed`);
       return;
     }
     const branchCreated = await module.exports.ensureBranch(upgrades);
@@ -236,7 +232,7 @@ async function updateBranch(upgrades) {
       }
     }
   } catch (error) {
-    logger.error(`Error updating branch ${branchName}: ${error}`);
+    logger.error(`Error updating branch: ${error}`);
     // Don't throw here - we don't want to stop the other renovations
   }
 }
diff --git a/lib/workers/dep-type/index.js b/lib/workers/dep-type/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f3be63c9b0629eae3e40e655a16b4c439525efa
--- /dev/null
+++ b/lib/workers/dep-type/index.js
@@ -0,0 +1,76 @@
+const configParser = require('../../config');
+const pkgWorker = require('../package');
+const packageJson = require('./package-json');
+let logger = require('../../helpers/logger');
+
+module.exports = {
+  findUpgrades,
+  getDepConfig,
+};
+
+async function findUpgrades(packageContent, config) {
+  logger = config.logger || logger;
+  logger.trace(
+    `findUpgrades(${JSON.stringify(packageContent)}, ${JSON.stringify(config)})`
+  );
+  // Extract all dependencies from the package.json
+  const currentDeps = await packageJson.extractDependencies(
+    packageContent,
+    config.depType
+  );
+  if (currentDeps.length === 0) {
+    return [];
+  }
+  logger.debug(`currentDeps=${JSON.stringify(currentDeps)}`);
+  // Filter out ignored dependencies
+  const filteredDeps = currentDeps.filter(
+    dependency => config.ignoreDeps.indexOf(dependency.depName) === -1
+  );
+  logger.debug(`filteredDeps=${JSON.stringify(filteredDeps)}`);
+  // Obtain full config for each dependency
+  const depConfigs = filteredDeps.map(dep =>
+    module.exports.getDepConfig(config, dep)
+  );
+  logger.debug(`depConfigs=${JSON.stringify(depConfigs)}`);
+  // findUpgrades can return more than one upgrade each
+  const pkgWorkers = depConfigs.map(depConfig =>
+    pkgWorker.findUpgrades(depConfig)
+  );
+  // Use Promise.all to execute npm queries in parallel
+  const allUpgrades = await Promise.all(pkgWorkers);
+  logger.debug(`allUpgrades=${JSON.stringify(allUpgrades)}`);
+  // Squash arrays into one
+  const combinedUpgrades = [].concat(...allUpgrades);
+  logger.debug(`combinedUpgrades=${JSON.stringify(combinedUpgrades)}`);
+  return combinedUpgrades;
+}
+
+function getDepConfig(depTypeConfig, dep) {
+  const depConfig = Object.assign({}, depTypeConfig, dep);
+  // Apply any matching package rules
+  if (depConfig.packages) {
+    let packageRuleApplied = false;
+    depConfig.packages.forEach(packageConfig => {
+      // Apply at most 1 package fule
+      if (!packageRuleApplied) {
+        const pattern =
+          packageConfig.packagePattern || `^${packageConfig.packageName}$`;
+        const packageRegex = new RegExp(pattern);
+        if (depConfig.depName.match(packageRegex)) {
+          packageRuleApplied = true;
+          // Package rule config overrides any existing config
+          Object.assign(depConfig, packageConfig);
+          delete depConfig.packageName;
+          delete depConfig.packagePattern;
+        }
+      }
+    });
+  }
+  depConfig.logger = logger.child({
+    repository: depConfig.repository,
+    packageFile: depConfig.packageFile,
+    depType: depConfig.depType,
+    dependency: depConfig.depName,
+  });
+  return configParser.filterConfig(depConfig, 'package');
+}
diff --git a/lib/workers/dep-type/package-json.js b/lib/workers/dep-type/package-json.js
new file mode 100644
index 0000000000000000000000000000000000000000..f469194eac419220844542c50beb6e6158659e23
--- /dev/null
+++ b/lib/workers/dep-type/package-json.js
@@ -0,0 +1,14 @@
+module.exports = {
+  extractDependencies,
+};
+
+function extractDependencies(packageJson, depType) {
+  const depNames = packageJson[depType]
+    ? Object.keys(packageJson[depType])
+    : [];
+  return depNames.map(depName => ({
+    depType,
+    depName,
+    currentVersion: packageJson[depType][depName].trim(),
+  }));
+}
diff --git a/lib/workers/global.js b/lib/workers/global.js
index a55382ee044b07bef226599da2a7ccc95a32b45e..058593989c7f1f3e29b48e9135da9216bb3e210f 100644
--- a/lib/workers/global.js
+++ b/lib/workers/global.js
@@ -4,6 +4,7 @@ const repositoryWorker = require('./repository');
 
 module.exports = {
   start,
+  getRepositoryConfig,
 };
 
 async function start() {
@@ -12,7 +13,7 @@ async function start() {
     const config = await configParser.parseConfigs(process.env, process.argv);
     // Iterate through repositories sequentially
     for (let index = 0; index < config.repositories.length; index += 1) {
-      const repoConfig = configParser.getRepositoryConfig(config, index);
+      const repoConfig = module.exports.getRepositoryConfig(config, index);
       repoConfig.logger.info('Renovating repository');
       await repositoryWorker.renovateRepository(repoConfig);
       repoConfig.logger.info('Finished repository');
@@ -23,3 +24,15 @@ async function start() {
     logger.error(err);
   }
 }
+
+function getRepositoryConfig(globalConfig, index) {
+  let repository = globalConfig.repositories[index];
+  if (typeof repository === 'string') {
+    repository = { repository };
+  }
+  const repoConfig = Object.assign({}, globalConfig, repository);
+  repoConfig.logger = logger.child({
+    repository: repoConfig.repository,
+  });
+  return configParser.filterConfig(repoConfig, 'repository');
+}
diff --git a/lib/workers/package-file.js b/lib/workers/package-file.js
deleted file mode 100644
index 774b20139c4d94881d3f419b8e2de57595d0e37c..0000000000000000000000000000000000000000
--- a/lib/workers/package-file.js
+++ /dev/null
@@ -1,178 +0,0 @@
-// API
-const npmApi = require('../api/npm');
-// Helpers
-const packageJson = require('../helpers/package-json');
-const versionsHelper = require('../helpers/versions');
-
-let logger = require('../helpers/logger');
-
-module.exports = {
-  processPackageFile,
-  assignDepConfigs,
-  findUpgrades,
-  getDepTypeConfig,
-};
-
-// This function manages the queue per-package file
-async function processPackageFile(config) {
-  // Initialize logger
-  logger = config.logger;
-
-  logger.info(`Processing package file`);
-
-  const packageContent = await config.api.getFileJson(config.packageFile);
-
-  if (!packageContent) {
-    logger.warn('No package.json content found - skipping');
-    return [];
-  }
-
-  // Check for renovate config inside the package.json
-  if (packageContent.renovate) {
-    logger.debug(
-      { config: packageContent.renovate },
-      'package.json>renovate config'
-    );
-    Object.assign(config, packageContent.renovate, {
-      renovateJsonPresent: true,
-    });
-  }
-  // Now check if config is disabled
-  if (config.enabled === false) {
-    logger.info('Config is disabled. Skipping');
-    return [];
-  }
-
-  const depTypes = config.depTypes.map(depType => {
-    if (typeof depType === 'string') {
-      return depType;
-    }
-    return depType.depType;
-  });
-
-  // Extract all dependencies from the package.json
-  let dependencies = await packageJson.extractDependencies(
-    packageContent,
-    depTypes
-  );
-  // Filter out ignored dependencies
-  dependencies = dependencies.filter(
-    dependency => config.ignoreDeps.indexOf(dependency.depName) === -1
-  );
-  dependencies = module.exports.assignDepConfigs(config, dependencies);
-  // Find all upgrades for remaining dependencies
-  const upgrades = await module.exports.findUpgrades(dependencies);
-  // Process all upgrades sequentially
-  if (config.maintainYarnLock) {
-    const upgrade = Object.assign({}, config, {
-      upgradeType: 'maintainYarnLock',
-    });
-    upgrade.upgradeType = 'maintainYarnLock';
-    upgrade.commitMessage = upgrade.yarnMaintenanceCommitMessage;
-    upgrade.branchName = upgrade.yarnMaintenanceBranchName;
-    upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
-    upgrade.prBody = upgrade.yarnMaintenancePrBody;
-    upgrades.push(upgrade);
-  }
-  logger.info('Finished processing package file');
-  return upgrades;
-}
-
-// Add custom config for each dep
-function assignDepConfigs(inputConfig, deps) {
-  return deps.map(dep => {
-    const returnDep = Object.assign({}, dep);
-    returnDep.config = Object.assign(
-      {},
-      inputConfig,
-      getDepTypeConfig(inputConfig.depTypes, dep.depType)
-    );
-    let packageRuleApplied = false;
-    if (returnDep.config.packages) {
-      // Loop through list looking for match
-      // Exit after first match
-      returnDep.config.packages.forEach(packageConfig => {
-        if (!packageRuleApplied) {
-          const pattern =
-            packageConfig.packagePattern || `^${packageConfig.packageName}$`;
-          const packageRegex = new RegExp(pattern);
-          if (dep.depName.match(packageRegex)) {
-            packageRuleApplied = true;
-            Object.assign(returnDep.config, packageConfig);
-            delete returnDep.config.packageName;
-            delete returnDep.config.packagePattern;
-          }
-        }
-      });
-    }
-    // TODO: clean this up
-    delete returnDep.config.depType;
-    delete returnDep.config.depTypes;
-    delete returnDep.config.enabled;
-    delete returnDep.config.onboarding;
-    delete returnDep.config.endpoint;
-    delete returnDep.config.autodiscover;
-    delete returnDep.config.token;
-    delete returnDep.config.githubAppId;
-    delete returnDep.config.githubAppKey;
-    delete returnDep.config.packageFiles;
-    delete returnDep.config.logLevel;
-    delete returnDep.config.renovateJsonPresent;
-    delete returnDep.config.ignoreDeps;
-    delete returnDep.config.packages;
-    delete returnDep.config.maintainYarnLock;
-    delete returnDep.config.yarnMaintenanceBranchName;
-    delete returnDep.config.yarnMaintenanceCommitMessage;
-    delete returnDep.config.yarnMaintenancePrTitle;
-    delete returnDep.config.yarnMaintenancePrBody;
-    return returnDep;
-  });
-}
-
-async function findUpgrades(dependencies) {
-  const allUpgrades = [];
-  // findDepUpgrades can add more than one upgrade to allUpgrades
-  async function findDepUpgrades(dep) {
-    const npmDependency = await npmApi.getDependency(dep.depName, logger);
-    if (!npmDependency) {
-      // If dependency lookup fails then ignore it and keep going
-      return;
-    }
-    const upgrades = await versionsHelper.determineUpgrades(
-      npmDependency,
-      dep.currentVersion,
-      dep.config
-    );
-    if (upgrades.length > 0) {
-      logger.info(
-        `Dependency ${dep.depName} has ${upgrades.length} upgrade(s) available: ${upgrades.map(
-          upgrade => upgrade.newVersion
-        )}`
-      );
-      upgrades.forEach(upgrade => {
-        const upgradeObj = Object.assign({}, dep, dep.config, upgrade);
-        delete upgradeObj.config;
-        allUpgrades.push(upgradeObj);
-      });
-    } else {
-      logger.debug(`${dep.depName}: No upgrades required`);
-    }
-  }
-  const promiseArray = dependencies.map(dep => findDepUpgrades(dep));
-  // Use Promise.all to execute npm queries in parallel
-  await Promise.all(promiseArray);
-  // Return the upgrade array once all Promises are complete
-  return allUpgrades;
-}
-
-function getDepTypeConfig(depTypes, depTypeName) {
-  let depTypeConfig = {};
-  if (depTypes) {
-    depTypes.forEach(depType => {
-      if (typeof depType !== 'string' && depType.depType === depTypeName) {
-        depTypeConfig = depType;
-      }
-    });
-  }
-  return depTypeConfig;
-}
diff --git a/lib/workers/package-file/index.js b/lib/workers/package-file/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ff276804132431f12093333f9d5835b3fcf9dd65
--- /dev/null
+++ b/lib/workers/package-file/index.js
@@ -0,0 +1,72 @@
+const configParser = require('../../config');
+const depTypeWorker = require('../dep-type');
+let logger = require('../../helpers/logger');
+
+module.exports = {
+  findUpgrades,
+  getDepTypeConfig,
+};
+
+async function findUpgrades(config) {
+  logger = config.logger || logger;
+  logger.info(`Processing package file`);
+  const packageContent = await config.api.getFileJson(config.packageFile);
+
+  if (!packageContent) {
+    logger.warn('No package.json content found - skipping');
+    return [];
+  }
+
+  // Check for renovate config inside the package.json
+  if (packageContent.renovate) {
+    logger.debug(
+      { config: packageContent.renovate },
+      'package.json>renovate config'
+    );
+    // package.json>renovate config takes precedence over existing config
+    Object.assign(config, packageContent.renovate);
+  } else {
+    logger.debug('Package file has no renovate configuration');
+  }
+  // Now check if config is disabled
+  if (config.enabled === false) {
+    logger.info('Config is disabled. Skipping');
+    return [];
+  }
+
+  const depTypeConfigs = config.depTypes.map(depType =>
+    module.exports.getDepTypeConfig(config, depType)
+  );
+  logger.debug(`depTypeConfigs=${JSON.stringify(depTypeConfigs)}`);
+  let upgrades = [];
+  for (const depTypeConfig of depTypeConfigs) {
+    upgrades = upgrades.concat(
+      await depTypeWorker.findUpgrades(packageContent, depTypeConfig)
+    );
+  }
+
+  if (config.maintainYarnLock) {
+    const upgrade = Object.assign({}, config, {
+      upgradeType: 'maintainYarnLock',
+    });
+    upgrade.upgradeType = 'maintainYarnLock';
+    upgrade.commitMessage = upgrade.yarnMaintenanceCommitMessage;
+    upgrade.branchName = upgrade.yarnMaintenanceBranchName;
+    upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
+    upgrade.prBody = upgrade.yarnMaintenancePrBody;
+    upgrades.push(upgrade);
+  }
+  logger.info('Finished processing package file');
+  return upgrades;
+}
+
+function getDepTypeConfig(packageFileConfig, depType) {
+  let depTypeConfig = typeof depType === 'string' ? { depType } : depType;
+  depTypeConfig = Object.assign({}, packageFileConfig, depTypeConfig);
+  depTypeConfig.logger = logger.child({
+    repository: depTypeConfig.repository,
+    packageFile: depTypeConfig.packageFile,
+    depType: depTypeConfig.depType,
+  });
+  return configParser.filterConfig(depTypeConfig, 'depType');
+}
diff --git a/lib/workers/package/index.js b/lib/workers/package/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d065c377a8404cd1baf8206a303feb015a3b3ab
--- /dev/null
+++ b/lib/workers/package/index.js
@@ -0,0 +1,32 @@
+const npmApi = require('../../api/npm');
+const versions = require('./versions');
+
+let logger = require('../../helpers/logger');
+
+module.exports = {
+  findUpgrades,
+};
+
+// Returns all upgrades for a given dependency config
+async function findUpgrades(config) {
+  logger = config.logger || logger;
+  const npmDep = await npmApi.getDependency(config.depName, logger);
+  // If dependency lookup fails then warn and return
+  if (!npmDep) {
+    logger.warn(`Failed to look up dependency ${config.depName}`);
+    return [];
+  }
+  const upgrades = await versions.determineUpgrades(npmDep, config);
+  if (upgrades.length > 0) {
+    logger.info(
+      { dependency: config.depName },
+      `${upgrades.length} upgrade(s) available: ${upgrades.map(
+        upgrade => upgrade.newVersion
+      )}`
+    );
+  } else {
+    logger.debug(`${config.depName}: No upgrades required`);
+  }
+  // Flatten the config on top of upgrade
+  return upgrades.map(upgrade => Object.assign({}, config, upgrade));
+}
diff --git a/lib/helpers/versions.js b/lib/workers/package/versions.js
similarity index 91%
rename from lib/helpers/versions.js
rename to lib/workers/package/versions.js
index 76c2da4836c0cea04fce9f4c79aa491f27084c0b..f6f226a562890a2c59342c80f0b771c6a14e80e9 100644
--- a/lib/helpers/versions.js
+++ b/lib/workers/package/versions.js
@@ -1,4 +1,4 @@
-const logger = require('../helpers/logger');
+const logger = require('../../helpers/logger');
 const semver = require('semver');
 const stable = require('semver-stable');
 const _ = require('lodash');
@@ -12,14 +12,15 @@ module.exports = {
   isPastLatest,
 };
 
-function determineUpgrades(dep, currentVersion, config) {
+function determineUpgrades(npmDep, config) {
+  const currentVersion = config.currentVersion;
   if (!isValidVersion(currentVersion)) {
-    logger.warn(`${dep.name} currentVersion ${currentVersion} is invalid`);
+    logger.warn(`${npmDep.name} currentVersion ${currentVersion} is invalid`);
     return [];
   }
-  const versions = dep.versions;
+  const versions = npmDep.versions;
   if (!versions || Object.keys(versions).length === 0) {
-    logger.warn(`${dep.name} - no versions`);
+    logger.warn(`${npmDep.name} - no versions`);
     return [];
   }
   const versionList = Object.keys(versions);
@@ -59,8 +60,8 @@ function determineUpgrades(dep, currentVersion, config) {
     .reject(
       version =>
         config.respectLatest &&
-        isPastLatest(dep, version) &&
-        !isPastLatest(dep, changeLogFromVersion)
+        isPastLatest(npmDep, version) &&
+        !isPastLatest(npmDep, changeLogFromVersion)
     )
     // Loop through all possible versions
     .forEach(newVersion => {
@@ -187,10 +188,10 @@ function isFuture(version) {
   );
 }
 
-function isPastLatest(dep, version) {
-  if (dep['dist-tags'] && dep['dist-tags'].latest) {
-    return semver.gt(version, dep['dist-tags'].latest);
+function isPastLatest(npmDep, version) {
+  if (npmDep['dist-tags'] && npmDep['dist-tags'].latest) {
+    return semver.gt(version, npmDep['dist-tags'].latest);
   }
-  logger.warn(`No dist-tags.latest for ${dep.name}`);
+  logger.warn(`No dist-tags.latest for ${npmDep.name}`);
   return false;
 }
diff --git a/lib/workers/pr.js b/lib/workers/pr.js
index d03d72f4437c84e516ae6c920ede9ce71070bda7..e1b8a448302d0dc09b6ad8c171108398c7faeb3c 100644
--- a/lib/workers/pr.js
+++ b/lib/workers/pr.js
@@ -149,7 +149,6 @@ async function checkAutoMerge(pr, config, logger) {
   logger.debug(`Checking #${pr.number} for automerge`);
   if (config.automergeEnabled && config.automergeType === 'pr') {
     logger.info('PR is configured for automerge');
-    logger.debug(JSON.stringify(pr));
     // Return if PR not ready for automerge
     if (pr.mergeable !== true || pr.mergeable_state === 'unstable') {
       logger.info('PR is not ready for merge');
diff --git a/lib/workers/repository/upgrades.js b/lib/workers/repository/upgrades.js
index e9e52b77882f302008d029ff2dccbae62bc4c271..87bbec075cc5e016182f32d2c525226188185b9b 100644
--- a/lib/workers/repository/upgrades.js
+++ b/lib/workers/repository/upgrades.js
@@ -5,6 +5,7 @@ const packageFileWorker = require('../package-file');
 module.exports = {
   determineRepoUpgrades,
   groupUpgradesByBranch,
+  getPackageFileConfig,
 };
 
 async function determineRepoUpgrades(config) {
@@ -15,12 +16,14 @@ async function determineRepoUpgrades(config) {
   let upgrades = [];
   // Iterate through repositories sequentially
   for (let index = 0; index < config.packageFiles.length; index += 1) {
-    const packageFileConfig = configParser.getPackageFileConfig(config, index);
-    packageFileConfig.logger.info('Renovating package file');
+    const packageFileConfig = module.exports.getPackageFileConfig(
+      config,
+      index
+    );
+    packageFileConfig.logger.info('Processing package file');
     upgrades = upgrades.concat(
-      await packageFileWorker.processPackageFile(packageFileConfig)
+      await packageFileWorker.findUpgrades(packageFileConfig)
     );
-    packageFileConfig.logger.info('Finished repository');
   }
   return upgrades;
 }
@@ -56,3 +59,26 @@ async function groupUpgradesByBranch(upgrades, logger) {
   logger.debug(`Returning ${Object.keys(branchUpgrades).length} branch(es)`);
   return branchUpgrades;
 }
+
+function getPackageFileConfig(repoConfig, index) {
+  let packageFile = repoConfig.packageFiles[index];
+  if (typeof packageFile === 'string') {
+    packageFile = { packageFile };
+  } else if (packageFile.fileName) {
+    // Retained deprecated 'fileName' for backwards compatibility
+    // TODO: Remove in renovate 9
+    packageFile.packageFile = packageFile.fileName;
+    delete packageFile.fileName;
+  }
+  const packageFileConfig = Object.assign({}, repoConfig, packageFile);
+  repoConfig.logger.trace({ config: repoConfig }, 'repoConfig');
+  packageFileConfig.logger = packageFileConfig.logger.child({
+    repository: packageFileConfig.repository,
+    packageFile: packageFileConfig.packageFile,
+  });
+  packageFileConfig.logger.trace(
+    { config: packageFileConfig },
+    'packageFileConfig'
+  );
+  return configParser.filterConfig(packageFileConfig, 'packageFile');
+}
diff --git a/test/config/__snapshots__/index.spec.js.snap b/test/config/__snapshots__/index.spec.js.snap
deleted file mode 100644
index 5bc93770e556e47b65d868c523a39c1f561f32ad..0000000000000000000000000000000000000000
--- a/test/config/__snapshots__/index.spec.js.snap
+++ /dev/null
@@ -1,18 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`config/index .(config, index) handles object repos 1`] = `
-Object {
-  "foo": "bar",
-  "maintainYarnLock": true,
-  "repoField": "g",
-  "repository": "e/f",
-}
-`;
-
-exports[`config/index .(config, index) massages string repos 1`] = `
-Object {
-  "foo": "bar",
-  "maintainYarnLock": true,
-  "repository": "c/d",
-}
-`;
diff --git a/test/config/index.spec.js b/test/config/index.spec.js
index 3efd7b517719b9bf5398bd53a9961c1da31ead57..31cc0fb07a4914ac732275dc9bda950429b2c88d 100644
--- a/test/config/index.spec.js
+++ b/test/config/index.spec.js
@@ -160,38 +160,4 @@ describe('config/index', () => {
       expect(glGot.mock.calls.length).toBe(0);
     });
   });
-  describe('.(config, index)', () => {
-    let configParser;
-    beforeEach(() => {
-      configParser = require('../../lib/config/index.js');
-    });
-    const config = {
-      githubAppKey: 'foo',
-      maintainYarnLock: true,
-      foo: 'bar',
-      repositories: [
-        'c/d',
-        {
-          repository: 'e/f',
-          repoField: 'g',
-        },
-      ],
-    };
-    it('massages string repos', () => {
-      const res = configParser.getRepositoryConfig(config, 0);
-      expect(res.githubAppKey).not.toBeDefined();
-      expect(res.maintainYarnLock).toBeDefined();
-      expect(res.logger).toBeDefined();
-      delete res.logger;
-      expect(res).toMatchSnapshot();
-    });
-    it('handles object repos', () => {
-      const res = configParser.getRepositoryConfig(config, 1);
-      expect(res.githubAppKey).not.toBeDefined();
-      expect(res.maintainYarnLock).toBeDefined();
-      expect(res.logger).toBeDefined();
-      delete res.logger;
-      expect(res).toMatchSnapshot();
-    });
-  });
 });
diff --git a/test/helpers/__snapshots__/package-json.spec.js.snap b/test/helpers/__snapshots__/platform.spec.js.snap
similarity index 100%
rename from test/helpers/__snapshots__/package-json.spec.js.snap
rename to test/helpers/__snapshots__/platform.spec.js.snap
diff --git a/test/helpers/package-json.spec.js b/test/helpers/package-json.spec.js
deleted file mode 100644
index 60fd09ddc51586ea33548fd3c24a1fd6f98af12d..0000000000000000000000000000000000000000
--- a/test/helpers/package-json.spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const platformHelper = require('../../lib/helpers/platform');
-
-describe('helpers/platform', () => {
-  describe('getApi(platform)', () => {
-    it('returns github', () => {
-      platformHelper.getApi('github');
-    });
-    it('returns gitlab', () => {
-      platformHelper.getApi('gitlab');
-    });
-    it('throws error', () => {
-      let e;
-      try {
-        platformHelper.getApi('foo');
-      } catch (err) {
-        e = err;
-      }
-      expect(e).toMatchSnapshot();
-    });
-  });
-});
diff --git a/test/helpers/platform-json.spec.js b/test/helpers/platform-json.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..793cbbacb6e73da1da919a1ab5d88a6682e48317
--- /dev/null
+++ b/test/helpers/platform-json.spec.js
@@ -0,0 +1,61 @@
+const fs = require('fs');
+const path = require('path');
+const packageJson = require('../../lib/helpers/package-json');
+const logger = require('../_fixtures/logger');
+
+function readFixture(fixture) {
+  return fs.readFileSync(
+    path.resolve(__dirname, `../_fixtures/package-json/${fixture}`),
+    'utf8'
+  );
+}
+
+const input01Content = readFixture('inputs/01.json');
+
+describe('helpers/package-json', () => {
+  describe('.setNewValue(currentFileContent, depType, depName, newVersion, logger)', () => {
+    it('replaces a dependency value', () => {
+      const outputContent = readFixture('outputs/011.json');
+      const testContent = packageJson.setNewValue(
+        input01Content,
+        'dependencies',
+        'cheerio',
+        '0.22.1',
+        logger
+      );
+      testContent.should.equal(outputContent);
+    });
+    it('replaces only the first instance of a value', () => {
+      const outputContent = readFixture('outputs/012.json');
+      const testContent = packageJson.setNewValue(
+        input01Content,
+        'devDependencies',
+        'angular-touch',
+        '1.6.1',
+        logger
+      );
+      testContent.should.equal(outputContent);
+    });
+    it('replaces only the second instance of a value', () => {
+      const outputContent = readFixture('outputs/013.json');
+      const testContent = packageJson.setNewValue(
+        input01Content,
+        'devDependencies',
+        'angular-sanitize',
+        '1.6.1',
+        logger
+      );
+      testContent.should.equal(outputContent);
+    });
+    it('handles the case where the desired version is already supported', () => {
+      const testContent = packageJson.setNewValue(
+        input01Content,
+        'devDependencies',
+        'angular-touch',
+        '1.5.8',
+        logger
+      );
+      testContent.should.equal(input01Content);
+    });
+  });
+});
diff --git a/test/helpers/platform.spec.js b/test/helpers/platform.spec.js
index 8b71735a81917a06ad75fd4a45377e9c79c2c626..60fd09ddc51586ea33548fd3c24a1fd6f98af12d 100644
--- a/test/helpers/platform.spec.js
+++ b/test/helpers/platform.spec.js
@@ -1,95 +1,21 @@
-const fs = require('fs');
-const path = require('path');
-const packageJson = require('../../lib/helpers/package-json');
-const logger = require('../_fixtures/logger');
+const platformHelper = require('../../lib/helpers/platform');
 
-const defaultTypes = [
-  'dependencies',
-  'devDependencies',
-  'optionalDependencies',
-];
-
-function readFixture(fixture) {
-  return fs.readFileSync(
-    path.resolve(__dirname, `../_fixtures/package-json/${fixture}`),
-    'utf8'
-  );
-}
-
-const input01Content = readFixture('inputs/01.json');
-const input02Content = readFixture('inputs/02.json');
-
-describe('helpers/package-json', () => {
-  describe('.extractDependencies(packageJson, sections)', () => {
-    it('returns an array of correct length', () => {
-      const extractedDependencies = packageJson.extractDependencies(
-        JSON.parse(input01Content),
-        defaultTypes
-      );
-      extractedDependencies.should.be.instanceof(Array);
-      extractedDependencies.should.have.length(10);
-    });
-    it('each element contains non-null depType, depName, currentVersion', () => {
-      const extractedDependencies = packageJson.extractDependencies(
-        JSON.parse(input01Content),
-        defaultTypes
-      );
-      extractedDependencies
-        .every(dep => dep.depType && dep.depName && dep.currentVersion)
-        .should.eql(true);
-    });
-    it('supports null devDependencies', () => {
-      const extractedDependencies = packageJson.extractDependencies(
-        JSON.parse(input02Content),
-        defaultTypes
-      );
-      extractedDependencies.should.be.instanceof(Array);
-      extractedDependencies.should.have.length(6);
-    });
-  });
-  describe('.setNewValue(currentFileContent, depType, depName, newVersion, logger)', () => {
-    it('replaces a dependency value', () => {
-      const outputContent = readFixture('outputs/011.json');
-      const testContent = packageJson.setNewValue(
-        input01Content,
-        'dependencies',
-        'cheerio',
-        '0.22.1',
-        logger
-      );
-      testContent.should.equal(outputContent);
-    });
-    it('replaces only the first instance of a value', () => {
-      const outputContent = readFixture('outputs/012.json');
-      const testContent = packageJson.setNewValue(
-        input01Content,
-        'devDependencies',
-        'angular-touch',
-        '1.6.1',
-        logger
-      );
-      testContent.should.equal(outputContent);
+describe('helpers/platform', () => {
+  describe('getApi(platform)', () => {
+    it('returns github', () => {
+      platformHelper.getApi('github');
     });
-    it('replaces only the second instance of a value', () => {
-      const outputContent = readFixture('outputs/013.json');
-      const testContent = packageJson.setNewValue(
-        input01Content,
-        'devDependencies',
-        'angular-sanitize',
-        '1.6.1',
-        logger
-      );
-      testContent.should.equal(outputContent);
+    it('returns gitlab', () => {
+      platformHelper.getApi('gitlab');
     });
-    it('handles the case where the desired version is already supported', () => {
-      const testContent = packageJson.setNewValue(
-        input01Content,
-        'devDependencies',
-        'angular-touch',
-        '1.5.8',
-        logger
-      );
-      testContent.should.equal(input01Content);
+    it('throws error', () => {
+      let e;
+      try {
+        platformHelper.getApi('foo');
+      } catch (err) {
+        e = err;
+      }
+      expect(e).toMatchSnapshot();
     });
   });
 });
diff --git a/test/helpers/versions.spec.js b/test/helpers/versions.spec.js
deleted file mode 100644
index 7c85dad9bc227af23ed79c1929a550074f9e9456..0000000000000000000000000000000000000000
--- a/test/helpers/versions.spec.js
+++ /dev/null
@@ -1,286 +0,0 @@
-const versionsHelper = require('../../lib/helpers/versions');
-const qJson = require('../_fixtures/npm/01.json');
-const helmetJson = require('../_fixtures/npm/02.json');
-
-let defaultConfig;
-
-describe('helpers/versions', () => {
-  beforeEach(() => {
-    defaultConfig = require('../../lib/config/defaults').getConfig();
-  });
-
-  describe('.determineUpgrades(dep, currentVersion, defaultConfig)', () => {
-    it('return empty if invalid current version', () => {
-      versionsHelper
-        .determineUpgrades(qJson, 'invalid', defaultConfig)
-        .should.have.length(0);
-    });
-    it('return empty if null versions', () => {
-      const testDep = {
-        name: 'q',
-      };
-      versionsHelper
-        .determineUpgrades(testDep, '1.0.0', defaultConfig)
-        .should.have.length(0);
-    });
-    it('return empty if empty versions', () => {
-      const testDep = {
-        name: 'q',
-        versions: [],
-      };
-      versionsHelper
-        .determineUpgrades(testDep, '1.0.0', defaultConfig)
-        .should.have.length(0);
-    });
-    it('supports minor and major upgrades for tilde ranges', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('returns only one update if grouping', () => {
-      defaultConfig.groupName = 'somegroup';
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('returns only one update if automerging any', () => {
-      defaultConfig.automerge = 'any';
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('returns both updates if automerging minor', () => {
-      defaultConfig.automerge = 'minor';
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.4.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('disables major release separation (major)', () => {
-      const config = Object.assign({}, defaultConfig, {
-        separateMajorReleases: false,
-      });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.4.0', config)
-      ).toMatchSnapshot();
-    });
-    it('disables major release separation (minor)', () => {
-      const config = Object.assign({}, defaultConfig, {
-        separateMajorReleases: false,
-      });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.0.0', config)
-      ).toMatchSnapshot();
-    });
-    it('supports minor and major upgrades for ranged versions', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~0.4.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('ignores pinning for ranges when other upgrade exists', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~0.9.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('upgrades minor ranged versions', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~1.0.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('pins minor ranged versions', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^1.0.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('ignores minor ranged versions when not pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^1.0.0', config)
-      ).toHaveLength(0);
-    });
-    it('upgrades tilde ranges', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~1.3.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('upgrades .x minor ranges', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.3.x', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('upgrades tilde ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~1.3.0', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades .x major ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '0.x', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades .x minor ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.3.x', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades shorthand major ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '0', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades shorthand minor ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.3', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades multiple tilde ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '~0.7.0', config)
-      ).toMatchSnapshot();
-    });
-    it('upgrades multiple caret ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.7.0', config)
-      ).toMatchSnapshot();
-    });
-    it('ignores complex ranges when not pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^0.7.0 || ^0.8.0', config)
-      ).toHaveLength(0);
-    });
-    it('returns nothing for greater than ranges', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '>= 0.7.0', config)
-      ).toHaveLength(0);
-    });
-    it('upgrades less than equal ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '<= 0.7.2', config)
-      ).toMatchSnapshot();
-    });
-    it('rejects less than ranges without pinning', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(qJson, '< 0.7.2', config)
-      ).toEqual([]);
-    });
-    it('supports > latest versions if configured', () => {
-      const config = Object.assign({}, defaultConfig);
-      config.respectLatest = false;
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.4.1', config)
-      ).toMatchSnapshot();
-    });
-    it('supports future versions if configured', () => {
-      const config = Object.assign({}, defaultConfig);
-      config.ignoreFuture = false;
-      config.respectLatest = false;
-      expect(
-        versionsHelper.determineUpgrades(qJson, '1.4.1', config)
-      ).toMatchSnapshot();
-    });
-    it('supports future versions if already future', () => {
-      expect(
-        versionsHelper.determineUpgrades(qJson, '^2.0.0', defaultConfig)
-      ).toMatchSnapshot();
-    });
-    it('should ignore unstable versions if the current version is stable', () => {
-      versionsHelper
-        .determineUpgrades(
-          {
-            name: 'amazing-package',
-            versions: {
-              '1.0.0': {},
-              '1.1.0-beta': {},
-            },
-          },
-          '1.0.0',
-          defaultConfig
-        )
-        .should.eql([]);
-    });
-    it('should allow unstable versions if the current version is unstable', () => {
-      expect(
-        versionsHelper.determineUpgrades(
-          {
-            name: 'amazing-package',
-            versions: {
-              '1.0.0-beta': {},
-              '1.1.0-beta': {},
-            },
-          },
-          '1.0.0-beta',
-          defaultConfig
-        )
-      ).toMatchSnapshot();
-    });
-    it('should treat zero zero tilde ranges as 0.0.x', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(helmetJson, '~0.0.34', config)
-      ).toEqual([]);
-    });
-    it('should treat zero zero caret ranges as pinned', () => {
-      const config = Object.assign({}, defaultConfig, { pinVersions: false });
-      expect(
-        versionsHelper.determineUpgrades(helmetJson, '^0.0.34', config)
-      ).toMatchSnapshot();
-    });
-  });
-  describe('.isRange(input)', () => {
-    it('rejects simple semver', () => {
-      versionsHelper.isRange('1.2.3').should.eql(false);
-    });
-    it('accepts tilde', () => {
-      versionsHelper.isRange('~1.2.3').should.eql(true);
-    });
-    it('accepts caret', () => {
-      versionsHelper.isRange('^1.2.3').should.eql(true);
-    });
-  });
-  describe('.isValidVersion(input)', () => {
-    it('should support simple semver', () => {
-      versionsHelper.isValidVersion('1.2.3').should.eql(true);
-    });
-    it('should support versions with dash', () => {
-      versionsHelper.isValidVersion('1.2.3-foo').should.eql(true);
-    });
-    it('should reject versions without dash', () => {
-      versionsHelper.isValidVersion('1.2.3foo').should.eql(false);
-    });
-    it('should support ranges', () => {
-      versionsHelper.isValidVersion('~1.2.3').should.eql(true);
-      versionsHelper.isValidVersion('^1.2.3').should.eql(true);
-      versionsHelper.isValidVersion('>1.2.3').should.eql(true);
-    });
-    it('should reject github repositories', () => {
-      versionsHelper.isValidVersion('singapore/renovate').should.eql(false);
-      versionsHelper
-        .isValidVersion('singapore/renovate#master')
-        .should.eql(false);
-      versionsHelper
-        .isValidVersion('https://github.com/singapore/renovate.git')
-        .should.eql(false);
-    });
-  });
-  describe('.isPastLatest(dep, version)', () => {
-    it('should return false for less than', () => {
-      versionsHelper.isPastLatest(qJson, '1.0.0').should.eql(false);
-    });
-    it('should return false for equal', () => {
-      versionsHelper.isPastLatest(qJson, '1.4.1').should.eql(false);
-    });
-    it('should return true for greater than', () => {
-      versionsHelper.isPastLatest(qJson, '2.0.3').should.eql(true);
-    });
-  });
-});
diff --git a/test/workers/__snapshots__/global.spec.js.snap b/test/workers/__snapshots__/global.spec.js.snap
deleted file mode 100644
index 0aaa44f801f7194bb46aab23e002f99b09b99892..0000000000000000000000000000000000000000
--- a/test/workers/__snapshots__/global.spec.js.snap
+++ /dev/null
@@ -1,26 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`lib/workers/global processes repositories 1`] = `
-Array [
-  Array [
-    Object {
-      "foo": 1,
-      "repositories": Array [
-        "a",
-        "b",
-      ],
-    },
-    0,
-  ],
-  Array [
-    Object {
-      "foo": 1,
-      "repositories": Array [
-        "a",
-        "b",
-      ],
-    },
-    1,
-  ],
-]
-`;
diff --git a/test/workers/__snapshots__/package-file.spec.js.snap b/test/workers/__snapshots__/package-file.spec.js.snap
deleted file mode 100644
index 0c7271025ec41f4ad7367532ec2004ee9ff07e24..0000000000000000000000000000000000000000
--- a/test/workers/__snapshots__/package-file.spec.js.snap
+++ /dev/null
@@ -1,215 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles depType config with override 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "beta",
-    },
-    "depName": "a",
-    "depType": "dependencies",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles depType config without override 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "alpha": "beta",
-      "foo": "bar",
-    },
-    "depName": "a",
-    "depType": "dependencies",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles multiple deps 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "a",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "b",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles non-regex package name 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "eslint",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "eslint-foo",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "a",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "also-eslint",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles package config 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "renovate",
-      ],
-    },
-    "depName": "a",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles regex package pattern 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "eslint",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "eslint-foo",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "a",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "also-eslint",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles regex wildcard package pattern 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "eslint",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-      "labels": Array [
-        "eslint",
-      ],
-    },
-    "depName": "eslint-foo",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "a",
-  },
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "also-eslint",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) handles string deps 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "bar",
-    },
-    "depName": "a",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) nested package config overrides depType and general config 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "gamma",
-    },
-    "depName": "a",
-    "depType": "dependencies",
-  },
-]
-`;
-
-exports[`packageFileWorker assignDepConfigs(inputConfig, deps) package config overrides depType and general config 1`] = `
-Array [
-  Object {
-    "config": Object {
-      "foo": "gamma",
-    },
-    "depName": "a",
-    "depType": "dependencies",
-  },
-]
-`;
-
-exports[`packageFileWorker processPackageFile(config) extracts dependencies for each depType 1`] = `
-Array [
-  Array [
-    Object {},
-    Array [
-      "dependencies",
-      "devDependencies",
-    ],
-  ],
-]
-`;
-
-exports[`packageFileWorker processPackageFile(config) filters dependencies 1`] = `
-Array [
-  "a",
-]
-`;
diff --git a/test/workers/dep-type/index.spec.js b/test/workers/dep-type/index.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..39eaa352d2a431512e32f7b3568a36fa33491ea4
--- /dev/null
+++ b/test/workers/dep-type/index.spec.js
@@ -0,0 +1,77 @@
+const packageJson = require('../../../lib/workers/dep-type/package-json');
+const pkgWorker = require('../../../lib/workers/package/index');
+const depTypeWorker = require('../../../lib/workers/dep-type/index');
+
+const logger = require('../../_fixtures/logger');
+
+jest.mock('../../../lib/workers/dep-type/package-json');
+jest.mock('../../../lib/workers/package/index');
+
+pkgWorker.findUpgrades = jest.fn(() => ['a']);
+
+describe('lib/workers/dep-type/index', () => {
+  describe('findUpgrades(packageContent, config)', () => {
+    let config;
+    beforeEach(() => {
+      config = {
+        ignoreDeps: ['a', 'b'],
+      };
+    });
+    it('returns empty if no deps found', async () => {
+      packageJson.extractDependencies.mockReturnValueOnce([]);
+      const res = await depTypeWorker.findUpgrades({}, config);
+      expect(res).toMatchObject([]);
+    });
+    it('returns empty if all deps are filtered', async () => {
+      packageJson.extractDependencies.mockReturnValueOnce([
+        { depName: 'a' },
+        { depName: 'b' },
+      ]);
+      const res = await depTypeWorker.findUpgrades({}, config);
+      expect(res).toMatchObject([]);
+    });
+    it('returns combined upgrades if all deps are filtered', async () => {
+      packageJson.extractDependencies.mockReturnValueOnce([
+        { depName: 'a' },
+        { depName: 'c' },
+        { depName: 'd' },
+      ]);
+      const res = await depTypeWorker.findUpgrades({}, config);
+      expect(res).toHaveLength(2);
+    });
+  });
+  describe('getDepConfig(depTypeConfig, dep)', () => {
+    const depTypeConfig = {
+      foo: 'bar',
+      logger,
+      packages: [
+        {
+          packageName: 'a',
+          x: 2,
+        },
+        {
+          packagePattern: 'a',
+          y: 2,
+        },
+      ],
+    };
+    it('applies only one rule', () => {
+      const dep = {
+        depName: 'a',
+      };
+      const res = depTypeWorker.getDepConfig(depTypeConfig, dep);
+      expect(res.x).toBe(2);
+      expect(res.y).toBeUndefined();
+      expect(res.packages).toBeUndefined();
+    });
+    it('applies the second rule', () => {
+      const dep = {
+        depName: 'abc',
+      };
+      const res = depTypeWorker.getDepConfig(depTypeConfig, dep);
+      expect(res.x).toBeUndefined();
+      expect(res.y).toBe(2);
+      expect(res.packages).toBeUndefined();
+    });
+  });
+});
diff --git a/test/workers/dep-type/package-json.spec.js b/test/workers/dep-type/package-json.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..ff9fe1531e5ee58983d0f3b248e92b5632cce7b8
--- /dev/null
+++ b/test/workers/dep-type/package-json.spec.js
@@ -0,0 +1,59 @@
+const fs = require('fs');
+const path = require('path');
+const packageJson = require('../../../lib/workers/dep-type/package-json');
+
+function readFixture(fixture) {
+  return fs.readFileSync(
+    path.resolve(__dirname, `../../_fixtures/package-json/${fixture}`),
+    'utf8'
+  );
+}
+
+const input01Content = readFixture('inputs/01.json');
+const input02Content = readFixture('inputs/02.json');
+
+describe('helpers/package-json', () => {
+  describe('.extractDependencies(packageJson, depType)', () => {
+    it('returns an array of correct length (dependencies)', () => {
+      const extractedDependencies = packageJson.extractDependencies(
+        JSON.parse(input01Content),
+        'dependencies'
+      );
+      extractedDependencies.should.be.instanceof(Array);
+      extractedDependencies.should.have.length(6);
+    });
+    it('returns an array of correct length (devDependencies)', () => {
+      const extractedDependencies = packageJson.extractDependencies(
+        JSON.parse(input01Content),
+        'devDependencies'
+      );
+      extractedDependencies.should.be.instanceof(Array);
+      extractedDependencies.should.have.length(4);
+    });
+    it('each element contains non-null depType, depName, currentVersion', () => {
+      const extractedDependencies = packageJson.extractDependencies(
+        JSON.parse(input01Content),
+        'dependencies'
+      );
+      extractedDependencies
+        .every(dep => dep.depType && dep.depName && dep.currentVersion)
+        .should.eql(true);
+    });
+    it('supports null devDependencies indirect', () => {
+      const extractedDependencies = packageJson.extractDependencies(
+        JSON.parse(input02Content),
+        'dependencies'
+      );
+      extractedDependencies.should.be.instanceof(Array);
+      extractedDependencies.should.have.length(6);
+    });
+    it('supports null', () => {
+      const extractedDependencies = packageJson.extractDependencies(
+        JSON.parse(input02Content),
+        'fooDependencies'
+      );
+      extractedDependencies.should.be.instanceof(Array);
+      extractedDependencies.should.have.length(0);
+    });
+  });
+});
diff --git a/test/workers/global.spec.js b/test/workers/global.spec.js
index 5bb78253c1cc8bfad592eb8f1ccca987a8959310..64795391adfc99986eee59c0924ce4cb72265076 100644
--- a/test/workers/global.spec.js
+++ b/test/workers/global.spec.js
@@ -1,7 +1,6 @@
 const globalWorker = require('../../lib/workers/global');
 const repositoryWorker = require('../../lib/workers/repository');
 const configParser = require('../../lib/config');
-const logger = require('../_fixtures/logger');
 
 describe('lib/workers/global', () => {
   beforeEach(() => {
@@ -21,13 +20,8 @@ describe('lib/workers/global', () => {
       foo: 1,
       repositories: ['a', 'b'],
     });
-    configParser.getRepositoryConfig.mockReturnValue({
-      repository: 'foo',
-      logger,
-    });
     await globalWorker.start();
     expect(configParser.parseConfigs.mock.calls.length).toBe(1);
-    expect(configParser.getRepositoryConfig.mock.calls).toMatchSnapshot();
     expect(repositoryWorker.renovateRepository.mock.calls.length).toBe(2);
   });
   it('catches errors', async () => {
diff --git a/test/workers/package-file.spec.js b/test/workers/package-file.spec.js
deleted file mode 100644
index 44d2f05920e8d671ac9ab35294651d210dfa0300..0000000000000000000000000000000000000000
--- a/test/workers/package-file.spec.js
+++ /dev/null
@@ -1,350 +0,0 @@
-const packageFileWorker = require('../../lib/workers/package-file');
-const npmApi = require('../../lib/api/npm');
-const versionsHelper = require('../../lib/helpers/versions');
-const packageJsonHelper = require('../../lib/helpers/package-json');
-const logger = require('../_fixtures/logger');
-
-jest.mock('../../lib/workers/branch');
-jest.mock('../../lib/workers/pr');
-jest.mock('../../lib/api/npm');
-jest.mock('../../lib/helpers/versions');
-
-describe('packageFileWorker', () => {
-  describe('findUpgrades(dependencies, config)', () => {
-    let config;
-    beforeEach(() => {
-      config = {};
-      packageFileWorker.updateBranch = jest.fn();
-    });
-    it('handles null', async () => {
-      const allUpgrades = await packageFileWorker.findUpgrades([], config);
-      expect(allUpgrades).toMatchObject([]);
-    });
-    it('handles one dep', async () => {
-      const dep = {
-        depName: 'foo',
-        currentVersion: '1.0.0',
-      };
-      const upgrade = { newVersion: '1.1.0' };
-      npmApi.getDependency = jest.fn(() => ({}));
-      versionsHelper.determineUpgrades = jest.fn(() => [upgrade]);
-      const allUpgrades = await packageFileWorker.findUpgrades([dep], config);
-      expect(allUpgrades).toMatchObject([Object.assign({}, dep, upgrade)]);
-    });
-    it('handles no return', async () => {
-      const dep = {
-        depName: 'foo',
-        currentVersion: '1.0.0',
-      };
-      const upgrade = { newVersion: '1.1.0' };
-      npmApi.getDependency = jest.fn(() => ({}));
-      npmApi.getDependency.mockReturnValueOnce(null);
-      versionsHelper.determineUpgrades = jest.fn(() => [upgrade]);
-      const allUpgrades = await packageFileWorker.findUpgrades([dep], config);
-      expect(allUpgrades).toMatchObject([]);
-    });
-    it('handles no upgrades', async () => {
-      const dep = {
-        depName: 'foo',
-        currentVersion: '1.0.0',
-      };
-      npmApi.getDependency = jest.fn(() => ({}));
-      versionsHelper.determineUpgrades = jest.fn(() => []);
-      const allUpgrades = await packageFileWorker.findUpgrades([dep], config);
-      expect(allUpgrades).toMatchObject([]);
-    });
-  });
-  describe('assignDepConfigs(inputConfig, deps)', () => {
-    let config;
-    let deps;
-    beforeEach(() => {
-      config = {};
-      deps = [];
-    });
-    it('handles empty deps', () => {
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchObject([]);
-    });
-    it('handles string deps', () => {
-      config.foo = 'bar';
-      config.depTypes = ['dependencies', 'devDependencies'];
-      deps.push({
-        depName: 'a',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles multiple deps', () => {
-      config.foo = 'bar';
-      deps.push({
-        depName: 'a',
-      });
-      deps.push({
-        depName: 'b',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles depType config without override', () => {
-      config.foo = 'bar';
-      config.depTypes = [
-        {
-          depType: 'dependencies',
-          alpha: 'beta',
-        },
-      ];
-      deps.push({
-        depName: 'a',
-        depType: 'dependencies',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles depType config with override', () => {
-      config.foo = 'bar';
-      config.depTypes = [
-        {
-          depType: 'dependencies',
-          foo: 'beta',
-        },
-      ];
-      deps.push({
-        depName: 'a',
-        depType: 'dependencies',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles package config', () => {
-      config.foo = 'bar';
-      config.packages = [
-        {
-          packageName: 'a',
-          labels: ['renovate'],
-        },
-      ];
-      deps.push({
-        depName: 'a',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('package config overrides depType and general config', () => {
-      config.foo = 'bar';
-      config.depTypes = [
-        {
-          depType: 'dependencies',
-          foo: 'beta',
-        },
-      ];
-      config.packages = [
-        {
-          packageName: 'a',
-          foo: 'gamma',
-        },
-      ];
-      deps.push({
-        depName: 'a',
-        depType: 'dependencies',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('nested package config overrides depType and general config', () => {
-      config.foo = 'bar';
-      config.depTypes = [
-        {
-          depType: 'dependencies',
-          foo: 'beta',
-          packages: [
-            {
-              packageName: 'a',
-              foo: 'gamma',
-            },
-          ],
-        },
-      ];
-      deps.push({
-        depName: 'a',
-        depType: 'dependencies',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles regex package pattern', () => {
-      config.foo = 'bar';
-      config.packages = [
-        {
-          packagePattern: 'eslint',
-          labels: ['eslint'],
-        },
-      ];
-      deps.push({
-        depName: 'eslint',
-      });
-      deps.push({
-        depName: 'eslint-foo',
-      });
-      deps.push({
-        depName: 'a',
-      });
-      deps.push({
-        depName: 'also-eslint',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles regex wildcard package pattern', () => {
-      config.foo = 'bar';
-      config.packages = [
-        {
-          packagePattern: '^eslint',
-          labels: ['eslint'],
-        },
-      ];
-      deps.push({
-        depName: 'eslint',
-      });
-      deps.push({
-        depName: 'eslint-foo',
-      });
-      deps.push({
-        depName: 'a',
-      });
-      deps.push({
-        depName: 'also-eslint',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-    it('handles non-regex package name', () => {
-      config.foo = 'bar';
-      config.packages = [
-        {
-          packageName: 'eslint',
-          labels: ['eslint'],
-        },
-      ];
-      deps.push({
-        depName: 'eslint',
-      });
-      deps.push({
-        depName: 'eslint-foo',
-      });
-      deps.push({
-        depName: 'a',
-      });
-      deps.push({
-        depName: 'also-eslint',
-      });
-      const updatedDeps = packageFileWorker.assignDepConfigs(config, deps);
-      expect(updatedDeps).toMatchSnapshot();
-    });
-  });
-  describe('getDepTypeConfig(depTypes, depTypeName)', () => {
-    it('handles empty depTypes', () => {
-      const depTypeConfig = packageFileWorker.getDepTypeConfig(
-        [],
-        'dependencies'
-      );
-      expect(depTypeConfig).toMatchObject({});
-    });
-    it('handles all strings', () => {
-      const depTypes = ['dependencies', 'devDependencies'];
-      const depTypeConfig = packageFileWorker.getDepTypeConfig(
-        depTypes,
-        'dependencies'
-      );
-      expect(depTypeConfig).toMatchObject({});
-    });
-    it('handles missed object', () => {
-      const depTypes = [
-        'dependencies',
-        {
-          depType: 'devDependencies',
-          foo: 'bar',
-        },
-      ];
-      const depTypeConfig = packageFileWorker.getDepTypeConfig(
-        depTypes,
-        'dependencies'
-      );
-      expect(depTypeConfig).toMatchObject({});
-    });
-    it('handles hit object', () => {
-      const depTypes = [
-        {
-          depType: 'dependencies',
-          foo: 'bar',
-        },
-        'devDependencies',
-      ];
-      const depTypeConfig = packageFileWorker.getDepTypeConfig(
-        depTypes,
-        'dependencies'
-      );
-      const expectedResult = {
-        foo: 'bar',
-      };
-      expect(depTypeConfig).toMatchObject(expectedResult);
-    });
-  });
-  describe('processPackageFile(config)', () => {
-    let config;
-    beforeEach(() => {
-      packageFileWorker.assignDepConfigs = jest.fn(() => []);
-      packageFileWorker.findUpgrades = jest.fn(() => []);
-      packageJsonHelper.extractDependencies = jest.fn(() => []);
-      config = require('../../lib/config/defaults').getConfig();
-      config.api = {
-        getFileJson: jest.fn(() => ({})),
-      };
-      config.logger = logger;
-    });
-    it('returns empty array if no package content', async () => {
-      config.api.getFileJson.mockReturnValueOnce(null);
-      const res = await packageFileWorker.processPackageFile(config);
-      expect(res).toEqual([]);
-    });
-    it('returns empty array if config disabled', async () => {
-      config.api.getFileJson.mockReturnValueOnce({
-        renovate: {
-          enabled: false,
-        },
-      });
-      const res = await packageFileWorker.processPackageFile(config);
-      expect(res).toEqual([]);
-    });
-    it('extracts dependencies for each depType', async () => {
-      config.depTypes = [
-        'dependencies',
-        {
-          depType: 'devDependencies',
-          foo: 'bar',
-        },
-      ];
-      const res = await packageFileWorker.processPackageFile(config);
-      expect(res).toEqual([]);
-      expect(
-        packageJsonHelper.extractDependencies.mock.calls
-      ).toMatchSnapshot();
-    });
-    it('filters dependencies', async () => {
-      packageJsonHelper.extractDependencies.mockReturnValueOnce([
-        {
-          depName: 'a',
-        },
-      ]);
-      packageFileWorker.assignDepConfigs.mockReturnValueOnce(['a']);
-      packageFileWorker.findUpgrades.mockReturnValueOnce(['a']);
-      const res = await packageFileWorker.processPackageFile(config);
-      expect(res).toHaveLength(1);
-      expect(res).toMatchSnapshot();
-    });
-    it('maintains yarn.lock', async () => {
-      config.maintainYarnLock = true;
-      const res = await packageFileWorker.processPackageFile(config);
-      expect(res).toHaveLength(1);
-    });
-  });
-});
diff --git a/test/workers/package-file/index.spec.js b/test/workers/package-file/index.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..231e52fe5107ed777f6f721241639e5a349fa1d1
--- /dev/null
+++ b/test/workers/package-file/index.spec.js
@@ -0,0 +1,52 @@
+const packageFileWorker = require('../../../lib/workers/package-file');
+const depTypeWorker = require('../../../lib/workers/dep-type');
+
+jest.mock('../../../lib/workers/dep-type');
+
+describe('packageFileWorker', () => {
+  describe('findUpgrades(config)', () => {
+    let config;
+    beforeEach(() => {
+      config = {
+        api: {
+          getFileJson: jest.fn(),
+        },
+        depTypes: ['dependencies', 'devDependencies'],
+      };
+      packageFileWorker.updateBranch = jest.fn();
+    });
+    it('handles null', async () => {
+      const allUpgrades = await packageFileWorker.findUpgrades(config);
+      expect(allUpgrades).toHaveLength(0);
+    });
+    it('handles no renovate config', async () => {
+      config.enabled = false;
+      config.api.getFileJson.mockReturnValueOnce({});
+      const res = await packageFileWorker.findUpgrades(config);
+      expect(res).toEqual([]);
+    });
+    it('returns empty array if config disabled', async () => {
+      config.api.getFileJson.mockReturnValueOnce({
+        renovate: {
+          enabled: false,
+        },
+      });
+      const res = await packageFileWorker.findUpgrades(config);
+      expect(res).toEqual([]);
+    });
+    it('calls depTypeWorker', async () => {
+      config.api.getFileJson.mockReturnValueOnce({});
+      depTypeWorker.findUpgrades.mockReturnValueOnce([{}]);
+      depTypeWorker.findUpgrades.mockReturnValueOnce([{}, {}]);
+      const res = await packageFileWorker.findUpgrades(config);
+      expect(res).toHaveLength(3);
+    });
+    it('maintains yarn.lock', async () => {
+      config.api.getFileJson.mockReturnValueOnce({});
+      config.maintainYarnLock = true;
+      depTypeWorker.findUpgrades.mockReturnValue([]);
+      const res = await packageFileWorker.findUpgrades(config);
+      expect(res).toHaveLength(1);
+    });
+  });
+});
diff --git a/test/helpers/__snapshots__/versions.spec.js.snap b/test/workers/package/__snapshots__/versions.spec.js.snap
similarity index 69%
rename from test/helpers/__snapshots__/versions.spec.js.snap
rename to test/workers/package/__snapshots__/versions.spec.js.snap
index e5ea3885f7f4ba4f6725d420d935dce92fa7a23d..c69f30ba91042222678cf2d57aec5645ccd04853 100644
--- a/test/helpers/__snapshots__/versions.spec.js.snap
+++ b/test/workers/package/__snapshots__/versions.spec.js.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) disables major release separation (major) 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) disables major release separation (major) 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -14,7 +14,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) disables major release separation (minor) 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) disables major release separation (minor) 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -28,7 +28,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) ignores pinning for ranges when other upgrade exists 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) ignores pinning for ranges when other upgrade exists 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -42,7 +42,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) pins minor ranged versions 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) pins minor ranged versions 1`] = `
 Array [
   Object {
     "automergeEnabled": true,
@@ -54,7 +54,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) returns both updates if automerging minor 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) returns both updates if automerging minor 1`] = `
 Array [
   Object {
     "automergeEnabled": true,
@@ -77,7 +77,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) returns only one update if automerging any 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) returns only one update if automerging any 1`] = `
 Array [
   Object {
     "automergeEnabled": true,
@@ -91,7 +91,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) returns only one update if grouping 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) returns only one update if grouping 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -105,7 +105,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) should allow unstable versions if the current version is unstable 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) should allow unstable versions if the current version is unstable 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -119,7 +119,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) should treat zero zero caret ranges as pinned 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) should treat zero zero caret ranges as pinned 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -134,7 +134,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) supports > latest versions if configured 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) supports > latest versions if configured 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -148,7 +148,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) supports future versions if already future 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) supports future versions if already future 1`] = `
 Array [
   Object {
     "automergeEnabled": true,
@@ -160,7 +160,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) supports future versions if configured 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) supports future versions if configured 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -174,7 +174,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) supports minor and major upgrades for ranged versions 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) supports minor and major upgrades for ranged versions 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -197,7 +197,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) supports minor and major upgrades for tilde ranges 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) supports minor and major upgrades for tilde ranges 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -220,7 +220,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades .x major ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades .x major ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -235,7 +235,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades .x minor ranges 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades .x minor ranges 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -249,7 +249,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades .x minor ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades .x minor ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -264,7 +264,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades less than equal ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades less than equal ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -289,7 +289,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades minor ranged versions 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades minor ranged versions 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -303,7 +303,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades multiple caret ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades multiple caret ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -328,7 +328,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades multiple tilde ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades multiple tilde ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -353,7 +353,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades shorthand major ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades shorthand major ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -368,7 +368,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades shorthand minor ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades shorthand minor ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -383,7 +383,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades tilde ranges 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades tilde ranges 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
@@ -397,7 +397,7 @@ Array [
 ]
 `;
 
-exports[`helpers/versions .determineUpgrades(dep, currentVersion, defaultConfig) upgrades tilde ranges without pinning 1`] = `
+exports[`workers/package/versions .determineUpgrades(npmDep, config) upgrades tilde ranges without pinning 1`] = `
 Array [
   Object {
     "automergeEnabled": false,
diff --git a/test/workers/package/index.spec.js b/test/workers/package/index.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..af3bc51bcf2303d80f9c4c2a98230db96af0b005
--- /dev/null
+++ b/test/workers/package/index.spec.js
@@ -0,0 +1,33 @@
+const npmApi = require('../../../lib/api/npm');
+const versions = require('../../../lib/workers/package/versions');
+const pkgWorker = require('../../../lib/workers/package/index');
+
+jest.mock('../../../lib/workers/package/versions');
+jest.mock('../../../lib/api/npm');
+
+describe('lib/workers/package/index', () => {
+  describe('findUpgrades(config)', () => {
+    let config;
+    beforeEach(() => {
+      config = {
+        depName: 'foo',
+      };
+    });
+    it('returns empty if no npm dep found', async () => {
+      const res = await pkgWorker.findUpgrades(config);
+      expect(res).toMatchObject([]);
+    });
+    it('returns empty if no upgrades found', async () => {
+      npmApi.getDependency.mockReturnValueOnce({});
+      versions.determineUpgrades.mockReturnValueOnce([]);
+      const res = await pkgWorker.findUpgrades(config);
+      expect(res).toMatchObject([]);
+    });
+    it('returns array if upgrades found', async () => {
+      npmApi.getDependency.mockReturnValueOnce({});
+      versions.determineUpgrades.mockReturnValueOnce([{}]);
+      const res = await pkgWorker.findUpgrades(config);
+      expect(res).toHaveLength(1);
+    });
+  });
+});
diff --git a/test/workers/package/versions.spec.js b/test/workers/package/versions.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..29964bcfe55ffee04e8c42b2830d38c200d627d8
--- /dev/null
+++ b/test/workers/package/versions.spec.js
@@ -0,0 +1,246 @@
+const versions = require('../../../lib/workers/package/versions');
+const qJson = require('../../_fixtures/npm/01.json');
+const helmetJson = require('../../_fixtures/npm/02.json');
+
+let config;
+
+describe('workers/package/versions', () => {
+  beforeEach(() => {
+    config = require('../../../lib/config/defaults').getConfig();
+  });
+
+  describe('.determineUpgrades(npmDep, config)', () => {
+    it('return empty if invalid current version', () => {
+      config.currentVersion = 'invalid';
+      versions.determineUpgrades(qJson, config).should.have.length(0);
+    });
+    it('return empty if null versions', () => {
+      config.currentVersion = '1.0.0';
+      const testDep = {
+        name: 'q',
+      };
+      versions.determineUpgrades(testDep, config).should.have.length(0);
+    });
+    it('return empty if empty versions', () => {
+      const testDep = {
+        name: 'q',
+        versions: [],
+      };
+      config.currentVersion = '1.0.0';
+      versions.determineUpgrades(testDep, config).should.have.length(0);
+    });
+    it('supports minor and major upgrades for tilde ranges', () => {
+      config.currentVersion = '^0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('returns only one update if grouping', () => {
+      config.groupName = 'somegroup';
+      config.currentVersion = '^0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('returns only one update if automerging any', () => {
+      config.automerge = 'any';
+      config.currentVersion = '^0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('returns both updates if automerging minor', () => {
+      config.automerge = 'minor';
+      config.currentVersion = '^0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('disables major release separation (major)', () => {
+      config.separateMajorReleases = false;
+      config.currentVersion = '^0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('disables major release separation (minor)', () => {
+      config.separateMajorReleases = false;
+      config.currentVersion = '1.0.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('supports minor and major upgrades for ranged versions', () => {
+      config.currentVersion = '~0.4.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('ignores pinning for ranges when other upgrade exists', () => {
+      config.currentVersion = '~0.9.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades minor ranged versions', () => {
+      config.currentVersion = '~1.0.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('pins minor ranged versions', () => {
+      config.currentVersion = '^1.0.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('ignores minor ranged versions when not pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '^1.0.0';
+      expect(versions.determineUpgrades(qJson, config)).toHaveLength(0);
+    });
+    it('upgrades tilde ranges', () => {
+      config.currentVersion = '~1.3.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades .x minor ranges', () => {
+      config.currentVersion = '1.3.x';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades tilde ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '~1.3.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades .x major ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '0.x';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades .x minor ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '1.3.x';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades shorthand major ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades shorthand minor ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '1.3';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades multiple tilde ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '~0.7.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('upgrades multiple caret ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '^0.7.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('ignores complex ranges when not pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '^0.7.0 || ^0.8.0';
+      expect(versions.determineUpgrades(qJson, config)).toHaveLength(0);
+    });
+    it('returns nothing for greater than ranges', () => {
+      config.pinVersions = false;
+      config.currentVersion = '>= 0.7.0';
+      expect(versions.determineUpgrades(qJson, config)).toHaveLength(0);
+    });
+    it('upgrades less than equal ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '<= 0.7.2';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('rejects less than ranges without pinning', () => {
+      config.pinVersions = false;
+      config.currentVersion = '< 0.7.2';
+      expect(versions.determineUpgrades(qJson, config)).toEqual([]);
+    });
+    it('supports > latest versions if configured', () => {
+      config.respectLatest = false;
+      config.currentVersion = '1.4.1';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('supports future versions if configured', () => {
+      config.ignoreFuture = false;
+      config.respectLatest = false;
+      config.currentVersion = '1.4.1';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('supports future versions if already future', () => {
+      config.currentVersion = '^2.0.0';
+      expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot();
+    });
+    it('should ignore unstable versions if the current version is stable', () => {
+      config.currentVersion = '1.0.0';
+      versions
+        .determineUpgrades(
+          {
+            name: 'amazing-package',
+            versions: {
+              '1.0.0': {},
+              '1.1.0-beta': {},
+            },
+          },
+          config
+        )
+        .should.eql([]);
+    });
+    it('should allow unstable versions if the current version is unstable', () => {
+      config.currentVersion = '1.0.0-beta';
+      expect(
+        versions.determineUpgrades(
+          {
+            name: 'amazing-package',
+            versions: {
+              '1.0.0-beta': {},
+              '1.1.0-beta': {},
+            },
+          },
+          config
+        )
+      ).toMatchSnapshot();
+    });
+    it('should treat zero zero tilde ranges as 0.0.x', () => {
+      config.pinVersions = false;
+      config.currentVersion = '~0.0.34';
+      expect(versions.determineUpgrades(helmetJson, config)).toEqual([]);
+    });
+    it('should treat zero zero caret ranges as pinned', () => {
+      config.pinVersions = false;
+      config.currentVersion = '^0.0.34';
+      expect(versions.determineUpgrades(helmetJson, config)).toMatchSnapshot();
+    });
+  });
+  describe('.isRange(input)', () => {
+    it('rejects simple semver', () => {
+      versions.isRange('1.2.3').should.eql(false);
+    });
+    it('accepts tilde', () => {
+      versions.isRange('~1.2.3').should.eql(true);
+    });
+    it('accepts caret', () => {
+      versions.isRange('^1.2.3').should.eql(true);
+    });
+  });
+  describe('.isValidVersion(input)', () => {
+    it('should support simple semver', () => {
+      versions.isValidVersion('1.2.3').should.eql(true);
+    });
+    it('should support versions with dash', () => {
+      versions.isValidVersion('1.2.3-foo').should.eql(true);
+    });
+    it('should reject versions without dash', () => {
+      versions.isValidVersion('1.2.3foo').should.eql(false);
+    });
+    it('should support ranges', () => {
+      versions.isValidVersion('~1.2.3').should.eql(true);
+      versions.isValidVersion('^1.2.3').should.eql(true);
+      versions.isValidVersion('>1.2.3').should.eql(true);
+    });
+    it('should reject github repositories', () => {
+      versions.isValidVersion('singapore/renovate').should.eql(false);
+      versions.isValidVersion('singapore/renovate#master').should.eql(false);
+      versions
+        .isValidVersion('https://github.com/singapore/renovate.git')
+        .should.eql(false);
+    });
+  });
+  describe('.isPastLatest(dep, version)', () => {
+    it('should return false for less than', () => {
+      versions.isPastLatest(qJson, '1.0.0').should.eql(false);
+    });
+    it('should return false for equal', () => {
+      versions.isPastLatest(qJson, '1.4.1').should.eql(false);
+    });
+    it('should return true for greater than', () => {
+      versions.isPastLatest(qJson, '2.0.3').should.eql(true);
+    });
+  });
+});
diff --git a/test/workers/repository/__snapshots__/onboarding.spec.js.snap b/test/workers/repository/__snapshots__/onboarding.spec.js.snap
index fd5c58b180779777a25fea7e3774fb9a85e795f3..680ece21f54bf1ef8f0c68fa05d9fb4a2421d2b7 100644
--- a/test/workers/repository/__snapshots__/onboarding.spec.js.snap
+++ b/test/workers/repository/__snapshots__/onboarding.spec.js.snap
@@ -10,9 +10,9 @@ Array [
   \\"enabled\\": true,
   \\"packageFiles\\": [],
   \\"depTypes\\": [\\"dependencies\\", \\"devDependencies\\", \\"optionalDependencies\\"],
+  \\"ignoreDeps\\": [],
   \\"pinVersions\\": true,
   \\"separateMajorReleases\\": true,
-  \\"ignoreDeps\\": [],
   \\"rebaseStalePrs\\": false,
   \\"prCreation\\": \\"immediate\\",
   \\"automerge\\": \\"none\\",
diff --git a/test/workers/repository/upgrades.spec.js b/test/workers/repository/upgrades.spec.js
index 02d338eb7c4d2a327cc5d6e32ef1f639c0b0bf25..2a27d13f80a6ec97cd5655733fa8260c6602e31f 100644
--- a/test/workers/repository/upgrades.spec.js
+++ b/test/workers/repository/upgrades.spec.js
@@ -24,7 +24,7 @@ describe('workers/repository/upgrades', () => {
           packageFile: 'backend/package.json',
         },
       ];
-      packageFileWorker.processPackageFile.mockReturnValue([]);
+      packageFileWorker.findUpgrades.mockReturnValue([]);
       const res = await upgrades.determineRepoUpgrades(config);
       expect(res.length).toBe(0);
     });
@@ -38,8 +38,8 @@ describe('workers/repository/upgrades', () => {
           fileName: 'frontend/package.json',
         },
       ];
-      packageFileWorker.processPackageFile.mockReturnValueOnce(['a']);
-      packageFileWorker.processPackageFile.mockReturnValueOnce(['b', 'c']);
+      packageFileWorker.findUpgrades.mockReturnValueOnce(['a']);
+      packageFileWorker.findUpgrades.mockReturnValueOnce(['b', 'c']);
       const res = await upgrades.determineRepoUpgrades(config);
       expect(res.length).toBe(3);
     });