Skip to content

Commit

Permalink
feat: support allowedVersions regular expressions (#5979)
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins committed Apr 15, 2020
1 parent 6dea8e9 commit 4104ba0
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 1 deletion.
26 changes: 26 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,32 @@ Use this - usually within a packageRule - to limit how far to upgrade a dependen
}
```

This field also supports Regular Expressions if they begin and end with `/`. For example, the following will enforce that only 3 or 4-section versions are supported, without any prefixes:

```json
{
"packageRules": [
{
"packageNames": ["com.thoughtworks.xstream:xstream"],
"allowedVersions": "/^[0-9]+\\.[0-9]+\\.[0-9]+(\\.[0-9]+)?$/"
}
]
}
```

This field also supports a special negated regex syntax for ignoring certain versions. Use the syntax `!/ /` like the following:

```json
{
"packageRules": [
{
"packageNames": ["chalk"],
"allowedVersions": "!/java$/"
}
]
}
```

### depTypeList

Use this field if you want to limit a `packageRule` to certain `depType` values. Invalid if used outside of a `packageRule`.
Expand Down
13 changes: 13 additions & 0 deletions lib/config/__snapshots__/validation.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`config/validation validateConfig(config) catches invalid allowedVersions regex 1`] = `
Array [
Object {
"depName": "Configuration Error",
"message": "Invalid regExp for packageRules[1].allowedVersions: \`/***$}{]][/\`",
},
Object {
"depName": "Configuration Error",
"message": "Invalid regExp for packageRules[3].allowedVersions: \`!/***$}{]][/\`",
},
]
`;

exports[`config/validation validateConfig(config) catches invalid templates 1`] = `
Array [
Object {
Expand Down
25 changes: 25 additions & 0 deletions lib/config/validation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@ describe('config/validation', () => {
expect(errors).toHaveLength(1);
expect(errors).toMatchSnapshot();
});
it('catches invalid allowedVersions regex', async () => {
const config = {
packageRules: [
{
packageNames: ['foo'],
allowedVersions: '/^2/',
},
{
packageNames: ['bar'],
allowedVersions: '/***$}{]][/',
},
{
packageNames: ['baz'],
allowedVersions: '!/^2/',
},
{
packageNames: ['quack'],
allowedVersions: '!/***$}{]][/',
},
],
};
const { errors } = await configValidation.validateConfig(config);
expect(errors).toHaveLength(2);
expect(errors).toMatchSnapshot();
});
it('returns nested errors', async () => {
const config: RenovateConfig = {
foo: 1,
Expand Down
30 changes: 30 additions & 0 deletions lib/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,36 @@ export async function validateConfig(
message: `Invalid ${currentPath}: \`${errorMessage}\``,
});
}
} else if (
key === 'allowedVersions' &&
is.string(val) &&
val.length > 1 &&
val.startsWith('/') &&
val.endsWith('/')
) {
try {
regEx(val.slice(1, -1));
} catch (err) {
errors.push({
depName: 'Configuration Error',
message: `Invalid regExp for ${currentPath}: \`${val}\``,
});
}
} else if (
key === 'allowedVersions' &&
is.string(val) &&
val.length > 2 &&
val.startsWith('!/') &&
val.endsWith('/')
) {
try {
regEx(val.slice(2, -1));
} catch (err) {
errors.push({
depName: 'Configuration Error',
message: `Invalid regExp for ${currentPath}: \`${val}\``,
});
}
} else if (key === 'timezone' && val !== null) {
const [validTimezone, errorMessage] = hasValidTimezone(val as string);
if (!validTimezone) {
Expand Down
25 changes: 24 additions & 1 deletion lib/workers/repository/process/lookup/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as allVersioning from '../../../../versioning';
import { Release } from '../../../../datasource';
import { CONFIG_VALIDATION } from '../../../../constants/error-messages';
import * as npmVersioning from '../../../../versioning/npm';
import { regEx } from '../../../../util/regex';

export interface FilterConfig {
allowedVersions?: string;
Expand All @@ -15,6 +16,8 @@ export interface FilterConfig {
versioning: string;
}

const regexes: Record<string, RegExp> = {};

export function filterVersions(
config: FilterConfig,
fromVersion: string,
Expand Down Expand Up @@ -57,7 +60,27 @@ export function filterVersions(
}

if (allowedVersions) {
if (version.isValid(allowedVersions)) {
if (
allowedVersions.length > 1 &&
allowedVersions.startsWith('/') &&
allowedVersions.endsWith('/')
) {
regexes[allowedVersions] =
regexes[allowedVersions] || regEx(allowedVersions.slice(1, -1));
filteredVersions = filteredVersions.filter((v) =>
regexes[allowedVersions].test(v)
);
} else if (
allowedVersions.length > 2 &&
allowedVersions.startsWith('!/') &&
allowedVersions.endsWith('/')
) {
regexes[allowedVersions] =
regexes[allowedVersions] || regEx(allowedVersions.slice(2, -1));
filteredVersions = filteredVersions.filter(
(v) => !regexes[allowedVersions].test(v)
);
} else if (version.isValid(allowedVersions)) {
filteredVersions = filteredVersions.filter((v) =>
version.matches(v, allowedVersions)
);
Expand Down
16 changes: 16 additions & 0 deletions lib/workers/repository/process/lookup/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ describe('workers/repository/process/lookup', () => {
nock('https://registry.npmjs.org').get('/q').reply(200, qJson);
expect((await lookup.lookupUpdates(config)).updates).toHaveLength(1);
});
it('enforces allowedVersions with regex', async () => {
config.currentValue = '0.4.0';
config.allowedVersions = '/^0/';
config.depName = 'q';
config.datasource = datasourceNpm.id;
nock('https://registry.npmjs.org').get('/q').reply(200, qJson);
expect((await lookup.lookupUpdates(config)).updates).toHaveLength(1);
});
it('enforces allowedVersions with negativee regex', async () => {
config.currentValue = '0.4.0';
config.allowedVersions = '!/^1/';
config.depName = 'q';
config.datasource = datasourceNpm.id;
nock('https://registry.npmjs.org').get('/q').reply(200, qJson);
expect((await lookup.lookupUpdates(config)).updates).toHaveLength(1);
});
it('falls back to semver syntax allowedVersions', async () => {
config.currentValue = '0.4.0';
config.allowedVersions = '<1';
Expand Down

0 comments on commit 4104ba0

Please sign in to comment.