From 40ae43817a6713423a9e968296806614740bef01 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Tue, 27 Oct 2020 14:02:34 +0100
Subject: [PATCH] feat(github-releases): use prerelease metadata in filtering
 (#7567)

---
 lib/datasource/common.ts                      |  2 +-
 .../__snapshots__/index.spec.ts.snap          |  6 +++++
 lib/datasource/github-releases/index.spec.ts  | 10 +++++++-
 lib/datasource/github-releases/index.ts       | 14 +++++++----
 .../lookup/__snapshots__/index.spec.ts.snap   | 14 +++++++++++
 .../repository/process/lookup/filter.ts       |  5 ++++
 .../repository/process/lookup/index.spec.ts   | 23 +++++++++++++++++++
 7 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/lib/datasource/common.ts b/lib/datasource/common.ts
index 8e0749f8a8..b700022afb 100644
--- a/lib/datasource/common.ts
+++ b/lib/datasource/common.ts
@@ -44,7 +44,7 @@ export interface Release {
   downloadUrl?: string;
   gitRef?: string;
   isDeprecated?: boolean;
-
+  isStable?: boolean;
   releaseTimestamp?: any;
   version: string;
   newDigest?: string;
diff --git a/lib/datasource/github-releases/__snapshots__/index.spec.ts.snap b/lib/datasource/github-releases/__snapshots__/index.spec.ts.snap
index ed04de002e..d317b5d8d5 100644
--- a/lib/datasource/github-releases/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/github-releases/__snapshots__/index.spec.ts.snap
@@ -13,6 +13,12 @@ Object {
       "releaseTimestamp": "2020-03-09T10:00:00Z",
       "version": "v1.1.0",
     },
+    Object {
+      "gitRef": "2.0.0",
+      "isStable": false,
+      "releaseTimestamp": "2020-04-09T10:00:00Z",
+      "version": "2.0.0",
+    },
   ],
   "sourceUrl": "https://github.com/some/dep",
 }
diff --git a/lib/datasource/github-releases/index.spec.ts b/lib/datasource/github-releases/index.spec.ts
index dd5b230706..551950b6d7 100644
--- a/lib/datasource/github-releases/index.spec.ts
+++ b/lib/datasource/github-releases/index.spec.ts
@@ -31,6 +31,11 @@ describe('datasource/github-releases', () => {
           { tag_name: 'v', published_at: '2020-03-09T12:00:00Z' },
           { tag_name: '1.0.0', published_at: '2020-03-09T11:00:00Z' },
           { tag_name: 'v1.1.0', published_at: '2020-03-09T10:00:00Z' },
+          {
+            tag_name: '2.0.0',
+            published_at: '2020-04-09T10:00:00Z',
+            prerelease: true,
+          },
         ]);
 
       const res = await getPkgReleases({
@@ -38,10 +43,13 @@ describe('datasource/github-releases', () => {
         depName: 'some/dep',
       });
       expect(res).toMatchSnapshot();
-      expect(res.releases).toHaveLength(2);
+      expect(res.releases).toHaveLength(3);
       expect(
         res.releases.find((release) => release.version === 'v1.1.0')
       ).toBeDefined();
+      expect(
+        res.releases.find((release) => release.version === '2.0.0').isStable
+      ).toBe(false);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
   });
