UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

188 lines (187 loc) • 8.33 kB
import { regEx } from "../../../util/regex.js"; import { logger } from "../../../logger/index.js"; import { ensureTrailingSlash, parseUrl, trimTrailingSlash } from "../../../util/url.js"; import { compare } from "../../versioning/maven/compare.js"; import "../../versioning/ivy/index.js"; import { get, set } from "../../../util/cache/package/index.js"; import { withCache } from "../../../util/cache/package/with-cache.js"; import { Http } from "../../../util/http/index.js"; import { asTimestamp } from "../../../util/timestamp.js"; import { MAVEN_REPO } from "../maven/common.js"; import { downloadHttpContent, downloadHttpProtocol } from "../maven/util.js"; import { MavenDatasource } from "../maven/index.js"; import { extractPageLinks, getLatestVersion } from "./util.js"; import upath from "upath"; import { XmlDocument } from "xmldoc"; //#region lib/modules/datasource/sbt-package/index.ts var SbtPackageDatasource = class SbtPackageDatasource extends MavenDatasource { static id = "sbt-package"; defaultRegistryUrls = [MAVEN_REPO]; defaultVersioning = "ivy"; registryStrategy = "hunt"; sourceUrlSupport = "package"; sourceUrlNote = "The source URL is determined from the `scm` tags in the results."; constructor(id = SbtPackageDatasource.id) { super(id); this.http = new Http("sbt"); } static parseDepCoordinate(packageName) { const [groupId, javaArtifactId] = packageName.split(":"); const [artifactId, scalaVersion] = javaArtifactId.split("_"); return { groupId, artifactId, scalaVersion }; } async getSbtReleases(registryUrl, packageName) { const { groupId, artifactId, scalaVersion } = SbtPackageDatasource.parseDepCoordinate(packageName); const groupIdSplit = groupId.split("."); const repoRootUrl = ensureTrailingSlash(registryUrl); const validRootUrlKey = `valid-root-url:${registryUrl}:${packageName}`; const validRootUrl = await get("datasource-sbt-package", validRootUrlKey); const packageRootUrls = []; // istanbul ignore if: not easily testable if (validRootUrl) packageRootUrls.push(validRootUrl); else { const packageRootUrlWith = (sep) => `${repoRootUrl}${groupIdSplit.join(sep)}`; packageRootUrls.push(ensureTrailingSlash(packageRootUrlWith("/"))); packageRootUrls.push(ensureTrailingSlash(packageRootUrlWith("."))); } let dependencyUrl; let packageUrls; for (const packageRootUrl of packageRootUrls) { const packageRootContent = await downloadHttpContent(this.http, packageRootUrl); if (!packageRootContent) continue; await set("datasource-sbt-package", validRootUrlKey, packageRootUrl, 720 * 60); dependencyUrl = trimTrailingSlash(packageRootUrl); const parsedPackageRootUrl = parseUrl(packageRootUrl); if (!parsedPackageRootUrl) { logger.warn({ packageRootUrl }, "Failed to parse packageURL"); continue; } const rootPath = parsedPackageRootUrl.pathname; const artifactSubdirs = extractPageLinks(packageRootContent, (href) => { const path = href.replace(rootPath, ""); if (path.startsWith(`${artifactId}_native`) || path.startsWith(`${artifactId}_sjs`)) return null; if (path === artifactId || path.startsWith(`${artifactId}_`)) return ensureTrailingSlash(`${packageRootUrl}${path}`); return null; }); if (scalaVersion) { const scalaSubdir = artifactSubdirs.find((x) => x.endsWith(`/${artifactId}_${scalaVersion}/`)); if (scalaSubdir) { packageUrls = [scalaSubdir]; break; } } packageUrls = artifactSubdirs; break; } if (!packageUrls) return null; const invalidPackageUrlsKey = `invalid-package-urls:${registryUrl}:${packageName}`; const invalidPackageUrls = new Set(await get("datasource-sbt-package", invalidPackageUrlsKey)); packageUrls = packageUrls.filter((url) => !invalidPackageUrls.has(url)); const allVersions = /* @__PURE__ */ new Set(); for (const pkgUrl of packageUrls) { const parsedPkgUrl = parseUrl(pkgUrl); if (!parsedPkgUrl) { invalidPackageUrls.add(pkgUrl); continue; } const packageContent = await downloadHttpContent(this.http, pkgUrl); // istanbul ignore if if (!packageContent) { invalidPackageUrls.add(pkgUrl); continue; } const rootPath = parsedPkgUrl.pathname; const versions = extractPageLinks(packageContent, (href) => { const path = href.replace(rootPath, ""); if (path.startsWith(".")) return null; return path; }); for (const version of versions) allVersions.add(version); } if (invalidPackageUrls.size > 0) await set("datasource-sbt-package", invalidPackageUrlsKey, [...invalidPackageUrls], 720 * 60); if (packageUrls.length > 0) await set("datasource-sbt-package", `package-urls:${registryUrl}:${packageName}`, packageUrls, 720 * 60); const versions = [...allVersions]; if (!versions.length) return null; const res = { releases: [...allVersions].sort(compare).map((version) => ({ version })), dependencyUrl }; const latestVersion = getLatestVersion(versions); const pomInfo = await this.getPomInfo(registryUrl, packageName, latestVersion, packageUrls); if (pomInfo?.homepage) res.homepage = pomInfo.homepage; if (pomInfo?.sourceUrl) res.sourceUrl = pomInfo.sourceUrl; return res; } async getPomInfo(registryUrl, packageName, version, pkgUrls) { const packageUrlsKey = `package-urls:${registryUrl}:${packageName}`; // istanbul ignore next: will be covered later const packageUrls = pkgUrls ?? await get("datasource-sbt-package", packageUrlsKey); // istanbul ignore if if (!packageUrls?.length) return null; // istanbul ignore if if (!version) return null; const invalidPomFilesKey = `invalid-pom-files:${registryUrl}:${packageName}:${version}`; const invalidPomFiles = new Set(await get("datasource-sbt-package", invalidPomFilesKey)); const saveCache = async () => { if (invalidPomFiles.size > 0) await set("datasource-sbt-package", invalidPomFilesKey, [...invalidPomFiles], 720 * 60); }; for (const packageUrl of packageUrls) { const artifactDir = upath.basename(packageUrl); const [artifact] = artifactDir.split("_"); for (const pomFilePrefix of [artifactDir, artifact]) { const pomUrl = `${packageUrl}${version}/${`${pomFilePrefix}-${version}.pom`}`; if (invalidPomFiles.has(pomUrl)) continue; const { val } = (await downloadHttpProtocol(this.http, pomUrl)).unwrap(); if (!val) { invalidPomFiles.add(pomUrl); continue; } const result = {}; const releaseTimestamp = asTimestamp(val.lastModified); if (releaseTimestamp) result.releaseTimestamp = releaseTimestamp; const pomXml = new XmlDocument(val.data); const homepage = pomXml.valueWithPath("url"); if (homepage) result.homepage = homepage; const sourceUrl = pomXml.valueWithPath("scm.url"); if (sourceUrl) result.sourceUrl = sourceUrl.replace(regEx(/^scm:/), "").replace(regEx(/^git:/), "").replace(regEx(/^git@github.com:/), "https://github.com/").replace(regEx(/\.git$/), ""); await saveCache(); return result; } } await saveCache(); return null; } async getReleases(config) { const { packageName, registryUrl } = config; // istanbul ignore if if (!registryUrl) return null; const sbtReleases = await this.getSbtReleases(registryUrl, packageName); if (sbtReleases) return sbtReleases; logger.debug(`Sbt: no versions discovered for ${packageName} listing organization root package folder, fallback to maven datasource for version discovery`); const mavenReleaseResult = await super.getReleases(config); if (mavenReleaseResult) return mavenReleaseResult; logger.debug(`Sbt: no versions found for "${packageName}"`); return null; } async _postprocessRelease(config, release) { /* v8 ignore next 3 -- should never happen */ if (!config.registryUrl) return release; const res = await this.getPomInfo(config.registryUrl, config.packageName, release.version); if (res?.releaseTimestamp) release.releaseTimestamp = res.releaseTimestamp; return release; } postprocessRelease(config, release) { return withCache({ namespace: "datasource-sbt-package", key: `postprocessRelease:${config.registryUrl}:${config.packageName}:${release.version}`, ttlMinutes: 720 * 60 }, () => this._postprocessRelease(config, release)); } }; //#endregion export { SbtPackageDatasource }; //# sourceMappingURL=index.js.map