Skip to content

Commit

Permalink
feat(packageRules)!: support glob/regex patterns for matchPackageNames (
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins authored Apr 23, 2024
1 parent 3e6fd6d commit cf7b4ea
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 89 deletions.
72 changes: 46 additions & 26 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -2830,10 +2830,22 @@ It is recommended that you avoid using "negative" globs, like `**/!(package.json

### matchDepNames

This field behaves the same as `matchPackageNames` except it matches against `depName` instead of `packageName`.

### matchDepPatterns

<!-- prettier-ignore -->
!!! note
`matchDepNames` now supports pattern matching and should be used instead.
Use of `matchDepPatterns` is now deprecated and will be migrated in future.

### matchDepPrefixes

<!-- prettier-ignore -->
!!! note
`matchDepNames` now supports pattern matching and should be used instead.
Use of `matchDepPrefixes` is now deprecated and will be migrated in future.

### matchNewValue

This option is matched against the `newValue` field of a dependency.
Expand Down Expand Up @@ -2870,54 +2882,68 @@ 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"
}
]
}
```

The above will configure `rangeStrategy` to `pin` only for the package `angular`.

<!-- prettier-ignore -->
!!! 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.
The above will configure `rangeStrategy` to `pin` only for the npm package `angular`.

### matchPackagePatterns
```json title="prefix match using Glob"
{
"packageRules": [
{
"matchDatasources": ["npm"],
"matchPackageNames": ["@angular/*", "!@angular/abc"],
"groupName": "Angular"
}
]
}
```

Use this field if you want to have one or more package names patterns in your package rule.
See also `excludePackagePatterns`.
The above will group together any npm package which starts with `@angular/` except `@angular/abc`.

```json
```json title="pattern match using RegEx"
{
"packageRules": [
{
"matchPackagePatterns": ["^angular"],
"rangeStrategy": "replace"
"matchDatasources": ["npm"],
"matchPackageNames": ["/^angular/"],
"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 the string `angular`.

### matchPackagePatterns

<!-- prettier-ignore -->
!!! 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

<!-- prettier-ignore -->
!!! 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`.

Expand All @@ -2934,12 +2960,6 @@ See also `excludePackagePrefixes`.

Like the earlier `matchPackagePatterns` example, the above will configure `rangeStrategy` to `replace` for any package starting with `angular`.

<!-- prettier-ignore -->
!!! 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.

### matchSourceUrlPrefixes

Here's an example of where you use this to group together all packages from the `renovatebot` GitHub org:
Expand Down
5 changes: 3 additions & 2 deletions lib/util/package-rules/dep-names.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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(
Expand All @@ -26,6 +27,6 @@ export class DepNameMatcher extends Matcher {
if (is.undefined(depName)) {
return false;
}
return excludeDepNames.includes(depName);
return matchRegexOrGlobList(depName, excludeDepNames);
}
}
48 changes: 48 additions & 0 deletions lib/util/package-rules/dep-patterns.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -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();
});
});
});
35 changes: 11 additions & 24 deletions lib/util/package-rules/dep-patterns.ts
Original file line number Diff line number Diff line change
@@ -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)) {
Expand All @@ -18,37 +16,26 @@ 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;
}
if (is.undefined(depName)) {
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);
}
}
5 changes: 3 additions & 2 deletions lib/util/package-rules/package-names.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -14,7 +15,7 @@ export class PackageNameMatcher extends Matcher {
if (!packageName) {
return false;
}
return matchPackageNames.includes(packageName);
return matchRegexOrGlobList(packageName, matchPackageNames);
}

override excludes(
Expand All @@ -28,6 +29,6 @@ export class PackageNameMatcher extends Matcher {
if (!packageName) {
return false;
}
return excludePackageNames.includes(packageName);
return matchRegexOrGlobList(packageName, excludePackageNames);
}
}
36 changes: 9 additions & 27 deletions lib/util/package-rules/package-patterns.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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(
Expand All @@ -48,15 +36,9 @@ export class PackagePatternsMatcher extends Matcher {
return false;
}

return matchPatternsAgainstName(excludePackagePatterns, packageName);
}
}

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;
const massagedPatterns = excludePackagePatterns.map((pattern) =>
pattern === '^*$' || pattern === '*' ? '*' : `/${pattern}/`,
);
return matchRegexOrGlobList(packageName, massagedPatterns);
}
return false;
}
11 changes: 7 additions & 4 deletions lib/util/package-rules/package-prefixes.ts
Original file line number Diff line number Diff line change
@@ -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 PackagePrefixesMatcher extends Matcher {
Expand All @@ -15,9 +16,10 @@ export class PackagePrefixesMatcher extends Matcher {
return false;
}

return matchPackagePrefixes.some((prefix) =>
packageName.startsWith(prefix),
const massagedPatterns = matchPackagePrefixes.map(
(pattern) => `${pattern}**`,
);
return matchRegexOrGlobList(packageName, massagedPatterns);
}

override excludes(
Expand All @@ -32,8 +34,9 @@ export class PackagePrefixesMatcher extends Matcher {
return false;
}

return excludePackagePrefixes.some((prefix) =>
packageName.startsWith(prefix),
const massagedPatterns = excludePackagePrefixes.map(
(pattern) => `${pattern}**`,
);
return matchRegexOrGlobList(packageName, massagedPatterns);
}
}
4 changes: 0 additions & 4 deletions lib/util/package-rules/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,3 @@ export function matcherOR(
}
return matchApplied ? false : null;
}

export function massagePattern(pattern: string): string {
return pattern === '^*$' || pattern === '*' ? '.*' : pattern;
}

0 comments on commit cf7b4ea

Please sign in to comment.