diff --git a/lib/datasource/maven/__fixtures__/child-all-info/meta.xml b/lib/datasource/maven/__fixtures__/child-all-info/meta.xml
new file mode 100644
index 00000000000000..8927f14aa205f0
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-all-info/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-all-info
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-all-info/pom.xml b/lib/datasource/maven/__fixtures__/child-all-info/pom.xml
new file mode 100644
index 00000000000000..38a060ce1769f1
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-all-info/pom.xml
@@ -0,0 +1,12 @@
+
+
+ org.example
+ parent
+ 1.0.0
+
+
+
+ scm:git:http://www.github.com/child-scm/child
+
+ https://child-home.example.com
+
diff --git a/lib/datasource/maven/__fixtures__/child-empty/meta.xml b/lib/datasource/maven/__fixtures__/child-empty/meta.xml
new file mode 100644
index 00000000000000..efcaf6091919d5
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-empty/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-no-info
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-empty/pom.xml b/lib/datasource/maven/__fixtures__/child-empty/pom.xml
new file mode 100644
index 00000000000000..b3f546cac09a4e
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-empty/pom.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-no-info/meta.xml b/lib/datasource/maven/__fixtures__/child-no-info/meta.xml
new file mode 100644
index 00000000000000..efcaf6091919d5
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-no-info/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-no-info
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-no-info/pom.xml b/lib/datasource/maven/__fixtures__/child-no-info/pom.xml
new file mode 100644
index 00000000000000..1ec845afb44865
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-no-info/pom.xml
@@ -0,0 +1,7 @@
+
+
+ org.example
+ parent
+ 1.0.0
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-parent-cycle/child.meta.xml b/lib/datasource/maven/__fixtures__/child-parent-cycle/child.meta.xml
new file mode 100644
index 00000000000000..07848472aec2ec
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-parent-cycle/child.meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ package
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-parent-cycle/child.pom.xml b/lib/datasource/maven/__fixtures__/child-parent-cycle/child.pom.xml
new file mode 100644
index 00000000000000..6e3c7456bae805
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-parent-cycle/child.pom.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ org.example
+ parent
+ 2.0.0
+
+ org.example
+ child
+ Generic Package
+ Generic Maven Package
+
diff --git a/lib/datasource/maven/__fixtures__/child-parent-cycle/parent.pom.xml b/lib/datasource/maven/__fixtures__/child-parent-cycle/parent.pom.xml
new file mode 100644
index 00000000000000..2760a1dd818d77
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-parent-cycle/parent.pom.xml
@@ -0,0 +1,8 @@
+
+
+ org.example
+ child
+ 2.0.0
+
+ https://parent-home.example.com
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/meta.xml b/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/meta.xml
new file mode 100644
index 00000000000000..f42fe8589746f0
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-scm-gitatcolon
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/pom.xml b/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/pom.xml
new file mode 100644
index 00000000000000..7c3157b5c445bb
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitatcolon/pom.xml
@@ -0,0 +1,6 @@
+
+
+
+ git@github.com:child-scm/child
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitatslash/meta.xml b/lib/datasource/maven/__fixtures__/child-scm-gitatslash/meta.xml
new file mode 100644
index 00000000000000..07a2b3af129a9e
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitatslash/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-scm-gitatslash
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitatslash/pom.xml b/lib/datasource/maven/__fixtures__/child-scm-gitatslash/pom.xml
new file mode 100644
index 00000000000000..2ad57eaa1ffde2
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitatslash/pom.xml
@@ -0,0 +1,6 @@
+
+
+
+ git@github.com/child-scm/child
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/meta.xml b/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/meta.xml
new file mode 100644
index 00000000000000..1741d3965409af
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-scm-gitprotocol
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/pom.xml b/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/pom.xml
new file mode 100644
index 00000000000000..da09dda8a96e76
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm-gitprotocol/pom.xml
@@ -0,0 +1,6 @@
+
+
+
+ git://github.com/child-scm/child
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm/meta.xml b/lib/datasource/maven/__fixtures__/child-scm/meta.xml
new file mode 100644
index 00000000000000..c0f390f2aee0f1
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-scm
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-scm/pom.xml b/lib/datasource/maven/__fixtures__/child-scm/pom.xml
new file mode 100644
index 00000000000000..a6cf6fea3a0ff7
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-scm/pom.xml
@@ -0,0 +1,11 @@
+
+
+ org.example
+ parent
+ 1.0.0
+
+
+
+ scm:git:https://www.github.com/child-scm/child
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-url/meta.xml b/lib/datasource/maven/__fixtures__/child-url/meta.xml
new file mode 100644
index 00000000000000..3fd1398f527e5f
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-url/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ child-url
+ 2.0.0
+
+
+ 2.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/child-url/pom.xml b/lib/datasource/maven/__fixtures__/child-url/pom.xml
new file mode 100644
index 00000000000000..f153707958a38a
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/child-url/pom.xml
@@ -0,0 +1,8 @@
+
+
+ org.example
+ parent
+ 1.0.0
+
+ https://child-home.example.com
+
diff --git a/lib/datasource/maven/__fixtures__/parent-scm-homepage/meta.xml b/lib/datasource/maven/__fixtures__/parent-scm-homepage/meta.xml
new file mode 100644
index 00000000000000..2a44ff77578734
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/parent-scm-homepage/meta.xml
@@ -0,0 +1,11 @@
+
+ org.example
+ parent
+ 1.0.0
+
+
+ 1.0.0
+
+ 20130301200000
+
+
diff --git a/lib/datasource/maven/__fixtures__/parent-scm-homepage/pom.xml b/lib/datasource/maven/__fixtures__/parent-scm-homepage/pom.xml
new file mode 100644
index 00000000000000..18357e50fb1351
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/parent-scm-homepage/pom.xml
@@ -0,0 +1,7 @@
+
+
+
+ scm:git:git://www.github.com/parent-scm/parent
+
+ https://parent-home.example.com
+
diff --git a/lib/datasource/maven/__snapshots__/index.spec.ts.snap b/lib/datasource/maven/__snapshots__/index.spec.ts.snap
index aba4930ded3c49..f401e28a77d53d 100644
--- a/lib/datasource/maven/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/maven/__snapshots__/index.spec.ts.snap
@@ -204,6 +204,366 @@ Array [
]
`;
+exports[`datasource/maven/index fetching parent info should be able to detect git://@github.com/child-scm as valid sourceUrl 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should be able to detect git@github.com/child-scm as valid sourceUrl 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should be able to detect git@github.com:child-scm as valid sourceUrl 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should deal with circular hierarchy 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/child/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/child/2.0.0/child-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/child/2.0.0/child-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/2.0.0/parent-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/child/2.0.0/child-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/2.0.0/parent-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/child/2.0.0/child-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/2.0.0/parent-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should deal with missing parent fields 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should get homepage and source from own pom 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should get homepage from own pom and source from parent 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/1.0.0/parent-1.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should get source and homepage from parent 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/1.0.0/parent-1.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index fetching parent info should get source from own pom and homepage from parent 1`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://repo.maven.apache.org/maven2/org/example/parent/1.0.0/parent-1.0.0.pom",
+ },
+]
+`;
+
exports[`datasource/maven/index handles optional slash at the end of registry url 1`] = `
Array [
Object {
diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts
index 4c9c719fcbcee4..e610a5cc68d35d 100644
--- a/lib/datasource/maven/index.spec.ts
+++ b/lib/datasource/maven/index.spec.ts
@@ -305,4 +305,191 @@ describe(getName(), () => {
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
+
+ describe('fetching parent info', () => {
+ const parentPackage = {
+ dep: 'org.example:parent',
+ meta: null,
+ pom: loadFixture('parent-scm-homepage/pom.xml'),
+ latest: '1.0.0',
+ jars: null,
+ };
+
+ it('should get source and homepage from parent', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-no-info/meta.xml'),
+ pom: loadFixture('child-no-info/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+ mockGenericPackage(parentPackage);
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/parent-scm/parent',
+ homepage: 'https://parent-home.example.com',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should deal with missing parent fields', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-empty/meta.xml'),
+ pom: loadFixture('child-empty/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ display: 'org.example:package',
+ group: 'org.example',
+ name: 'package',
+ });
+ expect(res).not.toHaveProperty('homepage');
+ expect(res).not.toHaveProperty('sourceUrl');
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should deal with circular hierarchy', async () => {
+ const parentPom = loadFixture('child-parent-cycle/parent.pom.xml');
+ const parentPomMock = {
+ dep: 'org.example:parent',
+ meta: null,
+ pom: parentPom,
+ latest: '2.0.0',
+ jars: null,
+ };
+
+ const childMeta = loadFixture('child-parent-cycle/child.meta.xml');
+ const childPom = loadFixture('child-parent-cycle/child.pom.xml');
+ const childPomMock = {
+ dep: 'org.example:child',
+ meta: null,
+ pom: childPom,
+ latest: '2.0.0',
+ jars: null,
+ };
+
+ mockGenericPackage({
+ ...childPomMock,
+ meta: childMeta,
+ jars: { '2.0.0': 200 },
+ });
+ mockGenericPackage(parentPomMock);
+ mockGenericPackage(childPomMock);
+ mockGenericPackage(parentPomMock);
+ mockGenericPackage(childPomMock);
+ mockGenericPackage(parentPomMock);
+
+ const res = await get('org.example:child');
+
+ expect(res).toMatchObject({
+ homepage: 'https://parent-home.example.com',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should get source from own pom and homepage from parent', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-scm/meta.xml'),
+ pom: loadFixture('child-scm/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+ mockGenericPackage(parentPackage);
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/child-scm/child',
+ homepage: 'https://parent-home.example.com',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should get homepage from own pom and source from parent', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-url/meta.xml'),
+ pom: loadFixture('child-url/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+ mockGenericPackage(parentPackage);
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/parent-scm/parent',
+ homepage: 'https://child-home.example.com',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should get homepage and source from own pom', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-all-info/meta.xml'),
+ pom: loadFixture('child-all-info/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/child-scm/child',
+ homepage: 'https://child-home.example.com',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should be able to detect git@github.com:child-scm as valid sourceUrl', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-scm-gitatcolon/meta.xml'),
+ pom: loadFixture('child-scm-gitatcolon/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/child-scm/child',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('should be able to detect git@github.com/child-scm as valid sourceUrl', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-scm-gitatslash/meta.xml'),
+ pom: loadFixture('child-scm-gitatslash/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/child-scm/child',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+ it('should be able to detect git://@github.com/child-scm as valid sourceUrl', async () => {
+ mockGenericPackage({
+ meta: loadFixture('child-scm-gitprotocol/meta.xml'),
+ pom: loadFixture('child-scm-gitprotocol/pom.xml'),
+ latest: '2.0.0',
+ jars: { '2.0.0': 200 },
+ });
+
+ const res = await get();
+
+ expect(res).toMatchObject({
+ sourceUrl: 'https://github.com/child-scm/child',
+ });
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+ });
});
diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts
index ed7f7355ce4678..18316d73df55b2 100644
--- a/lib/datasource/maven/util.ts
+++ b/lib/datasource/maven/util.ts
@@ -163,10 +163,22 @@ export async function downloadMavenXml(
return { authorization, xml: new XmlDocument(rawContent) };
}
+export function getDependencyParts(lookupName: string): MavenDependency {
+ const [group, name] = lookupName.split(':');
+ const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`;
+ return {
+ display: lookupName,
+ group,
+ name,
+ dependencyUrl,
+ };
+}
+
export async function getDependencyInfo(
dependency: MavenDependency,
repoUrl: string,
- version: string
+ version: string,
+ recursionLimit = 5
): Promise> {
const result: Partial = {};
const path = `${version}/${dependency.name}-${version}.pom`;
@@ -185,19 +197,46 @@ export async function getDependencyInfo(
const sourceUrl = pomContent.valueWithPath('scm.url');
if (sourceUrl && !containsPlaceholder(sourceUrl)) {
- result.sourceUrl = sourceUrl.replace(/^scm:/, '');
+ result.sourceUrl = sourceUrl
+ .replace(/^scm:/, '')
+ .replace(/^git:/, '')
+ .replace(/^git@github.com:/, 'https://github.com/')
+ .replace(/^git@github.com\//, 'https://github.com/')
+ .replace(/\.git$/, '');
+
+ if (result.sourceUrl.startsWith('//')) {
+ // most likely the result of us stripping scm:, git: etc
+ // going with prepending https: here which should result in potential information retrival
+ result.sourceUrl = `https:${result.sourceUrl}`;
+ }
}
- return result;
-}
+ const parent = pomContent.childNamed('parent');
+ if (recursionLimit > 0 && parent && (!result.sourceUrl || !result.homepage)) {
+ // if we found a parent and are missing some information
+ // trying to get the scm/homepage information from it
+ const [parentGroupId, parentArtifactId, parentVersion] = [
+ 'groupId',
+ 'artifactId',
+ 'version',
+ ].map((k) => parent.valueWithPath(k)?.replace(/\s+/g, ''));
+ if (parentGroupId && parentArtifactId && parentVersion) {
+ const parentDisplayId = `${parentGroupId}:${parentArtifactId}`;
+ const parentDependency = getDependencyParts(parentDisplayId);
+ const parentInformation = await getDependencyInfo(
+ parentDependency,
+ repoUrl,
+ parentVersion,
+ recursionLimit - 1
+ );
+ if (!result.sourceUrl && parentInformation.sourceUrl) {
+ result.sourceUrl = parentInformation.sourceUrl;
+ }
+ if (!result.homepage && parentInformation.homepage) {
+ result.homepage = parentInformation.homepage;
+ }
+ }
+ }
-export function getDependencyParts(lookupName: string): MavenDependency {
- const [group, name] = lookupName.split(':');
- const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`;
- return {
- display: lookupName,
- group,
- name,
- dependencyUrl,
- };
+ return result;
}