diff --git a/lib/datasource/maven/index.ts b/lib/datasource/maven/index.ts index 5867caa41ca61c..8ee4e527b475df 100644 --- a/lib/datasource/maven/index.ts +++ b/lib/datasource/maven/index.ts @@ -1,5 +1,4 @@ import url from 'url'; -import fs from 'fs-extra'; import pAll from 'p-all'; import { XmlDocument } from 'xmldoc'; import { logger } from '../../logger'; @@ -9,7 +8,14 @@ import * as mavenVersioning from '../../versioning/maven'; import { compare } from '../../versioning/maven/compare'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { MAVEN_REPO } from './common'; -import { downloadHttpProtocol, isHttpResourceExists } from './util'; +import type { MavenDependency } from './types'; +import { + downloadMavenXml, + getDependencyInfo, + getDependencyParts, + getMavenUrl, + isHttpResourceExists, +} from './util'; export { id } from './common'; @@ -18,93 +24,6 @@ export const defaultRegistryUrls = [MAVEN_REPO]; export const defaultVersioning = mavenVersioning.id; export const registryStrategy = 'merge'; -function containsPlaceholder(str: string): boolean { - return /\${.*?}/g.test(str); -} - -async function downloadFileProtocol(pkgUrl: url.URL): Promise { - const pkgPath = pkgUrl.toString().replace('file://', ''); - if (!(await fs.exists(pkgPath))) { - return null; - } - return fs.readFile(pkgPath, 'utf8'); -} - -function getMavenUrl( - dependency: MavenDependency, - repoUrl: string, - path: string -): url.URL | null { - return new url.URL(`${dependency.dependencyUrl}/${path}`, repoUrl); -} - -interface MavenXml { - authorization?: boolean; - xml?: XmlDocument; -} - -async function downloadMavenXml( - pkgUrl: url.URL | null -): Promise { - /* istanbul ignore if */ - if (!pkgUrl) { - return {}; - } - let rawContent: string; - let authorization: boolean; - switch (pkgUrl.protocol) { - case 'file:': - rawContent = await downloadFileProtocol(pkgUrl); - break; - case 'http:': - case 'https:': - ({ authorization, body: rawContent } = await downloadHttpProtocol( - pkgUrl - )); - break; - case 's3:': - logger.debug('Skipping s3 dependency'); - return {}; - default: - logger.debug({ url: pkgUrl.toString() }, `Unsupported Maven protocol`); - return {}; - } - - if (!rawContent) { - logger.debug(`Content is not found for Maven url: ${pkgUrl.toString()}`); - return {}; - } - - return { authorization, xml: new XmlDocument(rawContent) }; -} - -async function getDependencyInfo( - dependency: MavenDependency, - repoUrl: string, - version: string -): Promise> { - const result: Partial = {}; - const path = `${version}/${dependency.name}-${version}.pom`; - - const pomUrl = getMavenUrl(dependency, repoUrl, path); - const { xml: pomContent } = await downloadMavenXml(pomUrl); - if (!pomContent) { - return result; - } - - const homepage = pomContent.valueWithPath('url'); - if (homepage && !containsPlaceholder(homepage)) { - result.homepage = homepage; - } - - const sourceUrl = pomContent.valueWithPath('scm.url'); - if (sourceUrl && !containsPlaceholder(sourceUrl)) { - result.sourceUrl = sourceUrl.replace(/^scm:/, ''); - } - - return result; -} - function isStableVersion(x: string): boolean { return mavenVersion.isStable(x); } @@ -121,24 +40,6 @@ function getLatestStableVersion(releases: Release[]): string | null { return null; } -interface MavenDependency { - display: string; - group?: string; - name?: string; - dependencyUrl: string; -} - -function getDependencyParts(lookupName: string): MavenDependency { - const [group, name] = lookupName.split(':'); - const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`; - return { - display: lookupName, - group, - name, - dependencyUrl, - }; -} - function extractVersions(metadata: XmlDocument): string[] { const versions = metadata.descendantWithPath('versioning.versions'); const elements = versions?.childrenNamed('version'); diff --git a/lib/datasource/maven/types.ts b/lib/datasource/maven/types.ts new file mode 100644 index 00000000000000..06d8fd4c211d26 --- /dev/null +++ b/lib/datasource/maven/types.ts @@ -0,0 +1,13 @@ +import type { XmlDocument } from 'xmldoc'; + +export interface MavenDependency { + display: string; + group?: string; + name?: string; + dependencyUrl: string; +} + +export interface MavenXml { + authorization?: boolean; + xml?: XmlDocument; +} diff --git a/lib/datasource/maven/util.ts b/lib/datasource/maven/util.ts index 335634caac0749..311c1041d4374d 100644 --- a/lib/datasource/maven/util.ts +++ b/lib/datasource/maven/util.ts @@ -1,10 +1,14 @@ import url from 'url'; +import fs from 'fs-extra'; +import { XmlDocument } from 'xmldoc'; import { HOST_DISABLED } from '../../constants/error-messages'; import { logger } from '../../logger'; import { ExternalHostError } from '../../types/errors/external-host-error'; import { Http, HttpResponse } from '../../util/http'; +import type { ReleaseResult } from '../types'; import { MAVEN_REPO, id } from './common'; +import type { MavenDependency, MavenXml } from './types'; const http: Record = {}; @@ -96,6 +100,14 @@ export async function downloadHttpProtocol( } } +async function downloadFileProtocol(pkgUrl: url.URL): Promise { + const pkgPath = pkgUrl.toString().replace('file://', ''); + if (!(await fs.exists(pkgPath))) { + return null; + } + return fs.readFile(pkgPath, 'utf8'); +} + export async function isHttpResourceExists( pkgUrl: url.URL | string, hostType = id @@ -119,3 +131,88 @@ export async function isHttpResourceExists( return null; } } + +function containsPlaceholder(str: string): boolean { + return /\${.*?}/g.test(str); +} + +export function getMavenUrl( + dependency: MavenDependency, + repoUrl: string, + path: string +): url.URL | null { + return new url.URL(`${dependency.dependencyUrl}/${path}`, repoUrl); +} + +export async function downloadMavenXml( + pkgUrl: url.URL | null +): Promise { + /* istanbul ignore if */ + if (!pkgUrl) { + return {}; + } + let rawContent: string; + let authorization: boolean; + switch (pkgUrl.protocol) { + case 'file:': + rawContent = await downloadFileProtocol(pkgUrl); + break; + case 'http:': + case 'https:': + ({ authorization, body: rawContent } = await downloadHttpProtocol( + pkgUrl + )); + break; + case 's3:': + logger.debug('Skipping s3 dependency'); + return {}; + default: + logger.debug({ url: pkgUrl.toString() }, `Unsupported Maven protocol`); + return {}; + } + + if (!rawContent) { + logger.debug(`Content is not found for Maven url: ${pkgUrl.toString()}`); + return {}; + } + + return { authorization, xml: new XmlDocument(rawContent) }; +} + +export async function getDependencyInfo( + dependency: MavenDependency, + repoUrl: string, + version: string +): Promise> { + const result: Partial = {}; + const path = `${version}/${dependency.name}-${version}.pom`; + + const pomUrl = getMavenUrl(dependency, repoUrl, path); + const { xml: pomContent } = await downloadMavenXml(pomUrl); + if (!pomContent) { + return result; + } + + const homepage = pomContent.valueWithPath('url'); + if (homepage && !containsPlaceholder(homepage)) { + result.homepage = homepage; + } + + const sourceUrl = pomContent.valueWithPath('scm.url'); + if (sourceUrl && !containsPlaceholder(sourceUrl)) { + result.sourceUrl = sourceUrl.replace(/^scm:/, ''); + } + + return result; +} + +export function getDependencyParts(lookupName: string): MavenDependency { + const [group, name] = lookupName.split(':'); + const dependencyUrl = `${group.replace(/\./g, '/')}/${name}`; + return { + display: lookupName, + group, + name, + dependencyUrl, + }; +}