From 276ab91985a1571e14602374f3116972cd98eba9 Mon Sep 17 00:00:00 2001
From: Sergio Zharinov <zharinov@users.noreply.github.com>
Date: Thu, 22 Aug 2019 20:31:33 +0400
Subject: [PATCH] fix(maven): Use repository urls from parent POM files (#4311)

---
 lib/manager/maven/extract.ts                | 41 ++++++++++++++++-----
 test/manager/maven/_fixtures/parent.pom.xml |  8 ++++
 test/manager/maven/index.spec.ts            | 29 +++++++++++++--
 3 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/lib/manager/maven/extract.ts b/lib/manager/maven/extract.ts
index 9466289c38..7e23b16b2a 100644
--- a/lib/manager/maven/extract.ts
+++ b/lib/manager/maven/extract.ts
@@ -191,11 +191,12 @@ export function extractPackage(
   return result;
 }
 
-export function resolveProps(packages: PackageFile[]): PackageFile[] {
+export function resolveParents(packages: PackageFile[]): PackageFile[] {
   const packageFileNames: string[] = [];
   const extractedPackages: Record<string, PackageFile> = {};
   const extractedDeps: Record<string, PackageDependency[]> = {};
   const extractedProps: Record<string, MavenProp> = {};
+  const registryUrls: Record<string, Set<string>> = {};
   packages.forEach(pkg => {
     const name = pkg.packageFile;
     packageFileNames.push(name);
@@ -207,21 +208,42 @@ export function resolveProps(packages: PackageFile[]): PackageFile[] {
   // and merge them in reverse order,
   // which allows inheritance/overriding.
   packageFileNames.forEach(name => {
-    const hierarchy: Record<string, MavenProp>[] = [];
-    const alreadyExtracted: Record<string, boolean> = {};
+    registryUrls[name] = new Set();
+    const propsHierarchy: Record<string, MavenProp>[] = [];
+    const visitedPackages: Set<string> = new Set();
     let pkg = extractedPackages[name];
     while (pkg) {
-      hierarchy.unshift(pkg.mavenProps);
-      if (pkg.parent && !alreadyExtracted[pkg.parent]) {
-        alreadyExtracted[pkg.parent] = true;
+      propsHierarchy.unshift(pkg.mavenProps);
+
+      if (pkg.deps) {
+        pkg.deps.forEach(dep => {
+          if (dep.registryUrls) {
+            dep.registryUrls.forEach(url => {
+              registryUrls[name].add(url);
+            });
+          }
+        });
+      }
+
+      if (pkg.parent && !visitedPackages.has(pkg.parent)) {
+        visitedPackages.add(pkg.parent);
         pkg = extractedPackages[pkg.parent];
       } else {
         pkg = null;
       }
     }
-    hierarchy.unshift({});
+    propsHierarchy.unshift({});
     // @ts-ignore
-    extractedProps[name] = Object.assign.apply(null, hierarchy);
+    extractedProps[name] = Object.assign.apply(null, propsHierarchy);
+  });
+
+  // Resolve registryUrls
+  packageFileNames.forEach(name => {
+    const pkg = extractedPackages[name];
+    pkg.deps.forEach(rawDep => {
+      const urlsSet = new Set([...rawDep.registryUrls, ...registryUrls[name]]);
+      rawDep.registryUrls = [...urlsSet]; // eslint-disable-line no-param-reassign
+    });
   });
 
   // Resolve placeholders
@@ -270,6 +292,5 @@ export async function extractAllPackageFiles(
       logger.info({ packageFile }, 'packageFile has no content');
     }
   }
-
-  return cleanResult(resolveProps(packages));
+  return cleanResult(resolveParents(packages));
 }
diff --git a/test/manager/maven/_fixtures/parent.pom.xml b/test/manager/maven/_fixtures/parent.pom.xml
index aea9626f8e..4ec10243fa 100644
--- a/test/manager/maven/_fixtures/parent.pom.xml
+++ b/test/manager/maven/_fixtures/parent.pom.xml
@@ -19,4 +19,12 @@
     </quuxVersion>
     <repoUrl>http://example.com/</repoUrl>
   </properties>
+
+  <repositories>
+    <repository>
+      <id>xyz</id>
+      <name>xyz</name>
+      <url>http://example.com/nexus/xyz</url>
+    </repository>
+  </repositories>
 </project>
diff --git a/test/manager/maven/index.spec.ts b/test/manager/maven/index.spec.ts
index 1f43c9c35f..64f862e739 100644
--- a/test/manager/maven/index.spec.ts
+++ b/test/manager/maven/index.spec.ts
@@ -1,7 +1,7 @@
 import { readFileSync } from 'fs';
 import {
   extractPackage,
-  resolveProps,
+  resolveParents,
 } from '../../../lib/manager/maven/extract';
 import {
   extractAllPackageFiles,
@@ -77,7 +77,7 @@ describe('manager/maven', () => {
         depName === 'org.example:quux';
       const newValue = '9.9.9.9-final';
 
-      const packages = resolveProps([
+      const packages = resolveParents([
         extractPackage(pomParent, 'parent.pom.xml'),
         extractPackage(pomChild, 'child.pom.xml'),
       ]);
@@ -85,16 +85,37 @@ describe('manager/maven', () => {
       const dep = deps.find(finder);
       const upgrade = { ...dep, newValue };
       const updatedContent = updateDependency(pomParent, upgrade);
-      const [updatedPkg] = resolveProps([
+      const [updatedPkg] = resolveParents([
         extractPackage(updatedContent, 'parent.pom.xml'),
         extractPackage(pomChild, 'child.pom.xml'),
       ]);
       const updatedDep = updatedPkg.deps.find(finder);
 
-      expect(updatedDep.registryUrls.pop()).toEqual('http://example.com/');
+      expect(updatedDep.registryUrls).toContain('http://example.com/');
       expect(updatedDep.currentValue).toEqual(newValue);
     });
 
+    it('should include registryUrls from parent pom files', async () => {
+      platform.getFile
+        .mockReturnValueOnce(pomParent)
+        .mockReturnValueOnce(pomChild);
+      const packages = await extractAllPackageFiles({}, [
+        'parent.pom.xml',
+        'child.pom.xml',
+      ]);
+      const urls = new Set([
+        'https://repo.maven.apache.org/maven2',
+        'http://example.com/',
+        'http://example.com/nexus/xyz',
+      ]);
+      packages.forEach(({ deps }) => {
+        deps.forEach(({ registryUrls }) => {
+          const depUrls = new Set([...registryUrls]);
+          expect(depUrls).toEqual(urls);
+        });
+      });
+    });
+
     it('should not touch content if new and old versions are equal', () => {
       const newValue = '1.2.3';
 
-- 
GitLab