From 0246f6c2012feaf60ab7eca86cbd9334038ce7af Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Mon, 28 Jan 2019 06:40:37 +0100
Subject: [PATCH] refactor: getPkgReleases

---
 lib/datasource/index.js                       |  15 +--
 lib/manager/travis/package.js                 |   8 +-
 .../repository/process/lookup/index.js        |   2 +-
 test/datasource/docker.spec.js                |  16 +--
 test/datasource/github.spec.js                |  16 +--
 test/datasource/gitlab.spec.js                |   4 +-
 test/datasource/go.spec.js                    |  30 ++++--
 test/datasource/gradle-version.spec.js        |  11 +-
 test/datasource/index.spec.js                 |  10 +-
 test/datasource/maven.spec.js                 | 100 ++++++++++--------
 test/datasource/nuget.spec.js                 |  14 ++-
 test/datasource/orb.spec.js                   |  30 +++---
 test/datasource/packagist.spec.js             |  64 +++++------
 test/datasource/pypi.spec.js                  |  31 ++++--
 test/datasource/terraform.spec.js             |  24 +++--
 15 files changed, 218 insertions(+), 157 deletions(-)

diff --git a/lib/datasource/index.js b/lib/datasource/index.js
index 9c94f38eb0..06b8712ace 100644
--- a/lib/datasource/index.js
+++ b/lib/datasource/index.js
@@ -38,8 +38,8 @@ const datasources = {
 
 const cacheNamespace = 'datasource-releases';
 
-async function getPkgReleases(purlStr, config) {
-  const res = await getRawReleases(purlStr, config);
+async function getPkgReleases(config) {
+  const res = await getRawReleases(config);
   if (!res) {
     return res;
   }
@@ -55,7 +55,7 @@ async function getPkgReleases(purlStr, config) {
     res.releases = res.releases
       .filter(release => isVersion(release.version))
       .sort(sortReleases);
-    if (parse(purlStr).qualifiers.normalize === 'true') {
+    if (parse(config.purl).qualifiers.normalize === 'true') {
       for (const release of res.releases) {
         release.version = isVersion(release.version);
       }
@@ -64,17 +64,18 @@ async function getPkgReleases(purlStr, config) {
   return res;
 }
 
-function getRawReleases(purlStr, config) {
-  const cacheKey = cacheNamespace + purlStr;
+function getRawReleases(config) {
+  const cacheKey = cacheNamespace + config.purl;
   // The repoCache is initialized for each repo
   // By returning a Promise and reusing it, we should only fetch each package at most once
   if (!global.repoCache[cacheKey]) {
-    global.repoCache[cacheKey] = fetchReleases(purlStr, config);
+    global.repoCache[cacheKey] = fetchReleases(config);
   }
   return global.repoCache[cacheKey];
 }
 
-async function fetchReleases(purlStr, config) {
+async function fetchReleases(config) {
+  const purlStr = config.purl;
   const purl = parse(purlStr);
   if (!purl) {
     logger.info({ purlStr }, 'Cannot parse purl');
diff --git a/lib/manager/travis/package.js b/lib/manager/travis/package.js
index 4d304d02f1..0722149003 100644
--- a/lib/manager/travis/package.js
+++ b/lib/manager/travis/package.js
@@ -35,10 +35,10 @@ async function getPackageUpdates(config) {
     .sort((a, b) => a - b);
   const newMajor = newValue[newValue.length - 1];
   if (config.rangeStrategy === 'pin' || isVersion(config.currentValue[0])) {
-    const versions = (await getPkgReleases(
-      'pkg:github/nodejs/node',
-      config
-    )).releases.map(release => release.version);
+    const versions = (await getPkgReleases({
+      ...config,
+      purl: 'pkg:github/nodejs/node',
+    })).releases.map(release => release.version);
     newValue = newValue.map(value =>
       maxSatisfyingVersion(versions, `${value}`)
     );
diff --git a/lib/workers/repository/process/lookup/index.js b/lib/workers/repository/process/lookup/index.js
index d71fcd7938..9dd5ca673a 100644
--- a/lib/workers/repository/process/lookup/index.js
+++ b/lib/workers/repository/process/lookup/index.js
@@ -30,7 +30,7 @@ async function lookupUpdates(config) {
   } = versioning.get(config.versionScheme);
   const res = { updates: [], warnings: [] };
   if (isValid(currentValue)) {
-    const dependency = await getPkgReleases(config.purl, config);
+    const dependency = await getPkgReleases(config);
     if (!dependency) {
       // If dependency lookup fails then warn and return
       const result = {
diff --git a/test/datasource/docker.spec.js b/test/datasource/docker.spec.js
index 04f7f29df6..2911670a28 100644
--- a/test/datasource/docker.spec.js
+++ b/test/datasource/docker.spec.js
@@ -150,7 +150,7 @@ describe('api/docker', () => {
     });
     it('returns null if no token', async () => {
       got.mockReturnValueOnce({ body: {} });
-      const res = await getPkgReleases('pkg:docker/node');
+      const res = await getPkgReleases({ purl: 'pkg:docker/node' });
       expect(res).toBe(null);
     });
     it('uses custom registry', async () => {
@@ -162,7 +162,7 @@ describe('api/docker', () => {
       const config = {
         registryUrls: ['https://registry.company.com'],
       };
-      const res = await getPkgReleases('pkg:docker/node', config);
+      const res = await getPkgReleases({ ...config, purl: 'pkg:docker/node' });
       expect(res.releases).toHaveLength(1);
       expect(got).toMatchSnapshot();
     });
@@ -176,7 +176,7 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: { token: 'some-token ' } });
       got.mockReturnValueOnce({ headers: {}, body: { tags } });
-      const res = await getPkgReleases('pkg:docker/node');
+      const res = await getPkgReleases({ purl: 'pkg:docker/node' });
       expect(res.releases).toHaveLength(1);
       expect(got).toMatchSnapshot();
     });
@@ -190,7 +190,9 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: { token: 'some-token ' } });
       got.mockReturnValueOnce({ headers: {}, body: { tags } });
-      const res = await getPkgReleases('pkg:docker/node?registry=docker.io');
+      const res = await getPkgReleases({
+        purl: 'pkg:docker/node?registry=docker.io',
+      });
       expect(res.releases).toHaveLength(1);
       expect(got).toMatchSnapshot();
     });
@@ -204,9 +206,9 @@ describe('api/docker', () => {
       });
       got.mockReturnValueOnce({ headers: {}, body: { token: 'some-token ' } });
       got.mockReturnValueOnce({ headers: {}, body: { tags } });
-      const res = await getPkgReleases(
-        'pkg:docker/kubernetes-dashboard-amd64?registry=k8s.gcr.io'
-      );
+      const res = await getPkgReleases({
+        purl: 'pkg:docker/kubernetes-dashboard-amd64?registry=k8s.gcr.io',
+      });
       expect(res.releases).toHaveLength(1);
       expect(got).toMatchSnapshot();
     });
diff --git a/test/datasource/github.spec.js b/test/datasource/github.spec.js
index 71404262d7..d475423186 100644
--- a/test/datasource/github.spec.js
+++ b/test/datasource/github.spec.js
@@ -70,9 +70,9 @@ describe('datasource/github', () => {
         { name: 'v1.1.0' },
       ];
       ghGot.mockReturnValueOnce({ headers: {}, body });
-      const res = await datasource.getPkgReleases(
-        'pkg:github/some/dep?normalize=true'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:github/some/dep?normalize=true',
+      });
       expect(res).toMatchSnapshot();
       expect(res.releases).toHaveLength(2);
       expect(
@@ -87,9 +87,9 @@ describe('datasource/github', () => {
         { tag_name: 'v1.1.0' },
       ];
       ghGot.mockReturnValueOnce({ headers: {}, body });
-      const res = await datasource.getPkgReleases(
-        'pkg:github/some/dep?ref=release'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:github/some/dep?ref=release',
+      });
       expect(res).toMatchSnapshot();
       expect(res.releases).toHaveLength(2);
       expect(
@@ -98,7 +98,9 @@ describe('datasource/github', () => {
     });
     it('returns null for invalid ref', async () => {
       expect(
-        await datasource.getPkgReleases('pkg:github/some/dep?ref=invalid')
+        await datasource.getPkgReleases({
+          purl: 'pkg:github/some/dep?ref=invalid',
+        })
       ).toBeNull();
     });
   });
diff --git a/test/datasource/gitlab.spec.js b/test/datasource/gitlab.spec.js
index b0016d4851..86800ad911 100644
--- a/test/datasource/gitlab.spec.js
+++ b/test/datasource/gitlab.spec.js
@@ -52,7 +52,9 @@ describe('datasource/gitlab', () => {
     beforeAll(() => global.renovateCache.rmAll());
     it('returns null for invalid ref', async () => {
       expect(
-        await datasource.getPkgReleases('pkg:github/some/dep?ref=invalid')
+        await datasource.getPkgReleases({
+          purl: 'pkg:github/some/dep?ref=invalid',
+        })
       ).toBeNull();
     });
   });
diff --git a/test/datasource/go.spec.js b/test/datasource/go.spec.js
index 8fdd138a20..a9141b66a4 100644
--- a/test/datasource/go.spec.js
+++ b/test/datasource/go.spec.js
@@ -45,7 +45,9 @@ describe('datasource/go', () => {
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce(null);
       expect(
-        await datasource.getPkgReleases('pkg:go/golang.org/foo/something')
+        await datasource.getPkgReleases({
+          purl: 'pkg:go/golang.org/foo/something',
+        })
       ).toBeNull();
     });
     it('returns null for 404', async () => {
@@ -55,7 +57,9 @@ describe('datasource/go', () => {
         })
       );
       expect(
-        await datasource.getPkgReleases('pkg:go/golang.org/foo/something')
+        await datasource.getPkgReleases({
+          purl: 'pkg:go/golang.org/foo/something',
+        })
       ).toBeNull();
     });
     it('returns null for unknown error', async () => {
@@ -63,7 +67,9 @@ describe('datasource/go', () => {
         throw new Error();
       });
       expect(
-        await datasource.getPkgReleases('pkg:go/golang.org/foo/something')
+        await datasource.getPkgReleases({
+          purl: 'pkg:go/golang.org/foo/something',
+        })
       ).toBeNull();
     });
     it('processes real data', async () => {
@@ -73,7 +79,9 @@ describe('datasource/go', () => {
       github.getPkgReleases.mockReturnValueOnce({
         releases: [{ version: 'v1.0.0' }, { version: 'v2.0.0' }],
       });
-      const res = await datasource.getPkgReleases('pkg:go/golang.org/x/text');
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:go/golang.org/x/text',
+      });
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
       expect(res).toBeDefined();
@@ -82,7 +90,9 @@ describe('datasource/go', () => {
       got.mockReturnValueOnce({
         body: res1,
       });
-      const res = await datasource.getPkgReleases('pkg:go/golang.org/x/sys');
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:go/golang.org/x/sys',
+      });
       expect(res).toBeNull();
     });
     it('skips unsupported platform', async () => {
@@ -92,16 +102,18 @@ describe('datasource/go', () => {
           'https://google.com/golang/text/'
         ),
       });
-      const res = await datasource.getPkgReleases('pkg:go/golang.org/x/text');
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:go/golang.org/x/text',
+      });
       expect(res).toBeNull();
     });
     it('works for known servers', async () => {
       got.mockClear();
       github.getPkgReleases.mockClear();
       const packages = [
-        'pkg:go/github.com/x/text',
-        'pkg:go/gopkg.in/x/text',
-        'pkg:go/gopkg.in/x',
+        { purl: 'pkg:go/github.com/x/text' },
+        { purl: 'pkg:go/gopkg.in/x/text' },
+        { purl: 'pkg:go/gopkg.in/x' },
       ];
       const githubRes = { releases: [1, 2] };
       for (const pkg of packages) {
diff --git a/test/datasource/gradle-version.spec.js b/test/datasource/gradle-version.spec.js
index ce4ae4e41c..b32affc897 100644
--- a/test/datasource/gradle-version.spec.js
+++ b/test/datasource/gradle-version.spec.js
@@ -25,7 +25,7 @@ describe('datasource/gradle', () => {
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce({ body: {} });
       expect(
-        await datasource.getPkgReleases('pkg:gradleVersion', config)
+        await datasource.getPkgReleases({ purl: 'pkg:gradleVersion' }, config)
       ).toBeNull();
     });
 
@@ -37,7 +37,7 @@ describe('datasource/gradle', () => {
       );
       let e;
       try {
-        await datasource.getPkgReleases('pkg:gradleVersion', config);
+        await datasource.getPkgReleases({ purl: 'pkg:gradleVersion' }, config);
       } catch (err) {
         e = err;
       }
@@ -49,7 +49,7 @@ describe('datasource/gradle', () => {
         throw new Error();
       });
       expect(
-        await datasource.getPkgReleases('pkg:gradleVersion', config)
+        await datasource.getPkgReleases({ purl: 'pkg:gradleVersion' }, config)
       ).toBeNull();
     });
 
@@ -57,7 +57,10 @@ describe('datasource/gradle', () => {
       got.mockReturnValueOnce({
         body: JSON.parse(allResponse),
       });
-      const res = await datasource.getPkgReleases('pkg:gradleVersion', config);
+      const res = await datasource.getPkgReleases(
+        { purl: 'pkg:gradleVersion' },
+        config
+      );
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
     });
diff --git a/test/datasource/index.spec.js b/test/datasource/index.spec.js
index ef91beeeed..212a3f25e9 100644
--- a/test/datasource/index.spec.js
+++ b/test/datasource/index.spec.js
@@ -6,7 +6,9 @@ jest.mock('../../lib/datasource/npm');
 
 describe('datasource/index', () => {
   it('returns null for invalid purl', async () => {
-    expect(await datasource.getPkgReleases('pkggithub/some/dep')).toBeNull();
+    expect(
+      await datasource.getPkgReleases({ purl: 'pkggithub/some/dep' })
+    ).toBeNull();
   });
   it('returns getDigest', async () => {
     expect(
@@ -15,14 +17,16 @@ describe('datasource/index', () => {
   });
   it('adds changelogUrl', async () => {
     npmDatasource.getPkgReleases.mockReturnValue({});
-    const res = await datasource.getPkgReleases('pkg:npm/react-native');
+    const res = await datasource.getPkgReleases({
+      purl: 'pkg:npm/react-native',
+    });
     expect(res).toMatchSnapshot();
     expect(res.changelogUrl).toBeDefined();
     expect(res.sourceUrl).toBeDefined();
   });
   it('adds sourceUrl', async () => {
     npmDatasource.getPkgReleases.mockReturnValue({});
-    const res = await datasource.getPkgReleases('pkg:npm/node');
+    const res = await datasource.getPkgReleases({ purl: 'pkg:npm/node' });
     expect(res).toMatchSnapshot();
     expect(res.sourceUrl).toBeDefined();
   });
diff --git a/test/datasource/maven.spec.js b/test/datasource/maven.spec.js
index f98d4d6283..e37dfb8bb9 100644
--- a/test/datasource/maven.spec.js
+++ b/test/datasource/maven.spec.js
@@ -37,18 +37,20 @@ describe('datasource/maven', () => {
 
   describe('getPkgReleases', () => {
     it('should return empty if library is not found', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/unknown/unknown@1.0.5?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/unknown/unknown@1.0.5?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/',
+      });
       expect(releases).toBeNull();
     });
 
     it('should return all versions of a specific library', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/org.hamcrest/hamcrest-core@1.2?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/,file://test/_fixtures/gradle/maven/custom_maven_repo/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/org.hamcrest/hamcrest-core@1.2?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/,file://test/_fixtures/gradle/maven/custom_maven_repo/maven2/',
+      });
       expect(releases.releases).toEqual(
         generateReleases([
           '1.1',
@@ -63,28 +65,31 @@ describe('datasource/maven', () => {
     });
 
     it('should return versions in all repositories for a specific library', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/,file://test/_fixtures/gradle/maven/custom_maven_repo/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=file://test/_fixtures/gradle/maven/repo1.maven.org/maven2/,file://test/_fixtures/gradle/maven/custom_maven_repo/maven2/',
+      });
       expect(releases.releases).toEqual(
         generateReleases(['6.0.4', ...MYSQL_VERSIONS])
       );
     });
 
     it('should return all versions of a specific library for http repositories', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/',
+      });
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
     it('should return all versions of a specific library if a repository fails', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://failed_repo/,http://dns_error_repo',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://failed_repo/,http://dns_error_repo',
+      });
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
@@ -96,20 +101,22 @@ describe('datasource/maven', () => {
 
       expect.assertions(1);
       try {
-        await datasource.getPkgReleases(
-          'pkg:maven/org/artifact@6.0.5?repository_url=http://central.maven.org/maven2/',
-          config
-        );
+        await datasource.getPkgReleases({
+          ...config,
+          purl:
+            'pkg:maven/org/artifact@6.0.5?repository_url=http://central.maven.org/maven2/',
+        });
       } catch (e) {
         expect(e.message).toEqual('registry-failure');
       }
     });
 
     it('should return all versions of a specific library if a repository fails because invalid protocol', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://failed_repo/,ftp://protocol_error_repo',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://failed_repo/,ftp://protocol_error_repo',
+      });
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
@@ -122,15 +129,16 @@ describe('datasource/maven', () => {
           <versioning>
             <lastUpdated>20130301200000</lastUpdated>
           </versioning>
-        </metadata>      
+        </metadata>
       `;
       nock('http://invalid_metadata_repo')
         .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
         .reply(200, invalidMavenMetadata);
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://invalid_metadata_repo/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://invalid_metadata_repo/maven2/',
+      });
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
@@ -141,26 +149,28 @@ describe('datasource/maven', () => {
       nock('http://invalid_metadata_repo')
         .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
         .reply(200, invalidMavenMetadata);
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://invalid_metadata_repo/maven2/',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2/,http://invalid_metadata_repo/maven2/',
+      });
       expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
     });
 
     it('should return all versions of a specific library if a repository does not end with /', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        config,
+        purl:
+          'pkg:maven/mysql/mysql-connector-java@6.0.5?repository_url=http://central.maven.org/maven2',
+      });
       expect(releases).not.toBeNull();
     });
 
     it('should return null if no repositories defined', async () => {
-      const releases = await datasource.getPkgReleases(
-        'pkg:maven/mysql/mysql-connector-java@6.0.5',
-        config
-      );
+      const releases = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:maven/mysql/mysql-connector-java@6.0.5',
+      });
       expect(releases).toBeNull();
     });
   });
diff --git a/test/datasource/nuget.spec.js b/test/datasource/nuget.spec.js
index 6901f10c83..f947ebc4b4 100644
--- a/test/datasource/nuget.spec.js
+++ b/test/datasource/nuget.spec.js
@@ -14,7 +14,9 @@ describe('datasource/nuget', () => {
     });
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce({});
-      expect(await datasource.getPkgReleases('pkg:nuget/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:nuget/something' })
+      ).toBeNull();
     });
     it('returns null for 404', async () => {
       got.mockImplementationOnce(() =>
@@ -22,13 +24,17 @@ describe('datasource/nuget', () => {
           statusCode: 404,
         })
       );
-      expect(await datasource.getPkgReleases('pkg:nuget/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:nuget/something' })
+      ).toBeNull();
     });
     it('returns null for unknown error', async () => {
       got.mockImplementationOnce(() => {
         throw new Error();
       });
-      expect(await datasource.getPkgReleases('pkg:nuget/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:nuget/something' })
+      ).toBeNull();
     });
     it('processes real data', async () => {
       got.mockReturnValueOnce({
@@ -37,7 +43,7 @@ describe('datasource/nuget', () => {
       got.mockReturnValueOnce({
         body: res2,
       });
-      const res = await datasource.getPkgReleases('pkg:nuget/nunit');
+      const res = await datasource.getPkgReleases({ purl: 'pkg:nuget/nunit' });
       expect(res).not.toBeNull();
       expect(res).toMatchSnapshot();
       expect(res.sourceUrl).toBeDefined();
diff --git a/test/datasource/orb.spec.js b/test/datasource/orb.spec.js
index 1f4cd881b6..b03528afff 100644
--- a/test/datasource/orb.spec.js
+++ b/test/datasource/orb.spec.js
@@ -34,9 +34,9 @@ describe('datasource/orb', () => {
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce({ body: {} });
       expect(
-        await datasource.getPkgReleases(
-          'pkg:orb/hyper-expanse/library-release-workflows'
-        )
+        await datasource.getPkgReleases({
+          purl: 'pkg:orb/hyper-expanse/library-release-workflows',
+        })
       ).toBeNull();
     });
     it('returns null for 404', async () => {
@@ -46,9 +46,9 @@ describe('datasource/orb', () => {
         })
       );
       expect(
-        await datasource.getPkgReleases(
-          'pkg:orb/hyper-expanse/library-release-workflows'
-        )
+        await datasource.getPkgReleases({
+          purl: 'pkg:orb/hyper-expanse/library-release-workflows',
+        })
       ).toBeNull();
     });
     it('returns null for unknown error', async () => {
@@ -56,18 +56,18 @@ describe('datasource/orb', () => {
         throw new Error();
       });
       expect(
-        await datasource.getPkgReleases(
-          'pkg:orb/hyper-expanse/library-release-workflows'
-        )
+        await datasource.getPkgReleases({
+          purl: 'pkg:orb/hyper-expanse/library-release-workflows',
+        })
       ).toBeNull();
     });
     it('processes real data', async () => {
       got.post.mockReturnValueOnce({
         body: orbData,
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:orb/hyper-expanse/library-release-workflows'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:orb/hyper-expanse/library-release-workflows',
+      });
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
     });
@@ -76,9 +76,9 @@ describe('datasource/orb', () => {
       got.post.mockReturnValueOnce({
         body: orbData,
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:orb/hyper-expanse/library-release-workflows'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:orb/hyper-expanse/library-release-workflows',
+      });
       expect(res).toMatchSnapshot();
       expect(res.homepage).toEqual('https://google.com');
     });
diff --git a/test/datasource/packagist.spec.js b/test/datasource/packagist.spec.js
index 71cabe8bda..3741f98103 100644
--- a/test/datasource/packagist.spec.js
+++ b/test/datasource/packagist.spec.js
@@ -57,10 +57,10 @@ describe('datasource/packagist', () => {
           },
         ],
       };
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/something/one',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/something/one',
+      });
       expect(res).toBeNull();
     });
     it('supports plain packages', async () => {
@@ -77,10 +77,10 @@ describe('datasource/packagist', () => {
       got.mockReturnValueOnce({
         body: packagesOnly,
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/vendor/package-name',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/vendor/package-name',
+      });
       expect(res).toMatchSnapshot();
     });
     it('handles auth rejections', async () => {
@@ -89,10 +89,10 @@ describe('datasource/packagist', () => {
           statusCode: 401,
         })
       );
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/vendor/package-name',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/vendor/package-name',
+      });
       expect(res).toBeNull();
     });
     it('handles not found registries', async () => {
@@ -102,10 +102,10 @@ describe('datasource/packagist', () => {
           url: 'https://some.registry/packages.json',
         })
       );
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/drewm/mailchip-api',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/drewm/mailchip-api',
+      });
       expect(res).toBeNull();
     });
     it('supports includes packages', async () => {
@@ -127,10 +127,10 @@ describe('datasource/packagist', () => {
       got.mockReturnValueOnce({
         body: JSON.parse(includesJson),
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/guzzlehttp/guzzle',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/guzzlehttp/guzzle',
+      });
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
     });
@@ -166,10 +166,10 @@ describe('datasource/packagist', () => {
       got.mockReturnValueOnce({
         body: JSON.parse(beytJson),
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/wpackagist-plugin/1beyt',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/wpackagist-plugin/1beyt',
+      });
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
     });
@@ -205,10 +205,10 @@ describe('datasource/packagist', () => {
       got.mockReturnValueOnce({
         body: JSON.parse(beytJson),
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:packagist/some/other',
-        config
-      );
+      const res = await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:packagist/some/other',
+      });
       expect(res).toBeNull();
     });
     it('processes real versioned data', async () => {
@@ -217,10 +217,10 @@ describe('datasource/packagist', () => {
       });
       delete config.registryUrls;
       expect(
-        await datasource.getPkgReleases(
-          'pkg:packagist/drewm/mailchimp-api',
-          config
-        )
+        await datasource.getPkgReleases({
+          ...config,
+          purl: 'pkg:packagist/drewm/mailchimp-api',
+        })
       ).toMatchSnapshot();
     });
   });
diff --git a/test/datasource/pypi.spec.js b/test/datasource/pypi.spec.js
index deaa3af367..f0845caeb6 100644
--- a/test/datasource/pypi.spec.js
+++ b/test/datasource/pypi.spec.js
@@ -26,20 +26,24 @@ describe('datasource/pypi', () => {
     });
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce({});
-      expect(await datasource.getPkgReleases('pkg:pypi/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:pypi/something' })
+      ).toBeNull();
     });
     it('returns null for 404', async () => {
       got.mockImplementationOnce(() => {
         throw new Error();
       });
-      expect(await datasource.getPkgReleases('pkg:pypi/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:pypi/something' })
+      ).toBeNull();
     });
     it('processes real data', async () => {
       got.mockReturnValueOnce({
         body: JSON.parse(res1),
       });
       expect(
-        await datasource.getPkgReleases('pkg:pypi/azure-cli-monitor')
+        await datasource.getPkgReleases({ purl: 'pkg:pypi/azure-cli-monitor' })
       ).toMatchSnapshot();
     });
     it('supports custom datasource url', async () => {
@@ -49,7 +53,10 @@ describe('datasource/pypi', () => {
       const config = {
         registryUrls: ['https://custom.pypi.net/foo'],
       };
-      await datasource.getPkgReleases('pkg:pypi/azure-cli-monitor', config);
+      await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:pypi/azure-cli-monitor',
+      });
       expect(got.mock.calls).toMatchSnapshot();
     });
     it('supports custom datasource url from environmental variable', async () => {
@@ -58,7 +65,7 @@ describe('datasource/pypi', () => {
       });
       const pipIndexUrl = process.env.PIP_INDEX_URL;
       process.env.PIP_INDEX_URL = 'https://my.pypi.python/pypi/';
-      await datasource.getPkgReleases('pkg:pypi/azure-cli-monitor');
+      await datasource.getPkgReleases({ purl: 'pkg:pypi/azure-cli-monitor' });
       expect(got.mock.calls).toMatchSnapshot();
       process.env.PIP_INDEX_URL = pipIndexUrl;
     });
@@ -75,7 +82,10 @@ describe('datasource/pypi', () => {
           'https://third-index/foo',
         ],
       };
-      await datasource.getPkgReleases('pkg:pypi/azure-cli-monitor', config);
+      await datasource.getPkgReleases({
+        ...config,
+        purl: 'pkg:pypi/azure-cli-monitor',
+      });
       expect(got.mock.calls).toMatchSnapshot();
     });
     it('returns non-github home_page', async () => {
@@ -88,7 +98,7 @@ describe('datasource/pypi', () => {
         },
       });
       expect(
-        await datasource.getPkgReleases('pkg:pypi/something')
+        await datasource.getPkgReleases({ purl: 'pkg:pypi/something' })
       ).toMatchSnapshot();
     });
     it('returns null if mismatched name', async () => {
@@ -100,7 +110,9 @@ describe('datasource/pypi', () => {
           },
         },
       });
-      expect(await datasource.getPkgReleases('pkg:pypi/something')).toBeNull();
+      expect(
+        await datasource.getPkgReleases({ purl: 'pkg:pypi/something' })
+      ).toBeNull();
     });
 
     it('respects compatibility', async () => {
@@ -121,8 +133,9 @@ describe('datasource/pypi', () => {
         },
       });
       expect(
-        await datasource.getPkgReleases('pkg:pypi/doit', {
+        await datasource.getPkgReleases({
           compatibility: { python: '2.7' },
+          purl: 'pkg:pypi/doit',
         })
       ).toMatchSnapshot();
     });
diff --git a/test/datasource/terraform.spec.js b/test/datasource/terraform.spec.js
index e622f5eb64..fb145193fa 100644
--- a/test/datasource/terraform.spec.js
+++ b/test/datasource/terraform.spec.js
@@ -18,7 +18,9 @@ describe('datasource/terraform', () => {
     it('returns null for empty result', async () => {
       got.mockReturnValueOnce({ body: {} });
       expect(
-        await datasource.getPkgReleases('pkg:terraform/hashicorp/consul/aws')
+        await datasource.getPkgReleases({
+          purl: 'pkg:terraform/hashicorp/consul/aws',
+        })
       ).toBeNull();
     });
     it('returns null for 404', async () => {
@@ -28,7 +30,9 @@ describe('datasource/terraform', () => {
         })
       );
       expect(
-        await datasource.getPkgReleases('pkg:terraform/hashicorp/consul/aws')
+        await datasource.getPkgReleases({
+          purl: 'pkg:terraform/hashicorp/consul/aws',
+        })
       ).toBeNull();
     });
     it('returns null for unknown error', async () => {
@@ -36,16 +40,18 @@ describe('datasource/terraform', () => {
         throw new Error();
       });
       expect(
-        await datasource.getPkgReleases('pkg:terraform/hashicorp/consul/aws')
+        await datasource.getPkgReleases({
+          purl: 'pkg:terraform/hashicorp/consul/aws',
+        })
       ).toBeNull();
     });
     it('processes real data', async () => {
       got.mockReturnValueOnce({
         body: JSON.parse(consulData),
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:terraform/hashicorp/consul/aws'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:terraform/hashicorp/consul/aws',
+      });
       expect(res).toMatchSnapshot();
       expect(res).not.toBeNull();
     });
@@ -53,9 +59,9 @@ describe('datasource/terraform', () => {
       got.mockReturnValueOnce({
         body: JSON.parse(consulData),
       });
-      const res = await datasource.getPkgReleases(
-        'pkg:terraform/consul/foo?registry=hashicorp'
-      );
+      const res = await datasource.getPkgReleases({
+        purl: 'pkg:terraform/consul/foo?registry=hashicorp',
+      });
       expect(res).toBeNull();
     });
   });
-- 
GitLab