From 95e2edbb6f5ebabcf82365c2ddb0a62ee926e3c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Dahlgren?= <bjorn@dahlgren.at>
Date: Mon, 17 Feb 2020 09:15:55 +0100
Subject: [PATCH] =?UTF-8?q?feat(gradle):=20support=20version=20variables?=
 =?UTF-8?q?=20inside=20groovy=20map=20objec=E2=80=A6=20(#5491)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/manager/gradle/build-gradle.spec.ts | 45 +++++++++++++++++++++++++
 lib/manager/gradle/build-gradle.ts      | 38 +++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/lib/manager/gradle/build-gradle.spec.ts b/lib/manager/gradle/build-gradle.spec.ts
index 802ca2e75d..a8d0b3c5ff 100644
--- a/lib/manager/gradle/build-gradle.spec.ts
+++ b/lib/manager/gradle/build-gradle.spec.ts
@@ -514,6 +514,51 @@ describe('lib/manager/gradle/updateGradleVersion', () => {
     expect(updatedGradleFile).toEqual('String mysqlVersion = "7.0.0"');
   });
 
+  it('should replace a external groovy map variable assigned to a specific dependency', () => {
+    const gradleFile =
+      'runtime (  "mysql:mysql-connector-java:${versions.mysqlVersion}"  )'; // eslint-disable-line no-template-curly-in-string
+    const mysqlDependency = {
+      group: 'mysql',
+      depGroup: 'mysql',
+      name: 'mysql-connector-java',
+      version: '6.0.5',
+    };
+    collectVersionVariables([mysqlDependency], gradleFile);
+
+    const gradleWithVersionFile = 'ext.versions = [ mysqlVersion: "6.0.5" ]';
+    const updatedGradleFile = updateGradleVersion(
+      gradleWithVersionFile,
+      mysqlDependency,
+      '7.0.0'
+    );
+    expect(updatedGradleFile).toEqual(
+      'ext.versions = [ mysqlVersion: "7.0.0" ]'
+    );
+  });
+
+  it('should replace a external groovy map nested variable assigned to a specific dependency', () => {
+    const gradleFile =
+      'runtime (  "mysql:mysql-connector-java:${versions.nested.mysqlVersion}"  )'; // eslint-disable-line no-template-curly-in-string
+    const mysqlDependency = {
+      group: 'mysql',
+      depGroup: 'mysql',
+      name: 'mysql-connector-java',
+      version: '6.0.5',
+    };
+    collectVersionVariables([mysqlDependency], gradleFile);
+
+    const gradleWithVersionFile =
+      'ext.versions = [ nested: [ mysqlVersion: "6.0.5" ] ]';
+    const updatedGradleFile = updateGradleVersion(
+      gradleWithVersionFile,
+      mysqlDependency,
+      '7.0.0'
+    );
+    expect(updatedGradleFile).toEqual(
+      'ext.versions = [ nested: [ mysqlVersion: "7.0.0" ] ]'
+    );
+  });
+
   it('should replace a external property variable assigned to a specific dependency', () => {
     const gradleFile =
       'runtime (  "mysql:mysql-connector-java:${mysqlVersion}"  )'; // eslint-disable-line no-template-curly-in-string
diff --git a/lib/manager/gradle/build-gradle.ts b/lib/manager/gradle/build-gradle.ts
index def16a483b..a0eed71834 100644
--- a/lib/manager/gradle/build-gradle.ts
+++ b/lib/manager/gradle/build-gradle.ts
@@ -123,6 +123,13 @@ function variableDefinitionFormatMatch(variable: string): RegExp {
   return new RegExp(`(${variable}\\s*=\\s*?["'])(.*)(["'])`);
 }
 
+function variableMapDefinitionFormatMatch(
+  variable: string,
+  version: string
+): RegExp {
+  return new RegExp(`(${variable}\\s*:\\s*?["'])(${version})(["'])`);
+}
+
 export function collectVersionVariables(
   dependencies: BuildDependency[],
   buildGradleContent: string
@@ -214,6 +221,36 @@ function updateGlobalVariables(
   return null;
 }
 
+function updateGlobalMapVariables(
+  dependency: GradleDependency,
+  buildGradleContent: string,
+  newVersion: string
+): string | null {
+  let variable = variables[`${dependency.group}:${dependency.name}`];
+  if (variable) {
+    while (variable && variable.split('.').length > 0) {
+      const regex = variableMapDefinitionFormatMatch(
+        variable,
+        dependency.version
+      );
+      const match = regex.exec(buildGradleContent);
+      if (match) {
+        return buildGradleContent.replace(
+          variableMapDefinitionFormatMatch(variable, dependency.version),
+          `$1${newVersion}$3`
+        );
+      }
+
+      // Remove first path segment of variable and try again
+      variable = variable
+        .split('.')
+        .splice(1)
+        .join('.');
+    }
+  }
+  return null;
+}
+
 function updateKotlinVariablesByExtra(
   dependency: GradleDependency,
   buildGradleContent: string,
@@ -258,6 +295,7 @@ export function updateGradleVersion(
       updateVersionLiterals,
       updateLocalVariables,
       updateGlobalVariables,
+      updateGlobalMapVariables,
       updatePropertyFileGlobalVariables,
       updateKotlinVariablesByExtra,
     ];
-- 
GitLab