Skip to content
Snippets Groups Projects
Commit ad0479a1 authored by Rhys Arkins's avatar Rhys Arkins
Browse files

feat(npm): support constraintsFiltering=strict (#22447)

parent c2d3ca85
No related branches found
No related tags found
No related merge requests found
......@@ -602,11 +602,37 @@ Renovate supports two options:
- `none`: No release filtering (all releases allowed)
- `strict`: If the release's constraints match the package file constraints, then it's included
We are working on adding more advanced filtering options.
More advanced filtering options may come in future.
Note: There must be a `constraints` object in your Renovate config for this to work.
There must be a `constraints` object in your Renovate config, or constraints detected from package files, for this to work.
This feature is limited to `packagist`, `npm`, and `pypi` datasources.
<!-- prettier-ignore -->
!!! warning
Enabling this feature may result in many package updates being filtered out silently.
See below for a description of how it works.
When `constraintsFiltering=strict`, the following logic applies:
- Are there `constraints` for this repository, either detected from source or from config?
- Does this package's release declare constraints of its own (e.g. `engines` in Node.js)?
- If so, filter out this release unless the repository constraint is a _subset_ of the release constraint
Here are some examples:
| Your repo engines.node | Dependency release engines.node | Result |
| ------------------------ | ------------------------------- | -------- |
| `18` | `16 \|\| 18` | allowed |
| `^18.10.0` | `>=18` | allowed |
| `^16.10.0 \|\| >=18.0.0` | `>= 16.0.0` | allowed |
| `>=16` | `16 \|\| 18` | filtered |
| `16` | `^16.10.0` | filtered |
When using with `npm`, we recommend you:
- Use `constraintsFiltering` on `dependencies`, not `devDependencies` (usually you do not need to be strict about development dependencies)
- Do _not_ enable `rollbackPrs` at the same time (otherwise your _current_ version may be rolled back if it's incompatible)
## defaultRegistryUrls
Override a datasource's default registries with this config option.
......
......@@ -399,6 +399,7 @@ export async function getPkgReleases(
res.releases = uniq(res.releases, (x, y) => x.version === y.version);
if (config?.constraintsFiltering === 'strict') {
const filteredReleases: string[] = [];
// Filter releases for compatibility
for (const [constraintName, constraintValue] of Object.entries(
config.constraints ?? {}
......@@ -411,7 +412,7 @@ export async function getPkgReleases(
return true;
}
return constraint.some(
const satisfiesConstraints = constraint.some(
// If the constraint value is a subset of any release's constraints, then it's OK
// fallback to release's constraint match if subset is not supported by versioning
(releaseConstraint) =>
......@@ -419,9 +420,22 @@ export async function getPkgReleases(
(version.subset?.(constraintValue, releaseConstraint) ??
version.matches(constraintValue, releaseConstraint))
);
if (!satisfiesConstraints) {
filteredReleases.push(release.version);
}
return satisfiesConstraints;
});
}
}
if (filteredReleases.length) {
logger.debug(
`Filtered ${
filteredReleases.length
} releases for ${packageName} due to constraintsFiltering=strict: ${filteredReleases.join(
', '
)}`
);
}
}
// Strip constraints from releases result
res.releases.forEach((release) => {
......
......@@ -334,6 +334,9 @@ describe('modules/datasource/npm/get', () => {
type: 'git',
url: 'https://github.com/vuejs/vue-next.git',
},
engines: {
node: '>= 8.9.0',
},
},
},
'dist-tags': { latest: '2.0.0' },
......
......@@ -176,6 +176,10 @@ export async function getDependency(
if (res.versions?.[version].deprecated) {
release.isDeprecated = true;
}
const nodeConstraint = res.versions?.[version].engines?.node;
if (is.nonEmptyString(nodeConstraint)) {
release.constraints = { node: [nodeConstraint] };
}
const source = PackageSource.parse(res.versions?.[version].repository);
if (source.sourceUrl && source.sourceUrl !== dep.sourceUrl) {
release.sourceUrl = source.sourceUrl;
......
......@@ -17,6 +17,7 @@ export interface NpmResponseVersion {
gitHead?: string;
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
engines?: Record<string, string>;
}
export interface NpmResponse {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment