UNPKG

renovate

Version:

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

216 lines • 8.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.confidenceLevels = void 0; exports.initConfig = initConfig; exports.resetConfig = resetConfig; exports.isMergeConfidence = isMergeConfidence; exports.isActiveConfidenceLevel = isActiveConfidenceLevel; exports.satisfiesConfidenceLevel = satisfiesConfidenceLevel; exports.getMergeConfidenceLevel = getMergeConfidenceLevel; exports.initMergeConfidence = initMergeConfidence; exports.getApiToken = getApiToken; const tslib_1 = require("tslib"); const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const merge_confidence_1 = require("../../config/presets/internal/merge-confidence"); const logger_1 = require("../../logger"); const external_host_error_1 = require("../../types/errors/external-host-error"); const packageCache = tslib_1.__importStar(require("../cache/package")); const hostRules = tslib_1.__importStar(require("../host-rules")); const http_1 = require("../http"); const memory_http_cache_provider_1 = require("../http/cache/memory-http-cache-provider"); const regex_1 = require("../regex"); const url_1 = require("../url"); const common_1 = require("./common"); const hostType = 'merge-confidence'; const http = new http_1.Http(hostType); let token; let apiBaseUrl; let supportedDatasources = []; exports.confidenceLevels = { low: -1, neutral: 0, high: 1, 'very high': 2, }; function initConfig({ mergeConfidenceEndpoint, mergeConfidenceDatasources, }) { apiBaseUrl = getApiBaseUrl(mergeConfidenceEndpoint); token = getApiToken(); supportedDatasources = mergeConfidenceDatasources ?? merge_confidence_1.supportedDatasources; if (!is_1.default.nullOrUndefined(token)) { logger_1.logger.debug(`Merge confidence token found for ${apiBaseUrl}`); } } function resetConfig() { token = undefined; apiBaseUrl = undefined; supportedDatasources = []; } function isMergeConfidence(value) { return common_1.MERGE_CONFIDENCE.includes(value); } function isActiveConfidenceLevel(confidence) { return isMergeConfidence(confidence) && confidence !== 'low'; } function satisfiesConfidenceLevel(confidence, minimumConfidence) { return exports.confidenceLevels[confidence] >= exports.confidenceLevels[minimumConfidence]; } const updateTypeConfidenceMapping = { pin: 'high', digest: 'neutral', pinDigest: 'high', bump: 'neutral', lockFileMaintenance: 'neutral', lockfileUpdate: 'neutral', rollback: 'neutral', replacement: 'neutral', major: null, minor: null, patch: null, }; /** * Retrieves the merge confidence of a package update if the merge confidence API is enabled. Otherwise, undefined is returned. * * @param datasource * @param packageName * @param currentVersion * @param newVersion * @param updateType * * @returns The merge confidence level for the given package release. * @throws {ExternalHostError} If a request has been made and an error occurs during the request, such as a timeout, connection reset, authentication failure, or internal server error. */ async function getMergeConfidenceLevel(datasource, packageName, currentVersion, newVersion, updateType) { if (is_1.default.nullOrUndefined(apiBaseUrl) || is_1.default.nullOrUndefined(token)) { return undefined; } if (!supportedDatasources.includes(datasource)) { return undefined; } if (!(currentVersion && newVersion && updateType)) { return 'neutral'; } const mappedConfidence = updateTypeConfidenceMapping[updateType]; if (mappedConfidence) { return mappedConfidence; } return await queryApi(datasource, packageName, currentVersion, newVersion); } /** * Queries the Merge Confidence API with the given package release information. * * @param datasource * @param packageName * @param currentVersion * @param newVersion * * @returns The merge confidence level for the given package release. * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request. * * @remarks * Results are cached for 60 minutes to reduce the number of API calls. */ async function queryApi(datasource, packageName, currentVersion, newVersion) { // istanbul ignore if: defensive, already been validated before calling this function if (is_1.default.nullOrUndefined(apiBaseUrl) || is_1.default.nullOrUndefined(token)) { return 'neutral'; } const escapedPackageName = packageName.replace((0, regex_1.regEx)(/\//g), '%2f'); const url = (0, url_1.joinUrlParts)(apiBaseUrl, 'api/mc/json', datasource, escapedPackageName, currentVersion, newVersion); const cacheKey = `${token}:${url}`; const cachedResult = await packageCache.get(hostType, cacheKey); // istanbul ignore if if (cachedResult) { logger_1.logger.debug({ datasource, packageName, currentVersion, newVersion, cachedResult, }, 'using merge confidence cached result'); return cachedResult; } let confidence = 'neutral'; try { const res = (await http.getJsonUnchecked(url, { cacheProvider: memory_http_cache_provider_1.memCacheProvider, })).body; if (isMergeConfidence(res.confidence)) { confidence = res.confidence; } } catch (err) { apiErrorHandler(err); } await packageCache.set(hostType, cacheKey, confidence, 60); return confidence; } /** * Checks the health of the Merge Confidence API by attempting to authenticate with it. * * @returns Resolves when the API health check is completed successfully. * * @throws {ExternalHostError} if a timeout, connection reset error, authentication failure, or internal server error occurs during the request. * * @remarks * This function first checks that the API base URL and an authentication bearer token are defined before attempting to * authenticate with the API. If either the base URL or token is not defined, it will immediately return * without making a request. */ async function initMergeConfidence(config) { initConfig(config); if (is_1.default.nullOrUndefined(apiBaseUrl) || is_1.default.nullOrUndefined(token)) { logger_1.logger.trace('merge confidence API usage is disabled'); return; } const url = (0, url_1.joinUrlParts)(apiBaseUrl, 'api/mc/availability'); try { await http.get(url); } catch (err) { apiErrorHandler(err); } logger_1.logger.debug({ supportedDatasources }, 'merge confidence API - successfully authenticated'); return; } function getApiBaseUrl(mergeConfidenceEndpoint) { const defaultBaseUrl = 'https://developer.mend.io/'; const baseFromEnv = mergeConfidenceEndpoint ?? defaultBaseUrl; try { const parsedBaseUrl = new URL(baseFromEnv).toString(); logger_1.logger.trace({ baseUrl: parsedBaseUrl }, 'using merge confidence API base found in environment variables'); return (0, url_1.ensureTrailingSlash)(parsedBaseUrl); } catch (err) { logger_1.logger.warn({ err, baseFromEnv }, 'invalid merge confidence API base URL found in environment variables - using default value instead'); return defaultBaseUrl; } } function getApiToken() { return hostRules.find({ url: apiBaseUrl, hostType, })?.token; } /** * Handles errors returned by the Merge Confidence API. * * @param err - The error object returned by the API. * @throws {ExternalHostError} if a timeout or connection reset error, authentication failure, or internal server error occurs during the request. */ function apiErrorHandler(err) { if (err.code === 'ETIMEDOUT' || err.code === 'ECONNRESET') { logger_1.logger.error({ err }, 'merge confidence API request failed - aborting run'); throw new external_host_error_1.ExternalHostError(err, hostType); } if (err.statusCode === 403) { logger_1.logger.error({ err }, 'merge confidence API token rejected - aborting run'); throw new external_host_error_1.ExternalHostError(err, hostType); } if (err.statusCode >= 500 && err.statusCode < 600) { logger_1.logger.error({ err }, 'merge confidence API failure: 5xx - aborting run'); throw new external_host_error_1.ExternalHostError(err, hostType); } logger_1.logger.warn({ err }, 'error fetching merge confidence data'); } //# sourceMappingURL=index.js.map