Skip to content

Commit

Permalink
feat: extractVersion (#7307)
Browse files Browse the repository at this point in the history
Adds a new option extractVersion which allows for extracting a substring of raw versions from datasources, to be used as the actual version.

Closes #7297, Closes #6793
  • Loading branch information
rarkins committed Sep 17, 2020
1 parent 0115ae7 commit 62bc649
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 0 deletions.
45 changes: 45 additions & 0 deletions docs/usage/configuration-options.md
Expand Up @@ -387,6 +387,51 @@ The above would mean Renovate would not include files matching the above glob pa

See [shareable config presets](https://docs.renovatebot.com/config-presets) for details.

## extractVersion

Use this only when the raw version strings from the datasource do not match the expected format that you need in your package file. You must defined a "named capture group" called `version` as shown in the below examples.

For example, to extract only the major.minor precision from a GitHub release, the following would work:

```json
{
"packageRules": [
{
"packageNames": ["foo"],
"extractVersion": "^(?<version>v\\d+\\.\\d+)"
}
]
}
```

The above will change a raw version of `v1.31.5` to `v1.31`, for example.

Alternatively, to strip a `release-` prefix:

```json
{
"packageRules": [
{
"packageNames": ["bar"],
"extractVersion": "^release-(?<version>.*)$"
}
]
}
```

The above will change a raw version of `release-2.0.0` to `2.0.0`, for example. A similar one could strip leading `v` prefixes:

```json
{
"packageRules": [
{
"packageNames": ["baz"],
"extractVersion": "^v(?<version>.*)$"
}
]
}
```

## fileMatch

`fileMatch` is used by Renovate to know which files in a repository to parse and extract, and it is possible to override defaults values to customize for your project's needs.
Expand Down
9 changes: 9 additions & 0 deletions lib/config/definitions.ts
Expand Up @@ -704,6 +704,15 @@ const options: RenovateOptions[] = [
cli: false,
env: false,
},
{
name: 'extractVersion',
description:
"A regex (re2) to extract a version from a datasource's raw version string",
type: 'string',
format: 'regex',
cli: false,
env: false,
},
{
name: 'versioning',
description: 'versioning to use for filtering and comparisons',
Expand Down
1 change: 1 addition & 0 deletions lib/datasource/common.ts
Expand Up @@ -25,6 +25,7 @@ export interface GetPkgReleasesConfig extends ReleasesConfigBase {
depName: string;
lookupName?: string;
versioning?: string;
extractVersion?: string;
}

export function isGetPkgReleasesConfig(
Expand Down
17 changes: 17 additions & 0 deletions lib/datasource/index.spec.ts
Expand Up @@ -102,6 +102,23 @@ describe('datasource/index', () => {
expect(res.changelogUrl).toBeDefined();
expect(res.sourceUrl).toBeDefined();
});
it('applies extractVersion', async () => {
npmDatasource.getReleases.mockResolvedValue({
releases: [
{ version: 'v1.0.0' },
{ version: 'v1.0.1' },
{ version: 'v2' },
],
});
const res = await datasource.getPkgReleases({
datasource: datasourceNpm.id,
depName: 'react-native',
extractVersion: '^(?<version>v\\d+\\.\\d+)',
versioning: 'loose',
});
expect(res.releases).toHaveLength(1);
expect(res.releases[0].version).toEqual('v1.0');
});
it('adds sourceUrl', async () => {
npmDatasource.getReleases.mockResolvedValue({
releases: [{ version: '1.0.0' }],
Expand Down
21 changes: 21 additions & 0 deletions lib/datasource/index.ts
Expand Up @@ -5,6 +5,7 @@ import { logger } from '../logger';
import { ExternalHostError } from '../types/errors/external-host-error';
import * as memCache from '../util/cache/memory';
import { clone } from '../util/clone';
import { regEx } from '../util/regex';
import * as allVersioning from '../versioning';
import datasources from './api.generated';
import {
Expand Down Expand Up @@ -259,6 +260,19 @@ export async function getPkgReleases(
if (!res) {
return res;
}
if (config.extractVersion) {
const extractVersionRegEx = regEx(config.extractVersion);
res.releases = res.releases
.map((release) => {
const version = extractVersionRegEx.exec(release.version)?.groups
?.version;
if (version) {
return { ...release, version }; // overwrite version
}
return null; // filter out any we can't extract
})
.filter(Boolean);
}
// Filter by versioning
const version = allVersioning.get(config.versioning);
// Return a sorted list of valid Versions
Expand All @@ -270,6 +284,13 @@ export async function getPkgReleases(
.filter((release) => version.isVersion(release.version))
.sort(sortReleases);
}
// Filter versions for uniqueness
res.releases = res.releases.filter(
(filterRelease, filterIndex) =>
res.releases.findIndex(
(findRelease) => findRelease.version === filterRelease.version
) === filterIndex
);
return res;
}

Expand Down

0 comments on commit 62bc649

Please sign in to comment.