UNPKG

renovate

Version:

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

164 lines • 7.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDependency = getDependency; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const zod_1 = require("zod"); const error_messages_1 = require("../../../constants/error-messages"); const logger_1 = require("../../../logger"); const external_host_error_1 = require("../../../types/errors/external-host-error"); const hostRules = tslib_1.__importStar(require("../../../util/host-rules")); const package_http_cache_provider_1 = require("../../../util/http/cache/package-http-cache-provider"); const regex_1 = require("../../../util/regex"); const timestamp_1 = require("../../../util/timestamp"); const url_1 = require("../../../util/url"); const SHORT_REPO_REGEX = (0, regex_1.regEx)(/^((?<platform>bitbucket|github|gitlab):)?(?<shortRepo>[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)$/); const platformMapping = { bitbucket: 'https://bitbucket.org/', github: 'https://github.com/', gitlab: 'https://gitlab.com/', }; const PackageSource = zod_1.z .union([ zod_1.z .string() .nonempty() .transform((repository) => { let sourceUrl = null; const sourceDirectory = null; const shortMatch = repository.match(SHORT_REPO_REGEX); if (shortMatch?.groups) { const { platform = 'github', shortRepo } = shortMatch.groups; sourceUrl = platformMapping[platform] + shortRepo; } else { sourceUrl = repository; } return { sourceUrl, sourceDirectory }; }), zod_1.z .object({ url: zod_1.z.string().nonempty().nullish(), directory: zod_1.z.string().nonempty().nullish(), }) .transform(({ url, directory }) => { const res = { sourceUrl: null, sourceDirectory: null }; if (url) { res.sourceUrl = url; } if (directory) { res.sourceDirectory = directory; } return res; }), ]) .catch({ sourceUrl: null, sourceDirectory: null }); async function getDependency(http, registryUrl, packageName) { logger_1.logger.trace(`npm.getDependency(${packageName})`); const packageUrl = (0, url_1.joinUrlParts)(registryUrl, packageName.replace('/', '%2F')); try { const cacheProvider = new package_http_cache_provider_1.PackageHttpCacheProvider({ namespace: 'datasource-npm:cache-provider', checkAuthorizationHeader: false, // We don't rely on whether user token is provided or not checkCacheControlHeader: true, }); const options = { cacheProvider }; // set abortOnError for registry.npmjs.org if no hostRule with explicit abortOnError exists if (registryUrl === 'https://registry.npmjs.org' && hostRules.find({ url: 'https://registry.npmjs.org' })?.abortOnError === undefined) { logger_1.logger.trace({ packageName, registry: 'https://registry.npmjs.org' }, 'setting abortOnError hostRule for well known host'); hostRules.add({ matchHost: 'https://registry.npmjs.org', abortOnError: true, }); } const resp = await http.getJsonUnchecked(packageUrl, options); const { body: res } = resp; if (!res.versions || !Object.keys(res.versions).length) { // Registry returned a 200 OK but with no versions logger_1.logger.debug(`No versions returned for npm dependency ${packageName}`); return null; } const latestVersion = res.versions[res['dist-tags']?.latest ?? '']; res.repository ??= latestVersion?.repository; res.homepage ??= latestVersion?.homepage; const { sourceUrl, sourceDirectory } = PackageSource.parse(res.repository); // Simplify response before caching and returning const dep = { homepage: res.homepage, releases: [], tags: res['dist-tags'], registryUrl, }; if (sourceUrl) { dep.sourceUrl = sourceUrl; } if (sourceDirectory) { dep.sourceDirectory = sourceDirectory; } if (latestVersion?.deprecated) { dep.deprecationMessage = `On registry \`${registryUrl}\`, the "latest" version of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`; } dep.releases = Object.keys(res.versions).map((version) => { const release = { version, gitRef: res.versions?.[version].gitHead, dependencies: res.versions?.[version].dependencies, devDependencies: res.versions?.[version].devDependencies, }; const releaseTimestamp = (0, timestamp_1.asTimestamp)(res.time?.[version]); if (releaseTimestamp) { release.releaseTimestamp = releaseTimestamp; } if (res.versions?.[version].deprecated) { release.isDeprecated = true; } const nodeConstraint = res.versions?.[version].engines?.node; if (is_1.default.nonEmptyString(nodeConstraint)) { release.constraints = { node: [nodeConstraint] }; } const source = PackageSource.parse(res.versions?.[version].repository); if (source.sourceUrl && source.sourceUrl !== dep.sourceUrl) { release.sourceUrl = source.sourceUrl; } if (source.sourceDirectory && source.sourceDirectory !== dep.sourceDirectory) { release.sourceDirectory = source.sourceDirectory; } if (dep.deprecationMessage) { release.isDeprecated = true; } return release; }); const isPublic = resp.headers?.['cache-control'] ?.toLocaleLowerCase() ?.split((0, regex_1.regEx)(/\s*,\s*/)) ?.includes('public'); if (!isPublic) { dep.isPrivate = true; } logger_1.logger.trace({ dep }, 'dep'); return dep; } catch (err) { const actualError = err instanceof external_host_error_1.ExternalHostError ? err.err : err; const ignoredStatusCodes = [401, 402, 403, 404]; const ignoredResponseCodes = ['ENOTFOUND']; if (actualError.message === error_messages_1.HOST_DISABLED || ignoredStatusCodes.includes(actualError.statusCode) || ignoredResponseCodes.includes(actualError.code)) { return null; } if (err instanceof external_host_error_1.ExternalHostError) { if (actualError.name === 'ParseError' && actualError.body) { actualError.body = 'err.body deleted by Renovate'; err.err = actualError; } throw err; } logger_1.logger.debug({ err }, 'Unknown npm lookup error'); return null; } } //# sourceMappingURL=get.js.map