diff --git a/lib/config/env.ts b/lib/config/env.ts
index 46109a44317652005370cb057d56048ad194fd3c..3946d684bf42c62f0bb767472405e20218bfc5c6 100644
--- a/lib/config/env.ts
+++ b/lib/config/env.ts
@@ -3,7 +3,7 @@ import is from '@sindresorhus/is';
 import { getOptions, RenovateOptions } from './definitions';
 import { RenovateConfig } from './common';
 import { logger } from '../logger';
-import { DATASOURCE_DOCKER } from '../constants/data-binary-source';
+import * as datasourceDocker from '../datasource/docker';
 import { PLATFORM_TYPE_GITHUB } from '../constants/platforms';
 
 export function getEnvName(option: Partial<RenovateOptions>): string {
@@ -67,7 +67,7 @@ export function getConfig(env: NodeJS.ProcessEnv): RenovateConfig {
 
   if (env.DOCKER_USERNAME && env.DOCKER_PASSWORD) {
     config.hostRules.push({
-      hostType: DATASOURCE_DOCKER,
+      hostType: datasourceDocker.id,
       username: env.DOCKER_USERNAME,
       password: env.DOCKER_PASSWORD,
     });
diff --git a/lib/constants/data-binary-source.ts b/lib/constants/data-binary-source.ts
deleted file mode 100644
index 018db325d29667e5fb6f2bc41e437e2320ab6d5c..0000000000000000000000000000000000000000
--- a/lib/constants/data-binary-source.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// Datasource
-export const DATASOURCE_GALAXY = 'galaxy';
-export const DATASOURCE_CARGO = 'cargo';
-export const DATASOURCE_CDNJS = 'cdnjs';
-export const DATASOURCE_DART = 'dart';
-export const DATASOURCE_DOCKER = 'docker';
-export const DATASOURCE_GIT_SUBMODULES = 'git-submodules';
-export const DATASOURCE_GIT_TAGS = 'git-tags';
-export const DATASOURCE_GITHUB_RELEASES = 'github-releases';
-export const DATASOURCE_GITHUB_TAGS = 'github-tags';
-export const DATASOURCE_GITLAB_TAGS = 'gitlab-tags';
-export const DATASOURCE_GO = 'go';
-export const DATASOURCE_GRADLE_VERSION = 'gradle-version';
-export const DATASOURCE_HELM = 'helm';
-export const DATASOURCE_HEX = 'hex';
-export const DATASOURCE_MAVEN = 'maven';
-export const DATASOURCE_NPM = 'npm';
-export const DATASOURCE_NUGET = 'nuget';
-export const DATASOURCE_ORB = 'orb';
-export const DATASOURCE_PACKAGIST = 'packagist';
-export const DATASOURCE_PYPI = 'pypi';
-export const DATASOURCE_RUBYGEMS = 'rubygems';
-export const DATASOURCE_RUBY_VERSION = 'ruby-version';
-export const DATASOURCE_SBT_PACKAGE = 'sbt-package';
-export const DATASOURCE_SBT_PLUGIN = 'sbt-plugin';
-export const DATASOURCE_TERRAFORM = 'terraform';
-export const DATASOURCE_TERRAFORM_PROVIDER = 'terraform-provider';
diff --git a/lib/datasource/__snapshots__/index.spec.ts.snap b/lib/datasource/__snapshots__/index.spec.ts.snap
index 1d664daa3b54de012bbdd25e99047ffec29cece7..17fba1dd3366388c2933384152cff82297de7096 100644
--- a/lib/datasource/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/__snapshots__/index.spec.ts.snap
@@ -3,12 +3,14 @@
 exports[`datasource/index adds changelogUrl 1`] = `
 Object {
   "changelogUrl": "https://github.com/react-native-community/react-native-releases/blob/master/CHANGELOG.md",
+  "releases": Array [],
   "sourceUrl": "https://github.com/react-native-community/react-native-releases",
 }
 `;
 
 exports[`datasource/index adds sourceUrl 1`] = `
 Object {
+  "releases": Array [],
   "sourceUrl": "https://github.com/nodejs/node",
 }
 `;
diff --git a/lib/datasource/cargo/index.ts b/lib/datasource/cargo/index.ts
index 74318592b4ab46b8ae2978c6a80d763529eeff03..9becaca24c1c6ac4815ee787c07cb9b7cbe405a4 100644
--- a/lib/datasource/cargo/index.ts
+++ b/lib/datasource/cargo/index.ts
@@ -6,7 +6,8 @@ import {
   ReleaseResult,
   Release,
 } from '../common';
-import { DATASOURCE_CARGO } from '../../constants/data-binary-source';
+
+export const id = 'cargo';
 
 export async function getPkgReleases({
   lookupName,
@@ -45,7 +46,7 @@ export async function getPkgReleases({
   const crateUrl = baseUrl + path;
   try {
     let res: any = await got(crateUrl, {
-      hostType: DATASOURCE_CARGO,
+      hostType: id,
     });
     if (!res || !res.body) {
       logger.warn(
diff --git a/lib/datasource/cdnjs/index.ts b/lib/datasource/cdnjs/index.ts
index 38197558e62ce7951980f076142538bdd587454c..9b44c4ef24ac47eec5216b5563ce32b34ef437a9 100644
--- a/lib/datasource/cdnjs/index.ts
+++ b/lib/datasource/cdnjs/index.ts
@@ -1,7 +1,6 @@
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { DatasourceError, ReleaseResult, GetReleasesConfig } from '../common';
-import { DATASOURCE_CDNJS } from '../../constants/data-binary-source';
 
 export interface CdnjsAsset {
   version: string;
@@ -9,7 +8,9 @@ export interface CdnjsAsset {
   sri?: Record<string, string>;
 }
 
-const cacheNamespace = `datasource-${DATASOURCE_CDNJS}`;
+export const id = 'cdnjs';
+
+const cacheNamespace = `datasource-${id}`;
 const cacheMinutes = 60;
 
 export interface CdnjsResponse {
@@ -35,7 +36,7 @@ export async function getDigest(
   const assetName = lookupName.replace(`${library}/`, '');
   let res = null;
   try {
-    res = await got(url, { json: true });
+    res = await got(url, { hostType: id, json: true });
   } catch (e) /* istanbul ignore next */ {
     return null;
   }
@@ -69,7 +70,7 @@ export async function getPkgReleases({
   const url = depUrl(library);
 
   try {
-    const res = await got(url, { json: true });
+    const res = await got(url, { hostType: id, json: true });
 
     const cdnjsResp: CdnjsResponse = res.body;
 
diff --git a/lib/datasource/dart/index.ts b/lib/datasource/dart/index.ts
index 9369b318f31f022f6df9565686693c55117bb381..7c571066ad1cf01c73d404b350e3847cdef2536c 100644
--- a/lib/datasource/dart/index.ts
+++ b/lib/datasource/dart/index.ts
@@ -2,6 +2,8 @@ import got from '../../util/got';
 import { logger } from '../../logger';
 import { DatasourceError, ReleaseResult, GetReleasesConfig } from '../common';
 
+export const id = 'dart';
+
 export async function getPkgReleases({
   lookupName,
 }: GetReleasesConfig): Promise<ReleaseResult | null> {
@@ -21,6 +23,7 @@ export async function getPkgReleases({
   } = null;
   try {
     raw = await got(pkgUrl, {
+      hostType: id,
       json: true,
     });
   } catch (err) {
diff --git a/lib/datasource/docker/index.spec.ts b/lib/datasource/docker/index.spec.ts
index 18a3ff86e9ce4c3271f39ab4691d95099ef8a747..75b4ecf98acf27610de6fb2b148440348bdd2334 100644
--- a/lib/datasource/docker/index.spec.ts
+++ b/lib/datasource/docker/index.spec.ts
@@ -5,7 +5,6 @@ import * as docker from '.';
 import { getPkgReleases } from '..';
 import * as _hostRules from '../../util/host-rules';
 import { DATASOURCE_FAILURE } from '../../constants/error-messages';
-import { DATASOURCE_DOCKER } from '../../constants/data-binary-source';
 
 const got: any = _got;
 const hostRules: any = _hostRules;
@@ -279,7 +278,7 @@ describe('api/docker', () => {
     it('returns null if no token', async () => {
       got.mockReturnValueOnce({ body: {} });
       const res = await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'node',
       });
       expect(res).toBeNull();
@@ -302,7 +301,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: {} });
       const config = {
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'node',
         registryUrls: ['https://registry.company.com'],
       };
@@ -320,7 +319,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: { tags } });
       const res = await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'registry.company.com/node',
       });
       expect(res.releases).toHaveLength(1);
@@ -330,7 +329,7 @@ describe('api/docker', () => {
       got.mockReturnValueOnce({ headers: {} });
       got.mockReturnValueOnce({ headers: {}, body: {} });
       await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: '123456789.dkr.ecr.us-east-1.amazonaws.com/node',
       });
       // The  tag limit parameter `n` needs to be limited to 1000 for ECR
@@ -355,7 +354,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: {} });
       const res = await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'node',
       });
       expect(res.releases).toHaveLength(1);
@@ -376,7 +375,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: {} });
       const res = await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'docker.io/node',
       });
       expect(res.releases).toHaveLength(1);
@@ -397,7 +396,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: {} });
       const res = await getPkgReleases({
-        datasource: DATASOURCE_DOCKER,
+        datasource: docker.id,
         depName: 'k8s.gcr.io/kubernetes-dashboard-amd64',
       });
       expect(res.releases).toHaveLength(1);
diff --git a/lib/datasource/docker/index.ts b/lib/datasource/docker/index.ts
index 12d1469621353c896d38b3198d1fd88c7df6b8ea..1000420522fb7f7711833235bef1c756a5ef4363 100644
--- a/lib/datasource/docker/index.ts
+++ b/lib/datasource/docker/index.ts
@@ -10,11 +10,12 @@ import got from '../../util/got';
 import * as hostRules from '../../util/host-rules';
 import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
 import { GotResponse } from '../../platform';
-import { DATASOURCE_DOCKER } from '../../constants/data-binary-source';
 
 // TODO: add got typings when available
 // TODO: replace www-authenticate with https://www.npmjs.com/package/auth-header ?
 
+export const id = 'docker';
+
 const ecrRegex = /\d+\.dkr\.ecr\.([-a-z0-9]+)\.amazonaws\.com/;
 
 export interface RegistryRepository {
@@ -42,7 +43,7 @@ export function getRegistryRepository(
   if (!/^https?:\/\//.exec(registry)) {
     registry = `https://${registry}`;
   }
-  const opts = hostRules.find({ hostType: DATASOURCE_DOCKER, url: registry });
+  const opts = hostRules.find({ hostType: id, url: registry });
   if (opts && opts.insecureRegistry) {
     registry = registry.replace('https', 'http');
   }
@@ -106,7 +107,7 @@ async function getAuthHeaders(
 
     const opts: hostRules.HostRule & {
       headers?: Record<string, string>;
-    } = hostRules.find({ hostType: DATASOURCE_DOCKER, url: apiCheckUrl });
+    } = hostRules.find({ hostType: id, url: apiCheckUrl });
     opts.json = true;
     if (ecrRegex.test(registry)) {
       const [, region] = ecrRegex.exec(registry);
diff --git a/lib/datasource/galaxy/index.ts b/lib/datasource/galaxy/index.ts
index 6b96b63e8eb374e76d2149f590262a3acf437b5e..240f743a74b8597b1a838d6bdd6d140c58483354 100644
--- a/lib/datasource/galaxy/index.ts
+++ b/lib/datasource/galaxy/index.ts
@@ -2,6 +2,8 @@ import { logger } from '../../logger';
 import got from '../../util/got';
 import { GetReleasesConfig, ReleaseResult, Release } from '../common';
 
+export const id = 'galaxy';
+
 export async function getPkgReleases({
   lookupName,
 }: GetReleasesConfig): Promise<ReleaseResult | null> {
@@ -35,7 +37,7 @@ export async function getPkgReleases({
 
   try {
     let res: any = await got(galaxyAPIUrl, {
-      hostType: 'galaxy',
+      hostType: id,
     });
     if (!res || !res.body) {
       logger.warn(
diff --git a/lib/datasource/git-submodules/index.ts b/lib/datasource/git-submodules/index.ts
index c27d3b9e4302aee6056c7f8dc58ea16c94e806fe..95298dfd4920ae38bc2c53f5eb41cb2f492d8570 100644
--- a/lib/datasource/git-submodules/index.ts
+++ b/lib/datasource/git-submodules/index.ts
@@ -4,6 +4,8 @@ import { URL } from 'url';
 import { ReleaseResult, GetReleasesConfig, DigestConfig } from '../common';
 import { logger } from '../../logger';
 
+export const id = 'git-submodules';
+
 export async function getPkgReleases({
   lookupName,
   registryUrls,
diff --git a/lib/datasource/git-tags/index.ts b/lib/datasource/git-tags/index.ts
index a98409db0be4977ccce2fca01d96aa47620ea1e8..e2ccd341208c4f9d77c0bb0bbef90699689a1aab 100644
--- a/lib/datasource/git-tags/index.ts
+++ b/lib/datasource/git-tags/index.ts
@@ -3,6 +3,8 @@ import * as semver from '../../versioning/semver';
 import { logger } from '../../logger';
 import { ReleaseResult, GetReleasesConfig } from '../common';
 
+export const id = 'git-tags';
+
 const cacheNamespace = 'git-tags';
 const cacheMinutes = 10;
 
diff --git a/lib/datasource/github-releases/index.ts b/lib/datasource/github-releases/index.ts
index 4a3bc442144321e1149a66ffd910350194190518..f57f0434b5c394d5f70b9c9db47bd5ce5b3de97a 100644
--- a/lib/datasource/github-releases/index.ts
+++ b/lib/datasource/github-releases/index.ts
@@ -4,6 +4,8 @@ import { logger } from '../../logger';
 
 const { get: ghGot } = api;
 
+export const id = 'github-releases';
+
 const cacheNamespace = 'datasource-github-releases';
 
 /**
diff --git a/lib/datasource/github-tags/index.ts b/lib/datasource/github-tags/index.ts
index 59032a2f9822c3019157f9da34c0a8ce52b95b2f..9cfcf220602f0827a1f5f2fe1b29ef55e725094a 100644
--- a/lib/datasource/github-tags/index.ts
+++ b/lib/datasource/github-tags/index.ts
@@ -4,6 +4,8 @@ import { logger } from '../../logger';
 
 const { get: ghGot } = api;
 
+export const id = 'github-tags';
+
 const cacheNamespace = 'datasource-github-tags';
 function getCacheKey(repo: string, type: string): string {
   return `${repo}:${type}`;
diff --git a/lib/datasource/gitlab-tags/index.ts b/lib/datasource/gitlab-tags/index.ts
index c8e15086f2442eb42afdec10d467334636897e71..9a2a46f50314249be8a37d021d4ebbc86884051c 100644
--- a/lib/datasource/gitlab-tags/index.ts
+++ b/lib/datasource/gitlab-tags/index.ts
@@ -5,6 +5,8 @@ import { GetReleasesConfig, ReleaseResult } from '../common';
 
 const { get: glGot } = api;
 
+export const id = 'gitlab-tags';
+
 const cacheNamespace = 'datasource-gitlab';
 function getCacheKey(depHost: string, repo: string): string {
   const type = 'tags';
diff --git a/lib/datasource/go/index.ts b/lib/datasource/go/index.ts
index 972290716c552788dd8096193edbcf15d1b34478..6eaf0c16bf21a2bd324a2b7d726eaae59f4762cf 100644
--- a/lib/datasource/go/index.ts
+++ b/lib/datasource/go/index.ts
@@ -3,10 +3,8 @@ import got from '../../util/got';
 import * as github from '../github-tags';
 import { DigestConfig, GetReleasesConfig, ReleaseResult } from '../common';
 import { regEx } from '../../util/regex';
-import {
-  DATASOURCE_GITHUB_TAGS,
-  DATASOURCE_GO,
-} from '../../constants/data-binary-source';
+
+export const id = 'go';
 
 interface DataSource {
   datasource: string;
@@ -17,10 +15,10 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
   if (goModule.startsWith('gopkg.in/')) {
     const [pkg] = goModule.replace('gopkg.in/', '').split('.');
     if (pkg.includes('/')) {
-      return { datasource: DATASOURCE_GITHUB_TAGS, lookupName: pkg };
+      return { datasource: github.id, lookupName: pkg };
     }
     return {
-      datasource: DATASOURCE_GITHUB_TAGS,
+      datasource: github.id,
       lookupName: `go-${pkg}/${pkg}`,
     };
   }
@@ -28,7 +26,7 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
     const split = goModule.split('/');
     const lookupName = split[1] + '/' + split[2];
     return {
-      datasource: DATASOURCE_GITHUB_TAGS,
+      datasource: github.id,
       lookupName,
     };
   }
@@ -36,7 +34,7 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
   try {
     const res = (
       await got(pkgUrl, {
-        hostType: DATASOURCE_GO,
+        hostType: id,
       })
     ).body;
     const sourceMatch = res.match(
@@ -47,7 +45,7 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
       logger.debug({ goModule, goSourceUrl }, 'Go lookup source url');
       if (goSourceUrl && goSourceUrl.startsWith('https://github.com/')) {
         return {
-          datasource: DATASOURCE_GITHUB_TAGS,
+          datasource: github.id,
           lookupName: goSourceUrl
             .replace('https://github.com/', '')
             .replace(/\/$/, ''),
@@ -88,7 +86,7 @@ export async function getPkgReleases({
 }: Partial<GetReleasesConfig>): Promise<ReleaseResult | null> {
   logger.trace(`go.getPkgReleases(${lookupName})`);
   const source = await getDatasource(lookupName);
-  if (source && source.datasource === DATASOURCE_GITHUB_TAGS) {
+  if (source && source.datasource === github.id) {
     const res = await github.getPkgReleases(source);
     if (res && res.releases) {
       res.releases = res.releases.filter(
@@ -115,7 +113,7 @@ export async function getDigest(
   value?: string
 ): Promise<string | null> {
   const source = await getDatasource(lookupName);
-  if (source && source.datasource === DATASOURCE_GITHUB_TAGS) {
+  if (source && source.datasource === github.id) {
     // ignore v0.0.0- pseudo versions that are used Go Modules - look up default branch instead
     const tag = value && !value.startsWith('v0.0.0-2') ? value : undefined;
     const digest = await github.getDigest(source, tag);
diff --git a/lib/datasource/gradle-version/index.ts b/lib/datasource/gradle-version/index.ts
index c2f6bd572da1ea746e31d3a0bb9457719e415b43..b7b212158dc16f51d37cc341b8cb72f5d388d2d0 100644
--- a/lib/datasource/gradle-version/index.ts
+++ b/lib/datasource/gradle-version/index.ts
@@ -9,6 +9,8 @@ import {
   Release,
 } from '../common';
 
+export const id = 'gradle-version';
+
 const GradleVersionsServiceUrl = 'https://services.gradle.org/versions/all';
 
 interface GradleRelease {
@@ -33,6 +35,7 @@ export async function getPkgReleases({
     versionsUrls.map(async url => {
       try {
         const response: GradleRelease = await got(url, {
+          hostType: id,
           json: true,
         });
         const releases = response.body
diff --git a/lib/datasource/helm/index.ts b/lib/datasource/helm/index.ts
index 7964f53088d83b3bc3696663939a84d193a26a20..9f5c1b0ffd09a923af5f87dd7d6f83418df2c865 100644
--- a/lib/datasource/helm/index.ts
+++ b/lib/datasource/helm/index.ts
@@ -4,6 +4,8 @@ import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
 import got from '../../util/got';
 import { logger } from '../../logger';
 
+export const id = 'helm';
+
 export async function getRepositoryData(
   repository: string
 ): Promise<ReleaseResult[]> {
@@ -15,7 +17,7 @@ export async function getRepositoryData(
   }
   let res: any;
   try {
-    res = await got('index.yaml', { baseUrl: repository });
+    res = await got('index.yaml', { hostType: id, baseUrl: repository });
     if (!res || !res.body) {
       logger.warn(`Received invalid response from ${repository}`);
       return null;
diff --git a/lib/datasource/hex/index.ts b/lib/datasource/hex/index.ts
index 539312f41f76692140c847a646865e005ded0e6d..85a5c6335b1e840d31e344d65857e2690c8db7e3 100644
--- a/lib/datasource/hex/index.ts
+++ b/lib/datasource/hex/index.ts
@@ -1,7 +1,8 @@
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { DatasourceError, ReleaseResult, GetReleasesConfig } from '../common';
-import { DATASOURCE_HEX } from '../../constants/data-binary-source';
+
+export const id = 'hex';
 
 interface HexRelease {
   html_url: string;
@@ -28,7 +29,7 @@ export async function getPkgReleases({
   try {
     const response = await got(hexUrl, {
       json: true,
-      hostType: DATASOURCE_HEX,
+      hostType: id,
     });
 
     const hexRelease: HexRelease = response.body;
diff --git a/lib/datasource/index.spec.ts b/lib/datasource/index.spec.ts
index d0792ecc5ee30a83f535e72bd415eef3fb944ea3..67ef071cc35116a6b805b493f050288d9b5fba46 100644
--- a/lib/datasource/index.spec.ts
+++ b/lib/datasource/index.spec.ts
@@ -1,15 +1,14 @@
 import * as datasource from '.';
-import * as _npm from './npm';
-import {
-  DATASOURCE_DOCKER,
-  DATASOURCE_GITHUB_TAGS,
-  DATASOURCE_NPM,
-} from '../constants/data-binary-source';
+
+import * as datasourceDocker from './docker';
+import * as datasourceGithubTags from './github-tags';
+import * as datasourceNpm from './npm';
+import { mocked } from '../../test/util';
 
 jest.mock('./docker');
 jest.mock('./npm');
 
-const npmDatasource: any = _npm;
+const npmDatasource = mocked(datasourceNpm);
 
 describe('datasource/index', () => {
   it('returns datasources', () => {
@@ -18,7 +17,7 @@ describe('datasource/index', () => {
   });
   it('returns if digests are supported', () => {
     expect(
-      datasource.supportsDigests({ datasource: DATASOURCE_GITHUB_TAGS })
+      datasource.supportsDigests({ datasource: datasourceGithubTags.id })
     ).toBe(true);
   });
   it('returns null for no datasource', async () => {
@@ -39,15 +38,15 @@ describe('datasource/index', () => {
   it('returns getDigest', async () => {
     expect(
       await datasource.getDigest({
-        datasource: DATASOURCE_DOCKER,
+        datasource: datasourceDocker.id,
         depName: 'docker/node',
       })
     ).toBeUndefined();
   });
   it('adds changelogUrl', async () => {
-    npmDatasource.getPkgReleases.mockReturnValue({});
+    npmDatasource.getPkgReleases.mockResolvedValue({ releases: [] });
     const res = await datasource.getPkgReleases({
-      datasource: DATASOURCE_NPM,
+      datasource: datasourceNpm.id,
       depName: 'react-native',
     });
     expect(res).toMatchSnapshot();
@@ -55,30 +54,32 @@ describe('datasource/index', () => {
     expect(res.sourceUrl).toBeDefined();
   });
   it('adds sourceUrl', async () => {
-    npmDatasource.getPkgReleases.mockReturnValue({});
+    npmDatasource.getPkgReleases.mockResolvedValue({ releases: [] });
     const res = await datasource.getPkgReleases({
-      datasource: DATASOURCE_NPM,
+      datasource: datasourceNpm.id,
       depName: 'node',
     });
     expect(res).toMatchSnapshot();
     expect(res.sourceUrl).toBeDefined();
   });
   it('trims sourceUrl', async () => {
-    npmDatasource.getPkgReleases.mockReturnValue({
+    npmDatasource.getPkgReleases.mockResolvedValue({
       sourceUrl: ' https://abc.com',
+      releases: [],
     });
     const res = await datasource.getPkgReleases({
-      datasource: DATASOURCE_NPM,
+      datasource: datasourceNpm.id,
       depName: 'abc',
     });
     expect(res.sourceUrl).toEqual('https://abc.com');
   });
   it('massages sourceUrl', async () => {
-    npmDatasource.getPkgReleases.mockReturnValue({
+    npmDatasource.getPkgReleases.mockResolvedValue({
       sourceUrl: 'scm:git@github.com:Jasig/cas.git',
+      releases: [],
     });
     const res = await datasource.getPkgReleases({
-      datasource: DATASOURCE_NPM,
+      datasource: datasourceNpm.id,
       depName: 'cas',
     });
     expect(res.sourceUrl).toEqual('https://github.com/Jasig/cas');
diff --git a/lib/datasource/index.ts b/lib/datasource/index.ts
index 7e6b584976cf61d291400951a77fd335a0478dc5..a8573c56ea0af643978c8e934997bf7d34f78b57 100644
--- a/lib/datasource/index.ts
+++ b/lib/datasource/index.ts
@@ -15,7 +15,14 @@ import { loadModules } from '../util/modules';
 
 export * from './common';
 
-const datasources = loadModules<Datasource>(__dirname);
+// istanbul ignore next
+function validateDatasource(module, name): boolean {
+  if (!module.getPkgReleases) return false;
+  if (module.id !== name) return false;
+  return true;
+}
+
+const datasources = loadModules<Datasource>(__dirname, validateDatasource);
 export const getDatasources = (): Record<string, Datasource> => datasources;
 const datasourceList = Object.keys(datasources);
 export const getDatasourceList = (): string[] => datasourceList;
diff --git a/lib/datasource/maven/common.ts b/lib/datasource/maven/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7409e6493546f49518397b277ed61805bedb2d7b
--- /dev/null
+++ b/lib/datasource/maven/common.ts
@@ -0,0 +1 @@
+export const id = 'maven';
diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts
index b2e397a0229c229250b6400b501e78703bf0b40a..f8751149691d0adf08b0549855b2a58132032e80 100644
--- a/lib/datasource/maven/index.spec.ts
+++ b/lib/datasource/maven/index.spec.ts
@@ -4,7 +4,6 @@ import { resolve } from 'path';
 import * as maven from '.';
 import { DATASOURCE_FAILURE } from '../../constants/error-messages';
 import * as looseVersioning from '../../versioning/loose';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
 import * as hostRules from '../../util/host-rules';
 
 const MYSQL_VERSIONS = [
@@ -40,7 +39,7 @@ const config = {
 describe('datasource/maven', () => {
   beforeEach(() => {
     hostRules.add({
-      hostType: DATASOURCE_MAVEN,
+      hostType: maven.id,
       hostName: 'frontend_for_private_s3_repository',
       username: 'username',
       password: 'password',
diff --git a/lib/datasource/maven/index.ts b/lib/datasource/maven/index.ts
index c6abfa04b860354406ca76aa5f459fa2c41e6596..6fd5605f95340f2e337fdd778ed8e623f4cbfe4d 100644
--- a/lib/datasource/maven/index.ts
+++ b/lib/datasource/maven/index.ts
@@ -5,10 +5,15 @@ import { XmlDocument } from 'xmldoc';
 import { logger } from '../../logger';
 import { compare } from '../../versioning/maven/compare';
 import mavenVersion from '../../versioning/maven';
-import { containsPlaceholder } from '../../manager/maven/extract';
 import { downloadHttpProtocol } from './util';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 
+export { id } from './common';
+
+function containsPlaceholder(str: string): boolean {
+  return /\${.*?}/g.test(str);
+}
+
 async function downloadFileProtocol(pkgUrl: url.URL): Promise<string | null> {
   const pkgPath = pkgUrl.toString().replace('file://', '');
   if (!(await fs.exists(pkgPath))) {
diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts
index b79f5ca57f61c0e699b9913772674b3b67a3b30c..847c7280a741be244a9bc97049e8aad6ae73d843 100644
--- a/lib/datasource/maven/util.ts
+++ b/lib/datasource/maven/util.ts
@@ -1,9 +1,10 @@
 import url from 'url';
 import got from '../../util/got';
 import { logger } from '../../logger';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
 import { DatasourceError } from '../common';
 
+import { id } from './common';
+
 function isMavenCentral(pkgUrl: url.URL | string): boolean {
   return (
     (typeof pkgUrl === 'string' ? pkgUrl : pkgUrl.host) === 'central.maven.org'
@@ -38,7 +39,7 @@ function isConnectionError(err: { code: string }): boolean {
 
 export async function downloadHttpProtocol(
   pkgUrl: url.URL | string,
-  hostType = DATASOURCE_MAVEN
+  hostType = id
 ): Promise<string | null> {
   let raw: { body: string };
   try {
diff --git a/lib/datasource/metadata.spec.ts b/lib/datasource/metadata.spec.ts
index 5f1cf7a4dba57a482ede3f0ea370d60803857135..5a70c827b26c198e985d2a750fac9c381b67d89f 100644
--- a/lib/datasource/metadata.spec.ts
+++ b/lib/datasource/metadata.spec.ts
@@ -1,8 +1,6 @@
 import { addMetaData } from './metadata';
-import {
-  DATASOURCE_MAVEN,
-  DATASOURCE_PYPI,
-} from '../constants/data-binary-source';
+import * as datasourceMaven from './maven';
+import * as datasourcePypi from './pypi';
 
 describe('datasource/metadata', () => {
   it('Should do nothing if dep is not specified', () => {
@@ -22,7 +20,7 @@ describe('datasource/metadata', () => {
       ],
     };
 
-    const datasource = DATASOURCE_PYPI;
+    const datasource = datasourcePypi.id;
     const lookupName = 'django';
 
     addMetaData(dep, datasource, lookupName);
@@ -42,7 +40,7 @@ describe('datasource/metadata', () => {
       ],
     };
 
-    const datasource = DATASOURCE_PYPI;
+    const datasource = datasourcePypi.id;
     const lookupName = 'coverage';
 
     addMetaData(dep, datasource, lookupName);
@@ -62,7 +60,7 @@ describe('datasource/metadata', () => {
         { version: '2.2.0', releaseTimestamp: '2019-07-16T18:29:00' },
       ],
     };
-    const datasource = DATASOURCE_PYPI;
+    const datasource = datasourcePypi.id;
     const lookupName = 'django-filter';
 
     addMetaData(dep, datasource, lookupName);
@@ -74,7 +72,7 @@ describe('datasource/metadata', () => {
       sourceUrl: 'http://www.github.com/mockk/mockk/',
       releases: [{ version: '1.9.3' }],
     };
-    const datasource = DATASOURCE_MAVEN;
+    const datasource = datasourceMaven.id;
     const lookupName = 'io.mockk:mockk';
 
     addMetaData(dep, datasource, lookupName);
diff --git a/lib/datasource/npm/common.ts b/lib/datasource/npm/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a8364805b1390116c605b2d3d93d48af0e0a2fa
--- /dev/null
+++ b/lib/datasource/npm/common.ts
@@ -0,0 +1 @@
+export const id = 'npm';
diff --git a/lib/datasource/npm/get.ts b/lib/datasource/npm/get.ts
index c76b846312db942e27ec6f00a06c18c310f3f89f..9234fed79f016b30097144da19f9318dbb9f09e6 100644
--- a/lib/datasource/npm/get.ts
+++ b/lib/datasource/npm/get.ts
@@ -11,7 +11,7 @@ import got, { GotJSONOptions } from '../../util/got';
 import { maskToken } from '../../util/mask';
 import { getNpmrc } from './npmrc';
 import { DatasourceError, Release, ReleaseResult } from '../common';
-import { DATASOURCE_NPM } from '../../constants/data-binary-source';
+import { id } from './common';
 
 let memcache = {};
 
@@ -108,6 +108,7 @@ export async function getDependency(
   try {
     const useCache = retries === 3; // Disable cache if we're retrying
     const opts: GotJSONOptions = {
+      hostType: id,
       json: true,
       retry: 5,
       headers,
@@ -165,7 +166,7 @@ export async function getDependency(
     }
     if (latestVersion.deprecated) {
       dep.deprecationMessage = `On registry \`${regUrl}\`, the "latest" version (v${dep.latestVersion}) of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`;
-      dep.deprecationSource = DATASOURCE_NPM;
+      dep.deprecationSource = id;
     }
     dep.releases = Object.keys(res.versions).map(version => {
       const release: NpmRelease = {
diff --git a/lib/datasource/npm/index.ts b/lib/datasource/npm/index.ts
index 8a90451a27ffc2e82eac9bedad69b740f00e76e9..d9866922c4c2bd5241a68d513accfcd201d9ee7a 100644
--- a/lib/datasource/npm/index.ts
+++ b/lib/datasource/npm/index.ts
@@ -1,3 +1,4 @@
 export { resetMemCache, resetCache } from './get';
 export { getPkgReleases } from './releases';
 export { setNpmrc } from './npmrc';
+export { id } from './common';
diff --git a/lib/datasource/nuget/common.ts b/lib/datasource/nuget/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..234435b19cf3b464ae518ce076ebe1271ebfdad4
--- /dev/null
+++ b/lib/datasource/nuget/common.ts
@@ -0,0 +1 @@
+export const id = 'nuget';
diff --git a/lib/datasource/nuget/index.ts b/lib/datasource/nuget/index.ts
index 775a709c5200c9fa0716d7653a0e8ec1f158e0ba..e35d8b2299018d61bf6b741e58b5395a9e717da3 100644
--- a/lib/datasource/nuget/index.ts
+++ b/lib/datasource/nuget/index.ts
@@ -4,6 +4,8 @@ import * as v2 from './v2';
 import * as v3 from './v3';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 
+export { id } from './common';
+
 function detectFeedVersion(url: string): 2 | 3 | null {
   try {
     const parsecUrl = urlApi.parse(url);
diff --git a/lib/datasource/nuget/v2.ts b/lib/datasource/nuget/v2.ts
index 69b58f4d8398ef1c32dce902e20d5cb6737dce46..2d7c36be8d84cb8769662714e14908360f3de27e 100644
--- a/lib/datasource/nuget/v2.ts
+++ b/lib/datasource/nuget/v2.ts
@@ -2,7 +2,8 @@ import { XmlDocument, XmlElement } from 'xmldoc';
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { ReleaseResult } from '../common';
-import { DATASOURCE_NUGET } from '../../constants/data-binary-source';
+
+import { id } from './common';
 
 function getPkgProp(pkgInfo: XmlElement, propName: string): string {
   return pkgInfo.childNamed('m:properties').childNamed(`d:${propName}`).val;
@@ -20,7 +21,7 @@ export async function getPkgReleases(
     let pkgUrlList = `${feedUrl}/FindPackagesById()?id=%27${pkgName}%27&$select=Version,IsLatestVersion,ProjectUrl`;
     do {
       const pkgVersionsListRaw = await got(pkgUrlList, {
-        hostType: DATASOURCE_NUGET,
+        hostType: id,
       });
       if (pkgVersionsListRaw.statusCode !== 200) {
         logger.debug(
diff --git a/lib/datasource/nuget/v3.ts b/lib/datasource/nuget/v3.ts
index db9a9b3f74b9551b9d96107b265ee8576deaed11..9bbb381014e829f4790b00e88ceac021e2834406 100644
--- a/lib/datasource/nuget/v3.ts
+++ b/lib/datasource/nuget/v3.ts
@@ -3,7 +3,8 @@ import { XmlDocument } from 'xmldoc';
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { ReleaseResult } from '../common';
-import { DATASOURCE_NUGET } from '../../constants/data-binary-source';
+
+import { id } from './common';
 
 // https://api.nuget.org/v3/index.json is a default official nuget feed
 const defaultNugetFeed = 'https://api.nuget.org/v3/index.json';
@@ -30,7 +31,7 @@ export async function getQueryUrl(url: string): Promise<string | null> {
   try {
     const servicesIndexRaw = await got(url, {
       json: true,
-      hostType: DATASOURCE_NUGET,
+      hostType: id,
     });
     if (servicesIndexRaw.statusCode !== 200) {
       logger.debug(
@@ -79,7 +80,7 @@ export async function getPkgReleases(
   try {
     const pkgUrlListRaw = await got(queryUrl, {
       json: true,
-      hostType: DATASOURCE_NUGET,
+      hostType: id,
     });
     if (pkgUrlListRaw.statusCode !== 200) {
       logger.debug(
@@ -120,7 +121,7 @@ export async function getPkgReleases(
         const nugetOrgApi = `https://api.nuget.org/v3-flatcontainer/${pkgName.toLowerCase()}/${lastVersion}/${pkgName.toLowerCase()}.nuspec`;
         let metaresult: { body: string };
         try {
-          metaresult = await got(nugetOrgApi, { hostType: DATASOURCE_NUGET });
+          metaresult = await got(nugetOrgApi, { hostType: id });
         } catch (err) /* istanbul ignore next */ {
           logger.debug(
             `Cannot fetch metadata for ${pkgName} using popped version ${lastVersion}`
diff --git a/lib/datasource/orb/index.ts b/lib/datasource/orb/index.ts
index 0a9e8739ad6b6ffb13d55520bdfb6bf0db91170d..24385098637109c5903e058cb831f42ea4f48788 100644
--- a/lib/datasource/orb/index.ts
+++ b/lib/datasource/orb/index.ts
@@ -2,6 +2,8 @@ import { logger } from '../../logger';
 import got from '../../util/got';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 
+export const id = 'orb';
+
 interface OrbRelease {
   homeUrl?: string;
   versions: {
@@ -37,6 +39,7 @@ export async function getPkgReleases({
     const res: OrbRelease = (
       await got.post(url, {
         body,
+        hostType: id,
         json: true,
         retry: 5,
       })
diff --git a/lib/datasource/packagist/index.ts b/lib/datasource/packagist/index.ts
index 4a756117454b8004e1c7eb922abd5407bb31a46e..8c989a7ca38b5b9d68a32425377303a4d16d0a8d 100644
--- a/lib/datasource/packagist/index.ts
+++ b/lib/datasource/packagist/index.ts
@@ -8,14 +8,15 @@ import { logger } from '../../logger';
 import got, { GotJSONOptions } from '../../util/got';
 import * as hostRules from '../../util/host-rules';
 import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
-import { DATASOURCE_PACKAGIST } from '../../constants/data-binary-source';
+
+export const id = 'packagist';
 
 function getHostOpts(url: string): GotJSONOptions {
   const opts: GotJSONOptions = {
     json: true,
   };
   const { username, password } = hostRules.find({
-    hostType: DATASOURCE_PACKAGIST,
+    hostType: id,
     url,
   });
   if (username && password) {
diff --git a/lib/datasource/pypi/index.ts b/lib/datasource/pypi/index.ts
index 47b119fcbb60bab085bb17eee0487ca7777a42f9..bab4dc7a980bff9efad8ff2922b29e1eba28e84c 100644
--- a/lib/datasource/pypi/index.ts
+++ b/lib/datasource/pypi/index.ts
@@ -5,7 +5,8 @@ import { logger } from '../../logger';
 import { matches } from '../../versioning/pep440';
 import got from '../../util/got';
 import { GetReleasesConfig, ReleaseResult } from '../common';
-import { DATASOURCE_PYPI } from '../../constants/data-binary-source';
+
+export const id = 'pypi';
 
 function normalizeName(input: string): string {
   return input.toLowerCase().replace(/(-|\.)/g, '_');
@@ -39,7 +40,7 @@ async function getDependency(
     const dependency: ReleaseResult = { releases: null };
     const rep = await got(url.parse(lookupUrl), {
       json: true,
-      hostType: DATASOURCE_PYPI,
+      hostType: id,
     });
     const dep = rep && rep.body;
     if (!dep) {
@@ -121,7 +122,7 @@ async function getSimpleDependency(
   try {
     const dependency: ReleaseResult = { releases: null };
     const response = await got<string>(url.parse(lookupUrl), {
-      hostType: DATASOURCE_PYPI,
+      hostType: id,
     });
     const dep = response && response.body;
     if (!dep) {
diff --git a/lib/datasource/ruby-version/index.ts b/lib/datasource/ruby-version/index.ts
index 190d0575ead4884ec2cffdd166852eb4f8ee17ab..f19c3270be287402326ec43d197436faf851b311 100644
--- a/lib/datasource/ruby-version/index.ts
+++ b/lib/datasource/ruby-version/index.ts
@@ -4,6 +4,8 @@ import got from '../../util/got';
 import { isVersion } from '../../versioning/ruby';
 import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
 
+export const id = 'ruby-version';
+
 const rubyVersionsUrl = 'https://www.ruby-lang.org/en/downloads/releases/';
 
 export async function getPkgReleases(
diff --git a/lib/datasource/rubygems/common.ts b/lib/datasource/rubygems/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73a47c02d8821ec16f88bec87a969135dfaab69e
--- /dev/null
+++ b/lib/datasource/rubygems/common.ts
@@ -0,0 +1 @@
+export const id = 'rubygems';
diff --git a/lib/datasource/rubygems/get.ts b/lib/datasource/rubygems/get.ts
index a04efd06b8cf1979bb26d4ffe295142773992918..9a32f01c654b86b10bc354c39dd6e1128164b731 100644
--- a/lib/datasource/rubygems/get.ts
+++ b/lib/datasource/rubygems/get.ts
@@ -5,7 +5,7 @@ import { maskToken } from '../../util/mask';
 import retriable from './retriable';
 import { UNAUTHORIZED, FORBIDDEN, NOT_FOUND } from './errors';
 import { ReleaseResult } from '../common';
-import { DATASOURCE_RUBYGEMS } from '../../constants/data-binary-source';
+import { id } from './common';
 
 const INFO_PATH = '/api/v1/gems';
 const VERSIONS_PATH = '/api/v1/versions';
@@ -31,7 +31,7 @@ const processError = ({ err, ...rest }): null => {
 };
 
 const getHeaders = (): OutgoingHttpHeaders => {
-  return { hostType: DATASOURCE_RUBYGEMS };
+  return { hostType: id };
 };
 
 const fetch = async ({ dependency, registry, path }): Promise<any> => {
diff --git a/lib/datasource/rubygems/index.ts b/lib/datasource/rubygems/index.ts
index d55467325c9d0463aad8addd43f97e1dad5f9703..c7f56ead1810b0a51cfc0d954b0ef656e8ac3b21 100644
--- a/lib/datasource/rubygems/index.ts
+++ b/lib/datasource/rubygems/index.ts
@@ -1 +1,2 @@
 export { getPkgReleases } from './releases';
+export { id } from './common';
diff --git a/lib/datasource/sbt-package/index.ts b/lib/datasource/sbt-package/index.ts
index bb1659ea4cdbf489fa61dabada2d17d5d126ae98..6fcd00c10b67391171007ee0216d295cf2e66bde 100644
--- a/lib/datasource/sbt-package/index.ts
+++ b/lib/datasource/sbt-package/index.ts
@@ -4,6 +4,8 @@ import { parseIndexDir } from '../sbt-plugin/util';
 import { logger } from '../../logger';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 
+export const id = 'sbt-package';
+
 const ensureTrailingSlash = (str: string): string => str.replace(/\/?$/, '/');
 
 export async function resolvePackageReleases(
diff --git a/lib/datasource/sbt-plugin/index.ts b/lib/datasource/sbt-plugin/index.ts
index 450fb909f4c19049450d2762a585327724f3e357..7b3a717653cb80a105aad1a6da64f22ff937fe62 100644
--- a/lib/datasource/sbt-plugin/index.ts
+++ b/lib/datasource/sbt-plugin/index.ts
@@ -5,6 +5,8 @@ import { logger } from '../../logger';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 import { resolvePackageReleases } from '../sbt-package';
 
+export const id = 'sbt-plugin';
+
 const ensureTrailingSlash = (str: string): string => str.replace(/\/?$/, '/');
 
 async function resolvePluginReleases(
diff --git a/lib/datasource/terraform-provider/index.ts b/lib/datasource/terraform-provider/index.ts
index 072ed110bf84607ec5e48ef9f8c1332d7b2d8a50..0c3544d3bd65e904973e76a745a68e8c760265b1 100644
--- a/lib/datasource/terraform-provider/index.ts
+++ b/lib/datasource/terraform-provider/index.ts
@@ -1,7 +1,8 @@
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { GetReleasesConfig, ReleaseResult } from '../common';
-import { DATASOURCE_TERRAFORM } from '../../constants/data-binary-source';
+
+export const id = 'terraform-provider';
 
 interface TerraformProvider {
   namespace: string;
@@ -37,7 +38,7 @@ export async function getPkgReleases({
     const res: TerraformProvider = (
       await got(pkgUrl, {
         json: true,
-        hostType: DATASOURCE_TERRAFORM,
+        hostType: id,
       })
     ).body;
     // Simplify response before caching and returning
diff --git a/lib/datasource/terraform/index.ts b/lib/datasource/terraform/index.ts
index 1eb1d79d7c558c5b00b6d713b61c04d7d957a8ab..731192135ca74323fd8c29aad50ffb8f8c138b8c 100644
--- a/lib/datasource/terraform/index.ts
+++ b/lib/datasource/terraform/index.ts
@@ -2,7 +2,8 @@ import is from '@sindresorhus/is';
 import { logger } from '../../logger';
 import got from '../../util/got';
 import { GetReleasesConfig, ReleaseResult } from '../common';
-import { DATASOURCE_TERRAFORM } from '../../constants/data-binary-source';
+
+export const id = 'terraform';
 
 interface RegistryRepository {
   registry: string;
@@ -74,7 +75,7 @@ export async function getPkgReleases({
     const res: TerraformRelease = (
       await got(pkgUrl, {
         json: true,
-        hostType: DATASOURCE_TERRAFORM,
+        hostType: id,
       })
     ).body;
     const returnedName = res.namespace + '/' + res.name + '/' + res.provider;
diff --git a/lib/manager/ansible-galaxy/extract.ts b/lib/manager/ansible-galaxy/extract.ts
index ca7cc8913307c492a55871ea95db9fa49431844e..5b044403fc3402d1d77a7a1bbd22b024e62f7bf2 100644
--- a/lib/manager/ansible-galaxy/extract.ts
+++ b/lib/manager/ansible-galaxy/extract.ts
@@ -2,10 +2,8 @@ import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
 import * as semver from '../../versioning/semver';
 import * as git from '../../versioning/git';
-import {
-  DATASOURCE_GIT_TAGS,
-  DATASOURCE_GALAXY,
-} from '../../constants/data-binary-source';
+import * as datasourceGitTags from '../../datasource/git-tags';
+import * as datasourceGalaxy from '../../datasource/galaxy';
 
 function interpretLine(
   lineMatch: RegExpMatchArray,
@@ -53,12 +51,12 @@ function finalize(dependency: PackageDependency): boolean {
     /^(git|http|git\+http)s?(:\/\/|@).*(\/|:)(.+\/[^.]+)\/?(\.git)?$/
   ).exec(source);
   if (sourceMatch) {
-    dep.datasource = DATASOURCE_GIT_TAGS;
+    dep.datasource = datasourceGitTags.id;
     dep.depName = sourceMatch[4];
     // remove leading `git+` from URLs like `git+https://...`
     dep.lookupName = source.replace(/git\+/, '');
   } else if (new RegExp(/.+\..+/).exec(source)) {
-    dep.datasource = DATASOURCE_GALAXY;
+    dep.datasource = datasourceGalaxy.id;
     dep.depName = dep.managerData.src;
     dep.lookupName = dep.managerData.src;
   } else {
@@ -70,9 +68,9 @@ function finalize(dependency: PackageDependency): boolean {
   }
 
   if (
-    (dep.datasource === DATASOURCE_GIT_TAGS &&
+    (dep.datasource === datasourceGitTags.id &&
       !git.api.isValid(dependency.managerData.version)) ||
-    (dep.datasource === DATASOURCE_GALAXY &&
+    (dep.datasource === datasourceGalaxy.id &&
       !semver.isValid(dependency.managerData.version))
   ) {
     dep.skipReason = 'invalid-version';
diff --git a/lib/manager/bazel/extract.ts b/lib/manager/bazel/extract.ts
index c1a36e3a54a018bc6587c17084809c9eb05170da..1390bc9a24a931a13520d144bbd4606618a2d76b 100644
--- a/lib/manager/bazel/extract.ts
+++ b/lib/manager/bazel/extract.ts
@@ -5,11 +5,9 @@ import { logger } from '../../logger';
 import { PackageDependency, PackageFile } from '../common';
 import { regEx } from '../../util/regex';
 import * as dockerVersioning from '../../versioning/docker';
-import {
-  DATASOURCE_DOCKER,
-  DATASOURCE_GO,
-  DATASOURCE_GITHUB_RELEASES,
-} from '../../constants/data-binary-source';
+import * as datasourceDocker from '../../datasource/docker';
+import * as datasourceGo from '../../datasource/go';
+import * as datasourceGithubReleases from '../../datasource/github-releases';
 
 interface UrlParsedResult {
   repo: string;
@@ -183,7 +181,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       const githubURL = parse(remote);
       if (githubURL) {
         const repo = githubURL.substring('https://github.com/'.length);
-        dep.datasource = DATASOURCE_GITHUB_RELEASES;
+        dep.datasource = datasourceGithubReleases.id;
         dep.lookupName = repo;
         deps.push(dep);
       }
@@ -195,7 +193,7 @@ export function extractPackageFile(content: string): PackageFile | null {
     ) {
       dep.depName = depName;
       dep.currentValue = currentValue || commit.substr(0, 7);
-      dep.datasource = DATASOURCE_GO;
+      dep.datasource = datasourceGo.id;
       dep.lookupName = importpath;
       if (remote) {
         const remoteMatch = /https:\/\/github\.com(?:.*\/)(([a-zA-Z]+)([-])?([a-zA-Z]+))/.exec(
@@ -228,7 +226,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       } else {
         dep.currentValue = parsedUrl.currentValue;
       }
-      dep.datasource = DATASOURCE_GITHUB_RELEASES;
+      dep.datasource = datasourceGithubReleases.id;
       dep.lookupName = dep.repo;
       deps.push(dep);
     } else if (
@@ -242,7 +240,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       dep.currentValue = currentValue;
       dep.depName = depName;
       dep.versioning = dockerVersioning.id;
-      dep.datasource = DATASOURCE_DOCKER;
+      dep.datasource = datasourceDocker.id;
       dep.lookupName = repository;
       deps.push(dep);
     } else {
diff --git a/lib/manager/buildkite/extract.ts b/lib/manager/buildkite/extract.ts
index cbaf2bc25618f2269a9fcd221530d38fe21ce577..8b83061f17aa4c4d4f66aad950334100ddfb3a5e 100644
--- a/lib/manager/buildkite/extract.ts
+++ b/lib/manager/buildkite/extract.ts
@@ -1,7 +1,7 @@
 import { logger } from '../../logger';
 import { isVersion } from '../../versioning/semver';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_GITHUB_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGithubTags from '../../datasource/github-tags';
 
 export function extractPackageFile(content: string): PackageFile | null {
   const deps: PackageDependency[] = [];
@@ -61,7 +61,7 @@ export function extractPackageFile(content: string): PackageFile | null {
             skipReason,
           };
           if (repo) {
-            dep.datasource = DATASOURCE_GITHUB_TAGS;
+            dep.datasource = datasourceGithubTags.id;
             dep.lookupName = repo;
           }
           deps.push(dep);
diff --git a/lib/manager/bundler/extract.ts b/lib/manager/bundler/extract.ts
index b6b502eba6b46f1b375d4b6bf128c558ce5a1c98..1d084b0728e6225b18ffb555fc5f0a8fbff4ea75 100644
--- a/lib/manager/bundler/extract.ts
+++ b/lib/manager/bundler/extract.ts
@@ -4,7 +4,7 @@ import { PackageFile, PackageDependency } from '../common';
 import { platform } from '../../platform';
 import { regEx } from '../../util/regex';
 import { extractLockFileEntries } from './locked-version';
-import { DATASOURCE_RUBYGEMS } from '../../constants/data-binary-source';
+import * as datasourceRubygems from '../../datasource/rubygems';
 
 export async function extractPackageFile(
   content: string,
@@ -64,7 +64,7 @@ export async function extractPackageFile(
         dep.skipReason = 'no-version';
       }
       if (!dep.skipReason) {
-        dep.datasource = DATASOURCE_RUBYGEMS;
+        dep.datasource = datasourceRubygems.id;
       }
       res.deps.push(dep);
     }
diff --git a/lib/manager/cargo/extract.ts b/lib/manager/cargo/extract.ts
index 6543a855ba4a376371b0a65e0b5d71f86e3ac542..92c6e0be5569af0fdad163229760cd31114ddab6 100644
--- a/lib/manager/cargo/extract.ts
+++ b/lib/manager/cargo/extract.ts
@@ -3,7 +3,7 @@ import { logger } from '../../logger';
 import { isValid } from '../../versioning/cargo';
 import { PackageDependency, PackageFile } from '../common';
 import { CargoConfig, CargoSection } from './types';
-import { DATASOURCE_CARGO } from '../../constants/data-binary-source';
+import * as datasourceCargo from '../../datasource/cargo';
 
 function extractFromSection(
   parsedContent: CargoSection,
@@ -48,7 +48,7 @@ function extractFromSection(
       depType: section,
       currentValue: currentValue as any,
       managerData: { nestedVersion },
-      datasource: DATASOURCE_CARGO,
+      datasource: datasourceCargo.id,
     };
     if (skipReason) {
       dep.skipReason = skipReason;
diff --git a/lib/manager/cdnurl/extract.ts b/lib/manager/cdnurl/extract.ts
index 21eaac38f8798c71b42afea65ceb5ff1592649fb..e4658a3bbbfe3a77f953babb285ee491eba58a30 100644
--- a/lib/manager/cdnurl/extract.ts
+++ b/lib/manager/cdnurl/extract.ts
@@ -1,5 +1,5 @@
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_CDNJS } from '../../constants/data-binary-source';
+import * as datasourceCdnjs from '../../datasource/cdnjs';
 
 export const cloudflareUrlRegex = /\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/(?<depName>[^/]+?)\/(?<currentValue>[^/]+?)\/(?<asset>[-/_.a-zA-Z0-9]+)/;
 
@@ -21,7 +21,7 @@ export function extractPackageFile(content: string): PackageFile {
     match = cloudflareUrlRegex.exec(rest);
 
     deps.push({
-      datasource: DATASOURCE_CDNJS,
+      datasource: datasourceCdnjs.id,
       depName,
       lookupName: `${depName}/${asset}`,
       currentValue,
diff --git a/lib/manager/circleci/extract.ts b/lib/manager/circleci/extract.ts
index 975537af2392ec7d163ae6d5952e2b22f6b9f8bb..ab866a5bcc98ee885437a78d44af0f3278833e21 100644
--- a/lib/manager/circleci/extract.ts
+++ b/lib/manager/circleci/extract.ts
@@ -2,7 +2,7 @@ import { logger } from '../../logger';
 import { getDep } from '../dockerfile/extract';
 import { PackageFile, PackageDependency } from '../common';
 import * as npmVersioning from '../../versioning/npm';
-import { DATASOURCE_ORB } from '../../constants/data-binary-source';
+import * as datasourceOrb from '../../datasource/orb';
 
 export function extractPackageFile(content: string): PackageFile | null {
   const deps: PackageDependency[] = [];
@@ -30,7 +30,7 @@ export function extractPackageFile(content: string): PackageFile | null {
               depName,
               currentValue,
               managerData: { lineNumber },
-              datasource: DATASOURCE_ORB,
+              datasource: datasourceOrb.id,
               lookupName: orbName,
               commitMessageTopic: '{{{depName}}} orb',
               versioning: npmVersioning.id,
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index 4e73fca627c1902466f39ce5a3d45516cb0e4b3b..bd67233582d4a6090b3b5002076f7d78b4beeb4e 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -8,7 +8,7 @@ import { logger } from '../../logger';
 import * as hostRules from '../../util/host-rules';
 import { platform } from '../../platform';
 import { SYSTEM_INSUFFICIENT_DISK_SPACE } from '../../constants/error-messages';
-import { DATASOURCE_PACKAGIST } from '../../constants/data-binary-source';
+import * as datasourcePackagist from '../../datasource/packagist';
 import {
   PLATFORM_TYPE_GITHUB,
   PLATFORM_TYPE_GITLAB,
@@ -71,7 +71,7 @@ export async function updateArtifacts({
           if (regUrl) {
             const { host } = URL.parse(regUrl);
             const hostRule = hostRules.find({
-              hostType: DATASOURCE_PACKAGIST,
+              hostType: datasourcePackagist.id,
               url: regUrl,
             });
             // istanbul ignore else
diff --git a/lib/manager/composer/extract.ts b/lib/manager/composer/extract.ts
index f9ed1ca7c12098f6364511882dab5fbce8307ba5..8caa9392310ecf183e3587166ca545f954f4780c 100644
--- a/lib/manager/composer/extract.ts
+++ b/lib/manager/composer/extract.ts
@@ -3,10 +3,9 @@ import { logger } from '../../logger';
 import { api as semverComposer } from '../../versioning/composer';
 import { PackageFile, PackageDependency } from '../common';
 import { platform } from '../../platform';
-import {
-  DATASOURCE_GIT_TAGS,
-  DATASOURCE_PACKAGIST,
-} from '../../constants/data-binary-source';
+
+import * as datasourceGitTags from '../../datasource/git-tags';
+import * as datasourcePackagist from '../../datasource/packagist';
 
 interface Repo {
   name?: string;
@@ -131,7 +130,7 @@ export async function extractPackageFile(
         )) {
           const currentValue = version.trim();
           // Default datasource and lookupName
-          let datasource = DATASOURCE_PACKAGIST;
+          let datasource = datasourcePackagist.id;
           let lookupName = depName;
 
           // Check custom repositories by type
@@ -140,7 +139,7 @@ export async function extractPackageFile(
             switch (repositories[depName].type) {
               case 'vcs':
               case 'git':
-                datasource = DATASOURCE_GIT_TAGS;
+                datasource = datasourceGitTags.id;
                 lookupName = repositories[depName].url;
                 break;
             }
diff --git a/lib/manager/deps-edn/extract.ts b/lib/manager/deps-edn/extract.ts
index 1a4303aa54ea466e2331e1e5b99782f0077129fb..51216ff9696dd7d19bd2aa6aaf31eab2336159b8 100644
--- a/lib/manager/deps-edn/extract.ts
+++ b/lib/manager/deps-edn/extract.ts
@@ -1,7 +1,7 @@
 import { DEFAULT_MAVEN_REPO } from '../maven/extract';
 import { expandDepName, DEFAULT_CLOJARS_REPO } from '../leiningen/extract';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
+import * as datasourceMaven from '../../datasource/maven';
 
 export function extractPackageFile(content: string): PackageFile {
   const deps: PackageDependency[] = [];
@@ -20,7 +20,7 @@ export function extractPackageFile(content: string): PackageFile {
     match = regex.exec(rest);
 
     deps.push({
-      datasource: DATASOURCE_MAVEN,
+      datasource: datasourceMaven.id,
       depName: expandDepName(depName),
       currentValue,
       fileReplacePosition,
diff --git a/lib/manager/dockerfile/extract.ts b/lib/manager/dockerfile/extract.ts
index 381e0295b44875d08ebc8a0bfa2f16ef840c3418..70e57fdd5d0fca834d8ae5d89e1048ff127e47cf 100644
--- a/lib/manager/dockerfile/extract.ts
+++ b/lib/manager/dockerfile/extract.ts
@@ -1,6 +1,6 @@
 import { logger } from '../../logger';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_DOCKER } from '../../constants/data-binary-source';
+import * as datasourceDocker from '../../datasource/docker';
 
 export function splitImageParts(currentFrom: string): PackageDependency {
   if (currentFrom.includes('$')) {
@@ -31,7 +31,7 @@ export function splitImageParts(currentFrom: string): PackageDependency {
 
 export function getDep(currentFrom: string): PackageDependency {
   const dep = splitImageParts(currentFrom);
-  dep.datasource = DATASOURCE_DOCKER;
+  dep.datasource = datasourceDocker.id;
   if (
     dep.depName &&
     (dep.depName === 'node' || dep.depName.endsWith('/node')) &&
diff --git a/lib/manager/git-submodules/extract.ts b/lib/manager/git-submodules/extract.ts
index 497e913de73aca3537d1a6803417876fa34a4aad..1753278c46d488202ac10497c77a3a52290b904d 100644
--- a/lib/manager/git-submodules/extract.ts
+++ b/lib/manager/git-submodules/extract.ts
@@ -3,7 +3,7 @@ import upath from 'upath';
 import URL from 'url';
 
 import { ManagerConfig, PackageFile } from '../common';
-import { DATASOURCE_GIT_SUBMODULES } from '../../constants/data-binary-source';
+import * as datasourceGitSubmodules from '../../datasource/git-submodules';
 
 type GitModule = {
   name: string;
@@ -105,5 +105,5 @@ export default async function extractPackageFile(
     })
   );
 
-  return { deps, datasource: DATASOURCE_GIT_SUBMODULES };
+  return { deps, datasource: datasourceGitSubmodules.id };
 }
diff --git a/lib/manager/gitlabci-include/extract.ts b/lib/manager/gitlabci-include/extract.ts
index 485c7d2c11d0020eb72e59548680869e4c3e5511..7a7124689444510884850584d7fd4eae4d789748 100644
--- a/lib/manager/gitlabci-include/extract.ts
+++ b/lib/manager/gitlabci-include/extract.ts
@@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
 import yaml from 'js-yaml';
 import { logger } from '../../logger';
 import { PackageDependency, ExtractConfig, PackageFile } from '../common';
-import { DATASOURCE_GITLAB_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGitlabTags from '../../datasource/gitlab-tags';
 
 function extractDepFromInclude(includeObj: {
   file: any;
@@ -13,7 +13,7 @@ function extractDepFromInclude(includeObj: {
     return null;
   }
   const dep: PackageDependency = {
-    datasource: DATASOURCE_GITLAB_TAGS,
+    datasource: datasourceGitlabTags.id,
     depName: includeObj.project,
     depType: 'repository',
   };
diff --git a/lib/manager/gomod/extract.ts b/lib/manager/gomod/extract.ts
index f62326733c215fe82944e56ebfb22a856e613085..0e45ac0ef6bd10db2b3da7a2ade92e63886390f2 100644
--- a/lib/manager/gomod/extract.ts
+++ b/lib/manager/gomod/extract.ts
@@ -1,7 +1,7 @@
 import { logger } from '../../logger';
 import { isVersion } from '../../versioning/semver';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_GO } from '../../constants/data-binary-source';
+import * as datasourceGo from '../../datasource/go';
 
 function getDep(
   lineNumber: number,
@@ -30,7 +30,7 @@ function getDep(
     } else {
       dep.depNameShort = depName;
     }
-    dep.datasource = DATASOURCE_GO;
+    dep.datasource = datasourceGo.id;
   }
   const digestMatch = /v0\.0.0-\d{14}-([a-f0-9]{12})/.exec(currentValue);
   if (digestMatch) {
diff --git a/lib/manager/gradle-wrapper/extract.ts b/lib/manager/gradle-wrapper/extract.ts
index a12ce4dfa04ee29fe5566557fea1b3a9d4766644..97d5832183da6fb1aa131d6adf93bc267c96c938 100644
--- a/lib/manager/gradle-wrapper/extract.ts
+++ b/lib/manager/gradle-wrapper/extract.ts
@@ -2,7 +2,7 @@ import { coerce } from 'semver';
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
 import * as semverVersioning from '../../versioning/semver';
-import { DATASOURCE_GRADLE_VERSION } from '../../constants/data-binary-source';
+import * as datasourceGradleVersion from '../../datasource/gradle-version';
 
 export function extractPackageFile(fileContent: string): PackageFile | null {
   logger.debug('gradle-wrapper.extractPackageFile()');
@@ -15,7 +15,7 @@ export function extractPackageFile(fileContent: string): PackageFile | null {
     );
     if (match) {
       const dependency: PackageDependency = {
-        datasource: DATASOURCE_GRADLE_VERSION,
+        datasource: datasourceGradleVersion.id,
         depType: 'gradle-wrapper',
         depName: 'gradle',
         currentValue: coerce(match[1]).toString(),
diff --git a/lib/manager/gradle/gradle-updates-report.ts b/lib/manager/gradle/gradle-updates-report.ts
index 273238e9d34e08a8c5ca5d9fd75f9f3dd1da54bb..504708fea03861571ac671ee8b516c4e9e51296b 100644
--- a/lib/manager/gradle/gradle-updates-report.ts
+++ b/lib/manager/gradle/gradle-updates-report.ts
@@ -1,7 +1,7 @@
 import { join } from 'path';
 import { exists, readFile, writeFile } from 'fs-extra';
 import { logger } from '../../logger';
-import { DATASOURCE_SBT_PACKAGE } from '../../constants/data-binary-source';
+import * as datasourceSbtPackage from '../../datasource/sbt-package';
 
 export const GRADLE_DEPENDENCY_REPORT_FILENAME = 'gradle-renovate-report.json';
 
@@ -160,7 +160,7 @@ export async function extractDependenciesFromUpdatesReport(
         return {
           ...dep,
           depName: depName.replace(/_%%/, ''),
-          datasource: DATASOURCE_SBT_PACKAGE,
+          datasource: datasourceSbtPackage.id,
         };
       }
       if (/^%.*%$/.test(currentValue)) {
diff --git a/lib/manager/gradle/index.ts b/lib/manager/gradle/index.ts
index 4a4cff5f8b7c8207bfb4f06a0bf7d1de8a568c48..a5c71116abdf74ae6db9bfb3980e01a376163021 100644
--- a/lib/manager/gradle/index.ts
+++ b/lib/manager/gradle/index.ts
@@ -23,7 +23,7 @@ import {
 } from '../common';
 import { platform } from '../../platform';
 import { LANGUAGE_JAVA } from '../../constants/languages';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
+import * as datasourceMaven from '../../datasource/maven';
 import { DatasourceError } from '../../datasource';
 
 export const GRADLE_DEPENDENCY_REPORT_OPTIONS =
@@ -134,7 +134,7 @@ export async function extractAllPackageFiles(
     if (content) {
       gradleFiles.push({
         packageFile,
-        datasource: DATASOURCE_MAVEN,
+        datasource: datasourceMaven.id,
         deps: dependencies,
       });
 
diff --git a/lib/manager/helm-requirements/extract.ts b/lib/manager/helm-requirements/extract.ts
index 8990733b86cd378e760442bc5f551bacbde402cb..e3a751bdfab4fb24f45964182fcac47cf3b88d1b 100644
--- a/lib/manager/helm-requirements/extract.ts
+++ b/lib/manager/helm-requirements/extract.ts
@@ -5,7 +5,7 @@ import yaml from 'js-yaml';
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency, ExtractConfig } from '../common';
 import { platform } from '../../platform';
-import { DATASOURCE_HELM } from '../../constants/data-binary-source';
+import * as datasourceHelm from '../../datasource/helm';
 
 export async function extractPackageFile(
   content: string,
@@ -78,7 +78,7 @@ export async function extractPackageFile(
   });
   const res = {
     deps,
-    datasource: DATASOURCE_HELM,
+    datasource: datasourceHelm.id,
   };
   return res;
 }
diff --git a/lib/manager/homebrew/extract.ts b/lib/manager/homebrew/extract.ts
index d106c420b3d40cee321d368489c89d26ca596b43..dea0206a3e83e297d19fcec61944bf85ad08c2c8 100644
--- a/lib/manager/homebrew/extract.ts
+++ b/lib/manager/homebrew/extract.ts
@@ -2,7 +2,7 @@ import { isValid } from '../../versioning/semver';
 import { skip, isSpace, removeComments } from './util';
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_GITHUB_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGithubTags from '../../datasource/github-tags';
 
 function parseSha256(idx: number, content: string): string | null {
   let i = idx;
@@ -192,7 +192,7 @@ export function extractPackageFile(content: string): PackageFile | null {
     depName: `${ownerName}/${repoName}`,
     managerData: { ownerName, repoName, sha256, url },
     currentValue,
-    datasource: DATASOURCE_GITHUB_TAGS,
+    datasource: datasourceGithubTags.id,
   };
   if (skipReason) {
     dep.skipReason = skipReason;
diff --git a/lib/manager/html/extract.ts b/lib/manager/html/extract.ts
index f8357118744b49432bafdbce133fec24428ea329..92e63f181ce62f94a7b184c79dffcf045c653a3d 100644
--- a/lib/manager/html/extract.ts
+++ b/lib/manager/html/extract.ts
@@ -1,5 +1,5 @@
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_CDNJS } from '../../constants/data-binary-source';
+import * as datasourceCdnjs from '../../datasource/cdnjs';
 import { cloudflareUrlRegex } from '../cdnurl/extract';
 
 const regex = /<\s*(script|link)\s+[^>]*?\/?>/i;
@@ -13,7 +13,7 @@ export function extractDep(tag: string): PackageDependency | null {
   }
   const { depName, currentValue, asset } = match.groups;
   const dep: PackageDependency = {
-    datasource: DATASOURCE_CDNJS,
+    datasource: datasourceCdnjs.id,
     depName,
     lookupName: `${depName}/${asset}`,
     currentValue,
diff --git a/lib/manager/leiningen/extract.spec.ts b/lib/manager/leiningen/extract.spec.ts
index 4a61d4b134b6f43b0af9df7550ba2b5524143026..7bff374f5fd2e4f5f30fef23caeeb83896b0126c 100644
--- a/lib/manager/leiningen/extract.spec.ts
+++ b/lib/manager/leiningen/extract.spec.ts
@@ -2,7 +2,7 @@
 import { readFileSync } from 'fs';
 import { resolve } from 'path';
 import { trimAtKey, extractFromVectors, extractPackageFile } from './extract';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
+import * as datasourceMaven from '../../datasource/maven';
 
 const leinProjectClj = readFileSync(
   resolve(__dirname, `./__fixtures__/project.clj`),
@@ -23,7 +23,7 @@ describe('manager/clojure/extract', () => {
     expect(extractFromVectors('[[]]')).toEqual([]);
     expect(extractFromVectors('[[foo/bar "1.2.3"]]')).toEqual([
       {
-        datasource: DATASOURCE_MAVEN,
+        datasource: datasourceMaven.id,
         depName: 'foo:bar',
         currentValue: '1.2.3',
         fileReplacePosition: 11,
@@ -33,13 +33,13 @@ describe('manager/clojure/extract', () => {
       extractFromVectors('[\t[foo/bar "1.2.3"]\n["foo/baz"  "4.5.6"] ]')
     ).toEqual([
       {
-        datasource: DATASOURCE_MAVEN,
+        datasource: datasourceMaven.id,
         depName: 'foo:bar',
         currentValue: '1.2.3',
         fileReplacePosition: 12,
       },
       {
-        datasource: DATASOURCE_MAVEN,
+        datasource: datasourceMaven.id,
         depName: 'foo:baz',
         currentValue: '4.5.6',
         fileReplacePosition: 33,
diff --git a/lib/manager/leiningen/extract.ts b/lib/manager/leiningen/extract.ts
index a815f25bace2f480fc04d986ecb31a51c0565c97..4a09f1e95f667070181426b83669a75222f8d890 100644
--- a/lib/manager/leiningen/extract.ts
+++ b/lib/manager/leiningen/extract.ts
@@ -1,6 +1,6 @@
 import { DEFAULT_MAVEN_REPO } from '../maven/extract';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
+import * as datasourceMaven from '../../datasource/maven';
 
 export const DEFAULT_CLOJARS_REPO = 'https://clojars.org/repo/';
 
@@ -46,7 +46,7 @@ export function extractFromVectors(
     if (artifactId && version && fileReplacePosition) {
       result.push({
         ...ctx,
-        datasource: DATASOURCE_MAVEN,
+        datasource: datasourceMaven.id,
         depName: expandDepName(cleanStrLiteral(artifactId)),
         currentValue: cleanStrLiteral(version),
         fileReplacePosition,
diff --git a/lib/manager/maven/extract.ts b/lib/manager/maven/extract.ts
index 82beeb5eedddbb897a6b835ce9a4e8f3f0ef6bf6..0f4df6acee3eb6dc36eaeb385c2bd9e648377453 100644
--- a/lib/manager/maven/extract.ts
+++ b/lib/manager/maven/extract.ts
@@ -5,7 +5,7 @@ import { isValid } from '../../versioning/maven';
 import { logger } from '../../logger';
 import { ExtractConfig, PackageFile, PackageDependency } from '../common';
 import { platform } from '../../platform';
-import { DATASOURCE_MAVEN } from '../../constants/data-binary-source';
+import * as datasourceMaven from '../../datasource/maven';
 
 export const DEFAULT_MAVEN_REPO = 'https://repo.maven.apache.org/maven2';
 
@@ -28,7 +28,7 @@ export function parsePom(raw: string): XmlDocument | null {
   return null;
 }
 
-export function containsPlaceholder(str: string): boolean {
+function containsPlaceholder(str: string): boolean {
   return /\${.*?}/g.test(str);
 }
 
@@ -52,7 +52,7 @@ function depFromNode(node: XmlElement): PackageDependency | null {
     const depName = `${groupId}:${artifactId}`;
     const versionNode = node.descendantWithPath('version');
     const fileReplacePosition = versionNode.position;
-    const datasource = DATASOURCE_MAVEN;
+    const datasource = datasourceMaven.id;
     const registryUrls = [DEFAULT_MAVEN_REPO];
     return {
       datasource,
@@ -159,7 +159,7 @@ export function extractPackage(
   if (!project) return null;
 
   const result: PackageFile = {
-    datasource: DATASOURCE_MAVEN,
+    datasource: datasourceMaven.id,
     packageFile,
     deps: [],
   };
diff --git a/lib/manager/meteor/extract.ts b/lib/manager/meteor/extract.ts
index 227f65d2f56d958c015b7f883a45b4da1356edc2..e05c03b20ceb6dc0df2a18898a7a9c4e93c9975b 100644
--- a/lib/manager/meteor/extract.ts
+++ b/lib/manager/meteor/extract.ts
@@ -1,6 +1,6 @@
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_NPM } from '../../constants/data-binary-source';
+import * as datasourceNpm from '../../datasource/npm';
 
 export function extractPackageFile(content: string): PackageFile | null {
   let deps: PackageDependency[] = [];
@@ -24,7 +24,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         return {
           depName,
           currentValue,
-          datasource: DATASOURCE_NPM,
+          datasource: datasourceNpm.id,
         };
       })
       .filter(dep => dep.depName && dep.currentValue);
diff --git a/lib/manager/mix/extract.ts b/lib/manager/mix/extract.ts
index 499122eaab01874977104a3f3ef54d0da9870ea0..d5262b452039628f0a81b2af36482b8615956b11 100644
--- a/lib/manager/mix/extract.ts
+++ b/lib/manager/mix/extract.ts
@@ -1,7 +1,7 @@
 import { isValid } from '../../versioning/hex';
 import { logger } from '../../logger';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_HEX } from '../../constants/data-binary-source';
+import * as datasourceHex from '../../datasource/hex';
 
 const depSectionRegExp = /defp\s+deps.*do/g;
 const depMatchRegExp = /{:(\w+),\s*([^:"]+)?:?\s*"([^"]+)",?\s*(organization: "(.*)")?.*}/gm;
@@ -34,9 +34,9 @@ export function extractPackageFile(content: string): PackageFile {
             managerData: {},
           };
 
-          dep.datasource = datasource || DATASOURCE_HEX;
+          dep.datasource = datasource || datasourceHex.id;
 
-          if (dep.datasource === DATASOURCE_HEX) {
+          if (dep.datasource === datasourceHex.id) {
             dep.currentValue = currentValue;
             dep.lookupName = depName;
           }
@@ -49,7 +49,7 @@ export function extractPackageFile(content: string): PackageFile {
             dep.skipReason = 'unsupported-version';
           }
 
-          if (dep.datasource !== DATASOURCE_HEX) {
+          if (dep.datasource !== datasourceHex.id) {
             dep.skipReason = 'non-hex depTypes';
           }
 
diff --git a/lib/manager/npm/extract/index.ts b/lib/manager/npm/extract/index.ts
index 8c871e1d1b18bb7aa241e7f313c68b49b55babc4..1bda89750e65c1d007f807d93693a583aa9fb1df 100644
--- a/lib/manager/npm/extract/index.ts
+++ b/lib/manager/npm/extract/index.ts
@@ -18,10 +18,8 @@ import { NpmPackage } from './common';
 import { platform } from '../../../platform';
 import { CONFIG_VALIDATION } from '../../../constants/error-messages';
 import * as nodeVersioning from '../../../versioning/node';
-import {
-  DATASOURCE_GITHUB_TAGS,
-  DATASOURCE_NPM,
-} from '../../../constants/data-binary-source';
+import * as datasourceNpm from '../../../datasource/npm';
+import * as datasourceGithubTags from '../../../datasource/github-tags';
 
 export async function extractPackageFile(
   content: string,
@@ -156,14 +154,14 @@ export async function extractPackageFile(
     dep.currentValue = input.trim();
     if (depType === 'engines') {
       if (depName === 'node') {
-        dep.datasource = DATASOURCE_GITHUB_TAGS;
+        dep.datasource = datasourceGithubTags.id;
         dep.lookupName = 'nodejs/node';
         dep.versioning = nodeVersioning.id;
       } else if (depName === 'yarn') {
-        dep.datasource = DATASOURCE_NPM;
+        dep.datasource = datasourceNpm.id;
         dep.commitMessageTopic = 'Yarn';
       } else if (depName === 'npm') {
-        dep.datasource = DATASOURCE_NPM;
+        dep.datasource = datasourceNpm.id;
         dep.commitMessageTopic = 'npm';
       } else {
         dep.skipReason = 'unknown-engines';
@@ -177,11 +175,11 @@ export async function extractPackageFile(
     // support for volta
     if (depType === 'volta') {
       if (depName === 'node') {
-        dep.datasource = DATASOURCE_GITHUB_TAGS;
+        dep.datasource = datasourceGithubTags.id;
         dep.lookupName = 'nodejs/node';
         dep.versioning = nodeVersioning.id;
       } else if (depName === 'yarn') {
-        dep.datasource = DATASOURCE_NPM;
+        dep.datasource = datasourceNpm.id;
         dep.commitMessageTopic = 'Yarn';
       } else {
         dep.skipReason = 'unknown-volta';
@@ -211,7 +209,7 @@ export async function extractPackageFile(
       return dep;
     }
     if (isValid(dep.currentValue)) {
-      dep.datasource = DATASOURCE_NPM;
+      dep.datasource = datasourceNpm.id;
       if (dep.currentValue === '*') {
         dep.skipReason = 'any-version';
       }
@@ -248,7 +246,7 @@ export async function extractPackageFile(
     if (isVersion(depRefPart)) {
       dep.currentRawValue = dep.currentValue;
       dep.currentValue = depRefPart;
-      dep.datasource = DATASOURCE_GITHUB_TAGS;
+      dep.datasource = datasourceGithubTags.id;
       dep.lookupName = githubOwnerRepo;
       dep.pinDigests = false;
     } else if (
@@ -258,7 +256,7 @@ export async function extractPackageFile(
       dep.currentRawValue = dep.currentValue;
       dep.currentValue = null;
       dep.currentDigest = depRefPart;
-      dep.datasource = DATASOURCE_GITHUB_TAGS;
+      dep.datasource = datasourceGithubTags.id;
       dep.lookupName = githubOwnerRepo;
     } else {
       dep.skipReason = 'unversioned-reference';
diff --git a/lib/manager/nuget/extract.ts b/lib/manager/nuget/extract.ts
index cf4bc024b9c18593d3d91fae664ba01ae08b1cff..4891ada92e70d8d6733e43d2021248492e87de18 100644
--- a/lib/manager/nuget/extract.ts
+++ b/lib/manager/nuget/extract.ts
@@ -2,7 +2,7 @@ import { logger } from '../../logger';
 import { get } from '../../versioning';
 import { PackageDependency, ExtractConfig, PackageFile } from '../common';
 import * as semverVersioning from '../../versioning/semver';
-import { DATASOURCE_NUGET } from '../../constants/data-binary-source';
+import * as datasourceNuget from '../../datasource/nuget';
 
 export function extractPackageFile(
   content: string,
@@ -38,7 +38,7 @@ export function extractPackageFile(
         depName,
         currentValue,
         managerData: { lineNumber },
-        datasource: DATASOURCE_NUGET,
+        datasource: datasourceNuget.id,
       };
       if (!isVersion(currentValue)) {
         dep.skipReason = 'not-version';
diff --git a/lib/manager/nvm/extract.ts b/lib/manager/nvm/extract.ts
index f327e4c4afd15cca25a6e0db0b5519e0445fa468..b3132c2cf0ec34d151e56b86551fd786d919587d 100644
--- a/lib/manager/nvm/extract.ts
+++ b/lib/manager/nvm/extract.ts
@@ -1,12 +1,12 @@
 import { isValid } from '../../versioning/node';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_GITHUB_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGithubTags from '../../datasource/github-tags';
 
 export function extractPackageFile(content: string): PackageFile {
   const dep: PackageDependency = {
     depName: 'node',
     currentValue: content.trim(),
-    datasource: DATASOURCE_GITHUB_TAGS,
+    datasource: datasourceGithubTags.id,
     lookupName: 'nodejs/node',
   };
   if (!isValid(dep.currentValue)) {
diff --git a/lib/manager/pip_requirements/extract.ts b/lib/manager/pip_requirements/extract.ts
index 31fb5ad9a19b7b3e538e2f4bf75e97cbf2a98fcc..a121c48df61f8525f4f369ff75f969b4f8229d4a 100644
--- a/lib/manager/pip_requirements/extract.ts
+++ b/lib/manager/pip_requirements/extract.ts
@@ -4,7 +4,7 @@ import { logger } from '../../logger';
 import { isSkipComment } from '../../util/ignore';
 import { isValid, isSingleVersion } from '../../versioning/pep440';
 import { ExtractConfig, PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_PYPI } from '../../constants/data-binary-source';
+import * as datasourcePypi from '../../datasource/pypi';
 
 export const packagePattern =
   '[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]';
@@ -67,7 +67,7 @@ export function extractPackageFile(
         depName,
         currentValue,
         managerData: { lineNumber },
-        datasource: DATASOURCE_PYPI,
+        datasource: datasourcePypi.id,
       };
       if (
         isValid(currentValue) &&
diff --git a/lib/manager/pip_setup/extract.ts b/lib/manager/pip_setup/extract.ts
index 29506b064dab7e724a5090333f6f1de71eb30ea6..fe7dab277c2354e9e0861db16effe843081e9bdc 100644
--- a/lib/manager/pip_setup/extract.ts
+++ b/lib/manager/pip_setup/extract.ts
@@ -4,7 +4,7 @@ import { logger } from '../../logger';
 import { isSkipComment } from '../../util/ignore';
 import { dependencyPattern } from '../pip_requirements/extract';
 import { ExtractConfig, PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_PYPI } from '../../constants/data-binary-source';
+import * as datasourcePypi from '../../datasource/pypi';
 import { BinarySource } from '../../util/exec/common';
 
 export const pythonVersions = ['python', 'python3', 'python3.8'];
@@ -140,7 +140,7 @@ export async function extractPackageFile(
         depName,
         currentValue,
         managerData: { lineNumber },
-        datasource: DATASOURCE_PYPI,
+        datasource: datasourcePypi.id,
       };
       return dep;
     })
diff --git a/lib/manager/pipenv/extract.ts b/lib/manager/pipenv/extract.ts
index e9f0d6aea0e1f9dee3fbf76548c50e62b9ae1fa3..980e8d71733b667e0b1e806c1173472bb78ff97e 100644
--- a/lib/manager/pipenv/extract.ts
+++ b/lib/manager/pipenv/extract.ts
@@ -3,7 +3,7 @@ import toml from 'toml';
 import { RANGE_PATTERN } from '@renovate/pep440/lib/specifier';
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_PYPI } from '../../constants/data-binary-source';
+import * as datasourcePypi from '../../datasource/pypi';
 
 // based on https://www.python.org/dev/peps/pep-0508/#names
 const packageRegex = /^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$/i;
@@ -92,7 +92,7 @@ function extractFromSection(
       if (skipReason) {
         dep.skipReason = skipReason;
       } else {
-        dep.datasource = DATASOURCE_PYPI;
+        dep.datasource = datasourcePypi.id;
       }
       if (nestedVersion) dep.managerData.nestedVersion = nestedVersion;
       if (requirements.index) {
diff --git a/lib/manager/poetry/extract.ts b/lib/manager/poetry/extract.ts
index 5423ecb749f8639209b7c3d1cd1415a0caa9f8bc..ff7e57c5e6788dd866c03df7baa3d7beda818223 100644
--- a/lib/manager/poetry/extract.ts
+++ b/lib/manager/poetry/extract.ts
@@ -3,7 +3,7 @@ import { isValid } from '../../versioning/poetry';
 import { logger } from '../../logger';
 import { PackageFile, PackageDependency } from '../common';
 import { PoetryFile, PoetrySection } from './types';
-import { DATASOURCE_PYPI } from '../../constants/data-binary-source';
+import * as datasourcePypi from '../../datasource/pypi';
 
 function extractFromSection(
   parsedFile: PoetryFile,
@@ -47,7 +47,7 @@ function extractFromSection(
       depType: section,
       currentValue: currentValue as string,
       managerData: { nestedVersion },
-      datasource: DATASOURCE_PYPI,
+      datasource: datasourcePypi.id,
     };
     if (skipReason) {
       dep.skipReason = skipReason;
diff --git a/lib/manager/pub/extract.ts b/lib/manager/pub/extract.ts
index 59cb3a6ea3489a953acd126efaefa43441f0fb6f..ffb5ce933ec1610f2b9e381eab7352aa0996bb1f 100644
--- a/lib/manager/pub/extract.ts
+++ b/lib/manager/pub/extract.ts
@@ -2,7 +2,7 @@ import { safeLoad } from 'js-yaml';
 import { isValid } from '../../versioning/npm/index';
 import { logger } from '../../logger';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_DART } from '../../constants/data-binary-source';
+import * as datasourceDart from '../../datasource/dart';
 
 function getDeps(
   depsObj: { [x: string]: any },
@@ -50,7 +50,7 @@ export function extractPackageFile(
     if (deps.length) {
       return {
         packageFile,
-        datasource: DATASOURCE_DART,
+        datasource: datasourceDart.id,
         deps,
       };
     }
diff --git a/lib/manager/ruby-version/extract.ts b/lib/manager/ruby-version/extract.ts
index b0865874c5b36305908a71cc3f9932dae7f21200..19ffdc99f1996021058741ce145fbac234d69df7 100644
--- a/lib/manager/ruby-version/extract.ts
+++ b/lib/manager/ruby-version/extract.ts
@@ -1,14 +1,14 @@
 import { isValid } from '../../versioning/ruby';
 import { logger } from '../../logger';
 import { PackageDependency, PackageFile } from '../common';
-import { DATASOURCE_RUBY_VERSION } from '../../constants/data-binary-source';
+import * as datasourceRubyVersion from '../../datasource/ruby-version';
 
 export function extractPackageFile(content: string): PackageFile {
   logger.trace('ruby-version.extractPackageFile()');
   const dep: PackageDependency = {
     depName: 'ruby',
     currentValue: content.trim(),
-    datasource: DATASOURCE_RUBY_VERSION,
+    datasource: datasourceRubyVersion.id,
   };
   if (!isValid(dep.currentValue)) {
     dep.skipReason = 'unsupported-version';
diff --git a/lib/manager/sbt/extract.ts b/lib/manager/sbt/extract.ts
index 55972aaa2053a3da01c6e9f100f0ecdb0e142c6d..a6de0c2b21a3eee0b445f4920283e194fff7ac10 100644
--- a/lib/manager/sbt/extract.ts
+++ b/lib/manager/sbt/extract.ts
@@ -2,10 +2,8 @@ import { DEFAULT_MAVEN_REPO } from '../maven/extract';
 import { PackageFile, PackageDependency } from '../common';
 import { get } from '../../versioning';
 import * as mavenVersioning from '../../versioning/maven';
-import {
-  DATASOURCE_SBT_PACKAGE,
-  DATASOURCE_SBT_PLUGIN,
-} from '../../constants/data-binary-source';
+import * as datasourceSbtPackage from '../../datasource/sbt-package';
+import * as datasourceSbtPlugin from '../../datasource/sbt-plugin';
 
 const isComment = (str: string): boolean => /^\s*\/\//.test(str);
 
@@ -255,9 +253,9 @@ function parseSbtLine(
 
   if (dep) {
     if (dep.depType === 'plugin') {
-      dep.datasource = DATASOURCE_SBT_PLUGIN;
+      dep.datasource = datasourceSbtPlugin.id;
     } else {
-      dep.datasource = DATASOURCE_SBT_PACKAGE;
+      dep.datasource = datasourceSbtPackage.id;
     }
     deps.push({
       registryUrls,
diff --git a/lib/manager/swift/extract.ts b/lib/manager/swift/extract.ts
index 947c979a8f00a148d4623a9aa502523ca21c3493..36777ddff4ab7b26db8586144bc821ae3aa608d5 100644
--- a/lib/manager/swift/extract.ts
+++ b/lib/manager/swift/extract.ts
@@ -1,6 +1,6 @@
 import { isValid } from '../../versioning/swift';
 import { PackageFile, PackageDependency } from '../common';
-import { DATASOURCE_GIT_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGitTags from '../../datasource/git-tags';
 
 const regExps = {
   wildcard: /^.*?/,
@@ -158,7 +158,7 @@ export function extractPackageFile(
     const depName = getDepName(lookupName);
     if (depName && currentValue && fileReplacePosition) {
       const dep: PackageDependency = {
-        datasource: DATASOURCE_GIT_TAGS,
+        datasource: datasourceGitTags.id,
         depName,
         lookupName,
         currentValue,
diff --git a/lib/manager/terraform/extract.ts b/lib/manager/terraform/extract.ts
index c7e4d33545a98047df5d7ea71742197c00fb16cd..361d9b9ea3066bafc202cff3b1bc8aedd5a31996 100644
--- a/lib/manager/terraform/extract.ts
+++ b/lib/manager/terraform/extract.ts
@@ -1,12 +1,10 @@
 import { logger } from '../../logger';
 import { isValid, isVersion } from '../../versioning/hashicorp';
 import { PackageDependency, PackageFile } from '../common';
-import {
-  DATASOURCE_GIT_TAGS,
-  DATASOURCE_GITHUB_TAGS,
-  DATASOURCE_TERRAFORM,
-  DATASOURCE_TERRAFORM_PROVIDER,
-} from '../../constants/data-binary-source';
+import * as datasourceGitTags from '../../datasource/git-tags';
+import * as datasourceGithubTags from '../../datasource/github-tags';
+import * as datasourceTerraform from '../../datasource/terraform';
+import * as datasourceTerraformProvider from '../../datasource/terraform-provider';
 
 export enum TerraformDependencyTypes {
   unknown = 'unknown',
@@ -99,7 +97,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         dep.depName = 'github.com/' + githubRefMatch[2];
         dep.depNameShort = githubRefMatch[2];
         dep.currentValue = githubRefMatch[3];
-        dep.datasource = DATASOURCE_GITHUB_TAGS;
+        dep.datasource = datasourceGithubTags.id;
         dep.lookupName = githubRefMatch[2];
         dep.managerData.lineNumber = dep.sourceLine;
         if (!isVersion(dep.currentValue)) {
@@ -110,7 +108,7 @@ export function extractPackageFile(content: string): PackageFile | null {
         dep.depName = gitTagsRefMatch[2].replace('.git', '');
         dep.depNameShort = gitTagsRefMatch[3].replace('.git', '');
         dep.currentValue = gitTagsRefMatch[4];
-        dep.datasource = DATASOURCE_GIT_TAGS;
+        dep.datasource = datasourceGitTags.id;
         dep.lookupName = gitTagsRefMatch[1];
         dep.managerData.lineNumber = dep.sourceLine;
         if (!isVersion(dep.currentValue)) {
@@ -125,7 +123,7 @@ export function extractPackageFile(content: string): PackageFile | null {
           dep.depName = moduleParts.join('/');
           dep.depNameShort = dep.depName;
           dep.managerData.lineNumber = dep.versionLine;
-          dep.datasource = DATASOURCE_TERRAFORM;
+          dep.datasource = datasourceTerraform.id;
         }
         if (dep.managerData.lineNumber) {
           if (!isValid(dep.currentValue)) {
@@ -146,7 +144,7 @@ export function extractPackageFile(content: string): PackageFile | null {
       dep.depName = dep.moduleName;
       dep.depNameShort = dep.moduleName;
       dep.managerData.lineNumber = dep.versionLine;
-      dep.datasource = DATASOURCE_TERRAFORM_PROVIDER;
+      dep.datasource = datasourceTerraformProvider.id;
       if (dep.managerData.lineNumber) {
         if (!isValid(dep.currentValue)) {
           dep.skipReason = 'unsupported-version';
diff --git a/lib/manager/travis/package.ts b/lib/manager/travis/package.ts
index 8165cd612869150afd4e8663f1074654aa527492..c69842824052670617f2a3087947711dbac55e55 100644
--- a/lib/manager/travis/package.ts
+++ b/lib/manager/travis/package.ts
@@ -5,7 +5,7 @@ import { getPkgReleases } from '../../datasource';
 import { isVersion, maxSatisfyingVersion } from '../../versioning/semver';
 import nodeJsSchedule from '../../../data/node-js-schedule.json';
 import { PackageUpdateConfig, PackageUpdateResult } from '../common';
-import { DATASOURCE_GITHUB_TAGS } from '../../constants/data-binary-source';
+import * as datasourceGithubTags from '../../datasource/github-tags';
 
 interface NodeJsPolicies {
   all: number[];
@@ -102,7 +102,7 @@ export async function getPackageUpdates(
     const versions = (
       await getPkgReleases({
         ...config,
-        datasource: DATASOURCE_GITHUB_TAGS,
+        datasource: datasourceGithubTags.id,
         depName: 'nodejs/node',
       })
     ).releases.map(release => release.version);
diff --git a/lib/util/modules.ts b/lib/util/modules.ts
index 5cb6440c9c362aef1028c0e0ed0e770a69a1e432..3b3d0b644584afccaf511c05fbe3b06969e2e89a 100644
--- a/lib/util/modules.ts
+++ b/lib/util/modules.ts
@@ -22,7 +22,7 @@ function relatePath(here: string, there: string): string {
 
 export function loadModules<T>(
   dirname: string,
-  validate?: (x: unknown) => boolean
+  validate?: (module: T, moduleName?: string) => boolean
 ): Record<string, T> {
   const result: Record<string, T> = {};
 
@@ -37,7 +37,7 @@ export function loadModules<T>(
     const modulePath = join(relatePath(__dirname, dirname), moduleName);
     const module = require(modulePath); // eslint-disable-line
     // istanbul ignore if
-    if (!module || (validate && !validate(module)))
+    if (!module || (validate && !validate(module, moduleName)))
       throw new Error(`Invalid module: ${modulePath}`);
     result[moduleName] = module as T;
   }
diff --git a/lib/workers/branch/get-updated.ts b/lib/workers/branch/get-updated.ts
index 6b9bc43999b89e1aad636a5e22b3949bdf6274e5..3d51141ff9c9696bfa11f7364a0f3d6996322e30 100644
--- a/lib/workers/branch/get-updated.ts
+++ b/lib/workers/branch/get-updated.ts
@@ -5,7 +5,7 @@ import { get } from '../../manager';
 import { RenovateConfig } from '../../config';
 import { UpdateArtifactsConfig, ArtifactError } from '../../manager/common';
 import { WORKER_FILE_UPDATE_FAILED } from '../../constants/error-messages';
-import { DATASOURCE_GIT_SUBMODULES } from '../../constants/data-binary-source';
+import * as datasourceGitSubmodules from '../../datasource/git-submodules';
 import { doAutoReplace } from './auto-replace';
 
 export interface PackageFilesResult {
@@ -98,7 +98,7 @@ export async function getUpdatedPackageFiles(
       }
       if (
         newContent === existingContent &&
-        upgrade.datasource === DATASOURCE_GIT_SUBMODULES
+        upgrade.datasource === datasourceGitSubmodules.id
       ) {
         updatedFileContents[packageFile] = newContent;
       }
diff --git a/lib/workers/repository/init/vulnerability.ts b/lib/workers/repository/init/vulnerability.ts
index 8969138a8117c808ffc9e7d052a466be96549d67..b2ef0b4ef8b20888e00c4220f5d93c6fdfa04bbc 100644
--- a/lib/workers/repository/init/vulnerability.ts
+++ b/lib/workers/repository/init/vulnerability.ts
@@ -9,12 +9,11 @@ import * as pep440Versioning from '../../../versioning/pep440';
 import * as rubyVersioning from '../../../versioning/ruby';
 import * as semverVersioning from '../../../versioning/semver';
 
-import {
-  DATASOURCE_MAVEN,
-  DATASOURCE_NPM,
-  DATASOURCE_NUGET,
-  DATASOURCE_PYPI,
-} from '../../../constants/data-binary-source';
+import * as datasourceMaven from '../../../datasource/maven';
+import * as datasourceNpm from '../../../datasource/npm';
+import * as datasourceNuget from '../../../datasource/nuget';
+import * as datasourcePypi from '../../../datasource/pypi';
+import * as datasourceRubygems from '../../../datasource/rubygems';
 
 export async function detectVulnerabilityAlerts(
   input: RenovateConfig
@@ -49,11 +48,11 @@ export async function detectVulnerabilityAlerts(
         continue; // eslint-disable-line no-continue
       }
       const datasourceMapping = {
-        MAVEN: DATASOURCE_MAVEN,
-        NPM: DATASOURCE_NPM,
-        NUGET: DATASOURCE_NUGET,
-        PIP: DATASOURCE_PYPI,
-        RUBYGEMS: 'bundler',
+        MAVEN: datasourceMaven.id,
+        NPM: datasourceNpm.id,
+        NUGET: datasourceNuget.id,
+        PIP: datasourcePypi.id,
+        RUBYGEMS: datasourceRubygems.id,
       };
       const datasource =
         datasourceMapping[alert.securityVulnerability.package.ecosystem];
@@ -144,14 +143,14 @@ export async function detectVulnerabilityAlerts(
       let matchCurrentVersion = val.vulnerableRequirements;
       // istanbul ignore if
       if (!matchCurrentVersion) {
-        if (datasource === DATASOURCE_MAVEN) {
+        if (datasource === datasourceMaven.id) {
           matchCurrentVersion = `(,${val.firstPatchedVersion})`;
         } else {
           matchCurrentVersion = `< ${val.firstPatchedVersion}`;
         }
       }
       const allowedVersions =
-        datasource === DATASOURCE_PYPI
+        datasource === datasourcePypi.id
           ? `==${val.firstPatchedVersion}`
           : val.firstPatchedVersion;
       const matchRule = {
diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts
index a9740324cc14ec939ab8b17b3dadbb85a5312c47..95d7ad3be6e56c4151c009252c715047901ff5a3 100644
--- a/lib/workers/repository/process/lookup/index.ts
+++ b/lib/workers/repository/process/lookup/index.ts
@@ -13,7 +13,7 @@ import { LookupUpdate } from './common';
 import { RangeConfig } from '../../../../manager/common';
 import { RenovateConfig } from '../../../../config';
 import { clone } from '../../../../util/clone';
-import { DATASOURCE_GIT_SUBMODULES } from '../../../../constants/data-binary-source';
+import * as datasourceGitSubmodules from '../../../../datasource/git-submodules';
 
 export interface LookupWarning {
   updateType: 'warning';
@@ -351,7 +351,7 @@ export async function lookupUpdates(
   if (supportsDigests(config)) {
     if (
       config.currentDigest &&
-      config.datasource !== DATASOURCE_GIT_SUBMODULES
+      config.datasource !== datasourceGitSubmodules.id
     ) {
       if (!config.digestOneAndOnly || !res.updates.length) {
         // digest update
@@ -369,7 +369,7 @@ export async function lookupUpdates(
           newValue: config.currentValue,
         });
       }
-    } else if (config.datasource === DATASOURCE_GIT_SUBMODULES) {
+    } else if (config.datasource === datasourceGitSubmodules.id) {
       const dependency = clone(await getPkgReleases(config));
       res.updates.push({
         updateType: 'digest',
diff --git a/test/config/cli.spec.ts b/test/config/cli.spec.ts
index 8d685dcbec6e604547c50ef58a076168c4a842ca..03b0760cbac89f3fc02d9d7e764dac7b7ab69d89 100644
--- a/test/config/cli.spec.ts
+++ b/test/config/cli.spec.ts
@@ -1,7 +1,7 @@
 import * as cli from '../../lib/config/cli';
 import getArgv from './config/__fixtures__/argv';
 import { RenovateOptions } from '../../lib/config/definitions';
-import { DATASOURCE_DOCKER } from '../../lib/constants/data-binary-source';
+import * as datasourceDocker from '../../lib/datasource/docker';
 
 describe('config/cli', () => {
   let argv: string[];
@@ -78,13 +78,13 @@ describe('config/cli', () => {
     });
     it('parses json lists correctly', () => {
       argv.push(
-        `--host-rules=[{"domainName":"docker.io","hostType":"${DATASOURCE_DOCKER}","username":"user","password":"password"}]`
+        `--host-rules=[{"domainName":"docker.io","hostType":"${datasourceDocker.id}","username":"user","password":"password"}]`
       );
       expect(cli.getConfig(argv)).toEqual({
         hostRules: [
           {
             domainName: 'docker.io',
-            hostType: DATASOURCE_DOCKER,
+            hostType: datasourceDocker.id,
             username: 'user',
             password: 'password',
           },
diff --git a/test/util/host-rules.spec.ts b/test/util/host-rules.spec.ts
index 3e60d559d8cd05d78516f356a9fc0b8459c8144a..9d95f66a1d38b4e0c0874964838b62c2b3f09bd6 100644
--- a/test/util/host-rules.spec.ts
+++ b/test/util/host-rules.spec.ts
@@ -1,5 +1,5 @@
 import { add, find, findAll, clear, hosts } from '../../lib/util/host-rules';
-import { DATASOURCE_NUGET } from '../../lib/constants/data-binary-source';
+import * as datasourceNuget from '../../lib/datasource/nuget';
 import { PLATFORM_TYPE_AZURE } from '../../lib/constants/platforms';
 
 describe('util/host-rules', () => {
@@ -49,21 +49,21 @@ describe('util/host-rules', () => {
     });
     it('needs exact host matches', () => {
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         hostName: 'nuget.org',
         username: 'root',
         password: 'p4$$w0rd',
         token: undefined,
       });
-      expect(find({ hostType: DATASOURCE_NUGET })).toMatchSnapshot();
+      expect(find({ hostType: datasourceNuget.id })).toMatchSnapshot();
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://nuget.org' })
+        find({ hostType: datasourceNuget.id, url: 'https://nuget.org' })
       ).not.toEqual({});
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://not.nuget.org' })
+        find({ hostType: datasourceNuget.id, url: 'https://not.nuget.org' })
       ).toEqual({});
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://not-nuget.org' })
+        find({ hostType: datasourceNuget.id, url: 'https://not-nuget.org' })
       ).toEqual({});
     });
     it('matches on empty rules', () => {
@@ -71,16 +71,16 @@ describe('util/host-rules', () => {
         json: true,
       });
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://api.github.com' })
+        find({ hostType: datasourceNuget.id, url: 'https://api.github.com' })
       ).toEqual({ json: true });
     });
     it('matches on hostType', () => {
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         token: 'abc',
       });
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://nuget.local/api' })
+        find({ hostType: datasourceNuget.id, url: 'https://nuget.local/api' })
       ).toMatchSnapshot();
     });
     it('matches on domainName', () => {
@@ -89,7 +89,7 @@ describe('util/host-rules', () => {
         token: 'def',
       });
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://api.github.com' })
+        find({ hostType: datasourceNuget.id, url: 'https://api.github.com' })
           .token
       ).toEqual('def');
     });
@@ -99,50 +99,50 @@ describe('util/host-rules', () => {
         token: 'abc',
       });
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://nuget.local/api' })
+        find({ hostType: datasourceNuget.id, url: 'https://nuget.local/api' })
       ).toMatchSnapshot();
     });
     it('matches on hostType and endpoint', () => {
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         baseUrl: 'https://nuget.local/api',
         token: 'abc',
       });
       expect(
-        find({ hostType: DATASOURCE_NUGET, url: 'https://nuget.local/api' })
+        find({ hostType: datasourceNuget.id, url: 'https://nuget.local/api' })
           .token
       ).toEqual('abc');
     });
     it('matches on endpoint subresource', () => {
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         baseUrl: 'https://nuget.local/api',
         token: 'abc',
       });
       expect(
         find({
-          hostType: DATASOURCE_NUGET,
+          hostType: datasourceNuget.id,
           url: 'https://nuget.local/api/sub-resource',
         })
       ).toMatchSnapshot();
     });
     it('returns hosts', () => {
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         token: 'aaaaaa',
       });
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         baseUrl: 'https://nuget.local/api',
         token: 'abc',
       });
       add({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
         hostName: 'my.local.registry',
         token: 'def',
       });
       const res = hosts({
-        hostType: DATASOURCE_NUGET,
+        hostType: datasourceNuget.id,
       });
       expect(res).toMatchSnapshot();
       expect(res).toHaveLength(2);
diff --git a/test/util/package-rules.spec.ts b/test/util/package-rules.spec.ts
index ad497d00838b50f76ca3a02d27f202e594f153ec..214638d31d256d5bf53980e7e066a82b417db33b 100644
--- a/test/util/package-rules.spec.ts
+++ b/test/util/package-rules.spec.ts
@@ -7,10 +7,8 @@ import {
   LANGUAGE_PYTHON,
 } from '../../lib/constants/languages';
 
-import {
-  DATASOURCE_DOCKER,
-  DATASOURCE_ORB,
-} from '../../lib/constants/data-binary-source';
+import * as datasourceDocker from '../../lib/datasource/docker';
+import * as datasourceOrb from '../../lib/datasource/orb';
 
 type TestConfig = Config & { x?: number; y?: number };
 
@@ -263,14 +261,14 @@ describe('applyPackageRules()', () => {
     const config: TestConfig = {
       packageRules: [
         {
-          datasources: [DATASOURCE_ORB, DATASOURCE_DOCKER],
+          datasources: [datasourceOrb.id, datasourceDocker.id],
           x: 1,
         },
       ],
     };
     const dep = {
       depType: 'dependencies',
-      datasource: DATASOURCE_ORB,
+      datasource: datasourceOrb.id,
       baseBranch: 'master',
     };
     const res = applyPackageRules({ ...config, ...dep });
@@ -287,7 +285,7 @@ describe('applyPackageRules()', () => {
     };
     const dep = {
       depType: 'dependencies',
-      datasource: DATASOURCE_ORB,
+      datasource: datasourceOrb.id,
       baseBranch: 'master',
     };
     const res = applyPackageRules({ ...config, ...dep });
@@ -297,7 +295,7 @@ describe('applyPackageRules()', () => {
     const config: TestConfig = {
       packageRules: [
         {
-          datasources: [DATASOURCE_ORB],
+          datasources: [datasourceOrb.id],
           x: 1,
         },
       ],
diff --git a/test/workers/branch/get-updated.spec.ts b/test/workers/branch/get-updated.spec.ts
index be1b57bf52ef162104cdf7c940efbf03dcfc40f7..7a3cddcee26024741830be4d035334aecc52c16c 100644
--- a/test/workers/branch/get-updated.spec.ts
+++ b/test/workers/branch/get-updated.spec.ts
@@ -4,7 +4,7 @@ import * as _gitSubmodules from '../../../lib/manager/git-submodules';
 import * as _autoReplace from '../../../lib/workers/branch/auto-replace';
 import { getUpdatedPackageFiles } from '../../../lib/workers/branch/get-updated';
 import { mocked, defaultConfig, platform } from '../../util';
-import { DATASOURCE_GIT_SUBMODULES } from '../../../lib/constants/data-binary-source';
+import * as datasourceGitSubmodules from '../../../lib/datasource/git-submodules';
 
 const composer = mocked(_composer);
 const gitSubmodules = mocked(_gitSubmodules);
@@ -143,7 +143,7 @@ describe('workers/branch/get-updated', () => {
     it('handles git submodules', async () => {
       config.upgrades.push({
         manager: 'git-submodules',
-        datasource: DATASOURCE_GIT_SUBMODULES,
+        datasource: datasourceGitSubmodules.id,
       });
       gitSubmodules.updateDependency.mockResolvedValueOnce('existing content');
       const res = await getUpdatedPackageFiles(config);
diff --git a/test/workers/global/index.spec.ts b/test/workers/global/index.spec.ts
index 2efb94d69debf1f2ad34420b0b1cf70900ef3054..1ffcd45b75e37c0f9e11da5a93a14130e280e320 100644
--- a/test/workers/global/index.spec.ts
+++ b/test/workers/global/index.spec.ts
@@ -7,7 +7,7 @@ import {
   PLATFORM_TYPE_GITHUB,
   PLATFORM_TYPE_GITLAB,
 } from '../../../lib/constants/platforms';
-import { DATASOURCE_DOCKER } from '../../../lib/constants/data-binary-source';
+import * as datasourceDocker from '../../../lib/datasource/docker';
 
 jest.mock('../../../lib/workers/repository');
 
@@ -46,7 +46,7 @@ describe('lib/workers/global', () => {
       repositories: ['a', 'b'],
       hostRules: [
         {
-          hostType: DATASOURCE_DOCKER,
+          hostType: datasourceDocker.id,
           host: 'docker.io',
           username: 'some-user',
           password: 'some-password',
@@ -66,7 +66,7 @@ describe('lib/workers/global', () => {
       repositories: ['a', 'b'],
       hostRules: [
         {
-          hostType: DATASOURCE_DOCKER,
+          hostType: datasourceDocker.id,
           host: 'docker.io',
           username: 'some-user',
           password: 'some-password',
diff --git a/test/workers/repository/process/fetch.spec.ts b/test/workers/repository/process/fetch.spec.ts
index 255b3ea72cc3447a7bae5f5a4f2b574e97df08dc..334450b59af83a91d0a27c984da101cf9a27ce2a 100644
--- a/test/workers/repository/process/fetch.spec.ts
+++ b/test/workers/repository/process/fetch.spec.ts
@@ -3,7 +3,7 @@ import * as _npm from '../../../../lib/manager/npm';
 import * as lookup from '../../../../lib/workers/repository/process/lookup';
 import { getConfig, mocked, RenovateConfig } from '../../../util';
 import { ManagerApi } from '../../../../lib/manager/common';
-import { DATASOURCE_NPM } from '../../../../lib/constants/data-binary-source';
+import * as datasourceNpm from '../../../../lib/datasource/npm';
 
 const npm: ManagerApi = _npm;
 const lookupUpdates = mocked(lookup).lookupUpdates;
@@ -66,7 +66,7 @@ describe('workers/repository/process/fetch', () => {
             packageJsonType: 'app',
             deps: [
               {
-                datasource: DATASOURCE_NPM,
+                datasource: datasourceNpm.id,
                 depName: 'aaa',
                 depType: 'devDependencies',
               },
diff --git a/test/workers/repository/process/lookup/index.spec.ts b/test/workers/repository/process/lookup/index.spec.ts
index a33ac2d9683fb823ec17d9eb32934cfb1d5d9a36..9b74280fd8c8ad34c35ebde0c0627ef562256198 100644
--- a/test/workers/repository/process/lookup/index.spec.ts
+++ b/test/workers/repository/process/lookup/index.spec.ts
@@ -7,31 +7,26 @@ import webpackJson from '../../../../config/npm/__fixtures__/webpack.json';
 import nextJson from '../../../../config/npm/__fixtures__/next.json';
 import vueJson from '../../../../config/npm/__fixtures__/vue.json';
 import typescriptJson from '../../../../config/npm/__fixtures__/typescript.json';
-import * as _docker from '../../../../../lib/datasource/docker';
-import * as _gitSubmodules from '../../../../../lib/datasource/git-submodules';
 import { mocked, getConfig } from '../../../../util';
 import { CONFIG_VALIDATION } from '../../../../../lib/constants/error-messages';
 import * as dockerVersioning from '../../../../../lib/versioning/docker';
 import * as gitVersioning from '../../../../../lib/versioning/git';
 import * as npmVersioning from '../../../../../lib/versioning/npm';
 import * as pep440Versioning from '../../../../../lib/versioning/pep440';
-
-import {
-  DATASOURCE_DOCKER,
-  DATASOURCE_GIT_SUBMODULES,
-  DATASOURCE_GITHUB_TAGS,
-  DATASOURCE_NPM,
-  DATASOURCE_PACKAGIST,
-  DATASOURCE_PYPI,
-} from '../../../../../lib/constants/data-binary-source';
+import * as datasourceNpm from '../../../../../lib/datasource/npm';
+import * as datasourcePypi from '../../../../../lib/datasource/pypi';
+import * as datasourcePackagist from '../../../../../lib/datasource/packagist';
+import * as datasourceDocker from '../../../../../lib/datasource/docker';
+import * as datasourceGithubTags from '../../../../../lib/datasource/github-tags';
+import * as datasourceGitSubmodules from '../../../../../lib/datasource/git-submodules';
 
 jest.mock('../../../../../lib/datasource/docker');
 jest.mock('../../../../../lib/datasource/git-submodules');
 
 qJson.latestVersion = '1.4.1';
 
-const docker = mocked(_docker);
-const gitSubmodules = mocked(_gitSubmodules);
+const docker = mocked(datasourceDocker);
+const gitSubmodules = mocked(datasourceGitSubmodules);
 
 let config;
 
@@ -49,7 +44,7 @@ describe('workers/repository/process/lookup', () => {
     it('returns rollback for pinned version', async () => {
       config.currentValue = '0.9.99';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.rollbackPrs = true;
       nock('https://registry.npmjs.org')
         .get('/q')
@@ -59,7 +54,7 @@ describe('workers/repository/process/lookup', () => {
     it('returns rollback for ranged version', async () => {
       config.currentValue = '^0.9.99';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.rollbackPrs = true;
       nock('https://registry.npmjs.org')
         .get('/q')
@@ -70,7 +65,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -80,7 +75,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^0.4.0';
       config.rangeStrategy = 'update-lockfile';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.lockedVersion = '0.4.0';
       nock('https://registry.npmjs.org')
         .get('/q')
@@ -92,7 +87,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -106,7 +101,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'pin';
       config.depName = 'q';
       config.separateMinorPatch = true;
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -120,7 +115,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'pin';
       config.separateMajorMinor = false;
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -133,7 +128,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -146,7 +141,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -157,7 +152,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -167,7 +162,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.4.0';
       config.allowedVersions = '<1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -178,7 +173,7 @@ describe('workers/repository/process/lookup', () => {
       config.allowedVersions = '<1';
       config.depName = 'q';
       config.versioning = dockerVersioning.id; // this doesn't make sense but works for this test
-      config.datasource = DATASOURCE_NPM; // this doesn't make sense but works for this test
+      config.datasource = datasourceNpm.id; // this doesn't make sense but works for this test
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -188,7 +183,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.4.0';
       config.allowedVersions = 'less than 1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -200,7 +195,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.9.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -217,7 +212,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.9.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -235,7 +230,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.9.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -248,7 +243,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.9.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -259,7 +254,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '0.8.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -272,7 +267,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -283,7 +278,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '1.0.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -293,7 +288,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '1.0.0';
       config.vulnerabilityAlert = true;
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -305,7 +300,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~0.4.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -315,7 +310,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~0.9.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -325,7 +320,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~1.0.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -335,7 +330,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~1.3.0';
       config.rangeStrategy = 'widen';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -345,7 +340,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~1.2.0 || ~1.3.0';
       config.rangeStrategy = 'replace';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -355,7 +350,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^2.0.0';
       config.rangeStrategy = 'widen';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -365,7 +360,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^1.0.0 || ^2.0.0';
       config.rangeStrategy = 'replace';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -375,7 +370,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^1.0.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -386,7 +381,7 @@ describe('workers/repository/process/lookup', () => {
       config.lockedVersion = '1.0.0';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -396,7 +391,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '^1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -406,7 +401,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'pin';
       config.currentValue = '~1.3.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -416,7 +411,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '1.3.x';
       config.rangeStrategy = 'pin';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -426,7 +421,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '~1.3.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -436,7 +431,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '0.x';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -446,7 +441,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '1.3.x';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -456,7 +451,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '1.2.x - 1.3.x';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -466,7 +461,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -476,7 +471,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '1.3';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -486,7 +481,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '~0.7.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -496,7 +491,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '^0.7.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -506,7 +501,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '^0.7.0 || ^0.8.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -518,7 +513,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '^1.0.0 || ^2.0.0';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -528,7 +523,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '1.x - 2.x';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -538,7 +533,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '1.x || 2.x';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -548,7 +543,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '1 || 2';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -558,7 +553,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '~1.2.0 || ~1.3.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -568,7 +563,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '>= 0.7.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -578,7 +573,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '<= 0.7.2';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -588,7 +583,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '< 0.7.2';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -598,7 +593,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '< 1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -608,7 +603,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '<= 1.3';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -618,7 +613,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '=1.3.1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -629,7 +624,7 @@ describe('workers/repository/process/lookup', () => {
       config.respectLatest = false;
       config.currentValue = '<= 1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -639,7 +634,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '<= 1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -651,7 +646,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '< 1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -663,7 +658,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '>= 0.5.0 < 1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -675,7 +670,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '>= 0.5.0 <0.8';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -688,7 +683,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '>= 0.5.0 <= 0.8.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -701,7 +696,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'widen';
       config.currentValue = '<= 0.8.0 >= 0.5.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -712,7 +707,7 @@ describe('workers/repository/process/lookup', () => {
       config.respectLatest = false;
       config.currentValue = '1.4.1';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -721,7 +716,7 @@ describe('workers/repository/process/lookup', () => {
     it('should ignore unstable versions if the current version is stable', async () => {
       config.currentValue = '2.5.16';
       config.depName = 'vue';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/vue')
         .reply(200, vueJson);
@@ -731,7 +726,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '2.5.16';
       config.ignoreUnstable = false;
       config.depName = 'vue';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/vue')
         .reply(200, vueJson);
@@ -743,7 +738,7 @@ describe('workers/repository/process/lookup', () => {
     it('should allow unstable versions if the current version is unstable', async () => {
       config.currentValue = '3.1.0-dev.20180731';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/typescript')
         .reply(200, typescriptJson);
@@ -755,7 +750,7 @@ describe('workers/repository/process/lookup', () => {
     it('should not jump unstable versions', async () => {
       config.currentValue = '3.0.1-insiders.20180726';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/typescript')
         .reply(200, typescriptJson);
@@ -767,7 +762,7 @@ describe('workers/repository/process/lookup', () => {
     it('should follow dist-tag even if newer version exists', async () => {
       config.currentValue = '3.0.1-insiders.20180713';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.followTag = 'insiders';
       nock('https://registry.npmjs.org')
         .get('/typescript')
@@ -780,7 +775,7 @@ describe('workers/repository/process/lookup', () => {
     it('should roll back to dist-tag if current version is higher', async () => {
       config.currentValue = '3.1.0-dev.20180813';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.followTag = 'insiders';
       config.rollbackPrs = true;
       nock('https://registry.npmjs.org')
@@ -794,7 +789,7 @@ describe('workers/repository/process/lookup', () => {
     it('should jump unstable versions if followTag', async () => {
       config.currentValue = '3.0.0-insiders.20180706';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.followTag = 'insiders';
       nock('https://registry.npmjs.org')
         .get('/typescript')
@@ -807,7 +802,7 @@ describe('workers/repository/process/lookup', () => {
     it('should update nothing if current version is dist-tag', async () => {
       config.currentValue = '3.0.1-insiders.20180726';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.followTag = 'insiders';
       nock('https://registry.npmjs.org')
         .get('/typescript')
@@ -818,7 +813,7 @@ describe('workers/repository/process/lookup', () => {
     it('should warn if no version matches dist-tag', async () => {
       config.currentValue = '3.0.1-dev.20180726';
       config.depName = 'typescript';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.followTag = 'foo';
       nock('https://registry.npmjs.org')
         .get('/typescript')
@@ -835,7 +830,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '~0.0.34';
       config.depName = '@types/helmet';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/@types%2Fhelmet')
         .reply(200, helmetJson);
@@ -845,7 +840,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'replace';
       config.currentValue = '^0.0.34';
       config.depName = '@types/helmet';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/@types%2Fhelmet')
         .reply(200, helmetJson);
@@ -854,7 +849,7 @@ describe('workers/repository/process/lookup', () => {
     it('should downgrade from missing versions', async () => {
       config.currentValue = '1.16.1';
       config.depName = 'coffeelint';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.rollbackPrs = true;
       nock('https://registry.npmjs.org')
         .get('/coffeelint')
@@ -866,7 +861,7 @@ describe('workers/repository/process/lookup', () => {
     it('should upgrade to only one major', async () => {
       config.currentValue = '1.0.0';
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -877,7 +872,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '1.0.0';
       config.separateMultipleMajor = true;
       config.depName = 'webpack';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/webpack')
         .reply(200, webpackJson);
@@ -888,7 +883,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '^4.4.0-canary.3';
       config.rangeStrategy = 'replace';
       config.depName = 'next';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/next')
         .reply(200, nextJson);
@@ -899,7 +894,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '^1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -909,7 +904,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '~1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -920,7 +915,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~1.0.0';
       config.depName = 'q';
       config.separateMinorPatch = true;
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -930,7 +925,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '>=1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -940,7 +935,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '>=0.9.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -950,7 +945,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '>1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -960,7 +955,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '1.x';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -970,7 +965,7 @@ describe('workers/repository/process/lookup', () => {
       config.rangeStrategy = 'bump';
       config.currentValue = '^0.9.0 || ^1.0.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -978,7 +973,7 @@ describe('workers/repository/process/lookup', () => {
     });
     it('replaces non-range in-range updates', async () => {
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       config.packageFile = 'package.json';
       config.rangeStrategy = 'bump';
       config.currentValue = '1.0.0';
@@ -989,7 +984,7 @@ describe('workers/repository/process/lookup', () => {
     });
     it('handles github 404', async () => {
       config.depName = 'foo';
-      config.datasource = DATASOURCE_GITHUB_TAGS;
+      config.datasource = datasourceGithubTags.id;
       config.packageFile = 'package.json';
       config.currentValue = '1.0.0';
       nock('https://pypi.org')
@@ -999,7 +994,7 @@ describe('workers/repository/process/lookup', () => {
     });
     it('handles pypi 404', async () => {
       config.depName = 'foo';
-      config.datasource = DATASOURCE_PYPI;
+      config.datasource = datasourcePypi.id;
       config.packageFile = 'requirements.txt';
       config.currentValue = '1.0.0';
       nock('https://api.github.com')
@@ -1009,7 +1004,7 @@ describe('workers/repository/process/lookup', () => {
     });
     it('handles packagist', async () => {
       config.depName = 'foo/bar';
-      config.datasource = DATASOURCE_PACKAGIST;
+      config.datasource = datasourcePackagist.id;
       config.packageFile = 'composer.json';
       config.currentValue = '1.0.0';
       config.registryUrls = ['https://packagist.org'];
@@ -1035,7 +1030,7 @@ describe('workers/repository/process/lookup', () => {
       config.currentValue = '~=0.9';
       config.depName = 'q';
       // TODO: we are using npm as source to test pep440
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -1045,7 +1040,7 @@ describe('workers/repository/process/lookup', () => {
     it('returns complex object', async () => {
       config.currentValue = '1.3.0';
       config.depName = 'q';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       nock('https://registry.npmjs.org')
         .get('/q')
         .reply(200, qJson);
@@ -1056,7 +1051,7 @@ describe('workers/repository/process/lookup', () => {
     it('ignores deprecated', async () => {
       config.currentValue = '1.3.0';
       config.depName = 'q2';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       const returnJson = JSON.parse(JSON.stringify(qJson));
       returnJson.name = 'q2';
       returnJson.versions['1.4.1'].deprecated = 'true';
@@ -1070,7 +1065,7 @@ describe('workers/repository/process/lookup', () => {
     it('is deprecated', async () => {
       config.currentValue = '1.3.0';
       config.depName = 'q3';
-      config.datasource = DATASOURCE_NPM;
+      config.datasource = datasourceNpm.id;
       const returnJson = {
         ...JSON.parse(JSON.stringify(qJson)),
         name: 'q3',
@@ -1088,20 +1083,20 @@ describe('workers/repository/process/lookup', () => {
     it('skips unsupported values', async () => {
       config.currentValue = 'alpine';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot();
     });
     it('skips undefined values', async () => {
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot();
     });
     it('handles digest pin', async () => {
       config.currentValue = '8.0.0';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
         releases: [
@@ -1123,7 +1118,7 @@ describe('workers/repository/process/lookup', () => {
         config.currentValue = currentValue;
         config.depName = 'node';
         config.versioning = dockerVersioning.id;
-        config.datasource = DATASOURCE_DOCKER;
+        config.datasource = datasourceDocker.id;
         docker.getPkgReleases.mockResolvedValueOnce({
           releases: [
             { version: '8.1.0' },
@@ -1144,7 +1139,7 @@ describe('workers/repository/process/lookup', () => {
     it('handles digest pin for up to date version', async () => {
       config.currentValue = '8.1.0';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
         releases: [
@@ -1163,7 +1158,7 @@ describe('workers/repository/process/lookup', () => {
     it('handles digest pin for non-version', async () => {
       config.currentValue = 'alpine';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
         releases: [
@@ -1185,7 +1180,7 @@ describe('workers/repository/process/lookup', () => {
     it('handles digest lookup failure', async () => {
       config.currentValue = 'alpine';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
         releases: [
@@ -1207,7 +1202,7 @@ describe('workers/repository/process/lookup', () => {
     it('handles digest update', async () => {
       config.currentValue = '8.0.0';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.currentDigest = 'sha256:zzzzzzzzzzzzzzz';
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
@@ -1228,7 +1223,7 @@ describe('workers/repository/process/lookup', () => {
     it('handles digest update for non-version', async () => {
       config.currentValue = 'alpine';
       config.depName = 'node';
-      config.datasource = DATASOURCE_DOCKER;
+      config.datasource = datasourceDocker.id;
       config.currentDigest = 'sha256:zzzzzzzzzzzzzzz';
       config.pinDigests = true;
       docker.getPkgReleases.mockResolvedValueOnce({
@@ -1250,7 +1245,7 @@ describe('workers/repository/process/lookup', () => {
     });
     it('handles git submodule update', async () => {
       config.versioning = gitVersioning.id;
-      config.datasource = DATASOURCE_GIT_SUBMODULES;
+      config.datasource = datasourceGitSubmodules.id;
       gitSubmodules.getPkgReleases.mockResolvedValueOnce({
         releases: [
           {
diff --git a/test/workers/repository/updates/generate.spec.ts b/test/workers/repository/updates/generate.spec.ts
index 9b43af7b43f060872045b51c45c68003e444a254..8a6272f80b6b8c3b4db8a7bbe29609d446e4b4d9 100644
--- a/test/workers/repository/updates/generate.spec.ts
+++ b/test/workers/repository/updates/generate.spec.ts
@@ -1,6 +1,6 @@
 import { defaultConfig } from '../../../util';
 import { generateBranchConfig } from '../../../../lib/workers/repository/updates/generate';
-import { DATASOURCE_NPM } from '../../../../lib/constants/data-binary-source';
+import * as datasourceNpm from '../../../../lib/datasource/npm';
 
 beforeEach(() => {
   jest.resetAllMocks();
@@ -440,7 +440,7 @@ describe('workers/repository/updates/generate', () => {
       const branch = [
         {
           commitBodyTable: true,
-          datasource: DATASOURCE_NPM,
+          datasource: datasourceNpm.id,
           depName: '@types/some-dep',
           groupName: null,
           branchName: 'some-branch',
@@ -453,7 +453,7 @@ describe('workers/repository/updates/generate', () => {
         },
         {
           commitBodyTable: true,
-          datasource: DATASOURCE_NPM,
+          datasource: datasourceNpm.id,
           depName: 'some-dep',
           groupName: null,
           branchName: 'some-branch',