From a4178af2334f5f06a43ee453c4d1910f9ea2e9d4 Mon Sep 17 00:00:00 2001 From: Rhys Arkins Date: Sun, 15 Jan 2023 09:10:41 +0100 Subject: [PATCH] feat(composer): filter releases using php constraint Closes #18715 --- lib/modules/datasource/index.ts | 55 +++++++++++++++++++++++ lib/modules/datasource/packagist/index.ts | 22 ++++++++- lib/modules/manager/composer/extract.ts | 5 +++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts index dd0d5f198228cc..847671191289e8 100644 --- a/lib/modules/datasource/index.ts +++ b/lib/modules/datasource/index.ts @@ -10,6 +10,7 @@ import { regEx } from '../../util/regex'; import { trimTrailingSlash } from '../../util/url'; import * as allVersioning from '../versioning'; import datasources from './api'; +import { GithubTagsDatasource } from './github-tags'; import { addMetaData } from './metadata'; import { setNpmrc } from './npm'; import { resolveRegistryUrl } from './npm/npmrc'; @@ -415,6 +416,60 @@ export async function getPkgReleases( version.matches(constraintValue, releaseConstraint) ); }); + } else { + if (constraintName === 'php') { + const composerVersioning = allVersioning.get('composer'); + if (composerVersioning.isValid(constraintValue)) { + const lookupConfig: GetPkgReleasesConfig = { + datasource: GithubTagsDatasource.id, + depName: 'php/php-src', + extractVersion: '^php-(?\\S+)', + }; + const phpVersions = ( + await getPkgReleases(lookupConfig) + )?.releases.map((release) => release.version); + if (!phpVersions) { + logger.warn('Could not fetch php releases for compatibility check'); + return null; + } + const matchingVersions = phpVersions.filter((version) => + composerVersioning.matches(version, constraintValue) + ); + logger.debug( + `Found ${matchingVersions.length} matching php versions` + ); + if (matchingVersions.length) { + const originalReleaseCount = res.releases.length; + res.releases = res.releases.filter((release) => { + const constraint = release.constraints?.[constraintName]; + if (!is.nonEmptyArray(constraint)) { + // A release with no constraints is OK + return true; + } + return constraint.some( + // If any of the release's constraints match, then it's OK + (releaseConstraint) => { + const releaseMatchingVersions = phpVersions.filter( + (version) => + composerVersioning.matches(version, releaseConstraint) + ); + + const isMatch = matchingVersions.every((version) => + releaseMatchingVersions.includes(version) + ); + return isMatch; + } + ); + }); + const filteredReleaseCount = res.releases.length; + logger.debug( + `${filteredReleaseCount} of ${originalReleaseCount} releases have matching constraints` + ); + } + } else { + logger.warn({ constraintValue }, 'Invalid php constraint'); + } + } } } // Strip constraints from releases result diff --git a/lib/modules/datasource/packagist/index.ts b/lib/modules/datasource/packagist/index.ts index 877592193d9c4f..4df855b328bddf 100644 --- a/lib/modules/datasource/packagist/index.ts +++ b/lib/modules/datasource/packagist/index.ts @@ -102,6 +102,16 @@ export class PackagistDatasource extends Datasource { return url; } + private static minifyExpand(releases: any[]): any[] { + let expandedRelease: any; + return releases.map((release) => { + if (release.require) { + expandedRelease = release; + } + return { ...expandedRelease, ...release }; + }); + } + @cache({ namespace: `datasource-${PackagistDatasource.id}-public-files`, key: (regUrl: string, regFile: RegistryFile) => @@ -137,10 +147,16 @@ export class PackagistDatasource extends Datasource { if (release.source?.url) { dep.sourceUrl = release.source.url; } + const constraints: Record = {}; + if (release.require?.php) { + constraints.php = [release.require.php]; + } + return { version: parsedVersion.replace(regEx(/^v/), ''), gitRef: parsedVersion, releaseTimestamp: release.time, + constraints, }; }); return dep; @@ -218,8 +234,10 @@ export class PackagistDatasource extends Datasource { // TODO: fix types (#9610) let res = (await this.http.getJson(pkgUrl[0])).body.packages[name]; res = [ - ...res, - ...(await this.http.getJson(pkgUrl[1])).body.packages[name], + ...PackagistDatasource.minifyExpand(res), + ...PackagistDatasource.minifyExpand( + (await this.http.getJson(pkgUrl[1])).body.packages[name] + ), ]; if (res) { dep = PackagistDatasource.extractDepReleases(res); diff --git a/lib/modules/manager/composer/extract.ts b/lib/modules/manager/composer/extract.ts index 58978d7af275f1..31f11a0ae1f069 100644 --- a/lib/modules/manager/composer/extract.ts +++ b/lib/modules/manager/composer/extract.ts @@ -197,5 +197,10 @@ export async function extractPackageFile( }; res.managerData = managerData; } + + if (is.nonEmptyString(composerJson.require?.php)) { + res.extractedConstraints = { php: composerJson.require.php }; + } + return res; }