From c9e147fcbabadaeb0f28e43b817978c34006d176 Mon Sep 17 00:00:00 2001
From: Alex Kvak <metalalisa@gmail.com>
Date: Thu, 25 Mar 2021 14:20:49 +0300
Subject: [PATCH] fix(gitlab): skipped jobs are ignored (#9247)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

If GitLab pipeline has only skipped jobs — the result is yellow.
Otherwise standard rules are applied.
---
 .../gitlab/__snapshots__/index.spec.ts.snap   | 107 +++++++++++++++---
 lib/platform/gitlab/index.spec.ts             |  33 ++++++
 lib/platform/gitlab/index.ts                  |  18 ++-
 3 files changed, 141 insertions(+), 17 deletions(-)

diff --git a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
index 2e6a2fd131..abe2b8d2ab 100644
--- a/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/gitlab/__snapshots__/index.spec.ts.snap
@@ -1238,6 +1238,33 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) returns failure if any mandatory jobs fails and one job is skipped 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses",
+  },
+]
+`;
+
 exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) returns pending if no results 1`] = `
 Array [
   Object {
@@ -1319,6 +1346,33 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) returns success if job is skipped 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses",
+  },
+]
+`;
+
 exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) returns success if optional jobs fail 1`] = `
 Array [
   Object {
@@ -1346,6 +1400,33 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) returns yellow if there are no jobs expect skipped 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "Bearer abc123",
+      "host": "gitlab.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses",
+  },
+]
+`;
+
 exports[`platform/gitlab getBranchStatus(branchName, requiredStatusChecks) throws repository-changed 1`] = `
 Array [
   Object {
@@ -1714,19 +1795,6 @@ Array [
 ]
 `;
 
-exports[`platform/gitlab massageMarkdown(input) returns updated pr body 1`] = `
-"https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5
-
-  Merge Requests are the best, here are some MRs.
-
-  ## Open
-
-These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
-
- - [ ] <!-- rebase-branch=renovate/major-got-packages -->[build(deps): update got packages (major)](!2433) (\`gh-got\`, \`gl-got\`, \`got\`)
-"
-`;
-
 exports[`platform/gitlab getRepoForceRebase should return false 1`] = `
 Array [
   Object {
@@ -2026,6 +2094,19 @@ Array [
 ]
 `;
 
+exports[`platform/gitlab massageMarkdown(input) returns updated pr body 1`] = `
+"https://github.com/foo/bar/issues/5 plus also [a link](https://github.com/foo/bar/issues/5
+
+  Merge Requests are the best, here are some MRs.
+
+  ## Open
+
+These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
+
+ - [ ] <!-- rebase-branch=renovate/major-got-packages -->[build(deps): update got packages (major)](!2433) (\`gh-got\`, \`gl-got\`, \`got\`)
+"
+`;
+
 exports[`platform/gitlab mergePr(pr) merges the PR 1`] = `
 Array [
   Object {
diff --git a/lib/platform/gitlab/index.spec.ts b/lib/platform/gitlab/index.spec.ts
index 0755bbd7d4..3dbfc68527 100644
--- a/lib/platform/gitlab/index.spec.ts
+++ b/lib/platform/gitlab/index.spec.ts
@@ -488,6 +488,39 @@ describe('platform/gitlab', () => {
       expect(res).toEqual(BranchStatus.green);
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+    it('returns success if job is skipped', async () => {
+      const scope = await initRepo();
+      scope
+        .get(
+          '/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses'
+        )
+        .reply(200, [{ status: 'success' }, { status: 'skipped' }]);
+      const res = await gitlab.getBranchStatus('somebranch', []);
+      expect(res).toEqual(BranchStatus.green);
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+    it('returns yellow if there are no jobs expect skipped', async () => {
+      const scope = await initRepo();
+      scope
+        .get(
+          '/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses'
+        )
+        .reply(200, [{ status: 'skipped' }]);
+      const res = await gitlab.getBranchStatus('somebranch', []);
+      expect(res).toEqual(BranchStatus.yellow);
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
+    it('returns failure if any mandatory jobs fails and one job is skipped', async () => {
+      const scope = await initRepo();
+      scope
+        .get(
+          '/api/v4/projects/some%2Frepo/repository/commits/0d9c7726c3d628b7e28af234595cfd20febdbf8e/statuses'
+        )
+        .reply(200, [{ status: 'skipped' }, { status: 'failed' }]);
+      const res = await gitlab.getBranchStatus('somebranch', []);
+      expect(res).toEqual(BranchStatus.red);
+      expect(httpMock.getTrace()).toMatchSnapshot();
+    });
     it('returns failure if any mandatory jobs fails', async () => {
       const scope = await initRepo();
       scope
diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts
index 642e7a2803..fbef4e7a0f 100755
--- a/lib/platform/gitlab/index.ts
+++ b/lib/platform/gitlab/index.ts
@@ -272,7 +272,15 @@ export function getRepoForceRebase(): Promise<boolean> {
   return Promise.resolve(config?.mergeMethod !== 'merge');
 }
 
-type BranchState = 'pending' | 'running' | 'success' | 'failed' | 'canceled';
+type BranchState =
+  | 'pending'
+  | 'created'
+  | 'running'
+  | 'manual'
+  | 'success'
+  | 'failed'
+  | 'canceled'
+  | 'skipped';
 
 interface GitlabBranchStatus {
   status: BranchState;
@@ -303,7 +311,7 @@ async function getStatus(
   }
 }
 
-const gitlabToRenovateStatusMapping: Record<string, BranchStatus> = {
+const gitlabToRenovateStatusMapping: Record<BranchState, BranchStatus> = {
   pending: BranchStatus.yellow,
   created: BranchStatus.yellow,
   manual: BranchStatus.yellow,
@@ -334,8 +342,10 @@ export async function getBranchStatus(
     throw new Error(REPOSITORY_CHANGED);
   }
 
-  const res = await getStatus(branchName);
-  logger.debug(`Got res with ${res.length} results`);
+  const branchStatuses = await getStatus(branchName);
+  logger.debug(`Got res with ${branchStatuses.length} results`);
+  // ignore all skipped jobs
+  const res = branchStatuses.filter((check) => check.status !== 'skipped');
   if (res.length === 0) {
     // Return 'pending' if we have no status checks
     return BranchStatus.yellow;
-- 
GitLab