From e59004325f01412e8f40c1ec5fe1c49fc928657b Mon Sep 17 00:00:00 2001
From: George Georgiev <ggeorgiev@netskope.com>
Date: Mon, 16 May 2022 20:21:33 -0700
Subject: [PATCH] feat(droneci): support for multiline string image dependency
 (#15578)

---
 .../manager/droneci/__fixtures__/.drone.yml   | 15 ++++++
 .../__snapshots__/extract.spec.ts.snap        | 23 ++++++++
 lib/modules/manager/droneci/extract.spec.ts   |  2 +-
 lib/modules/manager/droneci/extract.ts        | 52 ++++++++++++++-----
 4 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/lib/modules/manager/droneci/__fixtures__/.drone.yml b/lib/modules/manager/droneci/__fixtures__/.drone.yml
index 54bbe22147..13eb993c04 100644
--- a/lib/modules/manager/droneci/__fixtures__/.drone.yml
+++ b/lib/modules/manager/droneci/__fixtures__/.drone.yml
@@ -29,3 +29,18 @@ services:
     image: redis:alpine
     ports:
       - 6379
+
+  - name: node
+    image: "amd64/node:10.0.0\
+            @sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201"
+    commands:
+      - npm install
+      - npm test
+
+  - name: node
+    image: 'amd64/node\
+            :10.0.0\
+            @sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201'
+    commands:
+      - npm install
+      - npm test
diff --git a/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
index 91019979b1..8e549914e3 100644
--- a/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/droneci/__snapshots__/extract.spec.ts.snap
@@ -39,5 +39,28 @@ Array [
     "depType": "docker",
     "replaceString": "redis:alpine",
   },
+  Object {
+    "autoReplaceStringTemplate": "{{packageName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+    "currentDigest": "sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201",
+    "currentValue": "10.0.0",
+    "datasource": "docker",
+    "depName": "node",
+    "depType": "docker",
+    "packageName": "amd64/node",
+    "replaceString": "\\\"amd64/node:10.0.0\\\\
+            @sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201\\\"",
+  },
+  Object {
+    "autoReplaceStringTemplate": "{{packageName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+    "currentDigest": "sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201",
+    "currentValue": "10.0.0",
+    "datasource": "docker",
+    "depName": "node",
+    "depType": "docker",
+    "packageName": "amd64/node",
+    "replaceString": "'amd64/node\\\\
+            :10.0.0\\\\
+            @sha256:36adc17e9cceab32179d3314da9cb9c737ffb11f0de4e688f407ad6d9ca32201'",
+  },
 ]
 `;
diff --git a/lib/modules/manager/droneci/extract.spec.ts b/lib/modules/manager/droneci/extract.spec.ts
index 0399d853fd..ca309dc78d 100644
--- a/lib/modules/manager/droneci/extract.spec.ts
+++ b/lib/modules/manager/droneci/extract.spec.ts
@@ -11,7 +11,7 @@ describe('modules/manager/droneci/extract', () => {
     it('extracts multiple image lines', () => {
       const res = extractPackageFile(Fixtures.get('.drone.yml'));
       expect(res.deps).toMatchSnapshot();
-      expect(res.deps).toHaveLength(4);
+      expect(res.deps).toHaveLength(6);
     });
   });
 });
diff --git a/lib/modules/manager/droneci/extract.ts b/lib/modules/manager/droneci/extract.ts
index 1882cd2263..ff4bbfa905 100644
--- a/lib/modules/manager/droneci/extract.ts
+++ b/lib/modules/manager/droneci/extract.ts
@@ -9,20 +9,44 @@ export function extractPackageFile(content: string): PackageFile | null {
     const lines = content.split(newlineRegex);
     for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
       const line = lines[lineNumber];
-      const match = regEx(/^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
-      if (match) {
-        const currentFrom = match[1];
-        const dep = getDep(currentFrom);
-        logger.debug(
-          {
-            depName: dep.depName,
-            currentValue: dep.currentValue,
-            currentDigest: dep.currentDigest,
-          },
-          'DroneCI docker image'
-        );
-        dep.depType = 'docker';
-        deps.push(dep);
+
+      const first_line_match = regEx(/^\s* image:\s*(['"]([^\s'"]+)\\)$/).exec(
+        line
+      );
+      if (first_line_match) {
+        let currentFrom = first_line_match[2];
+        let replaceString = first_line_match[1];
+
+        for (let i = lineNumber + 1; i < lines.length; i += 1) {
+          const internal_line = lines[i];
+          const middle_line_match =
+            regEx(/^(\s*([^\s'"]+)\\)$/).exec(internal_line);
+          if (middle_line_match) {
+            currentFrom += middle_line_match[2];
+            replaceString += '\n' + middle_line_match[1];
+          } else {
+            const final_line_match = regEx(/^(\s*([^\s'"]+)['"])$/).exec(
+              internal_line
+            );
+            if (final_line_match) {
+              currentFrom += final_line_match[2];
+              replaceString += '\n' + final_line_match[1];
+
+              const dep = getDep(currentFrom);
+              dep.depType = 'docker';
+              dep.replaceString = replaceString;
+              deps.push(dep);
+            }
+            break;
+          }
+        }
+      } else {
+        const match = regEx(/^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
+        if (match) {
+          const dep = getDep(match[1]);
+          dep.depType = 'docker';
+          deps.push(dep);
+        }
       }
     }
   } catch (err) /* istanbul ignore next */ {
-- 
GitLab