From 20147e30b9d004d9ffa38331e8c2d695e9af382d Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Sat, 3 Apr 2021 07:18:25 +0200 Subject: [PATCH] feat: packageRules.matchPackagePrefixes (#9365) --- docs/usage/configuration-options.md | 36 +++++++++ .../__snapshots__/validation.spec.ts.snap | 2 +- lib/config/definitions.ts | 26 ++++++ .../presets/__snapshots__/index.spec.ts.snap | 40 +++++----- lib/config/presets/index.spec.ts | 8 +- lib/config/presets/index.ts | 2 + lib/config/presets/internal/default.ts | 2 +- lib/config/presets/internal/group.ts | 80 +++++++++---------- lib/config/presets/internal/packages.ts | 21 ++--- lib/config/presets/internal/workarounds.ts | 4 +- lib/config/types.ts | 2 + lib/config/validation.ts | 2 + lib/util/package-rules.spec.ts | 17 ++++ lib/util/package-rules.ts | 26 +++++- 14 files changed, 186 insertions(+), 82 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 6e70a6897c..a8f43c2a7c 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -1276,6 +1276,24 @@ See also `matchPackagePatterns`. The above will match all package names starting with `eslint` but exclude ones starting with `eslint-foo`. +### excludePackagePrefixes + +Use this field if you want to have one or more package name prefixes excluded in your package rule, without needing to write a regex. +See also `matchPackagePrefixes`. + +```json +{ + "packageRules": [ + { + "matchPackagePrefixes": ["eslint"], + "excludePackagePrefixes": ["eslint-foo"] + } + ] +} +``` + +The above will match all package names starting with `eslint` but exclude ones starting with `eslint-foo`. + ### matchLanguages Use this field to restrict rules to a particular language. e.g. @@ -1419,6 +1437,24 @@ See also `excludePackagePatterns`. The above will configure `rangeStrategy` to `replace` for any package starting with `angular`. +### matchPackagePrefixes + +Use this field to match a package prefix without needing to write a regex expression. +See also `excludePackagePrefixes`. + +```json +{ + "packageRules": [ + { + "matchPackagePrefixes": ["angular"], + "rangeStrategy": "replace" + } + ] +} +``` + +Just like the earlier `matchPackagePatterns` example, the above will configure `rangeStrategy` to `replace` for any package starting with `angular`. + ### matchPaths Renovate will match `matchPaths` against both a partial string match or a minimatch glob pattern. diff --git a/lib/config/__snapshots__/validation.spec.ts.snap b/lib/config/__snapshots__/validation.spec.ts.snap index 0e19dfed7a..5cd68e1454 100644 --- a/lib/config/__snapshots__/validation.spec.ts.snap +++ b/lib/config/__snapshots__/validation.spec.ts.snap @@ -78,7 +78,7 @@ Array [ "topic": "Configuration Error", }, Object { - "message": "packageRules: Each packageRule must contain at least one selector (matchFiles, matchPaths, matchLanguages, matchBaseBranches, matchManagers, matchDatasources, matchDepTypes, matchPackageNames, matchPackagePatterns, excludePackageNames, excludePackagePatterns, matchCurrentVersion, matchSourceUrlPrefixes, matchUpdateTypes). If you wish for configuration to apply to all packages, it is not necessary to place it inside a packageRule at all.", + "message": "packageRules: Each packageRule must contain at least one selector (matchFiles, matchPaths, matchLanguages, matchBaseBranches, matchManagers, matchDatasources, matchDepTypes, matchPackageNames, matchPackagePatterns, matchPackagePrefixes, excludePackageNames, excludePackagePatterns, excludePackagePrefixes, matchCurrentVersion, matchSourceUrlPrefixes, matchUpdateTypes). If you wish for configuration to apply to all packages, it is not necessary to place it inside a packageRule at all.", "topic": "Configuration Error", }, Object { diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts index 0d357651a5..ecf25ed672 100644 --- a/lib/config/definitions.ts +++ b/lib/config/definitions.ts @@ -810,6 +810,32 @@ const options: RenovateOptions[] = [ cli: false, env: false, }, + { + name: 'matchPackagePrefixes', + description: + 'Package name prefixes to match. Valid only within `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parent: 'packageRules', + mergeable: true, + cli: false, + env: false, + }, + { + name: 'excludePackagePrefixes', + description: + 'Package name prefixes to exclude. Valid only within `packageRules` object.', + type: 'array', + subType: 'string', + allowString: true, + stage: 'package', + parent: 'packageRules', + mergeable: true, + cli: false, + env: false, + }, { name: 'matchPackagePatterns', description: diff --git a/lib/config/presets/__snapshots__/index.spec.ts.snap b/lib/config/presets/__snapshots__/index.spec.ts.snap index fd53ccc34d..1b661e5c00 100644 --- a/lib/config/presets/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/__snapshots__/index.spec.ts.snap @@ -379,10 +379,10 @@ Object { "matchPackageNames": Array [ "babel-eslint", ], - "matchPackagePatterns": Array [ - "^@typescript-eslint/", - "^eslint", - "^stylelint", + "matchPackagePrefixes": Array [ + "@typescript-eslint/", + "eslint", + "stylelint", ], } `; @@ -468,9 +468,9 @@ Object { "matchPackageNames": Array [ "babel-eslint", ], - "matchPackagePatterns": Array [ - "^@typescript-eslint/", - "^eslint", + "matchPackagePrefixes": Array [ + "@typescript-eslint/", + "eslint", ], } `; @@ -486,12 +486,14 @@ Object { "remark-lint", ], "matchPackagePatterns": Array [ - "^ember-template-lint", - "^@typescript-eslint/", - "^eslint", - "^stylelint", "\\\\btslint\\\\b", ], + "matchPackagePrefixes": Array [ + "ember-template-lint", + "@typescript-eslint/", + "eslint", + "stylelint", + ], } `; @@ -512,12 +514,14 @@ Object { "remark-lint", ], "matchPackagePatterns": Array [ - "^ember-template-lint", - "^@typescript-eslint/", - "^eslint", - "^stylelint", "\\\\btslint\\\\b", ], + "matchPackagePrefixes": Array [ + "ember-template-lint", + "@typescript-eslint/", + "eslint", + "stylelint", + ], }, ], } @@ -531,9 +535,9 @@ Object { "matchPackageNames": Array [ "babel-eslint", ], - "matchPackagePatterns": Array [ - "^@typescript-eslint/", - "^eslint", + "matchPackagePrefixes": Array [ + "@typescript-eslint/", + "eslint", ], }, ], diff --git a/lib/config/presets/index.spec.ts b/lib/config/presets/index.spec.ts index 59b3ff415d..42e573920a 100644 --- a/lib/config/presets/index.spec.ts +++ b/lib/config/presets/index.spec.ts @@ -176,14 +176,15 @@ describe('config/presets', () => { config.extends = ['packages:eslint']; const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); - expect(res.matchPackagePatterns).toHaveLength(2); + expect(res.matchPackagePrefixes).toHaveLength(2); }); it('resolves linters', async () => { config.extends = ['packages:linters']; const res = await presets.resolveConfigPresets(config); expect(res).toMatchSnapshot(); expect(res.matchPackageNames).toHaveLength(3); - expect(res.matchPackagePatterns).toHaveLength(5); + expect(res.matchPackagePatterns).toHaveLength(1); + expect(res.matchPackagePrefixes).toHaveLength(4); }); it('resolves nested groups', async () => { config.extends = [':automergeLinters']; @@ -192,7 +193,8 @@ describe('config/presets', () => { const rule = res.packageRules[0]; expect(rule.automerge).toBe(true); expect(rule.matchPackageNames).toHaveLength(3); - expect(rule.matchPackagePatterns).toHaveLength(5); + expect(rule.matchPackagePatterns).toHaveLength(1); + expect(rule.matchPackagePrefixes).toHaveLength(4); }); it('migrates automerge in presets', async () => { config.extends = ['ikatyang:library']; diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts index 42a4e9e18d..b3453affb2 100644 --- a/lib/config/presets/index.ts +++ b/lib/config/presets/index.ts @@ -200,6 +200,8 @@ export async function getPreset( 'excludePackageNames', 'matchPackagePatterns', 'excludePackagePatterns', + 'matchPackagePrefixes', + 'excludePackagePrefixes', ]; if (presetKeys.every((key) => packageListKeys.includes(key))) { delete presetConfig.description; diff --git a/lib/config/presets/internal/default.ts b/lib/config/presets/internal/default.ts index cfd08a1470..f07452536b 100644 --- a/lib/config/presets/internal/default.ts +++ b/lib/config/presets/internal/default.ts @@ -391,7 +391,7 @@ export const presets: Record<string, Preset> = { description: 'Update @types/* packages automatically if tests pass', packageRules: [ { - matchPackagePatterns: ['^@types/'], + matchPackagePrefixes: ['@types/'], automerge: true, }, ], diff --git a/lib/config/presets/internal/group.ts b/lib/config/presets/internal/group.ts index 2ab9dd1ed3..3f9d21d16b 100644 --- a/lib/config/presets/internal/group.ts +++ b/lib/config/presets/internal/group.ts @@ -89,7 +89,7 @@ const staticGroups = { packageRules: [ { groupName: 'definitelyTyped', - matchPackagePatterns: ['^@types/'], + matchPackagePrefixes: ['@types/'], }, ], }, @@ -98,7 +98,7 @@ const staticGroups = { packageRules: [ { matchDatasources: ['docker'], - matchPackagePatterns: ['^mcr.microsoft.com/dotnet/core/'], + matchPackagePrefixes: ['mcr.microsoft.com/dotnet/core/'], groupName: '.NET Core Docker containers', }, ], @@ -108,7 +108,7 @@ const staticGroups = { packageRules: [ { groupName: 'Font Awesome', - matchPackagePatterns: ['^@fortawesome/'], + matchPackagePrefixes: ['@fortawesome/'], }, ], }, @@ -120,11 +120,7 @@ const staticGroups = { 'fusion-test-utils', 'fusion-tokens', ], - matchPackagePatterns: [ - '^fusion-plugin-*', - '^fusion-react*', - '^fusion-apollo*', - ], + matchPackagePrefixes: ['fusion-plugin-', 'fusion-react', '^usion-apollo'], }, glimmer: { description: 'Group Glimmer.js packages together', @@ -140,7 +136,7 @@ const staticGroups = { description: 'Group PHP illuminate packages together', packageRules: [ { - matchPackagePatterns: ['^illuminate/'], + matchPackagePrefixes: ['illuminate/'], groupName: 'illuminate packages', groupSlug: 'illuminate', }, @@ -150,7 +146,7 @@ const staticGroups = { description: 'Group PHP symfony packages together', packageRules: [ { - matchPackagePatterns: ['^symfony/'], + matchPackagePrefixes: ['symfony/'], groupName: 'symfony packages', groupSlug: 'symfony', }, @@ -161,7 +157,7 @@ const staticGroups = { packageRules: [ { groupName: 'polymer packages', - matchPackagePatterns: ['^@polymer/'], + matchPackagePrefixes: ['@polymer/'], }, ], }, @@ -169,7 +165,7 @@ const staticGroups = { description: 'Group Java Hibernate Core packages', packageRules: [ { - matchPackagePatterns: ['^org.hibernate:'], + matchPackagePrefixes: ['org.hibernate:'], groupName: 'hibernate core', }, ], @@ -178,7 +174,7 @@ const staticGroups = { description: 'Group Java Hibernate Validator packages', packageRules: [ { - matchPackagePatterns: ['^org.hibernate.validator:'], + matchPackagePrefixes: ['org.hibernate.validator:'], groupName: 'hibernate validator', }, ], @@ -187,7 +183,7 @@ const staticGroups = { description: 'Group Java Hibernate OGM packages', packageRules: [ { - matchPackagePatterns: ['^org.hibernate.ogm:'], + matchPackagePrefixes: ['org.hibernate.ogm:'], groupName: 'hibernate ogm', }, ], @@ -196,7 +192,7 @@ const staticGroups = { description: 'Group Java Hibernate Commons packages', packageRules: [ { - matchPackagePatterns: ['^org.hibernate.common:'], + matchPackagePrefixes: ['org.hibernate.common:'], groupName: 'hibernate commons', }, ], @@ -205,7 +201,7 @@ const staticGroups = { description: 'Group Java Resilience4j packages', packageRules: [ { - matchPackagePatterns: ['^io.github.resilience4j:'], + matchPackagePrefixes: ['io.github.resilience4j:'], groupName: 'resilience4j', }, ], @@ -215,7 +211,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring amqp', - matchPackagePatterns: ['^org.springframework.amqp:'], + matchPackagePrefixes: ['org.springframework.amqp:'], }, ], }, @@ -224,7 +220,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring android', - matchPackagePatterns: ['^org.springframework.android:'], + matchPackagePrefixes: ['org.springframework.android:'], }, ], }, @@ -233,7 +229,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring batch', - matchPackagePatterns: ['^org.springframework.batch:'], + matchPackagePrefixes: ['org.springframework.batch:'], }, ], }, @@ -242,7 +238,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring boot', - matchPackagePatterns: ['^org.springframework.boot:'], + matchPackagePrefixes: ['org.springframework.boot:'], }, ], }, @@ -251,7 +247,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring cloud', - matchPackagePatterns: ['^org.springframework.cloud:'], + matchPackagePrefixes: ['org.springframework.cloud:'], }, ], }, @@ -260,7 +256,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring core', - matchPackagePatterns: ['^org.springframework:'], + matchPackagePrefixes: ['org.springframework:'], }, ], }, @@ -269,7 +265,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring data', - matchPackagePatterns: ['^org.springframework.data:'], + matchPackagePrefixes: ['org.springframework.data:'], }, ], }, @@ -278,7 +274,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring hateoas', - matchPackagePatterns: ['^org.springframework.hateoas:'], + matchPackagePrefixes: ['org.springframework.hateoas:'], }, ], }, @@ -287,7 +283,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring integration', - matchPackagePatterns: ['^org.springframework.integration:'], + matchPackagePrefixes: ['org.springframework.integration:'], }, ], }, @@ -296,7 +292,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring kafka', - matchPackagePatterns: ['^org.springframework.kafka:'], + matchPackagePrefixes: ['org.springframework.kafka:'], }, ], }, @@ -305,7 +301,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring ldap', - matchPackagePatterns: ['^org.springframework.ldap:'], + matchPackagePrefixes: ['org.springframework.ldap:'], }, ], }, @@ -314,7 +310,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring mobile', - matchPackagePatterns: ['^org.springframework.mobile:'], + matchPackagePrefixes: ['org.springframework.mobile:'], }, ], }, @@ -323,7 +319,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring osgi', - matchPackagePatterns: ['^org.springframework.osgi:'], + matchPackagePrefixes: ['org.springframework.osgi:'], }, ], }, @@ -332,7 +328,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring restdocs', - matchPackagePatterns: ['^org.springframework.restdocs:'], + matchPackagePrefixes: ['org.springframework.restdocs:'], }, ], }, @@ -341,7 +337,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring roo', - matchPackagePatterns: ['^org.springframework.roo:'], + matchPackagePrefixes: ['org.springframework.roo:'], }, ], }, @@ -350,7 +346,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring scala', - matchPackagePatterns: ['^org.springframework.scala:'], + matchPackagePrefixes: ['org.springframework.scala:'], }, ], }, @@ -359,7 +355,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring security', - matchPackagePatterns: ['^org.springframework.security:'], + matchPackagePrefixes: ['org.springframework.security:'], }, ], }, @@ -368,7 +364,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring session', - matchPackagePatterns: ['^org.springframework.session:'], + matchPackagePrefixes: ['org.springframework.session:'], }, ], }, @@ -377,7 +373,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring shell', - matchPackagePatterns: ['^org.springframework.shell:'], + matchPackagePrefixes: ['org.springframework.shell:'], }, ], }, @@ -386,7 +382,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring social', - matchPackagePatterns: ['^org.springframework.social:'], + matchPackagePrefixes: ['org.springframework.social:'], }, ], }, @@ -395,7 +391,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring statemachine', - matchPackagePatterns: ['^org.springframework.statemachine:'], + matchPackagePrefixes: ['org.springframework.statemachine:'], }, ], }, @@ -404,7 +400,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring webflow', - matchPackagePatterns: ['^org.springframework.webflow:'], + matchPackagePrefixes: ['org.springframework.webflow:'], }, ], }, @@ -413,7 +409,7 @@ const staticGroups = { packageRules: [ { groupName: 'spring ws', - matchPackagePatterns: ['^org.springframework.ws:'], + matchPackagePrefixes: ['org.springframework.ws:'], }, ], }, @@ -422,7 +418,7 @@ const staticGroups = { packageRules: [ { groupName: 'socket.io packages', - matchPackagePatterns: ['^socket.io'], + matchPackagePrefixes: ['socket.io'], }, ], }, @@ -452,7 +448,7 @@ const staticGroups = { packageRules: [ { matchDatasources: ['rubygems'], - matchPackagePatterns: ['^omniauth'], + matchPackagePrefixes: ['omniauth'], groupName: 'omniauth packages', }, ], @@ -464,7 +460,7 @@ const staticGroups = { matchDatasources: ['go'], groupName: 'go-openapi packages', groupSlug: 'go-openapi', - matchPackagePatterns: ['^github.com/go-openapi/'], + matchPackagePrefixes: ['github.com/go-openapi/'], }, ], }, diff --git a/lib/config/presets/internal/packages.ts b/lib/config/presets/internal/packages.ts index 9a3a27bb6f..7828a52d9f 100644 --- a/lib/config/presets/internal/packages.ts +++ b/lib/config/presets/internal/packages.ts @@ -16,20 +16,20 @@ export const presets: Record<string, Preset> = { }, mapbox: { description: 'All mapbox-related packages', - matchPackagePatterns: ['^(leaflet|mapbox)'], + matchPackagePrefixes: ['leaflet', 'mapbox'], }, emberTemplateLint: { description: 'All ember-template-lint packages', - matchPackagePatterns: ['^ember-template-lint'], + matchPackagePrefixes: ['ember-template-lint'], }, eslint: { description: 'All eslint packages', matchPackageNames: ['babel-eslint'], - matchPackagePatterns: ['^@typescript-eslint/', '^eslint'], + matchPackagePrefixes: ['@typescript-eslint/', 'eslint'], }, stylelint: { description: 'All stylelint packages', - matchPackagePatterns: ['^stylelint'], + matchPackagePrefixes: ['stylelint'], }, tslint: { description: 'All tslint packages', @@ -49,7 +49,7 @@ export const presets: Record<string, Preset> = { postcss: { description: 'All postcss packages', matchPackageNames: ['postcss'], - matchPackagePatterns: ['^postcss-'], + matchPackagePrefixes: ['postcss-'], }, jsUnitTest: { description: 'Unit test packages for javascript', @@ -65,14 +65,7 @@ export const presets: Record<string, Preset> = { 'proxyquire', 'supertest', ], - matchPackagePatterns: [ - '^chai', - '^jest', - '^mocha', - '^qunit', - '^sinon', - '^should', - ], + matchPackagePrefixes: ['chai', 'jest', 'mocha', 'qunit', 'sinon', 'should'], }, unitTest: { description: 'All unit test packages', @@ -93,6 +86,6 @@ export const presets: Record<string, Preset> = { googleapis: { matchDatasources: ['npm'], description: 'All googleapis packages', - matchPackagePatterns: ['^@google-cloud/'], + matchPackagePrefixes: ['@google-cloud/'], }, }; diff --git a/lib/config/presets/internal/workarounds.ts b/lib/config/presets/internal/workarounds.ts index 8cf6d33c0b..64f276438d 100644 --- a/lib/config/presets/internal/workarounds.ts +++ b/lib/config/presets/internal/workarounds.ts @@ -15,7 +15,7 @@ export const presets: Record<string, Preset> = { packageRules: [ { matchDatasources: ['maven', 'sbt-package'], - matchPackagePatterns: ['^commons-'], + matchPackagePrefixes: ['commons-'], allowedVersions: '!/^200\\d{5}(\\.\\d+)?/', }, ], @@ -37,7 +37,7 @@ export const presets: Record<string, Preset> = { packageRules: [ { matchManagers: ['sbt'], - matchPackagePatterns: ['^org\\.http4s:'], + matchPackagePrefixes: ['org.http4s:'], allowedVersions: `!/^1\\.0-\\d+-[a-fA-F0-9]{7}$/`, }, ], diff --git a/lib/config/types.ts b/lib/config/types.ts index befd58f74b..f98003293e 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -232,8 +232,10 @@ export interface PackageRule matchDepTypes?: string[]; matchPackageNames?: string[]; matchPackagePatterns?: string[]; + matchPackagePrefixes?: string[]; excludePackageNames?: string[]; excludePackagePatterns?: string[]; + excludePackagePrefixes?: string[]; matchCurrentVersion?: string | Range; matchSourceUrlPrefixes?: string[]; matchUpdateTypes?: UpdateType[]; diff --git a/lib/config/validation.ts b/lib/config/validation.ts index 55eda48f10..8bfd0b6955 100644 --- a/lib/config/validation.ts +++ b/lib/config/validation.ts @@ -228,8 +228,10 @@ export async function validateConfig( 'matchDepTypes', 'matchPackageNames', 'matchPackagePatterns', + 'matchPackagePrefixes', 'excludePackageNames', 'excludePackagePatterns', + 'excludePackagePrefixes', 'matchCurrentVersion', 'matchSourceUrlPrefixes', 'matchUpdateTypes', diff --git a/lib/util/package-rules.spec.ts b/lib/util/package-rules.spec.ts index 258388085f..23c7522002 100644 --- a/lib/util/package-rules.spec.ts +++ b/lib/util/package-rules.spec.ts @@ -19,6 +19,8 @@ describe('applyPackageRules()', () => { packageRules: [ { matchPackageNames: ['a', 'b'], + matchPackagePrefixes: ['xyz/'], + excludePackagePrefixes: ['xyz/foo'], x: 2, }, { @@ -85,6 +87,21 @@ describe('applyPackageRules()', () => { expect(res.x).toBeUndefined(); expect(res.y).toBe(2); }); + it('applies matchPackagePrefixes', () => { + const dep = { + depName: 'xyz/abc', + }; + const res = applyPackageRules({ ...config1, ...dep }); + expect(res.x).toBe(2); + expect(res.y).toBe(2); + }); + it('applies excludePackagePrefixes', () => { + const dep = { + depName: 'xyz/foo-a', + }; + const res = applyPackageRules({ ...config1, ...dep }); + expect(res.x).toBeUndefined(); + }); it('applies the second second rule', () => { const dep = { depName: 'bc', diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts index 2307452978..0d366ba942 100644 --- a/lib/util/package-rules.ts +++ b/lib/util/package-rules.ts @@ -53,8 +53,10 @@ function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { const matchDepTypes = packageRule.matchDepTypes || []; const matchPackageNames = packageRule.matchPackageNames || []; let matchPackagePatterns = packageRule.matchPackagePatterns || []; + const matchPackagePrefixes = packageRule.matchPackagePrefixes || []; const excludePackageNames = packageRule.excludePackageNames || []; const excludePackagePatterns = packageRule.excludePackagePatterns || []; + const excludePackagePrefixes = packageRule.excludePackagePrefixes || []; const matchSourceUrlPrefixes = packageRule.matchSourceUrlPrefixes || []; const matchCurrentVersion = packageRule.matchCurrentVersion || null; const matchUpdateTypes = packageRule.matchUpdateTypes || []; @@ -132,7 +134,12 @@ function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { } positiveMatch = true; } - if (depName && (matchPackageNames.length || matchPackagePatterns.length)) { + if ( + depName && + (matchPackageNames.length || + matchPackagePatterns.length || + matchPackagePrefixes.length) + ) { let isMatch = matchPackageNames.includes(depName); // name match is "or" so we check patterns if we didn't match names if (!isMatch) { @@ -148,6 +155,12 @@ function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { } } } + // prefix match is also "or" + if (!isMatch && matchPackagePrefixes.length) { + isMatch = matchPackagePrefixes.some((prefix) => + depName.startsWith(prefix) + ); + } if (!isMatch) { return false; } @@ -176,6 +189,15 @@ function matchesRule(inputConfig: Config, packageRule: PackageRule): boolean { } positiveMatch = true; } + if (depName && excludePackagePrefixes.length) { + const isMatch = excludePackagePrefixes.some((prefix) => + depName.startsWith(prefix) + ); + if (isMatch) { + return false; + } + positiveMatch = true; + } if (matchSourceUrlPrefixes.length) { const isMatch = matchSourceUrlPrefixes.some((prefix) => sourceUrl?.startsWith(prefix) @@ -248,8 +270,10 @@ export function applyPackageRules<T extends Config>(inputConfig: T): T { config = mergeChildConfig(config, packageRule); delete config.matchPackageNames; delete config.matchPackagePatterns; + delete config.matchPackagePrefixes; delete config.excludePackageNames; delete config.excludePackagePatterns; + delete config.excludePackagePrefixes; delete config.matchDepTypes; delete config.matchCurrentVersion; } -- GitLab