diff --git a/lib/util/package-rules.js b/lib/util/package-rules.js index 132e24f56c8a40e1b0a2f56b73fc5c0275716c41..56109ccf03d874eb2c112dfcfc9315c429e77524 100644 --- a/lib/util/package-rules.js +++ b/lib/util/package-rules.js @@ -7,8 +7,7 @@ module.exports = { applyPackageRules, }; -function applyPackageRules(inputConfig) { - let config = { ...inputConfig }; +function matchesRule(inputConfig, packageRule) { const { versionScheme, packageFile, @@ -25,155 +24,184 @@ function applyPackageRules(inputConfig) { baseBranch, manager, datasource, - } = config; - const packageRules = config.packageRules || []; - logger.trace( - { dependency: depName, packageRules }, - `Checking against ${packageRules.length} packageRules` - ); - packageRules.forEach(packageRule => { - let { - paths, - languages, - baseBranchList, - managers, - datasources, - depTypeList, - packageNames, - packagePatterns, - excludePackageNames, - excludePackagePatterns, - matchCurrentVersion, - sourceUrlPrefixes, - updateTypes, - } = packageRule; - // Setting empty arrays simplifies our logic later - paths = paths || []; - languages = languages || []; - baseBranchList = baseBranchList || []; - managers = managers || []; - datasources = datasources || []; - depTypeList = depTypeList || []; - packageNames = packageNames || []; - packagePatterns = packagePatterns || []; - excludePackageNames = excludePackageNames || []; - excludePackagePatterns = excludePackagePatterns || []; - sourceUrlPrefixes = sourceUrlPrefixes || []; - matchCurrentVersion = matchCurrentVersion || null; - updateTypes = updateTypes || []; - let positiveMatch = false; - let negativeMatch = false; - // Massage a positive patterns patch if an exclude one is present - if ( - (excludePackageNames.length || excludePackagePatterns.length) && - !(packageNames.length || packagePatterns.length) - ) { - packagePatterns = ['.*']; + } = inputConfig; + let { + paths, + languages, + baseBranchList, + managers, + datasources, + depTypeList, + packageNames, + packagePatterns, + excludePackageNames, + excludePackagePatterns, + matchCurrentVersion, + sourceUrlPrefixes, + updateTypes, + } = packageRule; + // Setting empty arrays simplifies our logic later + paths = paths || []; + languages = languages || []; + baseBranchList = baseBranchList || []; + managers = managers || []; + datasources = datasources || []; + depTypeList = depTypeList || []; + packageNames = packageNames || []; + packagePatterns = packagePatterns || []; + excludePackageNames = excludePackageNames || []; + excludePackagePatterns = excludePackagePatterns || []; + sourceUrlPrefixes = sourceUrlPrefixes || []; + matchCurrentVersion = matchCurrentVersion || null; + updateTypes = updateTypes || []; + let positiveMatch = false; + // Massage a positive patterns patch if an exclude one is present + if ( + (excludePackageNames.length || excludePackagePatterns.length) && + !(packageNames.length || packagePatterns.length) + ) { + packagePatterns = ['.*']; + } + if (paths.length) { + const isMatch = paths.some( + rulePath => + packageFile.includes(rulePath) || + minimatch(packageFile, rulePath, { dot: true }) + ); + if (!isMatch) { + return false; } - if (paths.length) { - const isMatch = paths.some( - rulePath => - packageFile.includes(rulePath) || - minimatch(packageFile, rulePath, { dot: true }) - ); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (depTypeList.length) { + const isMatch = + depTypeList.includes(depType) || + (depTypes && depTypes.some(dt => depTypeList.includes(dt))); + if (!isMatch) { + return false; } - if (depTypeList.length) { - const isMatch = - depTypeList.includes(depType) || - (depTypes && depTypes.some(dt => depTypeList.includes(dt))); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (languages.length) { + const isMatch = languages.includes(language); + if (!isMatch) { + return false; } - if (languages.length) { - const isMatch = languages.includes(language); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (baseBranchList.length) { + const isMatch = baseBranchList.includes(baseBranch); + if (!isMatch) { + return false; } - if (baseBranchList.length) { - const isMatch = baseBranchList.includes(baseBranch); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (managers.length) { + const isMatch = managers.includes(manager); + if (!isMatch) { + return false; } - if (managers.length) { - const isMatch = managers.includes(manager); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (datasources.length) { + const isMatch = datasources.includes(datasource); + if (!isMatch) { + return false; } - if (datasources.length) { - const isMatch = datasources.includes(datasource); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + positiveMatch = true; + } + if (updateTypes.length) { + const isMatch = + updateTypes.includes(updateType) || + (isBump && updateTypes.includes('bump')); + if (!isMatch) { + return false; } - if (updateTypes.length) { - const isMatch = - updateTypes.includes(updateType) || - (isBump && updateTypes.includes('bump')); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; - } - if (packageNames.length || packagePatterns.length) { - let isMatch = packageNames.includes(depName); - // name match is "or" so we check patterns if we didn't match names - if (!isMatch) { - for (const packagePattern of packagePatterns) { - const packageRegex = new RegExp( - packagePattern === '^*$' || packagePattern === '*' - ? '.*' - : packagePattern - ); - if (depName && depName.match(packageRegex)) { - logger.trace(`${depName} matches against ${packageRegex}`); - isMatch = true; - } - } - } - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; - } - if (excludePackageNames.length) { - const isMatch = excludePackageNames.includes(depName); - negativeMatch = negativeMatch || isMatch; - positiveMatch = positiveMatch || !isMatch; - } - if (excludePackagePatterns.length) { - let isMatch = false; - for (const pattern of excludePackagePatterns) { + positiveMatch = true; + } + if (packageNames.length || packagePatterns.length) { + let isMatch = packageNames.includes(depName); + // name match is "or" so we check patterns if we didn't match names + if (!isMatch) { + for (const packagePattern of packagePatterns) { const packageRegex = new RegExp( - pattern === '^*$' || pattern === '*' ? '.*' : pattern + packagePattern === '^*$' || packagePattern === '*' + ? '.*' + : packagePattern ); if (depName && depName.match(packageRegex)) { logger.trace(`${depName} matches against ${packageRegex}`); isMatch = true; } } - negativeMatch = negativeMatch || isMatch; - positiveMatch = positiveMatch || !isMatch; } - if (sourceUrlPrefixes.length) { - const isMatch = sourceUrlPrefixes.some( - prefix => sourceUrl && sourceUrl.startsWith(prefix) + if (!isMatch) { + return false; + } + positiveMatch = true; + } + if (excludePackageNames.length) { + const isMatch = excludePackageNames.includes(depName); + if (isMatch) { + return false; + } + positiveMatch = true; + } + if (excludePackagePatterns.length) { + let isMatch = false; + for (const pattern of excludePackagePatterns) { + const packageRegex = new RegExp( + pattern === '^*$' || pattern === '*' ? '.*' : pattern ); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; + if (depName && depName.match(packageRegex)) { + logger.trace(`${depName} matches against ${packageRegex}`); + isMatch = true; + } + } + if (isMatch) { + return false; + } + positiveMatch = true; + } + if (sourceUrlPrefixes.length) { + const isMatch = sourceUrlPrefixes.some( + prefix => sourceUrl && sourceUrl.startsWith(prefix) + ); + if (!isMatch) { + return false; } - if (matchCurrentVersion) { - const { matches, isVersion } = versioning.get(versionScheme); - const compareVersion = - currentValue && isVersion(currentValue) - ? currentValue // it's a version so we can match against it - : lockedVersion || fromVersion; // need to match against this fromVersion, if available - if (compareVersion && isVersion(compareVersion)) { - const isMatch = matches(compareVersion, matchCurrentVersion); - positiveMatch = positiveMatch || isMatch; - negativeMatch = negativeMatch || !isMatch; - } else { - negativeMatch = true; + positiveMatch = true; + } + if (matchCurrentVersion) { + const { matches, isVersion } = versioning.get(versionScheme); + const compareVersion = + currentValue && isVersion(currentValue) + ? currentValue // it's a version so we can match against it + : lockedVersion || fromVersion; // need to match against this fromVersion, if available + if (compareVersion && isVersion(compareVersion)) { + const isMatch = matches(compareVersion, matchCurrentVersion); + // istanbul ignore if + if (!isMatch) { + return false; } + positiveMatch = true; + } else { + return false; } + } + return positiveMatch; +} + +function applyPackageRules(inputConfig) { + let config = { ...inputConfig }; + const packageRules = config.packageRules || []; + logger.trace( + { dependency: config.depName, packageRules }, + `Checking against ${packageRules.length} packageRules` + ); + packageRules.forEach(packageRule => { // This rule is considered matched if there was at least one positive match and no negative matches - if (positiveMatch && !negativeMatch) { + if (matchesRule(config, packageRule)) { // Package rule config overrides any existing config config = mergeChildConfig(config, packageRule); delete config.packageNames;