From b0cc608045c1142bd68bff7fea8c3663d56d89df Mon Sep 17 00:00:00 2001
From: Timo Furrer <tuxtimo@gmail.com>
Date: Thu, 23 Sep 2021 16:43:17 +0200
Subject: [PATCH] Correctly support includes in gitlab-ci (#11839)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 .../__fixtures__/gitlab-ci.2.yaml             |  8 ++++++
 .../__fixtures__/gitlab-ci.3.yaml             |  5 ++++
 .../__snapshots__/extract.spec.ts.snap        | 11 ++++++++
 lib/manager/gitlabci-include/extract.spec.ts  | 25 ++++++++++++++++---
 lib/manager/gitlabci-include/extract.ts       | 18 +++++++------
 5 files changed, 57 insertions(+), 10 deletions(-)
 create mode 100644 lib/manager/gitlabci-include/__fixtures__/gitlab-ci.2.yaml
 create mode 100644 lib/manager/gitlabci-include/__fixtures__/gitlab-ci.3.yaml

diff --git a/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.2.yaml b/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.2.yaml
new file mode 100644
index 0000000000..68fae1f6fb
--- /dev/null
+++ b/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.2.yaml
@@ -0,0 +1,8 @@
+include:
+  project: mikebryant/include-source-example
+  file: /template.yaml
+  ref: 1.0.0
+
+script:
+- !reference [.setup, script]
+- !reference [arbitrary job name with space and no starting dot, nested1, nested2, nested3]
diff --git a/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.3.yaml b/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.3.yaml
new file mode 100644
index 0000000000..2264c9878d
--- /dev/null
+++ b/lib/manager/gitlabci-include/__fixtures__/gitlab-ci.3.yaml
@@ -0,0 +1,5 @@
+include:
+
+script:
+- !reference [.setup, script]
+- !reference [arbitrary job name with space and no starting dot, nested1, nested2, nested3]
diff --git a/lib/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap b/lib/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
index defb083287..d740078fce 100644
--- a/lib/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
+++ b/lib/manager/gitlabci-include/__snapshots__/extract.spec.ts.snap
@@ -22,3 +22,14 @@ Array [
   },
 ]
 `;
+
+exports[`manager/gitlabci-include/extract extractPackageFile() extracts single include block 1`] = `
+Array [
+  Object {
+    "currentValue": "1.0.0",
+    "datasource": "gitlab-tags",
+    "depName": "mikebryant/include-source-example",
+    "depType": "repository",
+  },
+]
+`;
diff --git a/lib/manager/gitlabci-include/extract.spec.ts b/lib/manager/gitlabci-include/extract.spec.ts
index e57a302d12..c7729dd9e8 100644
--- a/lib/manager/gitlabci-include/extract.spec.ts
+++ b/lib/manager/gitlabci-include/extract.spec.ts
@@ -1,7 +1,9 @@
 import { loadFixture } from '../../../test/util';
 import { extractPackageFile } from './extract';
 
-const yamlFile = loadFixture('gitlab-ci.1.yaml');
+const yamlFileMultiConfig = loadFixture('gitlab-ci.1.yaml');
+const yamlFileSingleConfig = loadFixture('gitlab-ci.2.yaml');
+const yamlWithEmptyIncludeConfig = loadFixture('gitlab-ci.3.yaml');
 
 describe('manager/gitlabci-include/extract', () => {
   describe('extractPackageFile()', () => {
@@ -10,8 +12,25 @@ describe('manager/gitlabci-include/extract', () => {
         extractPackageFile('nothing here', '.gitlab-ci.yml', {})
       ).toBeNull();
     });
+    it('returns null for include block without any actual includes', () => {
+      const res = extractPackageFile(
+        yamlWithEmptyIncludeConfig,
+        '.gitlab-ci.yml',
+        {}
+      );
+      expect(res).toBeNull();
+    });
+    it('extracts single include block', () => {
+      const res = extractPackageFile(
+        yamlFileSingleConfig,
+        '.gitlab-ci.yml',
+        {}
+      );
+      expect(res.deps).toMatchSnapshot();
+      expect(res.deps).toHaveLength(1);
+    });
     it('extracts multiple include blocks', () => {
-      const res = extractPackageFile(yamlFile, '.gitlab-ci.yml', {});
+      const res = extractPackageFile(yamlFileMultiConfig, '.gitlab-ci.yml', {});
       expect(res.deps).toMatchSnapshot();
       expect(res.deps).toHaveLength(3);
     });
@@ -22,7 +41,7 @@ describe('manager/gitlabci-include/extract', () => {
       ];
 
       for (const endpoint of endpoints) {
-        const res = extractPackageFile(yamlFile, '.gitlab-ci.yml', {
+        const res = extractPackageFile(yamlFileMultiConfig, '.gitlab-ci.yml', {
           endpoint,
         });
         expect(res.deps[0].registryUrls[0]).toEqual('http://gitlab.test');
diff --git a/lib/manager/gitlabci-include/extract.ts b/lib/manager/gitlabci-include/extract.ts
index ff1484b988..efdf7f3274 100644
--- a/lib/manager/gitlabci-include/extract.ts
+++ b/lib/manager/gitlabci-include/extract.ts
@@ -35,15 +35,19 @@ export function extractPackageFile(
     const doc: any = load(replaceReferenceTags(content), {
       json: true,
     });
+    let includes;
     if (doc?.include && is.array(doc.include)) {
-      for (const includeObj of doc.include) {
-        if (includeObj.file && includeObj.project) {
-          const dep = extractDepFromIncludeFile(includeObj);
-          if (config.endpoint) {
-            dep.registryUrls = [config.endpoint.replace(/\/api\/v4\/?/, '')];
-          }
-          deps.push(dep);
+      includes = doc.include;
+    } else {
+      includes = [doc.include];
+    }
+    for (const includeObj of includes) {
+      if (includeObj.file && includeObj.project) {
+        const dep = extractDepFromIncludeFile(includeObj);
+        if (config.endpoint) {
+          dep.registryUrls = [config.endpoint.replace(/\/api\/v4\/?/, '')];
         }
+        deps.push(dep);
       }
     }
   } catch (err) /* istanbul ignore next */ {
-- 
GitLab