diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 7f573b694c..d191b7e6ad 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -2950,13 +2950,12 @@ Use this field to restrict rules to a particular package manager. e.g. } ``` -For the full list of available managers, see the [Supported Managers](modules/manager/index.md#supported-managers) documentation. +### matchDepPrefixes -### matchMessage - -For log level remapping, use this field to match against the particular log messages. - -For more details on supported syntax see Renovate's [string pattern matching documentation](./string-pattern-matching.md). + +!!! note + `matchDepNames` now supports pattern matching and should be used instead. + Use of `matchDepPrefixes` is now deprecated and will be migrated in future. ### matchNewValue @@ -3007,13 +3006,17 @@ For more details on this syntax see Renovate's [string pattern matching document ### matchPackageNames -Use this field if you want to have one or more exact name matches in your package rule. -See also `excludePackageNames`. +Use this field to match against the `packageName` field. +This matching can be an exact match, Glob match, or Regular Expression match. -```json +For more details on supported syntax see Renovate's [string pattern matching documentation](./string-pattern-matching.md). +Note that Glob matching (including exact name matching) is case-insensitive. + +```json title="exact name match" { "packageRules": [ { + "matchDatasources": ["npm"], "matchPackageNames": ["angular"], "rangeStrategy": "pin" } @@ -3021,40 +3024,50 @@ See also `excludePackageNames`. } ``` -The above will configure `rangeStrategy` to `pin` only for the package `angular`. +The above will configure `rangeStrategy` to `pin` only for the npm package `angular`. - -!!! note - `matchPackageNames` will try matching `packageName` first and then fall back to matching `depName`. - If the fallback is used, Renovate will log a warning, because the fallback will be removed in a future release. - Use `matchDepNames` instead. - -### matchPackagePatterns - -Use this field if you want to have one or more package names patterns in your package rule. -See also `excludePackagePatterns`. - -```json +```json title="prefix match using Glob" { "packageRules": [ { - "matchPackagePatterns": ["^angular"], - "rangeStrategy": "replace" + "matchDatasources": ["npm"], + "matchPackageNames": ["@angular/*", "!@angular/abc"], + "groupName": "Angular" } ] } ``` -The above will configure `rangeStrategy` to `replace` for any package starting with `angular`. +The above will group together any npm package which starts with `@angular/` except `@angular/abc`. + +```json title="pattern match using RegEx" +{ + "packageRules": [ + { + "matchDatasources": ["npm"], + "matchPackageNames": ["/^angular/"], + "groupName": "Angular" + } + ] +} +``` + +The above will group together any npm package which starts with the string `angular`. + +### matchPackagePatterns !!! note - `matchPackagePatterns` will try matching `packageName` first and then fall back to matching `depName`. - If the fallback is used, Renovate will log a warning, because the fallback will be removed in a future release. - Use `matchDepPatterns` instead. + `matchPackageNames` now supports pattern matching and should be used instead. + Use of `matchPackagePatterns` is now deprecated and will be migrated in future. ### matchPackagePrefixes + +!!! note + `matchPackageNames` now supports pattern matching and should be used instead. + Use of `matchPackagePrefixes` is now deprecated and will be migrated in future. + Use this field to match a package prefix without needing to write a regex expression. See also `excludePackagePrefixes`. @@ -3071,11 +3084,6 @@ See also `excludePackagePrefixes`. Like the earlier `matchPackagePatterns` example, the above will configure `rangeStrategy` to `replace` for any package starting with `angular`. - -!!! note - `matchPackagePrefixes` will try matching `packageName` first and then fall back to matching `depName`. - If the fallback is used, Renovate will log a warning, because the fallback will be removed in a future release. - Use `matchDepPatterns` instead. ### matchRepositories diff --git a/lib/util/package-rules/dep-names.ts b/lib/util/package-rules/dep-names.ts index d745863ea4..f9278ba650 100644 --- a/lib/util/package-rules/dep-names.ts +++ b/lib/util/package-rules/dep-names.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; +import { matchRegexOrGlobList } from '../string-match'; import { Matcher } from './base'; export class DepNameMatcher extends Matcher { @@ -13,7 +14,7 @@ export class DepNameMatcher extends Matcher { if (is.undefined(depName)) { return false; } - return matchDepNames.includes(depName); + return matchRegexOrGlobList(depName, matchDepNames); } override excludes( @@ -26,6 +27,6 @@ export class DepNameMatcher extends Matcher { if (is.undefined(depName)) { return false; } - return excludeDepNames.includes(depName); + return matchRegexOrGlobList(depName, excludeDepNames); } } diff --git a/lib/util/package-rules/dep-patterns.spec.ts b/lib/util/package-rules/dep-patterns.spec.ts index 0f976a179b..103adcfb30 100644 --- a/lib/util/package-rules/dep-patterns.spec.ts +++ b/lib/util/package-rules/dep-patterns.spec.ts @@ -15,6 +15,30 @@ describe('util/package-rules/dep-patterns', () => { ); expect(result).toBeFalse(); }); + + it('should massage wildcards', () => { + const result = depPatternsMatcher.matches( + { + depName: 'http', + }, + { + matchDepPatterns: ['*'], + }, + ); + expect(result).toBeTrue(); + }); + + it('should convert to regex', () => { + const result = depPatternsMatcher.matches( + { + depName: 'http', + }, + { + matchDepPatterns: ['^h'], + }, + ); + expect(result).toBeTrue(); + }); }); describe('exclude', () => { @@ -29,5 +53,29 @@ describe('util/package-rules/dep-patterns', () => { ); expect(result).toBeFalse(); }); + + it('should massage wildcards', () => { + const result = depPatternsMatcher.excludes( + { + depName: 'http', + }, + { + excludeDepPatterns: ['*'], + }, + ); + expect(result).toBeTrue(); + }); + + it('should convert to regex', () => { + const result = depPatternsMatcher.excludes( + { + depName: 'http', + }, + { + excludeDepPatterns: ['^h'], + }, + ); + expect(result).toBeTrue(); + }); }); }); diff --git a/lib/util/package-rules/dep-patterns.ts b/lib/util/package-rules/dep-patterns.ts index 7a566a726f..21d5330100 100644 --- a/lib/util/package-rules/dep-patterns.ts +++ b/lib/util/package-rules/dep-patterns.ts @@ -1,13 +1,11 @@ import is from '@sindresorhus/is'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { logger } from '../../logger'; -import { regEx } from '../regex'; +import { matchRegexOrGlobList } from '../string-match'; import { Matcher } from './base'; -import { massagePattern } from './utils'; export class DepPatternsMatcher extends Matcher { override matches( - { depName, updateType }: PackageRuleInputConfig, + { depName }: PackageRuleInputConfig, { matchDepPatterns }: PackageRule, ): boolean | null { if (is.undefined(matchDepPatterns)) { @@ -18,22 +16,16 @@ export class DepPatternsMatcher extends Matcher { return false; } - let isMatch = false; - for (const packagePattern of matchDepPatterns) { - const packageRegex = regEx(massagePattern(packagePattern)); - if (packageRegex.test(depName)) { - logger.trace(`${depName} matches against ${String(packageRegex)}`); - isMatch = true; - } - } - return isMatch; + const massagedPatterns = matchDepPatterns.map((pattern) => + pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, + ); + return matchRegexOrGlobList(depName, massagedPatterns); } override excludes( - { depName, updateType }: PackageRuleInputConfig, + { depName }: PackageRuleInputConfig, { excludeDepPatterns }: PackageRule, ): boolean | null { - // ignore lockFileMaintenance for backwards compatibility if (is.undefined(excludeDepPatterns)) { return null; } @@ -41,14 +33,9 @@ export class DepPatternsMatcher extends Matcher { return false; } - let isMatch = false; - for (const pattern of excludeDepPatterns) { - const packageRegex = regEx(massagePattern(pattern)); - if (packageRegex.test(depName)) { - logger.trace(`${depName} matches against ${String(packageRegex)}`); - isMatch = true; - } - } - return isMatch; + const massagedPatterns = excludeDepPatterns.map((pattern) => + pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, + ); + return matchRegexOrGlobList(depName, massagedPatterns); } } diff --git a/lib/util/package-rules/package-names.ts b/lib/util/package-rules/package-names.ts index 51d35fd48f..fe21b0b8b8 100644 --- a/lib/util/package-rules/package-names.ts +++ b/lib/util/package-rules/package-names.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; +import { matchRegexOrGlobList } from '../string-match'; import { Matcher } from './base'; export class PackageNameMatcher extends Matcher { @@ -14,7 +15,7 @@ export class PackageNameMatcher extends Matcher { if (!packageName) { return false; } - return matchPackageNames.includes(packageName); + return matchRegexOrGlobList(packageName, matchPackageNames); } override excludes( @@ -28,6 +29,6 @@ export class PackageNameMatcher extends Matcher { if (!packageName) { return false; } - return excludePackageNames.includes(packageName); + return matchRegexOrGlobList(packageName, excludePackageNames); } } diff --git a/lib/util/package-rules/package-patterns.ts b/lib/util/package-rules/package-patterns.ts index 315e6a0ec2..8ca7ebdfab 100644 --- a/lib/util/package-rules/package-patterns.ts +++ b/lib/util/package-rules/package-patterns.ts @@ -1,22 +1,7 @@ import is from '@sindresorhus/is'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; -import { logger } from '../../logger'; -import { regEx } from '../regex'; +import { matchRegexOrGlobList } from '../string-match'; import { Matcher } from './base'; -import { massagePattern } from './utils'; - -function matchPatternsAgainstName( - matchPackagePatterns: string[], - name: string, -): boolean { - let isMatch = false; - for (const packagePattern of matchPackagePatterns) { - if (isPackagePatternMatch(packagePattern, name)) { - isMatch = true; - } - } - return isMatch; -} export class PackagePatternsMatcher extends Matcher { override matches( @@ -32,7 +17,10 @@ export class PackagePatternsMatcher extends Matcher { return false; } - return matchPatternsAgainstName(matchPackagePatterns, packageName); + const massagedPatterns = matchPackagePatterns.map((pattern) => + pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, + ); + return matchRegexOrGlobList(packageName, massagedPatterns); } override excludes( @@ -48,15 +36,9 @@ export class PackagePatternsMatcher extends Matcher { return false; } - return matchPatternsAgainstName(excludePackagePatterns, packageName); + const massagedPatterns = excludePackagePatterns.map((pattern) => + pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`, + ); + return matchRegexOrGlobList(packageName, massagedPatterns); } } - -function isPackagePatternMatch(pckPattern: string, pck: string): boolean { - const re = regEx(massagePattern(pckPattern)); - if (re.test(pck)) { - logger.trace(`${pck} matches against ${String(re)}`); - return true; - } - return false; -} diff --git a/lib/util/package-rules/package-prefixes.ts b/lib/util/package-rules/package-prefixes.ts index ef94572315..ff83d94059 100644 --- a/lib/util/package-rules/package-prefixes.ts +++ b/lib/util/package-rules/package-prefixes.ts @@ -1,13 +1,13 @@ import is from '@sindresorhus/is'; import type { PackageRule, PackageRuleInputConfig } from '../../config/types'; +import { matchRegexOrGlobList } from '../string-match'; import { Matcher } from './base'; export class PackagePrefixesMatcher extends Matcher { override matches( - { depName, packageName }: PackageRuleInputConfig, - packageRule: PackageRule, + { packageName }: PackageRuleInputConfig, + { matchPackagePrefixes }: PackageRule, ): boolean | null { - const { matchPackagePrefixes } = packageRule; if (is.undefined(matchPackagePrefixes)) { return null; } @@ -16,14 +16,10 @@ export class PackagePrefixesMatcher extends Matcher { return false; } - if ( - is.string(packageName) && - matchPackagePrefixes.some((prefix) => packageName.startsWith(prefix)) - ) { - return true; - } - - return false; + const massagedPatterns = matchPackagePrefixes.map( + (pattern) => `${pattern}**`, + ); + return matchRegexOrGlobList(packageName, massagedPatterns); } override excludes( @@ -38,13 +34,9 @@ export class PackagePrefixesMatcher extends Matcher { return false; } - if ( - is.string(packageName) && - excludePackagePrefixes.some((prefix) => packageName.startsWith(prefix)) - ) { - return true; - } - - return false; + const massagedPatterns = excludePackagePrefixes.map( + (pattern) => `${pattern}**`, + ); + return matchRegexOrGlobList(packageName, massagedPatterns); } } diff --git a/lib/util/package-rules/utils.ts b/lib/util/package-rules/utils.ts index 0a8cb830c6..2fd138eb1a 100644 --- a/lib/util/package-rules/utils.ts +++ b/lib/util/package-rules/utils.ts @@ -33,7 +33,3 @@ export function matcherOR( } return matchApplied ? false : null; } - -export function massagePattern(pattern: string): string { - return pattern === '^*$' || pattern === '*' ? '.*' : pattern; -}