diff --git a/lib/datasource/maven/__snapshots__/index.spec.ts.snap b/lib/datasource/maven/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..e094221364597c230eaa08c7151ee672381728e2 --- /dev/null +++ b/lib/datasource/maven/__snapshots__/index.spec.ts.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`datasource/maven getReleases should return all versions from a custom repository 1`] = ` +Object { + "display": "mysql:mysql-connector-java", + "group": "mysql", + "homepage": "http://dev.mysql.com/doc/connector-j/en/", + "name": "mysql-connector-java", + "releases": Array [ + Object { + "version": "6.0.5", + }, + Object { + "version": "6.0.6", + }, + Object { + "version": "8.0.7", + }, + Object { + "version": "8.0.8", + }, + Object { + "version": "8.0.9", + }, + Object { + "version": "8.0.11", + }, + Object { + "version": "8.0.12", + }, + ], + "sourceUrl": "https://github.com/mysql/mysql-connector-j", +} +`; diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts index b70f4a35a4f41970d6eb121c7310f85de48ee9f2..f0a7bdef19f21e9c56b3613c30e8d4bd5bb7bf2c 100644 --- a/lib/datasource/maven/index.spec.ts +++ b/lib/datasource/maven/index.spec.ts @@ -54,6 +54,11 @@ describe('datasource/maven', () => { password: 'password', timeout: 20000, }); + hostRules.add({ + hostType: datasource, + hostName: 'custom.registry.renovatebot.com', + token: 'abc123', + }); jest.resetAllMocks(); nock.cleanAll(); nock.disableNetConnect(); @@ -65,6 +70,12 @@ describe('datasource/maven', () => { '/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); @@ -119,6 +130,7 @@ describe('datasource/maven', () => { afterEach(() => { nock.enableNetConnect(); + delete process.env.RENOVATE_EXPERIMENTAL_NO_MAVEN_POM_CHECK; }); describe('getReleases', () => { @@ -180,6 +192,16 @@ describe('datasource/maven', () => { expect(releases.releases).toEqual(generateReleases(MYSQL_VERSIONS, true)); }); + 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(); + }); + it('should return all versions of a specific library if a repository fails', async () => { const releases = await getPkgReleases({ ...config, diff --git a/lib/datasource/maven/index.ts b/lib/datasource/maven/index.ts index bf76d3add64f681c2e0909cf09c69103da024c99..bf5775e0e6ad148d863c79f76822aded407d3f30 100644 --- a/lib/datasource/maven/index.ts +++ b/lib/datasource/maven/index.ts @@ -37,36 +37,44 @@ function getMavenUrl( return new url.URL(`${dependency.dependencyUrl}/${path}`, repoUrl); } +interface MavenXml { + authorization?: boolean; + xml?: XmlDocument; +} + async function downloadMavenXml( pkgUrl: url.URL | null -): Promise<XmlDocument | null> { +): Promise<MavenXml | null> { /* istanbul ignore if */ if (!pkgUrl) { - return null; + return {}; } let rawContent: string; + let authorization: boolean; switch (pkgUrl.protocol) { case 'file:': rawContent = await downloadFileProtocol(pkgUrl); break; case 'http:': case 'https:': - rawContent = await downloadHttpProtocol(pkgUrl); + ({ authorization, body: rawContent } = await downloadHttpProtocol( + pkgUrl + )); break; case 's3:': logger.debug('Skipping s3 dependency'); - return null; + return {}; default: logger.debug({ url: pkgUrl.toString() }, `Unsupported Maven protocol`); - return null; + return {}; } if (!rawContent) { logger.debug(`Content is not found for Maven url: ${pkgUrl.toString()}`); - return null; + return {}; } - return new XmlDocument(rawContent); + return { authorization, xml: new XmlDocument(rawContent) }; } async function getDependencyInfo( @@ -78,7 +86,7 @@ async function getDependencyInfo( const path = `${version}/${dependency.name}-${version}.pom`; const pomUrl = getMavenUrl(dependency, repoUrl, path); - const pomContent = await downloadMavenXml(pomUrl); + const { xml: pomContent } = await downloadMavenXml(pomUrl); if (!pomContent) { return result; } @@ -156,13 +164,17 @@ async function getVersionsFromMetadata( return cachedVersions; } - const mavenMetadata = await downloadMavenXml(metadataUrl); + const { authorization, xml: mavenMetadata } = await downloadMavenXml( + metadataUrl + ); if (!mavenMetadata) { return null; } const versions = extractVersions(mavenMetadata); - await packageCache.set(cacheNamespace, cacheKey, versions, 30); + if (!authorization) { + await packageCache.set(cacheNamespace, cacheKey, versions, 30); + } return versions; } diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts index 56a8be7fa89bde87a23a92a83ba952cde8306193..335634caac07496c80be1db1067e281277a4b763 100644 --- a/lib/datasource/maven/util.ts +++ b/lib/datasource/maven/util.ts @@ -2,7 +2,7 @@ import url from 'url'; import { HOST_DISABLED } from '../../constants/error-messages'; import { logger } from '../../logger'; import { ExternalHostError } from '../../types/errors/external-host-error'; -import { Http } from '../../util/http'; +import { Http, HttpResponse } from '../../util/http'; import { MAVEN_REPO, id } from './common'; @@ -57,12 +57,12 @@ function isUnsupportedHostError(err: { name: string }): boolean { export async function downloadHttpProtocol( pkgUrl: url.URL | string, hostType = id -): Promise<string | null> { - let raw: { body: string }; +): Promise<Partial<HttpResponse>> { + let raw: HttpResponse; try { const httpClient = httpByHostType(hostType); raw = await httpClient.get(pkgUrl.toString()); - return raw.body; + return raw; } catch (err) { const failedUrl = pkgUrl.toString(); if (err.message === HOST_DISABLED) { @@ -92,7 +92,7 @@ export async function downloadHttpProtocol( } else { logger.info({ failedUrl, err }, 'Unknown error'); } - return null; + return {}; } } diff --git a/lib/datasource/sbt-package/index.ts b/lib/datasource/sbt-package/index.ts index 979ce03ada1c87c20a0a2b9c416db18d3bef3f30..977dad57043c46b665becd675ec931b5a891f530 100644 --- a/lib/datasource/sbt-package/index.ts +++ b/lib/datasource/sbt-package/index.ts @@ -19,7 +19,7 @@ export async function getArtifactSubdirs( artifact: string, scalaVersion: string ): Promise<string[]> { - const indexContent = await downloadHttpProtocol( + const { body: indexContent } = await downloadHttpProtocol( ensureTrailingSlash(searchRoot), 'sbt' ); @@ -59,7 +59,7 @@ export async function getPackageReleases( const parseReleases = (content: string): string[] => parseIndexDir(content, (x) => !/^\.+$/.test(x)); for (const searchSubdir of artifactSubdirs) { - const content = await downloadHttpProtocol( + const { body: content } = await downloadHttpProtocol( ensureTrailingSlash(`${searchRoot}/${searchSubdir}`), 'sbt' ); @@ -109,7 +109,7 @@ export async function getUrls( for (const pomFileName of pomFileNames) { const pomUrl = `${searchRoot}/${artifactDir}/${version}/${pomFileName}`; - const content = await downloadHttpProtocol(pomUrl, 'sbt'); + const { body: content } = await downloadHttpProtocol(pomUrl, 'sbt'); if (content) { const pomXml = new XmlDocument(content); diff --git a/lib/datasource/sbt-plugin/index.ts b/lib/datasource/sbt-plugin/index.ts index 590774beeb04a855642ca2967198de085c37e5a5..23f3988b5169ce0ba502b132b310b759c331afa0 100644 --- a/lib/datasource/sbt-plugin/index.ts +++ b/lib/datasource/sbt-plugin/index.ts @@ -26,7 +26,7 @@ async function resolvePluginReleases( const searchRoot = `${rootUrl}/${artifact}`; const parse = (content: string): string[] => parseIndexDir(content, (x) => !/^\.+$/.test(x)); - const indexContent = await downloadHttpProtocol( + const { body: indexContent } = await downloadHttpProtocol( ensureTrailingSlash(searchRoot), 'sbt' ); @@ -41,7 +41,7 @@ async function resolvePluginReleases( : scalaVersions; for (const searchVersion of searchVersions) { const searchSubRoot = `${searchRoot}/scala_${searchVersion}`; - const subRootContent = await downloadHttpProtocol( + const { body: subRootContent } = await downloadHttpProtocol( ensureTrailingSlash(searchSubRoot), 'sbt' ); @@ -49,7 +49,7 @@ async function resolvePluginReleases( const sbtVersionItems = parse(subRootContent); for (const sbtItem of sbtVersionItems) { const releasesRoot = `${searchSubRoot}/${sbtItem}`; - const releasesIndexContent = await downloadHttpProtocol( + const { body: releasesIndexContent } = await downloadHttpProtocol( ensureTrailingSlash(releasesRoot), 'sbt' );