diff --git a/lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/mysql/mysql-connector-java/maven-metadata.xml b/lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/mysql/mysql-connector-java/maven-metadata.xml
deleted file mode 100644
index 38781a726fe7f8..00000000000000
--- a/lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/mysql/mysql-connector-java/maven-metadata.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
- mysql
- mysql-connector-java
- 6.0.5
-
-
- 6.0.5
- 6.0.4
-
- 20130301200000
-
-
diff --git a/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/5.13.0/realm-gradle-plugin-5.13.0.pom b/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/5.13.0/realm-gradle-plugin-5.13.0.pom
deleted file mode 100644
index 7cb22951e8a32e..00000000000000
--- a/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/5.13.0/realm-gradle-plugin-5.13.0.pom
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
- 4.0.0
- io.realm
- realm-gradle-plugin
- 5.13.0
-
-
- io.realm
- realm-transformer
- 5.13.0
- compile
-
-
- com.neenbedankt.gradle.plugins
- android-apt
- 1.8
- compile
-
-
- realm-gradle-plugin
- Gradle plugin for Realm. Realm is a mobile database: a replacement for SQLite & ORMs.
- http://realm.io
-
-
- The Apache Software License, Version 2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
-
-
- github
- https://github.com/realm/realm-java/issues
-
-
- scm:https://github.com/realm/realm-java
- scm:git@github.com:realm/realm-java.git
- scm:git@github.com:realm/realm-java.git
-
-
diff --git a/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/maven-metadata.xml b/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/maven-metadata.xml
deleted file mode 100644
index 514e83f8329c01..00000000000000
--- a/lib/datasource/maven/__fixtures__/jcenter/io/realm/realm-gradle-plugin/maven-metadata.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
- io.realm
- realm-gradle-plugin
- 5.13.0
-
- 5.13.0
- 5.13.0
-
- 0.85.0
- 0.85.1
- 0.86.0
- 0.86.1
- 0.87.0
- 0.87.1
- 0.87.2
- 0.87.3
- 0.87.4
- 0.87.5
- 0.88.0
- 0.88.1
- 0.88.2
- 0.88.3
- 0.89.0
- 0.89.1
- 0.90.0
- 0.90.1
- 0.91.0
- 0.91.1
- 1.0.0
- 1.0.1
- 1.1.0
- 1.1.1
- 1.2.0
- 2.0.0
- 2.0.1
- 2.0.2
- 2.1.0
- 2.1.1
- 2.2.0
- 2.2.1
- 2.2.2
- 2.3.0
- 2.3.1
- 2.3.2
- 3.0.0
- 3.1.0
- 3.1.1
- 3.1.2
- 3.1.3
- 3.1.4
- 3.2.0
- 3.2.1
- 3.3.0
- 3.3.1
- 3.3.2
- 3.4.0
- 3.5.0
- 3.6.0
- 3.7.0
- 3.7.1
- 3.7.2
- 4.0.0-RC1
- 4.0.0
- 4.1.0
- 4.1.1
- 4.2.0
- 4.3.0
- 4.3.1
- 4.3.2
- 4.3.3
- 4.3.4
- 4.4.0
- 5.0.0-BETA1
- 5.0.0
- 5.0.1
- 5.1.0
- 5.2.0
- 5.3.0
- 5.3.1
- 5.4.0
- 5.4.1
- 5.4.2
- 5.5.0
- 5.6.0
- 5.7.0
- 5.7.1
- 5.8.0-BETA1
- 5.8.0-BETA2
- 5.8.0
- 5.9.0
- 5.9.1
- 5.10.0
- 5.11.0
- 5.12.0
- 5.13.0
-
- 20190723221805
-
-
diff --git a/lib/datasource/maven/__fixtures__/metadata-extra.xml b/lib/datasource/maven/__fixtures__/metadata-extra.xml
new file mode 100644
index 00000000000000..d9607d4fda0847
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/metadata-extra.xml
@@ -0,0 +1,13 @@
+
+
+ org.example
+ package
+
+ 3.0.0
+ 3.0.0
+
+ 3.0.0
+
+ 20210101000000
+
+
diff --git a/lib/datasource/maven/__fixtures__/metadata-invalid.xml b/lib/datasource/maven/__fixtures__/metadata-invalid.xml
new file mode 100644
index 00000000000000..eb92a3c0ed6cfa
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/metadata-invalid.xml
@@ -0,0 +1,9 @@
+
+
+ org.example
+ package
+ 3.0.0-SNAPSHOT
+
+ 20210101010000
+
+
diff --git a/lib/datasource/maven/__fixtures__/metadata.xml b/lib/datasource/maven/__fixtures__/metadata.xml
new file mode 100644
index 00000000000000..a355205eb254e2
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/metadata.xml
@@ -0,0 +1,16 @@
+
+
+ org.example
+ package
+
+ 2.0.0
+ 2.0.0
+
+ 1.0.0
+ 1.0.1
+ 1.0.2
+ 2.0.0
+
+ 20210101000000
+
+
diff --git a/lib/datasource/maven/__fixtures__/pom.scm-prefix.xml b/lib/datasource/maven/__fixtures__/pom.scm-prefix.xml
new file mode 100644
index 00000000000000..d939ede245f393
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/pom.scm-prefix.xml
@@ -0,0 +1,18 @@
+
+
+
+ 4.0.0
+ org.example
+ package
+ Generic Package
+ Generic Maven Package
+
+ scm:https://github.com/example/test
+ scm:git@github.com:example/test.git
+ scm:git@github.com:example/test.git
+
+
diff --git a/lib/datasource/maven/__fixtures__/pom.xml b/lib/datasource/maven/__fixtures__/pom.xml
new file mode 100644
index 00000000000000..2183fc473fea9a
--- /dev/null
+++ b/lib/datasource/maven/__fixtures__/pom.xml
@@ -0,0 +1,14 @@
+
+
+
+ 4.0.0
+ org.example
+ package
+ Generic Package
+ Generic Maven Package
+ https://package.example.org/about
+
diff --git a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom b/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom
deleted file mode 100644
index 09e1cb25900e19..00000000000000
--- a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom
+++ /dev/null
@@ -1,38 +0,0 @@
-
- 4.0.0
- mysql
- mysql-connector-java
- 8.0.12
- jar
-
- MySQL Connector/J
- JDBC Type 4 driver for MySQL
-
-
-
- The GNU General Public License, v2 with FOSS exception
- repo
- For detailed license information see the LICENSE file in this distribution.
-
-
-
- http://dev.mysql.com/doc/connector-j/en/
-
-
- scm:git:git@github.com:mysql/mysql-connector-j.git
- https://github.com/mysql/mysql-connector-j
-
-
-
- Oracle Corporation
- http://www.oracle.com
-
-
-
-
- com.google.protobuf
- protobuf-java
- 2.6.0
-
-
-
diff --git a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/maven-metadata.xml b/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/maven-metadata.xml
deleted file mode 100644
index 4c3bd0fea3e1b6..00000000000000
--- a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/mysql/mysql-connector-java/maven-metadata.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
- mysql
- mysql-connector-java
- 8.0.12
-
-
- 8.0.12
- 8.0.11
- 8.0.9
- 8.0.8
- 8.0.7
- 6.0.6
- 6.0.5
-
- 20130301200000
-
-
diff --git a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/maven-metadata.xml b/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/maven-metadata.xml
deleted file mode 100644
index 027fecd11a88f3..00000000000000
--- a/lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/org/hamcrest/hamcrest-core/maven-metadata.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- org.hamcrest
- hamcrest-core
-
- 2.1-rc3
- 2.1-rc3
-
- 1.1
- 1.2
- 1.2.1
- 1.3.RC2
- 1.3
- 2.1-rc2
- 2.1-rc3
-
- 20181129182853
-
-
diff --git a/lib/datasource/maven/__snapshots__/index.spec.ts.snap b/lib/datasource/maven/__snapshots__/index.spec.ts.snap
index ddedb1b554257c..8906027ab35a76 100644
--- a/lib/datasource/maven/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/maven/__snapshots__/index.spec.ts.snap
@@ -1,186 +1,860 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`datasource/maven/index getReleases should return all versions from a custom repository 1`] = `
+exports[`datasource/maven/index collects releases from all registry urls 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/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/3.0.0/package-3.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/3.0.0/package-3.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index falls back to next registry url 1`] = `
Object {
- "display": "mysql:mysql-connector-java",
- "group": "mysql",
- "homepage": "http://dev.mysql.com/doc/connector-j/en/",
- "name": "mysql-connector-java",
- "registryUrl": "https://custom.registry.renovatebot.com",
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://repo.maven.apache.org/maven2",
"releases": Array [
Object {
- "version": "6.0.5",
+ "releaseTimestamp": "2020-01-01T01:00:00.000Z",
+ "version": "1.0.0",
},
Object {
- "version": "6.0.6",
+ "releaseTimestamp": "2020-01-01T02:00:00.000Z",
+ "version": "2.0.0",
},
- Object {
- "version": "8.0.7",
+ ],
+}
+`;
+
+exports[`datasource/maven/index falls back to next registry url 2`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "failed_repo",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://failed_repo/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "unauthorized_repo",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://unauthorized_repo/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "empty_repo",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://empty_repo/org/example/package/maven-metadata.xml",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "unknown_error",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://unknown_error/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": "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/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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 handles optional slash at the end of registry url 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/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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/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/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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 ignores unsupported protocols 1`] = `
+Array [
+ Object {
+ "releaseTimestamp": "2020-01-01T01:00:00.000Z",
+ "version": "1.0.0",
+ },
+ Object {
+ "releaseTimestamp": "2020-01-01T02:00:00.000Z",
+ "version": "2.0.0",
+ },
+]
+`;
+
+exports[`datasource/maven/index ignores unsupported protocols 2`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "http://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": "http://repo.maven.apache.org/maven2/org/example/package/1.0.0/package-1.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
},
+ "method": "HEAD",
+ "url": "http://repo.maven.apache.org/maven2/org/example/package/1.0.1/package-1.0.1.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "http://repo.maven.apache.org/maven2/org/example/package/1.0.2/package-1.0.2.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "repo.maven.apache.org",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "http://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": "http://repo.maven.apache.org/maven2/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+]
+`;
+
+exports[`datasource/maven/index removes authentication header after redirect 1`] = `
+Object {
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://frontend_for_private_s3_repository/maven2",
+ "releases": Array [
Object {
- "version": "8.0.8",
+ "version": "1.0.0",
},
Object {
- "version": "8.0.9",
+ "version": "1.0.1",
},
Object {
- "version": "8.0.11",
+ "version": "1.0.2",
},
Object {
- "version": "8.0.12",
+ "version": "2.0.0",
},
],
- "sourceUrl": "https://github.com/mysql/mysql-connector-j",
}
`;
-exports[`datasource/maven/index getReleases should return all versions of a specific library if a repository fails 1`] = `
+exports[`datasource/maven/index removes authentication header after redirect 2`] = `
Array [
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.650Z",
- "version": "6.0.5",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
+ "host": "frontend_for_private_s3_repository",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://frontend_for_private_s3_repository/maven2/org/example/package/maven-metadata.xml",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.660Z",
- "version": "6.0.6",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "private_s3_repository",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://private_s3_repository/maven2/org/example/package/maven-metadata.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.870Z",
- "version": "8.0.7",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=",
+ "host": "frontend_for_private_s3_repository",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://frontend_for_private_s3_repository/maven2/org/example/package/2.0.0/package-2.0.0.pom",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.880Z",
- "version": "8.0.8",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "private_s3_repository",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://private_s3_repository/maven2/org/example/package/2.0.0/package-2.0.0.pom?X-Amz-Algorithm=AWS4-HMAC-SHA256",
},
+]
+`;
+
+exports[`datasource/maven/index returns null when metadata is not found 1`] = `
+Array [
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.890Z",
- "version": "8.0.9",
+ "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",
},
]
`;
-exports[`datasource/maven/index getReleases should return all versions of a specific library if a repository fails because invalid metadata file is found in another repository 1`] = `
+exports[`datasource/maven/index returns releases 1`] = `
Object {
- "display": "mysql:mysql-connector-java",
- "group": "mysql",
- "name": "mysql-connector-java",
- "registryUrl": "https://repo.maven.apache.org/maven2/",
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://repo.maven.apache.org/maven2",
"releases": Array [
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.650Z",
- "version": "6.0.5",
+ "releaseTimestamp": "2020-01-01T01:00:00.000Z",
+ "version": "1.0.0",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.660Z",
- "version": "6.0.6",
+ "releaseTimestamp": "2020-01-01T02:00:00.000Z",
+ "version": "2.0.0",
},
- Object {
- "releaseTimestamp": "2020-01-01T00:00:00.870Z",
- "version": "8.0.7",
+ ],
+}
+`;
+
+exports[`datasource/maven/index returns releases 2`] = `
+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/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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 returns releases from custom repository 1`] = `
+Object {
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://custom.registry.renovatebot.com",
+ "releases": Array [
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.880Z",
- "version": "8.0.8",
+ "version": "1.0.0",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.890Z",
- "version": "8.0.9",
+ "version": "2.0.0",
},
],
}
`;
-exports[`datasource/maven/index getReleases should return all versions of a specific library if a repository fails because invalid protocol 1`] = `
+exports[`datasource/maven/index returns releases from custom repository 2`] = `
Array [
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.650Z",
- "version": "6.0.5",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/maven-metadata.xml",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.660Z",
- "version": "6.0.6",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/1.0.0/package-1.0.0.pom",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.870Z",
- "version": "8.0.7",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/1.0.1/package-1.0.1.pom",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.880Z",
- "version": "8.0.8",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/1.0.2/package-1.0.2.pom",
},
Object {
- "releaseTimestamp": "2020-01-01T00:00:00.890Z",
- "version": "8.0.9",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "HEAD",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/2.0.0/package-2.0.0.pom",
+ },
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "authorization": "Bearer abc123",
+ "host": "custom.registry.renovatebot.com",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://custom.registry.renovatebot.com/org/example/package/2.0.0/package-2.0.0.pom",
},
]
`;
-exports[`datasource/maven/index getReleases should return versions in all repositories for a specific library 1`] = `
+exports[`datasource/maven/index skips registry with invalid XML 1`] = `
Object {
- "display": "mysql:mysql-connector-java",
- "group": "mysql",
- "homepage": "http://dev.mysql.com/doc/connector-j/en/",
- "name": "mysql-connector-java",
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://repo.maven.apache.org/maven2",
"releases": Array [
Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/",
- "version": "6.0.4",
+ "releaseTimestamp": "2020-01-01T01:00:00.000Z",
+ "version": "1.0.0",
},
Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "6.0.5",
+ "releaseTimestamp": "2020-01-01T02:00:00.000Z",
+ "version": "2.0.0",
},
- Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "6.0.6",
+ ],
+}
+`;
+
+exports[`datasource/maven/index skips registry with invalid XML 2`] = `
+Array [
+ Object {
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "invalid_metadata_repo",
+ "user-agent": "https://github.com/renovatebot/renovate",
},
- Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "8.0.7",
+ "method": "GET",
+ "url": "https://invalid_metadata_repo/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",
},
- Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "8.0.8",
+ "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",
},
- Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "8.0.9",
+ "method": "HEAD",
+ "url": "https://repo.maven.apache.org/maven2/org/example/package/1.0.0/package-1.0.0.pom",
+ },
+ 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/1.0.1/package-1.0.1.pom",
+ },
+ 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/1.0.2/package-1.0.2.pom",
+ },
+ 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 skips registry with invalid metadata structure 1`] = `
+Object {
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "https://repo.maven.apache.org/maven2",
+ "releases": Array [
Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "8.0.11",
+ "releaseTimestamp": "2020-01-01T01:00:00.000Z",
+ "version": "1.0.0",
},
Object {
- "registryUrl": "file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/",
- "version": "8.0.12",
+ "releaseTimestamp": "2020-01-01T02:00:00.000Z",
+ "version": "2.0.0",
},
],
- "sourceUrl": "https://github.com/mysql/mysql-connector-j",
}
`;
-exports[`datasource/maven/index getReleases should simply return all versions of a specific library 1`] = `
+exports[`datasource/maven/index skips registry with invalid metadata structure 2`] = `
Array [
Object {
- "version": "1.1",
+ "headers": Object {
+ "accept-encoding": "gzip, deflate, br",
+ "host": "invalid_metadata_repo",
+ "user-agent": "https://github.com/renovatebot/renovate",
+ },
+ "method": "GET",
+ "url": "https://invalid_metadata_repo/org/example/package/maven-metadata.xml",
},
Object {
- "version": "1.2",
+ "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 {
- "version": "1.2.1",
+ "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/1.0.0/package-1.0.0.pom",
},
Object {
- "version": "1.3.RC2",
+ "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/1.0.1/package-1.0.1.pom",
},
Object {
- "version": "1.3",
+ "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/1.0.2/package-1.0.2.pom",
},
Object {
- "version": "2.1-rc2",
+ "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 {
- "version": "2.1-rc3",
+ "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 supports file protocol 1`] = `
+Object {
+ "display": "org.example:package",
+ "group": "org.example",
+ "homepage": "https://package.example.org/about",
+ "name": "package",
+ "registryUrl": "file:///bar",
+ "releases": Array [
+ Object {
+ "version": "1.0.0",
+ },
+ Object {
+ "version": "1.0.1",
+ },
+ Object {
+ "version": "1.0.2",
+ },
+ Object {
+ "version": "2.0.0",
+ },
+ ],
+}
+`;
+
+exports[`datasource/maven/index supports file protocol 2`] = `
+Array [
+ Array [
+ "/bar/org/example/package/maven-metadata.xml",
+ "utf8",
+ ],
+ Array [
+ "/bar/org/example/package/2.0.0/package-2.0.0.pom",
+ "utf8",
+ ],
+]
+`;
+
+exports[`datasource/maven/index throws EXTERNAL_HOST_ERROR for 50x 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",
},
]
`;
diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts
index 33f60510fadc7f..43bdf411619c3f 100644
--- a/lib/datasource/maven/index.spec.ts
+++ b/lib/datasource/maven/index.spec.ts
@@ -1,314 +1,321 @@
-import nock from 'nock';
-import { Release, getPkgReleases } from '..';
-import { getName, loadFixture } from '../../../test/util';
+import _fs from 'fs-extra';
+import { ReleaseResult, getPkgReleases } from '..';
+import * as httpMock from '../../../test/http-mock';
+import { getName, loadFixture, mocked } from '../../../test/util';
import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
import * as hostRules from '../../util/host-rules';
-import * as mavenVersioning from '../../versioning/maven';
+import { id as versioning } from '../../versioning/maven';
import { id as datasource } from '.';
-const MYSQL_VERSIONS = ['6.0.5', '6.0.6', '8.0.7', '8.0.8', '8.0.9'];
+jest.mock('fs-extra');
+const fs = mocked(_fs);
-const MYSQL_MAVEN_METADATA = loadFixture(
- 'repo1.maven.org/maven2/mysql/mysql-connector-java/maven-metadata.xml'
-);
+const baseUrl = 'https://repo.maven.apache.org/maven2';
+const baseUrlCustom = 'https://custom.registry.renovatebot.com';
-const MYSQL_MAVEN_MYSQL_POM = loadFixture(
- 'repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom'
-);
+interface MockOpts {
+ base?: string;
+ meta?: string;
+ pom?: string;
+ heads?: Record;
+}
+
+function mockGenericPackage(opts: MockOpts = {}) {
+ const {
+ base = baseUrl,
+ meta = loadFixture('metadata.xml'),
+ pom = loadFixture('pom.xml'),
+ heads = {
+ '1.0.0': 200,
+ '1.0.1': 404,
+ '1.0.2': 500,
+ '2.0.0': 200,
+ },
+ } = opts;
-const config = {
- versioning: mavenVersioning.id,
- datasource,
-};
+ const scope = httpMock.scope(base);
-function timestamp(version: string): string {
- const millis = (version.replace(/[^1-9]/g, '') + '000').slice(0, 3);
- return `2020-01-01T00:00:00.${millis}Z`;
+ scope.get('/org/example/package/maven-metadata.xml').reply(200, meta);
+
+ if (heads) {
+ const pairs = Object.entries(heads);
+ const latest = pairs
+ .filter(([, s]) => s >= 200 && s < 300)
+ .map(([v]) => v)
+ .sort()
+ .pop();
+ scope
+ .get(`/org/example/package/${latest}/package-${latest}.pom`)
+ .reply(200, pom);
+ pairs.forEach(([version, status]) => {
+ const [major, minor, patch] = version
+ .split('.')
+ .map((x) => parseInt(x, 10))
+ .map((x) => (x < 10 ? `0${x}` : `${x}`));
+ const timestamp = `2020-01-01T${major}:${minor}:${patch}.000Z`;
+ scope
+ .head(`/org/example/package/${version}/package-${version}.pom`)
+ .reply(status, '', { 'Last-Modified': timestamp });
+ });
+ }
}
-function generateReleases(versions: string[], ts = false): Release[] {
- return versions.map((version) => {
- if (ts) {
- const releaseTimestamp = timestamp(version);
- return { version, releaseTimestamp };
- }
- return { version };
- });
+function get(
+ depName: string,
+ ...registryUrls: string[]
+): Promise {
+ const conf = { versioning, datasource, depName };
+ return getPkgReleases(registryUrls ? { ...conf, registryUrls } : conf);
}
describe(getName(), () => {
beforeEach(() => {
- hostRules.add({
- hostType: datasource,
- hostName: 'frontend_for_private_s3_repository',
- username: 'username',
- password: 'password',
- timeout: 20000,
- });
hostRules.add({
hostType: datasource,
hostName: 'custom.registry.renovatebot.com',
token: 'abc123',
});
jest.resetAllMocks();
- nock.cleanAll();
- nock.disableNetConnect();
- nock('https://repo.maven.apache.org')
- .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(200, MYSQL_MAVEN_METADATA);
- nock('https://repo.maven.apache.org')
- .get(
- '/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom'
- )
- .reply(200, MYSQL_MAVEN_MYSQL_POM);
- nock('https://custom.registry.renovatebot.com')
- .get('/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(200, MYSQL_MAVEN_METADATA);
- nock('https://custom.registry.renovatebot.com')
- .get('/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom')
- .reply(200, MYSQL_MAVEN_MYSQL_POM);
- nock('http://failed_repo')
- .get('/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(404, null);
- nock('http://unauthorized_repo')
- .get('/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(403, null);
- nock('http://empty_repo')
- .get('/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(200, 'non-sense');
- nock('http://frontend_for_private_s3_repository')
- .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
- .basicAuth({ user: 'username', pass: 'password' })
- .reply(302, '', {
- Location:
- 'http://private_s3_repository/maven2/mysql/mysql-connector-java/maven-metadata.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256',
- })
- .get(
- '/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom'
- )
- .basicAuth({ user: 'username', pass: 'password' })
- .reply(302, '', {
- Location:
- 'http://private_s3_repository/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom?X-Amz-Algorithm=AWS4-HMAC-SHA256',
- });
- nock('http://private_s3_repository', { badheaders: ['authorization'] })
- .get(
- '/maven2/mysql/mysql-connector-java/maven-metadata.xml?X-Amz-Algorithm=AWS4-HMAC-SHA256'
- )
- .reply(200, MYSQL_MAVEN_METADATA)
- .get(
- '/maven2/mysql/mysql-connector-java/8.0.12/mysql-connector-java-8.0.12.pom?X-Amz-Algorithm=AWS4-HMAC-SHA256'
- )
- .reply(200, MYSQL_MAVEN_MYSQL_POM);
- Object.entries({
- '6.0.5': 200,
- '6.0.6': 200,
- '8.0.7': 200,
- '8.0.8': 200,
- '8.0.9': 200,
- '8.0.11': 404,
- '8.0.12': 500,
- }).forEach(([v, status]) => {
- const path = `/maven2/mysql/mysql-connector-java/${v}/mysql-connector-java-${v}.pom`;
- nock('https://repo.maven.apache.org')
- .head(path)
- .reply(status, '', { 'Last-Modified': timestamp(v) });
- nock('http://frontend_for_private_s3_repository')
- .head(path)
- .reply(status, '', { 'Last-Modified': timestamp(v) });
- });
+ httpMock.setup();
});
afterEach(() => {
- nock.enableNetConnect();
+ hostRules.clear();
+ httpMock.reset();
delete process.env.RENOVATE_EXPERIMENTAL_NO_MAVEN_POM_CHECK;
});
- describe('getReleases', () => {
- it('should return empty if library is not found', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'unknown:unknown',
- registryUrls: [
- 's3://somewhere.s3.aws.amazon.com',
- 'file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/',
- ],
- });
- expect(releases).toBeNull();
- });
+ it('returns null when metadata is not found', async () => {
+ httpMock
+ .scope(baseUrl)
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(404);
- it('should simply return all versions of a specific library', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'org.hamcrest:hamcrest-core',
- registryUrls: [
- 'file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/',
- 'file://lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/',
- 's3://somewhere.s3.aws.amazon.com',
- ],
- });
- expect(releases.releases).toMatchSnapshot();
- });
+ const res = await get('org.example:package');
- it('should return versions in all repositories for a specific library', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: [
- 'file://lib/datasource/maven/__fixtures__/repo1.maven.org/maven2/',
- 'file://lib/datasource/maven/__fixtures__/custom_maven_repo/maven2/',
- ],
- });
- expect(releases).toMatchSnapshot();
- });
+ expect(res).toBeNull();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
- it('should return all versions of a specific library for http repositories', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: ['https://repo.maven.apache.org/maven2/'],
- });
- expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS, true));
- });
+ it('returns releases', async () => {
+ mockGenericPackage();
- it('should return all versions from a custom repository', async () => {
- process.env.RENOVATE_EXPERIMENTAL_NO_MAVEN_POM_CHECK = 'true';
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: ['https://custom.registry.renovatebot.com'],
- });
- expect(releases).toMatchSnapshot();
- });
+ const res = await get('org.example:package');
- it('should return all versions of a specific library if a repository fails', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: [
- 'https://repo.maven.apache.org/maven2/',
- 'http://failed_repo/',
- 'http://unauthorized_repo/',
- 'http://dns_error_repo',
- 'http://empty_repo',
- ],
- });
- expect(releases.releases).toMatchSnapshot();
- });
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
- it('should throw external-host-error if default maven repo fails', async () => {
- nock('https://repo.maven.apache.org')
- .get('/maven2/org/artifact/maven-metadata.xml')
- .times(4)
- .reply(503);
-
- expect.assertions(1);
- await expect(
- getPkgReleases({
- ...config,
- depName: 'org:artifact',
- registryUrls: ['https://repo.maven.apache.org/maven2/'],
- })
- ).rejects.toThrow(EXTERNAL_HOST_ERROR);
- });
+ it('returns releases from custom repository', async () => {
+ mockGenericPackage({ base: baseUrlCustom });
- it('should return all versions of a specific library if a repository fails because invalid protocol', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: [
- 'https://repo.maven.apache.org/maven2/',
- 'http://failed_repo/',
- 'ftp://protocol_error_repo',
- ],
- });
- expect(releases.releases).toMatchSnapshot();
- });
+ const res = await get('org.example:package', baseUrlCustom);
- it('should return all versions of a specific library if a repository fails because invalid metadata file is found in another repository', async () => {
- const invalidMavenMetadata = `
-
- mysql
- mysql-connector-java
- 8.0.12
-
- 20130301200000
-
-
- `;
- nock('http://invalid_metadata_repo')
- .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(200, invalidMavenMetadata);
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: [
- 'https://repo.maven.apache.org/maven2/',
- 'http://invalid_metadata_repo/maven2/',
- ],
- });
- expect(releases).toMatchSnapshot();
- });
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
- it('should return all versions of a specific library if a repository fails because a metadata file is not xml', async () => {
- const invalidMavenMetadata = `
- Invalid XML
- `;
- nock('http://invalid_metadata_repo')
- .get('/maven2/mysql/mysql-connector-java/maven-metadata.xml')
- .reply(200, invalidMavenMetadata);
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: [
- 'https://repo.maven.apache.org/maven2/',
- 'http://invalid_metadata_repo/maven2/',
- ],
- });
- expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS, true));
+ it('collects releases from all registry urls', async () => {
+ mockGenericPackage();
+ mockGenericPackage({
+ base: baseUrlCustom,
+ meta: loadFixture('metadata-extra.xml'),
+ heads: { '3.0.0': 200 },
});
- it('should return all versions of a specific library if a repository does not end with /', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: ['https://repo.maven.apache.org/maven2'],
- });
- expect(releases).not.toBeNull();
- });
+ const { releases } = await get(
+ 'org.example:package',
+ baseUrl,
+ baseUrlCustom
+ );
- it('should return null if no repositories defined', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- });
- expect(releases).not.toBeNull();
- });
- it('should return null for invalid registryUrls', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- // eslint-disable-next-line no-template-curly-in-string
- registryUrls: ['${project.baseUri}../../repository/'],
- });
- expect(releases).toBeNull();
- });
- it('should support scm.url values prefixed with "scm:"', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'io.realm:realm-gradle-plugin',
- registryUrls: ['file://lib/datasource/maven/__fixtures__/jcenter/'],
- });
- expect(releases.sourceUrl).toEqual('https://github.com/realm/realm-java');
+ expect(releases).toMatchObject([
+ { version: '1.0.0' },
+ { version: '2.0.0' },
+ { version: '3.0.0' },
+ ]);
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('falls back to next registry url', async () => {
+ mockGenericPackage();
+ httpMock
+ .scope('https://failed_repo')
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(404, null);
+ httpMock
+ .scope('https://unauthorized_repo')
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(403, null);
+ httpMock
+ .scope('https://empty_repo')
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(200, 'non-sense');
+ httpMock
+ .scope('https://unknown_error')
+ .get('/org/example/package/maven-metadata.xml')
+ .replyWithError('unknown');
+
+ const res = await get(
+ 'org.example:package',
+ 'https://failed_repo/',
+ 'https://unauthorized_repo/',
+ 'https://empty_repo',
+ 'https://unknown_error',
+ baseUrl
+ );
+
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('throws EXTERNAL_HOST_ERROR for 50x', async () => {
+ httpMock
+ .scope(baseUrl)
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(503);
+
+ await expect(get('org.example:package')).rejects.toThrow(
+ EXTERNAL_HOST_ERROR
+ );
+
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('ignores unsupported protocols', async () => {
+ const base = baseUrl.replace('https', 'http');
+ mockGenericPackage({ base });
+
+ const { releases } = await get(
+ 'org.example:package',
+ 'ftp://protocol_error_repo',
+ 's3://protocol_error_repo',
+ base
+ );
+
+ expect(releases).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('skips registry with invalid metadata structure', async () => {
+ mockGenericPackage();
+ httpMock
+ .scope('https://invalid_metadata_repo')
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(200, loadFixture('metadata-invalid.xml'));
+
+ const res = await get(
+ 'org.example:package',
+ 'https://invalid_metadata_repo',
+ baseUrl
+ );
+
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('skips registry with invalid XML', async () => {
+ mockGenericPackage();
+ httpMock
+ .scope('https://invalid_metadata_repo')
+ .get('/org/example/package/maven-metadata.xml')
+ .reply(200, '###');
+
+ const res = await get(
+ 'org.example:package',
+ 'https://invalid_metadata_repo',
+ baseUrl
+ );
+
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('handles optional slash at the end of registry url', async () => {
+ mockGenericPackage();
+ const resA = await get('org.example:package', baseUrl.replace(/\/+$/, ''));
+ mockGenericPackage();
+ const resB = await get('org.example:package', baseUrl.replace(/\/*$/, '/'));
+ expect(resA).not.toBeNull();
+ expect(resB).not.toBeNull();
+ expect(resA.releases).toEqual(resB.releases);
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('returns null for invalid registryUrls', async () => {
+ const res = await get(
+ 'org.example:package',
+ // eslint-disable-next-line no-template-curly-in-string
+ '${project.baseUri}../../repository/'
+ );
+ expect(res).toBeNull();
+ });
+
+ it('supports scm.url values prefixed with "scm:"', async () => {
+ const pom = loadFixture('pom.scm-prefix.xml');
+ mockGenericPackage({ pom });
+
+ const { sourceUrl } = await get('org.example:package');
+
+ expect(sourceUrl).toEqual('https://github.com/example/test');
+ });
+
+ it('removes authentication header after redirect', async () => {
+ process.env.RENOVATE_EXPERIMENTAL_NO_MAVEN_POM_CHECK = 'true';
+
+ const frontendHost = 'frontend_for_private_s3_repository';
+ const frontendUrl = `https://${frontendHost}/maven2`;
+ const backendUrl = 'https://private_s3_repository/maven2';
+ const metadataPath = '/org/example/package/maven-metadata.xml';
+ const pomfilePath = '/org/example/package/2.0.0/package-2.0.0.pom';
+ const queryStr = '?X-Amz-Algorithm=AWS4-HMAC-SHA256';
+
+ hostRules.add({
+ hostType: datasource,
+ hostName: frontendHost,
+ username: 'username',
+ password: 'password',
+ timeout: 20000,
});
- it('should remove authentication header when redirected with authentication in query string', async () => {
- const releases = await getPkgReleases({
- ...config,
- depName: 'mysql:mysql-connector-java',
- registryUrls: ['http://frontend_for_private_s3_repository/maven2'],
+ httpMock
+ .scope(frontendUrl)
+ .get(metadataPath)
+ .basicAuth({ user: 'username', pass: 'password' })
+ .reply(302, '', {
+ Location: `${backendUrl}${metadataPath}${queryStr}`,
+ })
+ .get(pomfilePath)
+ .basicAuth({ user: 'username', pass: 'password' })
+ .reply(302, '', {
+ Location: `${backendUrl}${pomfilePath}${queryStr}`,
});
- expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS));
- });
+
+ httpMock
+ .scope(backendUrl, { badheaders: ['authorization'] })
+ .get(`${metadataPath}${queryStr}`)
+ .reply(200, loadFixture('metadata.xml'))
+ .get(`${pomfilePath}${queryStr}`)
+ .reply(200, loadFixture('pom.xml'));
+
+ const res = await get('org.example:package', frontendUrl);
+
+ expect(res).toMatchSnapshot();
+ expect(httpMock.getTrace()).toMatchSnapshot();
+ });
+
+ it('supports file protocol', async () => {
+ fs.exists.mockResolvedValueOnce(false);
+
+ fs.exists.mockResolvedValueOnce(true);
+ fs.readFile.mockResolvedValueOnce(Buffer.from(loadFixture('metadata.xml')));
+
+ fs.exists.mockResolvedValueOnce(true);
+ fs.readFile.mockResolvedValueOnce(Buffer.from(loadFixture('pom.xml')));
+
+ const res = await get('org.example:package', 'file:///foo', 'file:///bar');
+
+ expect(res).toMatchSnapshot();
+ expect(fs.readFile.mock.calls).toMatchSnapshot();
});
});
diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts
index 311c1041d4374d..464d2709fd31ac 100644
--- a/lib/datasource/maven/util.ts
+++ b/lib/datasource/maven/util.ts
@@ -189,6 +189,7 @@ export async function getDependencyInfo(
const pomUrl = getMavenUrl(dependency, repoUrl, path);
const { xml: pomContent } = await downloadMavenXml(pomUrl);
+ // istanbul ignore if
if (!pomContent) {
return result;
}