diff --git a/lib/datasource/github-releases/index.ts b/lib/datasource/github-releases/index.ts
index de2ecd435b..55893b7e4b 100644
--- a/lib/datasource/github-releases/index.ts
+++ b/lib/datasource/github-releases/index.ts
@@ -11,6 +11,7 @@ const http = new GithubHttp();
 type GithubRelease = {
   tag_name: string;
   published_at: string;
+  prerelease: boolean;
 };
 
 /**
@@ -43,11 +44,14 @@ export async function getReleases({
     sourceUrl: 'https://github.com/' + repo,
     releases: null,
   };
-  dependency.releases = githubReleases.map(({ tag_name, published_at }) => ({
-    version: tag_name,
-    gitRef: tag_name,
-    releaseTimestamp: published_at,
-  }));
+  dependency.releases = githubReleases.map(
+    ({ tag_name, published_at, prerelease }) => ({
+      version: tag_name,
+      gitRef: tag_name,
+      releaseTimestamp: published_at,
+      isStable: prerelease ? false : undefined,
+    })
+  );
   const cacheMinutes = 10;
   await packageCache.set(cacheNamespace, repo, dependency, cacheMinutes);
   return dependency;
diff --git a/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap b/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
index e464dfa1a6..09764e427d 100644
--- a/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
@@ -777,6 +777,20 @@ Array [
 ]
 `;
 
+exports[`workers/repository/process/lookup .lookupUpdates() should ignore unstable versions from datasource 1`] = `
+Array [
+  Object {
+    "fromVersion": "1.4.4",
+    "isSingleVersion": true,
+    "newMajor": 2,
+    "newMinor": 0,
+    "newValue": "2.0.0",
+    "toVersion": "2.0.0",
+    "updateType": "major",
+  },
+]
+`;
+
 exports[`workers/repository/process/lookup .lookupUpdates() should jump unstable versions if followTag 1`] = `
 Array [
   Object {
diff --git a/lib/workers/repository/process/lookup/filter.ts b/lib/workers/repository/process/lookup/filter.ts
index 6fbaa7e9b8..af92486c3a 100644
--- a/lib/workers/repository/process/lookup/filter.ts
+++ b/lib/workers/repository/process/lookup/filter.ts
@@ -37,6 +37,11 @@ export function filterVersions(
     if (!versioning.isStable(version)) {
       return false;
     }
+    // Check if the datasource returned isStable = false
+    const release = releases.find((r) => r.version === version);
+    if (release?.isStable === false) {
+      return false;
+    }
     return true;
   }
   versioning = allVersioning.get(config.versioning);
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index a4829cf3ba..accb10cceb 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -12,6 +12,7 @@ import * as datasourceDocker from '../../../../datasource/docker';
 import { id as datasourceDockerId } from '../../../../datasource/docker';
 import * as datasourceGitSubmodules from '../../../../datasource/git-submodules';
 import { id as datasourceGitSubmodulesId } from '../../../../datasource/git-submodules';
+import * as datasourceGithubReleases from '../../../../datasource/github-releases';
 import { id as datasourceGithubTagsId } from '../../../../datasource/github-tags';
 import { id as datasourceNpmId } from '../../../../datasource/npm';
 import { id as datasourcePackagistId } from '../../../../datasource/packagist';
@@ -25,12 +26,14 @@ import * as lookup from '.';
 
 jest.mock('../../../../datasource/docker');
 jest.mock('../../../../datasource/git-submodules');
+jest.mock('../../../../datasource/github-releases');
 
 qJson.latestVersion = '1.4.1';
 
 const docker = mocked(datasourceDocker) as any;
 docker.defaultRegistryUrls = ['https://index.docker.io'];
 const gitSubmodules = mocked(datasourceGitSubmodules);
+const githubReleases = mocked(datasourceGithubReleases);
 
 let config: lookup.LookupUpdateConfig;
 
@@ -639,6 +642,26 @@ describe('workers/repository/process/lookup', () => {
       nock('https://registry.npmjs.org').get('/vue').reply(200, vueJson);
       expect((await lookup.lookupUpdates(config)).updates).toHaveLength(0);
     });
+    it('should ignore unstable versions from datasource', async () => {
+      config.currentValue = '1.4.4';
+      config.depName = 'some/action';
+      config.datasource = datasourceGithubReleases.id;
+      githubReleases.getReleases.mockResolvedValueOnce({
+        releases: [
+          {
+            version: '1.4.4',
+          },
+          {
+            version: '2.0.0',
+          },
+          {
+            version: '2.1.0',
+            isStable: false,
+          },
+        ],
+      });
+      expect((await lookup.lookupUpdates(config)).updates).toMatchSnapshot();
+    });
     it('should allow unstable versions if the ignoreUnstable=false', async () => {
       config.currentValue = '2.5.16';
       config.ignoreUnstable = false;
-- 
GitLab