diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts index 43de52583e779fc93c838e8f39d59d0eecec527c..a5448742d0aa9fc05c1250a52cdda1e6eea0ac46 100644 --- a/lib/datasource/api.ts +++ b/lib/datasource/api.ts @@ -4,6 +4,7 @@ import { AwsMachineImageDataSource } from './aws-machine-image'; import { BitBucketTagsDatasource } from './bitbucket-tags'; import { CdnJsDatasource } from './cdnjs'; import { ClojureDatasource } from './clojure'; +import { ConanDatasource } from './conan'; import { CrateDatasource } from './crate'; import { DartDatasource } from './dart'; import * as docker from './docker'; @@ -48,6 +49,7 @@ api.set(AwsMachineImageDataSource.id, new AwsMachineImageDataSource()); api.set('bitbucket-tags', new BitBucketTagsDatasource()); api.set('cdnjs', new CdnJsDatasource()); api.set('clojure', new ClojureDatasource()); +api.set(ConanDatasource.id, new ConanDatasource()); api.set('crate', new CrateDatasource()); api.set('dart', new DartDatasource()); api.set('docker', docker); diff --git a/lib/datasource/conan/__fixtures__/fake.json b/lib/datasource/conan/__fixtures__/fake.json new file mode 100644 index 0000000000000000000000000000000000000000..be9d4f096c737dcf01ed588e01fac0d10846471f --- /dev/null +++ b/lib/datasource/conan/__fixtures__/fake.json @@ -0,0 +1,3 @@ +{ + "results" : [ ] +} diff --git a/lib/datasource/conan/__fixtures__/malformed.json b/lib/datasource/conan/__fixtures__/malformed.json new file mode 100644 index 0000000000000000000000000000000000000000..5c5d2a7d8e890ab011a14f875131a676ad547abf --- /dev/null +++ b/lib/datasource/conan/__fixtures__/malformed.json @@ -0,0 +1,3 @@ +{ + "results" : [ "bad/@conan/stable", "bad/1.3", "bad/1.8.1@conan", "bad/1.9.3@_/_", "bad1.20.3@_/_" ] +} diff --git a/lib/datasource/conan/__fixtures__/poco.json b/lib/datasource/conan/__fixtures__/poco.json new file mode 100644 index 0000000000000000000000000000000000000000..064057f4890f86a5dcf3fcb1ac573669f0f20fe8 --- /dev/null +++ b/lib/datasource/conan/__fixtures__/poco.json @@ -0,0 +1,3 @@ +{ + "results" : [ "poco/1.10.0@_/_", "poco/1.10.1@_/_", "poco/1.8.1@_/_", "poco/1.9.3@_/_", "poco/1.9.4@_/_" ] +} diff --git a/lib/datasource/conan/common.ts b/lib/datasource/conan/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ba8bb6061ee20692b36f228a47880a1c9199e41 --- /dev/null +++ b/lib/datasource/conan/common.ts @@ -0,0 +1,10 @@ +import { regEx } from '../../util/regex'; + +export const defaultRegistryUrl = 'https://center.conan.io/'; + +export const datasource = 'conan'; + +export const conanDatasourceRegex = regEx( + /(?<name>[a-z\-_0-9]+)\/(?<version>[^@/\n]+)(?<userChannel>@\S+\/\S+)/, + 'gim' +); diff --git a/lib/datasource/conan/index.spec.ts b/lib/datasource/conan/index.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0faf02ce47d0154d754a6894b52b9a73e88c63f --- /dev/null +++ b/lib/datasource/conan/index.spec.ts @@ -0,0 +1,182 @@ +import { getPkgReleases } from '..'; +import { Fixtures } from '../../../test/fixtures'; +import * as httpMock from '../../../test/http-mock'; +import * as conan from '../../versioning/conan'; +import type { GetPkgReleasesConfig } from '../types'; +import { defaultRegistryUrl } from './common'; +import { ConanDatasource } from '.'; + +const pocoJson = Fixtures.get('poco.json'); +const malformedJson = Fixtures.get('malformed.json'); +const fakeJson = Fixtures.get('fake.json'); +const datasource = ConanDatasource.id; + +const config: GetPkgReleasesConfig = { + depName: '', + datasource, + versioning: conan.id, + registryUrls: [defaultRegistryUrl], +}; + +describe('datasource/conan/index', () => { + beforeEach(() => { + config.registryUrls = [defaultRegistryUrl]; + }); + + describe('getReleases', () => { + it('handles bad return', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=fakepackage') + .reply(200, null); + config.depName = 'fakepackage'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'fakepackage/1.2@_/_', + }) + ).toBeNull(); + }); + + it('handles empty return', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=fakepackage') + .reply(200, {}); + config.depName = 'fakepackage'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'fakepackage/1.2@_/_', + }) + ).toBeNull(); + }); + + it('handles bad registries', async () => { + httpMock + .scope('https://fake.bintray.com/') + .get('/v2/conans/search?q=poco') + .reply(404); + config.registryUrls = ['https://fake.bintray.com/']; + config.depName = 'poco'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'poco/1.2@_/_', + }) + ).toBeNull(); + }); + + it('handles missing packages', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=fakepackage') + .reply(200, fakeJson); + config.depName = 'fakepackage'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'fakepackage/1.2@_/_', + }) + ).toBeNull(); + }); + + it('processes real versioned data', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=poco') + .reply(200, pocoJson); + config.depName = 'poco'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'poco/1.2@_/_', + }) + ).toEqual({ + registryUrl: 'https://center.conan.io', + releases: [ + { + version: '1.8.1', + }, + { + version: '1.9.3', + }, + { + version: '1.9.4', + }, + { + version: '1.10.0', + }, + { + version: '1.10.1', + }, + ], + }); + }); + + it('it handles mismatched userAndChannel versioned data', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=poco') + .reply(200, pocoJson); + config.depName = 'poco'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'poco/1.2@un/matched', + }) + ).toBeNull(); + }); + + it('handles malformed packages', async () => { + httpMock + .scope(defaultRegistryUrl) + .get('/v2/conans/search?q=bad') + .reply(200, malformedJson); + config.depName = 'bad'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'bad/1.2@_/_', + }) + ).toEqual({ + registryUrl: 'https://center.conan.io', + releases: [ + { + version: '1.9.3', + }, + ], + }); + }); + + it('handles non 404 errors', async () => { + httpMock + .scope('https://fake.bintray.com/') + .get('/v2/conans/search?q=poco') + .replyWithError('error'); + config.registryUrls = ['https://fake.bintray.com/']; + config.depName = 'poco'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'poco/1.2@_/_', + }) + ).toBeNull(); + }); + + it('handles missing slash on registries', async () => { + httpMock + .scope('https://fake.bintray.com/') + .get('/v2/conans/search?q=poco') + .reply(200, fakeJson); + config.registryUrls = ['https://fake.bintray.com']; + config.depName = 'poco'; + expect( + await getPkgReleases({ + ...config, + lookupName: 'poco/1.2@_/_', + }) + ).toBeNull(); + }); + }); +}); diff --git a/lib/datasource/conan/index.ts b/lib/datasource/conan/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ca85f878cb12288bd6246d54d8e3c1672f316f31 --- /dev/null +++ b/lib/datasource/conan/index.ts @@ -0,0 +1,67 @@ +import { logger } from '../../logger'; +import { cache } from '../../util/cache/package/decorator'; +import { ensureTrailingSlash, joinUrlParts } from '../../util/url'; +import { Datasource } from '../datasource'; +import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; +import { conanDatasourceRegex, datasource, defaultRegistryUrl } from './common'; +import type { ConanJSON } from './types'; + +export class ConanDatasource extends Datasource { + static readonly id = datasource; + + override readonly defaultRegistryUrls = [defaultRegistryUrl]; + + override readonly caching = true; + + override readonly registryStrategy = 'merge'; + + constructor() { + super(ConanDatasource.id); + } + + @cache({ + namespace: `datasource-${datasource}`, + key: ({ registryUrl, lookupName }: GetReleasesConfig) => + `${registryUrl}:${lookupName}`, + }) + async getReleases({ + registryUrl, + lookupName, + }: GetReleasesConfig): Promise<ReleaseResult | null> { + const depName = lookupName.split('/')[0]; + const userAndChannel = '@' + lookupName.split('@')[1]; + + logger.trace({ depName, registryUrl }, 'Looking up conan api dependency'); + if (registryUrl) { + const url = ensureTrailingSlash(registryUrl); + const lookupUrl = joinUrlParts(url, `v2/conans/search?q=${depName}`); + + try { + const rep = await this.http.getJson<ConanJSON>(lookupUrl); + const versions = rep?.body; + if (versions) { + logger.trace({ lookupUrl }, 'Got conan api result'); + const dep: ReleaseResult = { releases: [] }; + + for (const resultString of Object.values(versions.results || {})) { + const fromMatch = conanDatasourceRegex.exec(resultString); + if (fromMatch?.groups?.version && fromMatch?.groups?.userChannel) { + const version = fromMatch.groups.version; + if (fromMatch.groups.userChannel === userAndChannel) { + const result: Release = { + version, + }; + dep.releases.push(result); + } + } + } + return dep; + } + } catch (err) { + this.handleGenericErrors(err); + } + } + + return null; + } +} diff --git a/lib/datasource/conan/types.ts b/lib/datasource/conan/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..b062195a3e57a5c02271195563b3900179306475 --- /dev/null +++ b/lib/datasource/conan/types.ts @@ -0,0 +1,3 @@ +export interface ConanJSON { + results?: Record<string, string>; +} diff --git a/lib/manager/api.ts b/lib/manager/api.ts index 109301ab1e16b763eebd796a1c5ff396cd7a7f46..76fad55f08a9088063d4097785025a803f0900eb 100644 --- a/lib/manager/api.ts +++ b/lib/manager/api.ts @@ -15,6 +15,7 @@ import * as circleci from './circleci'; import * as cloudbuild from './cloudbuild'; import * as cocoapods from './cocoapods'; import * as composer from './composer'; +import * as conan from './conan'; import * as depsEdn from './deps-edn'; import * as dockerCompose from './docker-compose'; import * as dockerfile from './dockerfile'; @@ -86,6 +87,7 @@ api.set('circleci', circleci); api.set('cloudbuild', cloudbuild); api.set('cocoapods', cocoapods); api.set('composer', composer); +api.set('conan', conan); api.set('deps-edn', depsEdn); api.set('docker-compose', dockerCompose); api.set('dockerfile', dockerfile); diff --git a/lib/manager/conan/__fixtures__/conanfile.py b/lib/manager/conan/__fixtures__/conanfile.py new file mode 100644 index 0000000000000000000000000000000000000000..b1cfdb5f902910f257f54e5c0aa4ea99a2857c00 --- /dev/null +++ b/lib/manager/conan/__fixtures__/conanfile.py @@ -0,0 +1,27 @@ +from conans import ConanFile + +class Pkg(ConanFile): + python_requires = "pyreq/0.1@user/channel" # recipe to reuse code from + build_requires = "tool_a/0.2@user/testing", "tool_b/0.2@user/testing" + requires = "req_a/1.0", "req_l/2.1@otheruser/testing" + + requires = [("req_b/0.1@user/testing"), + ("req_d/0.2@dummy/stable", "override"), + ("req_e/2.1@coder/beta", "private")] + + requires = (("req_c/1.0@user/stable", "private"), ) + requires = ("req_f/1.0@user/stable", ("req_h/3.0@other/beta", "override")) + requires = "req_g/[>1.0 <1.8]@user/stable" + + +def requirements(self): + if self.options.myoption: + self.requires("req_i/1.2@drl/testing") + else: + self.requires("req_i/2.2@drl/stable") + self.requires("req_k/1.2@drl/testing", private=True, override=False) + + +def build_requirements(self): + if self.settings.os == "Windows": + self.build_requires("tool_win/0.1@user/stable") diff --git a/lib/manager/conan/__fixtures__/conanfile.txt b/lib/manager/conan/__fixtures__/conanfile.txt new file mode 100644 index 0000000000000000000000000000000000000000..e06417f57dd93bdc8a9cf5c8a9bfff220d7f85d0 --- /dev/null +++ b/lib/manager/conan/__fixtures__/conanfile.txt @@ -0,0 +1,30 @@ +[requires] +poco/1.9.4 +zlib/[~1.2.3, loose=False] +fake/8.62.134@test/dev + +[build_requires] +7zip/[>1.1 <2.1, include_prerelease=True] +curl/[~1.2.3, loose=False, include_prerelease=True]@test/dev +boost/[>1.1 <2.1] +catch2/[2.8] +openssl/[~=3.0]@test/prod +cmake/[>1.1 || 0.8] +cryptopp/[1.2.7 || >=1.2.9 <2.0.0]@test/local +#commentedout/1.2 +# commentedout/3.4 + +[generators] +xcode +cmake +qmake + +[options] +poco:shared=True +openssl:shared=True + +# A comment + +[imports] +bin, *.dll -> ./bin # Copies all dll files from packages bin folder to my local "bin" folder +lib, *.dylib* -> ./bin # Copies all dylib files from packages lib folder to my local "bin" folder \ No newline at end of file diff --git a/lib/manager/conan/__fixtures__/conanfile2.txt b/lib/manager/conan/__fixtures__/conanfile2.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8e88c919169ab2575134c7a99f1c8756cb4a836 --- /dev/null +++ b/lib/manager/conan/__fixtures__/conanfile2.txt @@ -0,0 +1,10 @@ +[generators] +xcode +cmake +qmake + +[options] +poco:shared=True +openssl:shared=True + +# A comment diff --git a/lib/manager/conan/extract.spec.ts b/lib/manager/conan/extract.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..1aad1e2ba9a39744f933ab52fa61bbfb733dc368 --- /dev/null +++ b/lib/manager/conan/extract.spec.ts @@ -0,0 +1,212 @@ +import { Fixtures } from '../../../test/fixtures'; +import { extractPackageFile } from '.'; + +const conanfile1 = Fixtures.get('conanfile.txt'); +const conanfile2 = Fixtures.get('conanfile2.txt'); +const conanfile3 = Fixtures.get('conanfile.py'); + +describe('manager/conan/extract', () => { + describe('extractPackageFile', () => { + it('returns null for empty', () => { + expect(extractPackageFile('nothing here')).toBeNull(); + }); + it('extracts multiple image lines from conanfile.txt', () => { + const res = extractPackageFile(conanfile1); + expect(res?.deps).toEqual([ + { + currentValue: '1.9.4', + depName: 'poco', + depType: 'requires', + lookupName: 'poco/1.9.4@_/_', + replaceString: 'poco/1.9.4', + }, + { + currentValue: '[~1.2.3, loose=False]', + depName: 'zlib', + depType: 'requires', + lookupName: 'zlib/[~1.2.3, loose=False]@_/_', + replaceString: 'zlib/[~1.2.3, loose=False]', + }, + { + currentValue: '8.62.134', + depName: 'fake', + depType: 'requires', + lookupName: 'fake/8.62.134@test/dev', + replaceString: 'fake/8.62.134@test/dev', + }, + { + currentValue: '[>1.1 <2.1, include_prerelease=True]', + depName: '7zip', + depType: 'build_requires', + lookupName: '7zip/[>1.1 <2.1, include_prerelease=True]@_/_', + replaceString: '7zip/[>1.1 <2.1, include_prerelease=True]', + }, + { + currentValue: '[~1.2.3, loose=False, include_prerelease=True]', + depName: 'curl', + depType: 'build_requires', + lookupName: + 'curl/[~1.2.3, loose=False, include_prerelease=True]@test/dev', + replaceString: + 'curl/[~1.2.3, loose=False, include_prerelease=True]@test/dev', + }, + { + currentValue: '[>1.1 <2.1]', + depName: 'boost', + depType: 'build_requires', + lookupName: 'boost/[>1.1 <2.1]@_/_', + replaceString: 'boost/[>1.1 <2.1]', + }, + { + currentValue: '[2.8]', + depName: 'catch2', + depType: 'build_requires', + lookupName: 'catch2/[2.8]@_/_', + replaceString: 'catch2/[2.8]', + }, + { + currentValue: '[~=3.0]', + depName: 'openssl', + depType: 'build_requires', + lookupName: 'openssl/[~=3.0]@test/prod', + replaceString: 'openssl/[~=3.0]@test/prod', + }, + { + currentValue: '[>1.1 || 0.8]', + depName: 'cmake', + depType: 'build_requires', + lookupName: 'cmake/[>1.1 || 0.8]@_/_', + replaceString: 'cmake/[>1.1 || 0.8]', + }, + { + currentValue: '[1.2.7 || >=1.2.9 <2.0.0]', + depName: 'cryptopp', + depType: 'build_requires', + lookupName: 'cryptopp/[1.2.7 || >=1.2.9 <2.0.0]@test/local', + replaceString: 'cryptopp/[1.2.7 || >=1.2.9 <2.0.0]@test/local', + }, + ]); + }); + it('extracts multiple 0 lines from conanfile.txt', () => { + const res = extractPackageFile(conanfile2); + expect(res).toBeNull(); + }); + it('extracts multiple image lines from conanfile.py', () => { + const res = extractPackageFile(conanfile3); + expect(res?.deps).toEqual([ + { + currentValue: '0.1', + depName: 'pyreq', + depType: 'python_requires', + lookupName: 'pyreq/0.1@user/channel', + replaceString: 'pyreq/0.1@user/channel', + }, + { + currentValue: '0.2', + depName: 'tool_a', + depType: 'build_requires', + lookupName: 'tool_a/0.2@user/testing', + replaceString: 'tool_a/0.2@user/testing', + }, + { + currentValue: '0.2', + depName: 'tool_b', + depType: 'build_requires', + lookupName: 'tool_b/0.2@user/testing', + replaceString: 'tool_b/0.2@user/testing', + }, + { + currentValue: '1.0', + depName: 'req_a', + depType: 'requires', + lookupName: 'req_a/1.0@_/_', + replaceString: 'req_a/1.0', + }, + { + currentValue: '2.1', + depName: 'req_l', + depType: 'requires', + lookupName: 'req_l/2.1@otheruser/testing', + replaceString: 'req_l/2.1@otheruser/testing', + }, + { + currentValue: '0.1', + depName: 'req_b', + depType: 'requires', + lookupName: 'req_b/0.1@user/testing', + replaceString: 'req_b/0.1@user/testing', + }, + { + currentValue: '0.2', + depName: 'req_d', + depType: 'requires', + lookupName: 'req_d/0.2@dummy/stable', + replaceString: 'req_d/0.2@dummy/stable', + }, + { + currentValue: '2.1', + depName: 'req_e', + depType: 'requires', + lookupName: 'req_e/2.1@coder/beta', + replaceString: 'req_e/2.1@coder/beta', + }, + { + currentValue: '1.0', + depName: 'req_c', + depType: 'requires', + lookupName: 'req_c/1.0@user/stable', + replaceString: 'req_c/1.0@user/stable', + }, + { + currentValue: '1.0', + depName: 'req_f', + depType: 'requires', + lookupName: 'req_f/1.0@user/stable', + replaceString: 'req_f/1.0@user/stable', + }, + { + currentValue: '3.0', + depName: 'req_h', + depType: 'requires', + lookupName: 'req_h/3.0@other/beta', + replaceString: 'req_h/3.0@other/beta', + }, + { + currentValue: '[>1.0 <1.8]', + depName: 'req_g', + depType: 'requires', + lookupName: 'req_g/[>1.0 <1.8]@user/stable', + replaceString: 'req_g/[>1.0 <1.8]@user/stable', + }, + { + currentValue: '1.2', + depName: 'req_i', + depType: 'requires', + lookupName: 'req_i/1.2@drl/testing', + replaceString: 'req_i/1.2@drl/testing', + }, + { + currentValue: '2.2', + depName: 'req_i', + depType: 'requires', + lookupName: 'req_i/2.2@drl/stable', + replaceString: 'req_i/2.2@drl/stable', + }, + { + currentValue: '1.2', + depName: 'req_k', + depType: 'requires', + lookupName: 'req_k/1.2@drl/testing', + replaceString: 'req_k/1.2@drl/testing', + }, + { + currentValue: '0.1', + depName: 'tool_win', + depType: 'build_requires', + lookupName: 'tool_win/0.1@user/stable', + replaceString: 'tool_win/0.1@user/stable', + }, + ]); + }); + }); +}); diff --git a/lib/manager/conan/extract.ts b/lib/manager/conan/extract.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0f2eb5c1bedd9dd5dc3c42be12019090643f7cd --- /dev/null +++ b/lib/manager/conan/extract.ts @@ -0,0 +1,75 @@ +import is from '@sindresorhus/is'; +import { regEx } from '../../util/regex'; +import type { PackageDependency, PackageFile } from '../types'; + +const regex = regEx( + `(?<name>[-_a-z0-9]+)/(?<version>[^@\n{*"']+)(?<userChannel>@[-_a-zA-Z0-9]+/[^\n.{*"' ]+)?` +); + +function setDepType(content: string, originalType: string): string { + let depType = originalType; + if (content.includes('python_requires')) { + depType = 'python_requires'; + } else if (content.includes('build_require')) { + depType = 'build_requires'; + } else if (content.includes('requires')) { + depType = 'requires'; + } + return depType; +} + +export function extractPackageFile(content: string): PackageFile | null { + // only process sections where requirements are defined + const sections = content.split(/def |\n\[/).filter( + (part) => + part.includes('python_requires') || // only matches python_requires + part.includes('build_require') || // matches [build_requires], build_requirements(), and build_requires + part.includes('require') // matches [requires], requirements(), and requires + ); + + const deps: PackageDependency[] = []; + for (const section of sections) { + let depType = setDepType(section, 'requires'); + const rawLines = section.split('\n').filter(is.nonEmptyString); + + for (const rawline of rawLines) { + // don't process after a comment + const sanitizedLine = rawline.split('#')[0].split('//')[0]; + if (sanitizedLine) { + depType = setDepType(sanitizedLine, depType); + // extract all dependencies from each line + const lines = sanitizedLine.split(/["'],/); + for (const line of lines) { + const matches = regex.exec(line.trim()); + if (matches?.groups) { + let dep: PackageDependency = {}; + const depName = matches.groups?.name; + const currentValue = matches.groups?.version.trim(); + + let replaceString = `${depName}/${currentValue}`; + // conan uses @_/_ as a placeholder for no userChannel + let userAndChannel = '@_/_'; + + if (matches.groups.userChannel) { + userAndChannel = matches.groups.userChannel; + replaceString = `${depName}/${currentValue}${userAndChannel}`; + } + const lookupName = `${depName}/${currentValue}${userAndChannel}`; + + dep = { + ...dep, + depName, + lookupName, + currentValue, + replaceString, + depType, + }; + deps.push(dep); + } + } + } + } + } + + return deps.length ? { deps } : null; +} diff --git a/lib/manager/conan/index.ts b/lib/manager/conan/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..80d820ef1a02b87edb39885e057cf8dfdd2b672f --- /dev/null +++ b/lib/manager/conan/index.ts @@ -0,0 +1,12 @@ +export { extractPackageFile } from './extract'; +import { ConanDatasource } from '../../datasource/conan'; +import * as conan from '../../versioning/conan'; + +export const defaultConfig = { + fileMatch: ['(^|/)conanfile\\.(txt|py)$'], + datasource: ConanDatasource.id, + versioning: conan.id, + rangeStrategy: 'bump', +}; + +export const supportedDatasources = [ConanDatasource.id]; diff --git a/lib/manager/conan/readme.md b/lib/manager/conan/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..a2d109bffc6f69b51b8d685b7b53eeb6bd0b6bc8 --- /dev/null +++ b/lib/manager/conan/readme.md @@ -0,0 +1,17 @@ +Automated dependency updates for Conan + +Renovate can upgrade dependencies in `conanfile.txt` or `conanfile.py` files. + +How it works: + +1. Renovate searches in each repository for any `conanfile.txt` or `conanfile.py` file +1. Renovate extracts existing dependencies from: + - the `[requires]` and `[build_requires]` sections in the `conanfile.txt` format + - the `requirements()` and `build_requirements()` functions in the `conanfile.py` format + - and the `python_requires`, `requires` and `build_requires` variables in the `conanfile.py` format +1. Renovate resolves the dependency's version using the Conan v2 API +1. If Renovate finds an update, Renovate will update `conanfile.txt` or `conanfile.py` + +Enabling Conan updating + +Renovate updates Conan packages by default. diff --git a/lib/versioning/api.ts b/lib/versioning/api.ts index 932441370655fa578be24e800614bff2e52dea8f..a76a544750e28a466c581fefeccc06ccffde9ed5 100644 --- a/lib/versioning/api.ts +++ b/lib/versioning/api.ts @@ -1,6 +1,7 @@ import * as amazonMachineImage from './aws-machine-image'; import * as cargo from './cargo'; import * as composer from './composer'; +import * as conan from './conan'; import * as docker from './docker'; import * as git from './git'; import * as gradle from './gradle'; @@ -30,6 +31,7 @@ export default api; api.set(amazonMachineImage.id, amazonMachineImage.api); api.set('cargo', cargo.api); api.set('composer', composer.api); +api.set('conan', conan.api); api.set('docker', docker.api); api.set('git', git.api); api.set('gradle', gradle.api); diff --git a/lib/versioning/conan/common.ts b/lib/versioning/conan/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6009901a16133093deeae0c9b403ef41c143092 --- /dev/null +++ b/lib/versioning/conan/common.ts @@ -0,0 +1,108 @@ +import * as semver from 'semver'; +import { regEx } from '../../util/regex'; + +export function makeVersion( + version: string, + options: semver.Options +): string | boolean | null { + const splitVersion = version.split('.'); + const prerelease = semver.prerelease(version, options); + + if (prerelease && !options.includePrerelease) { + if (!Number.isNaN(parseInt(prerelease.toString()[0], 10))) { + const stringVersion = `${splitVersion[0]}.${splitVersion[1]}.${splitVersion[2]}`; + return semver.valid(stringVersion, options); + } + return false; + } + + if ( + options.loose && + !semver.valid(version, options) && + splitVersion.length !== 3 + ) { + return semver.valid(semver.coerce(version, options), options); + } + return semver.valid(version, options); +} + +export function cleanVersion(version: string): string { + if (version) { + return version + .replace(regEx(/,|\[|\]|"|include_prerelease=|loose=|True|False/g), '') + .trim(); + } + return version; +} + +export function getOptions(input: string): { + loose: boolean; + includePrerelease: boolean; +} { + let includePrerelease = false; + let loose = true; + if (input) { + includePrerelease = + input.includes('include_prerelease=True') && + !input.includes('include_prerelease=False'); + loose = input.includes('loose=True') || !input.includes('loose=False'); + } + return { loose, includePrerelease }; +} + +export function containsOperators(input: string): boolean { + return regEx('[<=>^~]').test(input); +} + +export function matchesWithOptions( + version: string, + cleanRange: string, + options: semver.Options +): boolean { + let cleanedVersion = version; + if ( + cleanedVersion && + semver.prerelease(cleanedVersion) && + options.includePrerelease + ) { + const coercedVersion = semver.coerce(cleanedVersion)?.raw; + cleanedVersion = coercedVersion ? coercedVersion : ''; + } + return semver.satisfies(cleanedVersion, cleanRange, options); +} + +export function findSatisfyingVersion( + versions: string[], + range: string, + compareRt: number +): string | null { + const options = getOptions(range); + let cur: any = null; + let curSV: any = null; + let index = 0; + let curIndex = -1; + + for (const v of versions) { + const versionFromList = makeVersion(v, options); + if (typeof versionFromList === 'string') { + const cleanedVersion = cleanVersion(versionFromList); + const options = getOptions(range); + const cleanRange = cleanVersion(range); + if (matchesWithOptions(cleanedVersion, cleanRange, options)) { + if ( + !cur || + semver.compare(curSV, versionFromList, options) === compareRt + ) { + cur = versionFromList; + curIndex = index; + curSV = new semver.SemVer(cur, options); + } + } + } + index += 1; + } + if (curIndex >= 0) { + return versions[curIndex]; + } + return null; +} diff --git a/lib/versioning/conan/index.spec.ts b/lib/versioning/conan/index.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..51926b987f4c8eb9983af2bf826b9ccc1f5ccc1e --- /dev/null +++ b/lib/versioning/conan/index.spec.ts @@ -0,0 +1,907 @@ +import { api as conan } from '.'; + +describe('versioning/conan/index', () => { + // isValid(version: string): boolean; + test.each` + version | result + ${'[1.2.3.4, loose=False]'} | ${false} + ${'[NOT VALID, loose=False]'} | ${false} + ${'[1.2, loose=False]'} | ${true} + ${'[1.a.2, loose=False]'} | ${false} + ${'[Infinity.NaN.Infinity, loose=False]'} | ${false} + ${'1.2.3.4'} | ${true} + ${'NOT VALID'} | ${false} + ${'1.2'} | ${true} + ${'1.a.2'} | ${false} + ${''} | ${true} + ${'Infinity.NaN.Infinity'} | ${false} + ${'17.04.0'} | ${true} + ${'1.2.3'} | ${true} + ${'1.2.3-foo'} | ${true} + ${'[>1.1 <2.0]'} | ${true} + ${'1.2.3foo'} | ${true} + ${'[~1.2.3]'} | ${true} + ${'[^1.2.3]'} | ${true} + ${'1.x'} | ${true} + ${'[>1.2.3]'} | ${true} + ${'[>1.1 <2.1]'} | ${true} + ${'[~=3.0]'} | ${true} + ${'[>1.1 || 0.8]'} | ${true} + ${'[1.2.7 || >=1.2.9 <2.0.0]'} | ${true} + ${'[>1.1 <2.1, include_prerelease=True]'} | ${true} + ${'[~1.2.3, loose=False]'} | ${true} + ${'[~1.2.3, loose=False, include_prerelease=True]'} | ${true} + ${'renovatebot/renovate'} | ${false} + ${'renovatebot/renovate#main'} | ${false} + ${'https://github.com/renovatebot/renovate.git'} | ${false} + ${'[>=01.02.03]'} | ${true} + ${'[~1.02.03beta]'} | ${true} + ${'[">1.0.0 <1.0.2", loose=False, include_prerelease=True]'} | ${true} + ${'[1.0.0 - 2.0.0, loose=False]'} | ${true} + ${'[1.0.0, loose=False]'} | ${true} + ${'[>=*, loose=False]'} | ${true} + ${'[, loose=False]'} | ${true} + ${'[*, loose=False]'} | ${true} + ${'[>=1.0.0, loose=False]'} | ${true} + ${'[>1.0.0, loose=False]'} | ${true} + ${'[<=2.0.0, loose=False]'} | ${true} + ${'[1, loose=False]'} | ${true} + ${'[<=2.0.0, loose=False]'} | ${true} + ${'[<=2.0.0, loose=False]'} | ${true} + ${'[<2.0.0, loose=False]'} | ${true} + ${'[<2.0.0, loose=False]'} | ${true} + ${'[>= 1.0.0, loose=False]'} | ${true} + ${'[>= 1.0.0, loose=False]'} | ${true} + ${'[>= 1.0.0, loose=False]'} | ${true} + ${'[> 1.0.0, loose=False]'} | ${true} + ${'[> 1.0.0, loose=False]'} | ${true} + ${'[<= 2.0.0, loose=False]'} | ${true} + ${'[<= 2.0.0, loose=False]'} | ${true} + ${'[<= 2.0.0, loose=False]'} | ${true} + ${'[< 2.0.0, loose=False]'} | ${true} + ${'[< 2.0.0, loose=False]'} | ${true} + ${'[>=0.1.97, loose=False]'} | ${true} + ${'[>=0.1.97, loose=False]'} | ${true} + ${'[0.1.20 || 1.2.4, loose=False]'} | ${true} + ${'[>=0.2.3 || <0.0.1, loose=False]'} | ${true} + ${'[>=0.2.3 || <0.0.1, loose=False]'} | ${true} + ${'[>=0.2.3 || <0.0.1, loose=False]'} | ${true} + ${'[||, loose=False]'} | ${true} + ${'[2.x.x, loose=False]'} | ${true} + ${'[1.2.x, loose=False]'} | ${true} + ${'[1.2.x || 2.x, loose=False]'} | ${true} + ${'[1.2.x || 2.x, loose=False]'} | ${true} + ${'[x, loose=False]'} | ${true} + ${'[2.*.*, loose=False]'} | ${true} + ${'[1.2.*, loose=False]'} | ${true} + ${'[1.2.* || 2.*, loose=False]'} | ${true} + ${'[*, loose=False]'} | ${true} + ${'[2, loose=False]'} | ${true} + ${'[2.3, loose=False]'} | ${true} + ${'[~2.4, loose=False]'} | ${true} + ${'[~>3.2.1, loose=False]'} | ${true} + ${'[~1, loose=False]'} | ${true} + ${'[~>1, loose=False]'} | ${true} + ${'[~> 1, loose=False]'} | ${true} + ${'[~1.0, loose=False]'} | ${true} + ${'[~ 1.0, loose=False]'} | ${true} + ${'[^0, loose=False]'} | ${true} + ${'[^ 1, loose=False]'} | ${true} + ${'[^0.1, loose=False]'} | ${true} + ${'[^1.0, loose=False]'} | ${true} + ${'[^1.2, loose=False]'} | ${true} + ${'[^0.0.1, loose=False]'} | ${true} + ${'[^0.0.1-beta, loose=False]'} | ${true} + ${'[^0.1.2, loose=False]'} | ${true} + ${'[^1.2.3, loose=False]'} | ${true} + ${'[^1.2.3-beta.4, loose=False]'} | ${true} + ${'[<1, loose=False]'} | ${true} + ${'[< 1, loose=False]'} | ${true} + ${'[>=1, loose=False]'} | ${true} + ${'[>= 1, loose=False]'} | ${true} + ${'[<1.2, loose=False]'} | ${true} + ${'[< 1.2, loose=False]'} | ${true} + ${'[1, loose=False]'} | ${true} + ${'[>01.02.03, loose=True]'} | ${true} + ${'[>01.02.03, loose=False]'} | ${false} + ${'[~1.2.3beta, loose=True]'} | ${true} + ${'[~1.2.3beta, loose=False]'} | ${false} + ${'[^ 1.2 ^ 1, loose=False]'} | ${true} + `('isValid("$version") === $result', ({ version, result }) => { + const res = conan.isValid(version); + expect(res).toBe(result); + }); + + // isVersion(version: string): boolean; + // isSingleVersion(version: string): boolean; + test.each` + version | result + ${'1.0.7-prerelease.1'} | ${true} + ${'1.0.7-prerelease.1, include_prerelease=True'} | ${true} + ${'NOT VALID, loose=False'} | ${false} + ${'NOT VALID'} | ${false} + ${'1.a.2, loose=False'} | ${false} + ${'1.a.2'} | ${true} + ${null} | ${false} + ${'1.2, loose=False'} | ${false} + ${'1.2'} | ${true} + ${'1.2.3.4, loose=False'} | ${false} + ${'1.2.3.4'} | ${true} + ${'1.2.23.4'} | ${true} + ${'4.1.3-pre, include_prerelease=True'} | ${true} + ${'X.2, loose=False'} | ${false} + ${'X.2'} | ${true} + ${'Infinity.NaN.Infinity, loose=False'} | ${false} + ${'Infinity.NaN.Infinity'} | ${false} + ${'1.2.3'} | ${true} + ${'"1.2.3", loose=False'} | ${true} + ${'"1.2.3", loose=False, include_prerelease=True'} | ${true} + ${'"1.2.3", include_prerelease=True'} | ${true} + ${'1.2.3-alpha.1'} | ${true} + ${'"1.2.3-alpha.1", include_prerelease=True'} | ${true} + ${'"1.2.6-pre.1", include_prerelease=True'} | ${true} + ${'"1.2.3-dev.1+abc", include_prerelease=True'} | ${true} + ${'1.2.3-dev.1+abc'} | ${true} + ${'1.2.6-pre.1'} | ${true} + ${'=1.2.3'} | ${true} + ${'= 1.2.3'} | ${true} + ${'1.x'} | ${true} + ${'"1.x", loose=False'} | ${false} + ${'01.02.03'} | ${true} + ${'1.2.3-beta.01, include_prerelease=True'} | ${true} + ${' =1.2.3'} | ${true} + ${'1.2.3foo, include_prerelease=True'} | ${true} + ${'5.0.20210712-T1759Z+b563c1478'} | ${true} + ${'0.2'} | ${true} + ${'16.00'} | ${true} + `('isVersion("$version") === $result', ({ version, result }) => { + const res = conan.isVersion(version); + expect(res).toBe(result); + }); + + // isCompatible(version: string, range?: string): boolean; + test.each` + range | version | result + ${'[>1.1 <2.0]'} | ${'1.2.3'} | ${true} + ${'["~1.2.3", loose=False, include_prerelease=True]'} | ${'1.2.3-pre.1'} | ${false} + ${'["1.0.0 - 2.0.0", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["^1.2.3+build", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["^1.2.3+build", loose=False, include_prerelease=False]'} | ${'1.3.0'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3pre+asdf - 2.4.3-pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3pre+asdf - 2.4.3pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3-pre.2'} | ${false} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'2.4.3-alpha'} | ${false} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">=*", loose=False, include_prerelease=False]'} | ${'0.2.4'} | ${true} + ${'["", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'["*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["*", loose=True, include_prerelease=False]'} | ${'v1.2.3'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=True]'} | ${'1.0.1-pre.1'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'2.0.0'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'["<2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["> 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'["> 1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'2.0.0'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'["< 2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<\t2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'[">=0.1.97", loose=True, include_prerelease=False]'} | ${'v0.1.97'} | ${true} + ${'[">=0.1.97", loose=False, include_prerelease=False]'} | ${'0.1.97'} | ${true} + ${'["0.1.20 || 1.2.4", loose=False, include_prerelease=False]'} | ${'1.2.4'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.0.0'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.2.3'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.2.4'} | ${true} + ${'["||", loose=False, include_prerelease=False]'} | ${'1.3.4'} | ${true} + ${'["2.x.x", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.x || 2.x", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.x || 2.x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["2.*.*", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.* || 2.*", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.* || 2.*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["2", loose=False, include_prerelease=False]'} | ${'2.1.2'} | ${true} + ${'["2.3", loose=False, include_prerelease=False]'} | ${'2.3.1'} | ${true} + ${'["~x", loose=False, include_prerelease=False]'} | ${'0.0.9'} | ${true} + ${'["~2", loose=False, include_prerelease=False]'} | ${'2.0.9'} | ${true} + ${'["~2.4", loose=False, include_prerelease=False]'} | ${'2.4.0'} | ${true} + ${'["~2.4", loose=False, include_prerelease=False]'} | ${'2.4.5'} | ${true} + ${'["~>3.2.1", loose=False, include_prerelease=False]'} | ${'3.2.2'} | ${true} + ${'["~1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~>1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~> 1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.0", loose=False, include_prerelease=False]'} | ${'1.0.2'} | ${true} + ${'["~ 1.0", loose=False, include_prerelease=False]'} | ${'1.0.2'} | ${true} + ${'[">=1", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">= 1", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'["<1.2", loose=False, include_prerelease=False]'} | ${'1.1.1'} | ${true} + ${'["< 1.2", loose=False, include_prerelease=False]'} | ${'1.1.1'} | ${true} + ${'["~v0.5.4-pre", loose=False, include_prerelease=False]'} | ${'0.5.5'} | ${true} + ${'["~v0.5.4-pre", loose=False, include_prerelease=False]'} | ${'0.5.4'} | ${true} + ${'["=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'["<=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'[">=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'["<=0.7.x", loose=False, include_prerelease=False]'} | ${'0.6.2'} | ${true} + ${'["~1.2.1 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 =1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 >=1.2.3 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">1.1.0 <2.0.0", include_prerelease=True]'} | ${'1.2.3-dev.1+abc'} | ${true} + ${'["~ 1.0.3", loose=False, include_prerelease=False]'} | ${'1.0.12'} | ${true} + ${'[">=1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3 >=1.2.1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2.3 >=1.2.1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2.1 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2", loose=False, include_prerelease=False]'} | ${'1.2.8'} | ${true} + ${'["^1.2.3", loose=False, include_prerelease=False]'} | ${'1.8.1'} | ${true} + ${'["^0.1.2", loose=False, include_prerelease=False]'} | ${'0.1.2'} | ${true} + ${'["^0.1", loose=False, include_prerelease=False]'} | ${'0.1.2'} | ${true} + ${'["^0.0.1", loose=False, include_prerelease=False]'} | ${'0.0.1'} | ${true} + ${'["^1.2", loose=False, include_prerelease=False]'} | ${'1.4.2'} | ${true} + ${'["^1.2 ^1", loose=False, include_prerelease=False]'} | ${'1.4.2'} | ${true} + ${'["^1.2.3-alpha", loose=False, include_prerelease=False]'} | ${'1.2.3-pre'} | ${false} + ${'["^1.2.3-alpha", loose=False, include_prerelease=True]'} | ${'1.2.4-pre'} | ${true} + ${'["^1.2.0-alpha", loose=False, include_prerelease=False]'} | ${'"1.2.0-pre'} | ${false} + ${'["^0.0.1-alpha", loose=False, include_prerelease=False]'} | ${'0.0.1-beta'} | ${false} + ${'["^0.1.1-alpha", loose=False, include_prerelease=False]'} | ${'"0.1.1-beta'} | ${false} + ${'["^x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["x - 1.0.0", loose=False, include_prerelease=False]'} | ${'0.9.7'} | ${true} + ${'["x - 1.x", loose=False, include_prerelease=False]'} | ${'0.9.7'} | ${true} + ${'["1.0.0 - x", loose=False, include_prerelease=False]'} | ${'1.9.7'} | ${true} + ${'["1.x - x", loose=False, include_prerelease=False]'} | ${'1.9.7'} | ${true} + ${'["<=7.x", loose=False, include_prerelease=False]'} | ${'7.9.9'} | ${true} + ${'[>1.1.0 <2.0.0]'} | ${'1.2.3-dev.1+abc'} | ${false} + ${'[">1.0.0 <1.0.2", loose=False, include_prerelease=True]'} | ${'1.0.2-beta'} | ${true} + ${'[">1.1.0 <2.0.0", include_prerelease=False]'} | ${'1.2.3-dev.1+abc'} | ${false} + ${'["1.0.0 - 2.0.0", loose=False]'} | ${'2.2.3'} | ${true} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False]'} | ${'1.2.3-pre.2'} | ${false} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False]'} | ${'2.4.3-alpha'} | ${false} + ${'["^1.2.3+build", loose=False]'} | ${'2.0.0'} | ${true} + ${'["^1.2.3+build", loose=False]'} | ${'1.2.0'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.3-pre'} | ${false} + ${'["^1.2", loose=False]'} | ${'1.2.0-pre'} | ${false} + ${'[">1.2", loose=False]'} | ${'1.3.0-beta'} | ${false} + ${'["<=1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["=0.7.x", loose=False]'} | ${'0.7.0-asdf'} | ${false} + ${'[">=0.7.x", loose=False]'} | ${'0.7.0-asdf'} | ${false} + ${'["1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["<1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["< 1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["1.0.0", loose=False]'} | ${'1.0.1'} | ${true} + ${'[">=1.0.0", loose=False]'} | ${'0.0.0'} | ${false} + ${'[">=1.0.0", loose=False]'} | ${'0.0.1'} | ${false} + ${'[">=1.0.0", loose=False]'} | ${'0.1.0'} | ${false} + ${'[">1.0.0", loose=False]'} | ${'0.0.1'} | ${false} + ${'[">1.0.0", loose=False]'} | ${'0.1.0'} | ${false} + ${'["<=2.0.0", loose=False]'} | ${'3.0.0'} | ${true} + ${'["<=2.0.0", loose=False]'} | ${'2.9999.9999'} | ${true} + ${'["<=2.0.0", loose=False]'} | ${'2.2.9'} | ${true} + ${'["<2.0.0", loose=False]'} | ${'2.9999.9999'} | ${true} + ${'["<2.0.0", loose=False]'} | ${'2.2.9'} | ${true} + ${'[">=0.1.97", loose=True]'} | ${'v0.1.93'} | ${false} + ${'[">=0.1.97", loose=False]'} | ${'0.1.93'} | ${false} + ${'["0.1.20 || 1.2.4", loose=False]'} | ${'1.2.3'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False]'} | ${'0.0.3'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False]'} | ${'0.2.2'} | ${true} + ${'["2.x.x", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.x.x", loose=False]'} | ${'3.1.3'} | ${true} + ${'["1.2.x", loose=False]'} | ${'1.3.3'} | ${true} + ${'["1.2.x || 2.x", loose=False]'} | ${'3.1.3'} | ${true} + ${'["1.2.x || 2.x", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.*.*", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.*.*", loose=False]'} | ${'3.1.3'} | ${true} + ${'["1.2.*", loose=False]'} | ${'1.3.3'} | ${true} + ${'["1.2.* || 2.*", loose=False]'} | ${'3.1.3'} | ${true} + ${'["1.2.* || 2.*", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2", loose=False]'} | ${'1.1.2'} | ${false} + ${'["2.3", loose=False]'} | ${'2.4.1'} | ${true} + ${'["~2.4", loose=False]'} | ${'2.5.0'} | ${true} + ${'["~2.4", loose=False]'} | ${'2.3.9'} | ${false} + ${'["~>3.2.1", loose=False]'} | ${'3.3.2'} | ${true} + ${'["~>3.2.1", loose=False]'} | ${'3.2.0'} | ${false} + ${'["~1", loose=False]'} | ${'0.2.3'} | ${false} + ${'["~>1", loose=False]'} | ${'2.2.3'} | ${true} + ${'["~1.0", loose=False]'} | ${'1.1.0'} | ${true} + ${'["<1", loose=False]'} | ${'1.0.0'} | ${true} + ${'[">=1.2", loose=False]'} | ${'1.1.1'} | ${false} + ${'["1", loose=True]'} | ${'2.0.0beta'} | ${false} + ${'["~v0.5.4-beta", loose=False]'} | ${'0.5.4-alpha'} | ${false} + ${'["=0.7.x", loose=False]'} | ${'0.8.2'} | ${true} + ${'[">=0.7.x", loose=False]'} | ${'0.6.2'} | ${false} + ${'["<0.7.x", loose=False]'} | ${'0.7.2'} | ${true} + ${'["<1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["=1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'[">1.2", loose=False]'} | ${'1.2.8'} | ${false} + ${'["^0.0.1", loose=False]'} | ${'0.0.2'} | ${true} + ${'["^1.2.3", loose=False]'} | ${'2.0.0-alpha'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.2'} | ${false} + ${'["^1.2", loose=False]'} | ${'1.1.9'} | ${false} + ${'["*", loose=True]'} | ${'v1.2.3-foo'} | ${false} + ${'["blerg", loose=False]'} | ${'1.2.3'} | ${true} + ${'["git+https: #user:password0123@github.com/foo", loose=True]'} | ${'123.0.0'} | ${true} + ${'["^1.2.3", loose=False]'} | ${'2.0.0-pre'} | ${false} + ${'[~=1.18]'} | ${'1.20.0'} | ${true} + ${'[0.2.0]'} | ${'0.3.0'} | ${true} + ${'[~8.4.0, loose=False]'} | ${'8.5.0'} | ${true} + ${'[~=1.0 include_prerelease=True]'} | ${'1.21.2'} | ${true} + ${'1.0.7'} | ${'1.21.2'} | ${true} + ${'16.00'} | ${'19.00'} | ${true} + `( + 'isCompatible("$version", "$range") === $result', + ({ version, range, result }) => { + const res = !!conan.isCompatible(version, range); + expect(res).toBe(result); + } + ); + + // matches(version: string, range: string | Range): string | boolean | null; + test.each` + range | version | result + ${'[>1.1 <2.0]'} | ${'1.2.3'} | ${true} + ${'["~1.2.3", loose=False, include_prerelease=True]'} | ${'1.2.3-pre.1'} | ${true} + ${'["1.0.0 - 2.0.0", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["^1.2.3+build", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["^1.2.3+build", loose=False, include_prerelease=False]'} | ${'1.3.0'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3pre+asdf - 2.4.3-pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3pre+asdf - 2.4.3pre+asdf", loose=True, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3-pre.2'} | ${true} + ${'["1.2.3-pre+asdf - 2.4.3-pre+asdf", loose=False, include_prerelease=False]'} | ${'2.4.3-alpha'} | ${true} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">=*", loose=False, include_prerelease=False]'} | ${'0.2.4'} | ${true} + ${'["", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'["*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["*", loose=True, include_prerelease=False]'} | ${'v1.2.3'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">=1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=True]'} | ${'1.0.1-pre.1'} | ${true} + ${'[">1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'2.0.0'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<=2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'["<2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'[">= 1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["> 1.0.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} | ${true} + ${'["> 1.0.0", loose=False, include_prerelease=False]'} | ${'1.1.0'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'2.0.0'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<= 2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'["< 2.0.0", loose=False, include_prerelease=False]'} | ${'1.9999.9999'} | ${true} + ${'["<\t2.0.0", loose=False, include_prerelease=False]'} | ${'0.2.9'} | ${true} + ${'[">=0.1.97", loose=True, include_prerelease=False]'} | ${'v0.1.97'} | ${true} + ${'[">=0.1.97", loose=False, include_prerelease=False]'} | ${'0.1.97'} | ${true} + ${'["0.1.20 || 1.2.4", loose=False, include_prerelease=False]'} | ${'1.2.4'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.0.0'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.2.3'} | ${true} + ${'[">=0.2.3 || <0.0.1", loose=False, include_prerelease=False]'} | ${'0.2.4'} | ${true} + ${'["||", loose=False, include_prerelease=False]'} | ${'1.3.4'} | ${true} + ${'["2.x.x", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.x || 2.x", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.x || 2.x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["2.*.*", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.* || 2.*", loose=False, include_prerelease=False]'} | ${'2.1.3'} | ${true} + ${'["1.2.* || 2.*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["*", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["2", loose=False, include_prerelease=False]'} | ${'2.1.2'} | ${true} + ${'["2.3", loose=False, include_prerelease=False]'} | ${'2.3.1'} | ${true} + ${'["~x", loose=False, include_prerelease=False]'} | ${'0.0.9'} | ${true} + ${'["~2", loose=False, include_prerelease=False]'} | ${'2.0.9'} | ${true} + ${'["~2.4", loose=False, include_prerelease=False]'} | ${'2.4.0'} | ${true} + ${'["~2.4", loose=False, include_prerelease=False]'} | ${'2.4.5'} | ${true} + ${'["~>3.2.1", loose=False, include_prerelease=False]'} | ${'3.2.2'} | ${true} + ${'["~1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~>1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~> 1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.0", loose=False, include_prerelease=False]'} | ${'1.0.2'} | ${true} + ${'["~ 1.0", loose=False, include_prerelease=False]'} | ${'1.0.2'} | ${true} + ${'[">=1", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'[">= 1", loose=False, include_prerelease=False]'} | ${'1.0.0'} | ${true} + ${'["<1.2", loose=False, include_prerelease=False]'} | ${'1.1.1'} | ${true} + ${'["< 1.2", loose=False, include_prerelease=False]'} | ${'1.1.1'} | ${true} + ${'["~v0.5.4-pre", loose=False, include_prerelease=False]'} | ${'0.5.5'} | ${true} + ${'["~v0.5.4-pre", loose=False, include_prerelease=False]'} | ${'0.5.4'} | ${true} + ${'["=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'["<=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'[">=0.7.x", loose=False, include_prerelease=False]'} | ${'0.7.2'} | ${true} + ${'["<=0.7.x", loose=False, include_prerelease=False]'} | ${'0.6.2'} | ${true} + ${'["~1.2.1 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 =1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 >=1.2.3 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["~1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">1.1.0 <2.0.0", include_prerelease=True]'} | ${'1.2.3-dev.1+abc'} | ${true} + ${'["~ 1.0.3", loose=False, include_prerelease=False]'} | ${'1.0.12'} | ${true} + ${'[">=1.2.1 1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["1.2.3 >=1.2.1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2.3 >=1.2.1", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2.1 >=1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'[">=1.2", loose=False, include_prerelease=False]'} | ${'1.2.8'} | ${true} + ${'["^1.2.3", loose=False, include_prerelease=False]'} | ${'1.8.1'} | ${true} + ${'["^0.1.2", loose=False, include_prerelease=False]'} | ${'0.1.2'} | ${true} + ${'["^0.1", loose=False, include_prerelease=False]'} | ${'0.1.2'} | ${true} + ${'["^0.0.1", loose=False, include_prerelease=False]'} | ${'0.0.1'} | ${true} + ${'["^1.2", loose=False, include_prerelease=False]'} | ${'1.4.2'} | ${true} + ${'["^1.2 ^1", loose=False, include_prerelease=False]'} | ${'1.4.2'} | ${true} + ${'["^1.2.3-alpha", loose=False, include_prerelease=False]'} | ${'1.2.3-pre'} | ${true} + ${'["^1.2.3-alpha", loose=False, include_prerelease=True]'} | ${'1.2.4-pre'} | ${true} + ${'["^1.2.0-alpha", loose=False, include_prerelease=False]'} | ${'"1.2.0-pre'} | ${true} + ${'["^0.0.1-alpha", loose=False, include_prerelease=False]'} | ${'0.0.1-beta'} | ${true} + ${'["^0.1.1-alpha", loose=False, include_prerelease=False]'} | ${'"0.1.1-beta'} | ${true} + ${'["^x", loose=False, include_prerelease=False]'} | ${'1.2.3'} | ${true} + ${'["x - 1.0.0", loose=False, include_prerelease=False]'} | ${'0.9.7'} | ${true} + ${'["x - 1.x", loose=False, include_prerelease=False]'} | ${'0.9.7'} | ${true} + ${'["1.0.0 - x", loose=False, include_prerelease=False]'} | ${'1.9.7'} | ${true} + ${'["1.x - x", loose=False, include_prerelease=False]'} | ${'1.9.7'} | ${true} + ${'["<=7.x", loose=False, include_prerelease=False]'} | ${'7.9.9'} | ${true} + ${'[>1.1.0 <2.0.0]'} | ${'1.2.3-dev.1+abc'} | ${false} + ${'[">1.0.0 <1.0.2", loose=False, include_prerelease=True]'} | ${'1.0.2-beta'} | ${false} + ${'[">1.1.0 <2.0.0", include_prerelease=False]'} | ${'1.2.3-dev.1+abc'} | ${false} + ${'["1.0.0 - 2.0.0", loose=False]'} | ${'2.2.3'} | ${false} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False]'} | ${'1.2.3-pre.2'} | ${false} + ${'["1.2.3+asdf - 2.4.3+asdf", loose=False]'} | ${'2.4.3-alpha'} | ${false} + ${'["^1.2.3+build", loose=False]'} | ${'2.0.0'} | ${false} + ${'["^1.2.3+build", loose=False]'} | ${'1.2.0'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.3-pre'} | ${false} + ${'["^1.2", loose=False]'} | ${'1.2.0-pre'} | ${false} + ${'[">1.2", loose=False]'} | ${'1.3.0-beta'} | ${false} + ${'["<=1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["=0.7.x", loose=False]'} | ${'0.7.0-asdf'} | ${false} + ${'[">=0.7.x", loose=False]'} | ${'0.7.0-asdf'} | ${false} + ${'["1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["<1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["< 1", loose=True]'} | ${'1.0.0beta'} | ${false} + ${'["1.0.0", loose=False]'} | ${'1.0.1'} | ${false} + ${'[">=1.0.0", loose=False]'} | ${'0.0.0'} | ${false} + ${'[">=1.0.0", loose=False]'} | ${'0.0.1'} | ${false} + ${'[">=1.0.0", loose=False]'} | ${'0.1.0'} | ${false} + ${'[">1.0.0", loose=False]'} | ${'0.0.1'} | ${false} + ${'[">1.0.0", loose=False]'} | ${'0.1.0'} | ${false} + ${'["<=2.0.0", loose=False]'} | ${'3.0.0'} | ${false} + ${'["<=2.0.0", loose=False]'} | ${'2.9999.9999'} | ${false} + ${'["<=2.0.0", loose=False]'} | ${'2.2.9'} | ${false} + ${'["<2.0.0", loose=False]'} | ${'2.9999.9999'} | ${false} + ${'["<2.0.0", loose=False]'} | ${'2.2.9'} | ${false} + ${'[">=0.1.97", loose=True]'} | ${'v0.1.93'} | ${false} + ${'[">=0.1.97", loose=False]'} | ${'0.1.93'} | ${false} + ${'["0.1.20 || 1.2.4", loose=False]'} | ${'1.2.3'} | ${false} + ${'[">=0.2.3 || <0.0.1", loose=False]'} | ${'0.0.3'} | ${false} + ${'[">=0.2.3 || <0.0.1", loose=False]'} | ${'0.2.2'} | ${false} + ${'["2.x.x", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.x.x", loose=False]'} | ${'3.1.3'} | ${false} + ${'["1.2.x", loose=False]'} | ${'1.3.3'} | ${false} + ${'["1.2.x || 2.x", loose=False]'} | ${'3.1.3'} | ${false} + ${'["1.2.x || 2.x", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.*.*", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2.*.*", loose=False]'} | ${'3.1.3'} | ${false} + ${'["1.2.*", loose=False]'} | ${'1.3.3'} | ${false} + ${'["1.2.* || 2.*", loose=False]'} | ${'3.1.3'} | ${false} + ${'["1.2.* || 2.*", loose=False]'} | ${'1.1.3'} | ${false} + ${'["2", loose=False]'} | ${'1.1.2'} | ${false} + ${'["2.3", loose=False]'} | ${'2.4.1'} | ${false} + ${'["~2.4", loose=False]'} | ${'2.5.0'} | ${false} + ${'["~2.4", loose=False]'} | ${'2.3.9'} | ${false} + ${'["~>3.2.1", loose=False]'} | ${'3.3.2'} | ${false} + ${'["~>3.2.1", loose=False]'} | ${'3.2.0'} | ${false} + ${'["~1", loose=False]'} | ${'0.2.3'} | ${false} + ${'["~>1", loose=False]'} | ${'2.2.3'} | ${false} + ${'["~1.0", loose=False]'} | ${'1.1.0'} | ${false} + ${'["<1", loose=False]'} | ${'1.0.0'} | ${false} + ${'[">=1.2", loose=False]'} | ${'1.1.1'} | ${false} + ${'["1", loose=True]'} | ${'2.0.0beta'} | ${false} + ${'["~v0.5.4-beta", loose=False]'} | ${'0.5.4-alpha'} | ${false} + ${'["=0.7.x", loose=False]'} | ${'0.8.2'} | ${false} + ${'[">=0.7.x", loose=False]'} | ${'0.6.2'} | ${false} + ${'["<0.7.x", loose=False]'} | ${'0.7.2'} | ${false} + ${'["<1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'["=1.2.3", loose=False]'} | ${'1.2.3-beta'} | ${false} + ${'[">1.2", loose=False]'} | ${'1.2.8'} | ${false} + ${'["^0.0.1", loose=False]'} | ${'0.0.2'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'2.0.0-alpha'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'1.2.2'} | ${false} + ${'["^1.2", loose=False]'} | ${'1.1.9'} | ${false} + ${'["*", loose=True]'} | ${'v1.2.3-foo'} | ${false} + ${'["blerg", loose=False]'} | ${'1.2.3'} | ${false} + ${'["git+https: #user:password0123@github.com/foo", loose=True]'} | ${'123.0.0'} | ${false} + ${'["^1.2.3", loose=False]'} | ${'2.0.0-pre'} | ${false} + ${'[~=1.18]'} | ${'1.20.0'} | ${false} + ${'[0.2.0]'} | ${'0.3.0'} | ${false} + ${'[~8.4.0, loose=False]'} | ${'8.5.0'} | ${false} + ${'[~=1.0 include_prerelease=True]'} | ${'1.21.2'} | ${false} + ${'1.0.7'} | ${'1.21.2'} | ${true} + ${'16.00'} | ${'19.00'} | ${true} + `( + 'matches("$version", "$range") === $result', + ({ version, range, result }) => { + const res = !!conan.matches(version, range); + expect(res).toBe(result); + } + ); + + // isStable(version: string): boolean; + test.each` + version | result + ${'5.0.1'} | ${true} + ${'19.00'} | ${true} + ${'1.0.7-prerelease.1'} | ${false} + ${'1.0.7-prerelease.1, include_prerelease=True'} | ${true} + `('isStable("$version") === $result', ({ version, result }) => { + const res = conan.isStable(version); + expect(res).toBe(result); + }); + + // getNewValue(newValueConfig: NewValueConfig): string; + test.each` + currentValue | rangeStrategy | currentVersion | newVersion | result + ${'[<=1.2.3]'} | ${'widen'} | ${'1.0.0'} | ${'1.2.3'} | ${'[<=1.2.3]'} + ${'[<1.2.3]'} | ${'widen'} | ${'1.5.5'} | ${'1.5.6'} | ${'[<1.5.7]'} + ${'[>1.2.7 >3.0.0 5.0]'} | ${'widen'} | ${'0.1.21'} | ${'0.1.24'} | ${'[>1.2.7 >3.0.0 5.0 || 0.1.24]'} + ${'[>=1.2.7 >3.0.0 >5.0]'} | ${'widen'} | ${'0.1.21'} | ${'0.1.24'} | ${null} + ${'[>=1.2.7]'} | ${'widen'} | ${'0.1.21'} | ${'0.1.24'} | ${'[>=1.2.7 || 0.1.24]'} + ${'[<= 1.2.3]'} | ${'widen'} | ${'1.0.0'} | ${'1.2.4'} | ${'[<= 1.2.4]'} + ${'[4.5.5 - 1.2.3 - 2.0]'} | ${'widen'} | ${'1.0.0'} | ${'1.4.8'} | ${'[4.5.5 - 1.2.3 - 1.4.8]'} + ${'1.0.0'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'1.1.0'} + ${'[<1.0.0]'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'[<3.0.0]'} + ${'[<1.1]'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'[<2.2]'} + ${'[1.0.*]'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'[1.1.*]'} + ${'[1.*]'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'[2.*]'} + ${'[1.0.x]'} | ${'replace'} | ${'1.0.0'} | ${'1.1.0'} | ${'[1.1.x]'} + ${'[1.x]'} | ${'replace'} | ${'1.0.0'} | ${'2.1.0'} | ${'[2.x]'} + ${'[~0.6]'} | ${'replace'} | ${'0.6.8'} | ${'0.7.0'} | ${'[~0.7.0]'} + ${'[~0.6.1]'} | ${'replace'} | ${'0.7.0'} | ${'0.7.0-rc.2'} | ${'[~0.7.0-rc]'} + ${'[~>0.6.1]'} | ${'replace'} | ${'0.7.0'} | ${'0.7.0-rc.2'} | ${'[~> 0.7.0]'} + ${'[<=1.2]'} | ${'replace'} | ${'1.0.0'} | ${'1.2.3'} | ${'[<=1.2]'} + ${'[<=1]'} | ${'replace'} | ${'1.0.0'} | ${'1.2.3'} | ${'[<=1]'} + ${'[<1.6.11]'} | ${'replace'} | ${'0.6.14'} | ${'1.6.14'} | ${'[<1.6.15]'} + ${'[0.2.0]'} | ${'replace'} | ${'0.6.14'} | ${'0.3.0'} | ${'[0.3.0]'} + ${'[< 1]'} | ${'replace'} | ${'1.0.0'} | ${'1.0.1'} | ${'[< 2]'} + ${'[<3.6 loose=False, include_prerelease=True]'} | ${'replace'} | ${'0.1'} | ${'3.7.0'} | ${'[<3.8 loose=False, include_prerelease=True]'} + ${'[<1.8 loose=False]'} | ${'replace'} | ${'0.2'} | ${'1.17.1'} | ${'[<1.18 loose=False]'} + ${'[=8.4.0]'} | ${'replace'} | ${'0.6.14'} | ${'8.5.0'} | ${'[=8.5.0]'} + ${'[>8.0.0]'} | ${'replace'} | ${'0.6.14'} | ${'8.5.0'} | ${'[>9.0.0]'} + ${'[>8]'} | ${'replace'} | ${'0.6.14'} | ${'8.5.0'} | ${'[>8]'} + ${'[> 8]'} | ${'replace'} | ${'0.6.14'} | ${'8.5.0'} | ${'[>8]'} + ${'5.0.1'} | ${'pin'} | ${'5.0.1'} | ${'5.0.7'} | ${'5.0.7'} + ${'2.1'} | ${'pin'} | ${'2.1'} | ${'3.1'} | ${'3.1'} + ${'0.1'} | ${'pin'} | ${'0.1'} | ${'2.7.1'} | ${'2.7.1'} + ${'0.2'} | ${'pin'} | ${'0.2'} | ${'3.6.5'} | ${'3.6.5'} + ${'1.0'} | ${'pin'} | ${'1.0'} | ${'1.0.0'} | ${'1.0.0'} + ${'2.1'} | ${'pin'} | ${'2.1'} | ${'11.0.12'} | ${'11.0.12'} + ${'0.1'} | ${'pin'} | ${'0.1'} | ${'3.5.0'} | ${'3.5.0'} + ${'2.1'} | ${'pin'} | ${'2.1'} | ${'1.19.0'} | ${'1.19.0'} + ${'1.15.0'} | ${'pin'} | ${'1.15.0'} | ${'1.42.0'} | ${'1.42.0'} + ${'1.0'} | ${'pin'} | ${'1.0'} | ${'1.10.2'} | ${'1.10.2'} + ${'0.2'} | ${'pin'} | ${'0.2'} | ${'1.1.9'} | ${'1.1.9'} + ${'2.2'} | ${'pin'} | ${'2.2'} | ${'1.21.1'} | ${'1.21.1'} + ${'1.2'} | ${'pin'} | ${'1.2'} | ${'1.12.20'} | ${'1.12.20'} + ${'16.00'} | ${'pin'} | ${'16.00'} | ${'19.00'} | ${'19.00'} + ${'2.9.2'} | ${'pin'} | ${'2.9.2'} | ${'2.13.7'} | ${'2.13.7'} + ${'[^0.5.12]'} | ${'pin'} | ${'0.5.12'} | ${'0.5.13'} | ${'0.5.13'} + ${'0.5.12'} | ${'pin'} | ${'0.5.12'} | ${'0.5.13'} | ${'0.5.13'} + ${'5.0.20210712-T1759Z+b563c1478'} | ${'pin'} | ${'5.0.20210712-T1759Z+b563c1478'} | ${'5.0.20211022-T0612Z+743f9e41b'} | ${'5.0.20211022-T0612Z+743f9e41b'} + ${'[=8.4.0]'} | ${'bump'} | ${'0.6.14'} | ${'8.5.0'} | ${'[=8.5.0]'} + ${'[~8.4.0, loose=False]'} | ${'bump'} | ${'0.6.14'} | ${'8.5.0'} | ${'[~8.5.0, loose=False]'} + ${'[~0.7.15, loose=False, include_prerelease=True]'} | ${'bump'} | ${'0.6.14'} | ${'0.9.7'} | ${'[~0.9.7, loose=False, include_prerelease=True]'} + ${'[~=1.0 include_prerelease=True]'} | ${'bump'} | ${'0.2'} | ${'1.21.1'} | ${'[~=1.21 include_prerelease=True]'} + ${'[~=1.18]'} | ${'bump'} | ${'0.6.14'} | ${'1.20.0'} | ${'[~=1.20]'} + ${'[0.2.0]'} | ${'bump'} | ${'0.6.14'} | ${'0.3.0'} | ${'[0.3.0]'} + ${'[~1]'} | ${'bump'} | ${'2'} | ${'1.1.7'} | ${'[~1]'} + ${'[~1]'} | ${'bump'} | ${'1.0.0'} | ${'2.1.7'} | ${'[~2]'} + ${'[~1.0]'} | ${'bump'} | ${'1.0.0'} | ${'1.1.7'} | ${'[~1.1]'} + ${'[~1.0.0]'} | ${'bump'} | ${'1.0.0'} | ${'1.1.7'} | ${'[~1.1.7]'} + ${'[~1.0]'} | ${'bump'} | ${'1.0.0'} | ${'1.0.7-prerelease.1'} | ${'[~1.0.7-prerelease.1]'} + ${'[~1.0.7-prerelease.1]'} | ${'bump'} | ${'1.0.0'} | ${'1.0.7-prerelease.1'} | ${'[~1.0.7-prerelease.1]'} + ${'[5]'} | ${'bump'} | ${'5.0.0'} | ${'6.1.7'} | ${'[6]'} + ${'[>=1.0.0]'} | ${'bump'} | ${'1.0.0'} | ${'1.1.0'} | ${'[>=1.1.0]'} + ${'[<1.0.0]'} | ${'bump'} | ${'1.0.0'} | ${'1.1.0'} | ${'[<1.0.0]'} + ${'[>1.1 <3.0, include_prerelease=True]'} | ${'bump'} | ${'0.6.14'} | ${'1.1.1l'} | ${'[>1.1 <3.0, include_prerelease=True]'} + ${'[>= 0.0.1 < 1]'} | ${'bump'} | ${'1.0.0'} | ${'1.0.1'} | ${'[>= 1.0.1 < 2]'} + ${'[>3.0 <3.6 loose=False, include_prerelease=True]'} | ${'bump'} | ${'0.1'} | ${'3.7.0'} | ${'[>3.7 <3.8 loose=False, include_prerelease=True]'} + ${'[>1.0 <1.8 loose=False]'} | ${'bump'} | ${'0.2'} | ${'1.17.1'} | ${'[>1.17 <1.18 loose=False]'} + ${'[>0.6.7 <1.6.11]'} | ${'bump'} | ${'0.6.14'} | ${'1.6.14'} | ${'[>1.6.14 <1.6.15]'} + ${'[3.17.2 || 3.15.7]'} | ${'bump'} | ${'0.6.14'} | ${'3.21.3'} | ${'[3.17.2 || 3.15.7 || 3.21.3]'} + ${'[>3.17.2 || 3.15.7]'} | ${'bump'} | ${'0.6.14'} | ${'3.21.3'} | ${'[>3.21.3 || 3.15.7]'} + ${'[1.69.0 || >=1.71.0 <1.76.0]'} | ${'bump'} | ${'0.6.14'} | ${'1.76.0'} | ${'[1.69.0 || >=1.76.0 <1.76.1]'} + `( + 'getNewValue("$currentValue", "$rangeStrategy", "$currentVersion", "$newVersion") === "$result"', + ({ currentValue, rangeStrategy, currentVersion, newVersion, result }) => { + const res = conan.getNewValue({ + currentValue, + rangeStrategy, + currentVersion, + newVersion, + }); + expect(res).toEqual(result); + } + ); + + // getSatisfyingVersion(versions: string[], range: string): string | null; + test.each` + versions | range | result + ${['1.2.4', '1.2.3', '1.2.5-beta']} | ${'["~1.2.3", loose=False, include_prerelease=True]'} | ${'1.2.5-beta'} + ${['1.2.4', '1.2.3', '1.2.5-beta']} | ${'["~1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.4'} + ${['1.2.3', '1.2.4']} | ${'["1.2", loose=False, include_prerelease=False]'} | ${'1.2.4'} + ${['1.2.4', '1.2.3']} | ${'["1.2", loose=False, include_prerelease=False]'} | ${'1.2.4'} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6']} | ${'["~1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.6'} + ${['1.0.1-beta']} | ${'["1.x", loose=False, include_prerelease=False]'} | ${null} + ${['1.0.1-beta']} | ${'["1.x", loose=False, include_prerelease=True]'} | ${'1.0.1-beta'} + ${['1.0.0-beta']} | ${'["1.x", loose=False, include_prerelease=True]'} | ${'1.0.0-beta'} + ${['1.1.0-beta']} | ${'["1.0.x", loose=False, include_prerelease=True]'} | ${null} + ${['1.0.0-beta', '1.1.0-beta', '1.1.0']} | ${'["1.0.x", loose=False, include_prerelease=False]'} | ${null} + ${['1.0.0-beta', '1.1.0-beta', '1.1.0']} | ${'["1.0.x", loose=False, include_prerelease=True]'} | ${'1.0.0-beta'} + ${['1.0.0-beta', '1.0.0', '1.0.1-beta', '1.0.2-beta']} | ${'[">1.0.0 <1.0.2", loose=False, include_prerelease=False]'} | ${null} + ${['1.0.0-beta', '1.0.0', '1.0.1-beta', '1.0.2-beta']} | ${'[">1.0.0 <1.0.2", loose=False, include_prerelease=True]'} | ${'1.0.1-beta'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta', '1.1.0']} | ${'[">1.0.0 <1.1.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta', '1.1.0']} | ${'[">1.0.0 <1.1.0", loose=False, include_prerelease=True]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.1.0-beta']} | ${'[">1.0.0 <1.1.0", loose=False, include_prerelease=True]'} | ${null} + ${['1.0.0-beta', '1.1.0-beta', '1.0.0']} | ${'[">=1.0.0 <=1.0.1", loose=False, include_prerelease=False]'} | ${'1.0.0'} + ${['1.0.0-beta', '1.1.0-beta', '1.0.0']} | ${'[">=1.0.0 <=1.0.1", loose=False, include_prerelease=True]'} | ${'1.0.0'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta']} | ${'[">=1.0.0 <=1.1.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta']} | ${'[">=1.0.0 <=1.1.0", loose=False, include_prerelease=True]'} | ${'1.1.0-beta'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta']} | ${'[">=1.0.0 <1.1.0", loose=False, include_prerelease=False]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta']} | ${'[">=1.0.0 <1.1.0", loose=False, include_prerelease=True]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.1.0-beta']} | ${'[">=1.0.0 <=1.1.0", loose=False, include_prerelease=False]'} | ${null} + ${['1.0.0-beta', '1.1.0-beta']} | ${'[">=1.0.0 <=1.1.0", loose=False, include_prerelease=True]'} | ${'1.1.0-beta'} + ${['1.0.0-beta', '1.1.0-beta', '1.0.0']} | ${'[">=1.0.0-0 <1.0.1", loose=False, include_prerelease=True]'} | ${'1.0.0'} + ${['1.0.0-beta', '1.1.0-beta', '1.1.0']} | ${'[">=1.0.0-0 <1.1.0-0", loose=False, include_prerelease=True]'} | ${'1.0.0-beta'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta', '1.1.0']} | ${'[">=1.0.0-0 <1.1.0-0", loose=False, include_prerelease=False]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.0.0', '1.0.1', '1.1.0-beta', '1.1.0']} | ${'[">=1.0.0-0 <1.1.0-0", loose=False, include_prerelease=True]'} | ${'1.0.1'} + ${['1.0.0-beta', '1.1.0-beta']} | ${'[">=1.0.0-0 <1.1.0", loose=False, include_prerelease=True]'} | ${'1.0.0-beta'} + ${['1.0.0-pre']} | ${'[1.0.x", loose=False, include_prerelease=True]'} | ${'1.0.0-pre'} + ${['1.0.0-pre']} | ${'[">=1.0.x", loose=False, include_prerelease=True]'} | ${'1.0.0-pre'} + ${['1.1.0-pre']} | ${'[">=1.0.0 <1.1.1-z", loose=False, include_prerelease=False]'} | ${null} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6', '2.0.1']} | ${'["~1.2.3", loose=False]'} | ${'1.2.6'} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.0.0', '2.1.0']} | ${'[~2.0.0]'} | ${'2.0.0'} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.1.0']} | ${'["~2.0.0", loose=False]'} | ${null} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.0.1', '2.1.0']} | ${'["~2.0.0", loose=False]'} | ${'2.0.1'} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6-pre.1', '2.0.1']} | ${'["~1.2.3", loose=False, include_prerelease=True]'} | ${'1.2.6-pre.1'} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6-pre.1', '2.0.1']} | ${'["~1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.5'} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6-pre.1', '2.0.1']} | ${'["~1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.5'} + ${['1.1.1', '1.2.0-pre', '1.2.0', '1.1.1-111', '1.1.1-21']} | ${'[<=1.2]'} | ${'1.2.0'} + ${['1.1.1', '1.2.0-pre', '1.2', '1.1.1-111', '1.1.1-21']} | ${'[<=1.2]'} | ${'1.2'} + ${['1.1.1', '1.2.0-pre', '1.2.0', '1.1.1-111', '1.1.1-21']} | ${'[<=1.2.0]'} | ${'1.2.0'} + ${['1.1.1', '1.2.0-pre', '1.2', '1.1.1-111', '1.1.1-21']} | ${'[<=1.2.0]'} | ${'1.2'} + ${['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0b3', '2.0.0', '2.1.0']} | ${'["~2.0.0", loose=True, include_prerelease=False]'} | ${'2.0.0'} + ${['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0b3', '2.0.0', '2.1.0']} | ${'["~2.0.0", loose=False, include_prerelease=False]'} | ${'2.0.0'} + ${['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0', '2.0.1b1', '2.1.0']} | ${'["~2.0.0", loose=True, include_prerelease=False]'} | ${'2.0.0'} + ${['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0', '2.0.1b1', '2.1.0']} | ${'["~2.0.0", loose=True, include_prerelease=True]'} | ${'2.0.1b1'} + `( + 'getSatisfyingVersion("$versions", "$range") === "$result"', + ({ versions, range, result }) => { + const res = conan.getSatisfyingVersion(versions, range); + expect(res).toEqual(result); + } + ); + + // minSatisfyingVersion(versions: string[], range: string): string | null; + test.each` + versions | range | result + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6', '2.0.1']} | ${'["~1.2.3", loose=False]'} | ${'1.2.3'} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.0.0', '2.1.0']} | ${'[~2.0.0]'} | ${'2.0.0'} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.1.0']} | ${'["~2.0.0", loose=False]'} | ${null} + ${['1.1.0', '1.2.0', '1.3.0', '2.0.0b1', '2.0.0b3', '2.0.1', '2.1.0']} | ${'["~2.0.0", loose=False]'} | ${'2.0.1'} + ${['1.2.3-pre.1', '1.2.4', '1.2.5', '1.2.6-pre.1', '2.0.1']} | ${'["~1.2.3", loose=False, include_prerelease=True]'} | ${'1.2.3-pre.1'} + ${['1.2.3-pre.1', '1.2.4', '1.2.5', '1.2.6-pre.1', '2.0.1']} | ${'["~1.2.3", loose=False, include_prerelease=False]'} | ${'1.2.4'} + ${['1.2.3', '1.2.4']} | ${'["1.2", loose=False]'} | ${'1.2.3'} + ${['1.2.4', '1.2.3']} | ${'["1.2", loose=False]'} | ${'1.2.3'} + ${['1.2.3', '1.2.4', '1.2.5', '1.2.6']} | ${'[~1.2.3, loose=False]'} | ${'1.2.3'} + ${['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0b3', '2.0.0', '2.1.0']} | ${'[~2.0.0, loose=True]'} | ${'2.0.0'} + `( + 'minSatisfyingVersion("$versions", "$range") === "$result"', + ({ versions, range, result }) => { + const res = conan.minSatisfyingVersion(versions, range); + expect(res).toEqual(result); + } + ); + + // test 4-digit + test.each` + version | major | minor | patch + ${'4.1.3'} | ${4} | ${1} | ${3} + ${'4.1.3+jenkins'} | ${4} | ${1} | ${3} + ${'4.1.3-pre'} | ${4} | ${1} | ${3} + ${'4.1.3.2'} | ${4} | ${1} | ${3} + ${'4.1.3.2+jenkins'} | ${4} | ${1} | ${3} + ${'4.1.3.2-pre'} | ${4} | ${1} | ${3} + ${'4.1.3.2-pre2'} | ${4} | ${1} | ${3} + ${'4.1.3.2-pre.2'} | ${4} | ${1} | ${3} + ${'4.1.3.2-pre.2+xxx'} | ${4} | ${1} | ${3} + ${'4.1.33.2'} | ${4} | ${1} | ${33} + ${'1.a.2'} | ${null} | ${null} | ${null} + `( + 'getMajor("$version") === $major getMinor("$version") === $minor getPatch("$version") === $patch', + ({ version, major, minor, patch }) => { + expect(conan.getMajor(version)).toBe(major); + expect(conan.getMinor(version)).toBe(minor); + expect(conan.getPatch(version)).toBe(patch); + } + ); + + // getMajor(version: string): null | number; + test.each` + version | result + ${'4.1.33.2'} | ${4} + `('getMajor("$version") === "$result"', ({ version, result }) => { + const res = conan.getMajor(version); + expect(res).toEqual(result); + }); + + // getMinor(version: string): null | number; + test.each` + version | result + ${'1.2.3'} | ${2} + ${'5.2.1'} | ${2} + ${'4.1.33.2'} | ${1} + `('getMinor("$version") === "$result"', ({ version, result }) => { + const res = conan.getMinor(version); + expect(res).toEqual(result); + }); + + // getPatch(version: string): null | number; + test.each` + version | result + ${'1.2.3'} | ${3} + ${'5.2.1'} | ${1} + ${'4.1.33.2'} | ${33} + `('getPatch("$version") === "$result"', ({ version, result }) => { + const res = conan.getPatch(version); + expect(res).toEqual(result); + }); + + // equals(version: string, other: string): boolean; + test.each` + version | other | result + ${'1.2.3'} | ${'1.2.3'} | ${true} + ${'2.3.1'} | ${'1.2.3'} | ${false} + ${'1.2.3'} | ${'v1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${'=1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${'v 1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${'= 1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${' v1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${' =1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${' v 1.2.3, loose=True'} | ${true} + ${'1.2.3'} | ${' = 1.2.3, loose=True'} | ${true} + ${'1.2.3-0'} | ${'v1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${'=1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${'v 1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${'= 1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${' v1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${' =1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${' v 1.2.3-0, loose=True'} | ${true} + ${'1.2.3-0'} | ${' = 1.2.3-0, loose=True'} | ${true} + ${'1.2.3-1'} | ${'v1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${'=1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${'v 1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${'= 1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${' v1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${' =1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${' v 1.2.3-1, loose=True'} | ${true} + ${'1.2.3-1'} | ${' = 1.2.3-1, loose=True'} | ${true} + ${'1.2.3-beta'} | ${'v1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${'=1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${'v 1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${'= 1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${' v1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${' =1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${' v 1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta'} | ${' = 1.2.3-beta, loose=True'} | ${true} + ${'1.2.3-beta+build'} | ${' = 1.2.3-beta+otherbuild, loose=True'} | ${true} + ${'1.2.3+build'} | ${' = 1.2.3+otherbuild, loose=True'} | ${true} + ${'1.2.3-beta+build'} | ${'1.2.3-beta+otherbuild, loose=False'} | ${true} + ${'1.2.3+build'} | ${'1.2.3+otherbuild, loose=False'} | ${true} + ${' v1.2.3+build'} | ${'1.2.3+otherbuild, loose=False'} | ${true} + ${'1.3'} | ${'1.2'} | ${false} + `( + 'equals("$version", "$other) === "$result"', + ({ version, other, result }) => { + const res = conan.equals(version, other); + expect(res).toEqual(result); + } + ); + + // isGreaterThan(version: string, other: string): boolean; + test.each` + version | other | result + ${'1.2.3'} | ${'1.2.3'} | ${false} + ${'19.00'} | ${'16.00'} | ${true} + ${'1.2'} | ${'1.0'} | ${true} + ${'2.3.1'} | ${'1.2.3'} | ${true} + ${'0.0.0, loose=False'} | ${'0.0.0-foo, loose=False'} | ${true} + ${'0.0.1, loose=False'} | ${'0.0.0, loose=False'} | ${true} + ${'1.0.0, loose=False'} | ${'0.9.9, loose=False'} | ${true} + ${'0.10.0, loose=False'} | ${'0.9.0, loose=False'} | ${true} + ${'0.99.0, loose=False'} | ${'0.10.0, loose=False'} | ${true} + ${'2.0.0, loose=False'} | ${'1.2.3, loose=False'} | ${true} + ${'v0.0.0'} | ${'0.0.0-foo'} | ${true} + ${'v0.0.1'} | ${'0.0.0'} | ${true} + ${'v1.0.0'} | ${'0.9.9'} | ${true} + ${'v0.10.0'} | ${'0.9.0'} | ${true} + ${'v0.99.0'} | ${'0.10.0'} | ${true} + ${'v2.0.0'} | ${'1.2.3'} | ${true} + ${'0.0.0, loose=False'} | ${'v0.0.0-foo, loose=False'} | ${true} + ${'0.0.1, loose=False'} | ${'v0.0.0, loose=False'} | ${true} + ${'1.0.0, loose=False'} | ${'v0.9.9, loose=False'} | ${true} + ${'0.10.0, loose=False'} | ${'v0.9.0, loose=False'} | ${true} + ${'0.99.0, loose=False'} | ${'v0.10.0, loose=False'} | ${true} + ${'2.0.0, loose=False'} | ${'v1.2.3, loose=False'} | ${true} + ${'1.2.3, loose=False'} | ${'1.2.3-asdf, loose=False'} | ${true} + ${'1.2.3, loose=False'} | ${'1.2.3-4, loose=False'} | ${true} + ${'1.2.3, loose=False'} | ${'1.2.3-4-foo, loose=False'} | ${true} + ${'1.2.3-5-foo, loose=False'} | ${'1.2.3-5, loose=False'} | ${true} + ${'1.2.3-5, loose=False'} | ${'1.2.3-4, loose=False'} | ${true} + ${'1.2.3-5-foo, loose=False'} | ${'1.2.3-5-Foo, loose=False'} | ${true} + ${'3.0.0, loose=False'} | ${'2.7.2+asdf, loose=False'} | ${true} + ${'1.2.3-a.10, loose=False'} | ${'1.2.3-a.5, loose=False'} | ${true} + ${'1.2.3-a.b, loose=False'} | ${'1.2.3-a.5, loose=False'} | ${true} + ${'1.2.3-a.b, loose=False'} | ${'1.2.3-a, loose=False'} | ${true} + ${'1.2.3-a.b.c.10.d.5, loose=False'} | ${'1.2.3-a.b.c.5.d.100, loose=False'} | ${true} + ${'1.2.3-r2, loose=False'} | ${'1.2.3-r100, loose=False'} | ${true} + ${'1.2.3-r100, loose=False'} | ${'1.2.3-R2, loose=False'} | ${true} + `( + 'isGreaterThan("$version", "$other) === "$result"', + ({ version, other, result }) => { + const res = conan.isGreaterThan(version, other); + expect(res).toEqual(result); + } + ); + + // sortVersions(version: string, other: string): boolean; + test.each` + version | other | result + ${'1.2'} | ${'1.3'} | ${-1} + ${'1.2.3'} | ${'1.2.3'} | ${0} + ${'2.3.1'} | ${'1.2.3'} | ${1} + ${'1.2.3'} | ${'2.3.1'} | ${-1} + `( + 'sortVersions("$version", "$other) === "$result"', + ({ version, other, result }) => { + const res = conan.sortVersions(version, other); + expect(res).toEqual(result); + } + ); + + // isLessThanRange(version: string, range: string): boolean; + test.each` + version | range | result + ${'1.2.3'} | ${'[>1.2.3]'} | ${true} + ${'2.3.1'} | ${'[>1.2.3]'} | ${false} + ${'1.2.3'} | ${'[>2.3.1]'} | ${true} + `( + 'isLessThanRange("$version", "$range") === "$result"', + ({ version, range, result }) => { + const res = conan.isLessThanRange?.(version, range); + expect(res).toEqual(result); + } + ); +}); diff --git a/lib/versioning/conan/index.ts b/lib/versioning/conan/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a27ffae2c15df60a504c5925f789f119b3c5e8af --- /dev/null +++ b/lib/versioning/conan/index.ts @@ -0,0 +1,215 @@ +import * as semver from 'semver'; +import { api as looseAPI } from '../loose'; +import type { NewValueConfig, VersioningApi } from '../types'; +import { + cleanVersion, + findSatisfyingVersion, + getOptions, + makeVersion, + matchesWithOptions, +} from './common'; +import { + bumpRange, + getMajor, + getMinor, + getPatch, + replaceRange, + widenRange, +} from './range'; + +export const id = 'conan'; +export const displayName = 'conan'; +export const urls = [ + 'https://semver.org/', + 'https://github.com/podhmo/python-node-semver', + 'https://github.com/podhmo/python-node-semver/tree/master/examples', + 'https://docs.conan.io/en/latest/versioning/version_ranges.html#version-ranges', +]; +export const supportsRanges = true; +export const supportedRangeStrategies = ['auto', 'bump', 'widen', 'replace']; + +const MIN = 1; +const MAX = -1; + +function isVersion(input: string): boolean { + if (input && !input.includes('[')) { + const qualifiers = getOptions(input); + const version = cleanVersion(input); + if (qualifiers.loose) { + if (looseAPI.isVersion(version)) { + return true; + } + } + return makeVersion(version, qualifiers) !== null; + } + return false; +} + +function isValid(input: string): boolean { + const version = cleanVersion(input); + const qualifiers = getOptions(input); + if (makeVersion(version, qualifiers)) { + return version !== null; + } + + return semver.validRange(version, qualifiers) !== null; +} + +function equals(version: string, other: string): boolean { + const cleanedVersion = cleanVersion(version); + const cleanOther = cleanVersion(other); + const options = { loose: true, includePrerelease: true }; + const looseResult = looseAPI.equals(cleanedVersion, cleanOther); + try { + return semver.eq(cleanedVersion, cleanOther, options) || looseResult; + } catch { + return looseResult; + } +} + +function isGreaterThan(version: string, other: string): boolean { + const cleanedVersion = cleanVersion(version); + const cleanOther = cleanVersion(other); + const options = { loose: true, includePrerelease: true }; + const looseResult = looseAPI.isGreaterThan(cleanedVersion, cleanOther); + try { + return semver.gt(cleanedVersion, cleanOther, options) || looseResult; + } catch { + return looseResult; + } +} + +function isLessThanRange(version: string, range: string): boolean { + const cleanedVersion = cleanVersion(version); + const cleanRange = cleanVersion(range); + const options = getOptions(range); + const looseResult: any = looseAPI.isLessThanRange?.( + cleanedVersion, + cleanRange + ); + try { + return semver.ltr(cleanedVersion, cleanRange, options) || looseResult; + } catch { + return looseResult; + } +} + +function sortVersions(version: string, other: string): number { + const cleanedVersion = cleanVersion(version); + const cleanOther = cleanVersion(other); + const options = { loose: true, includePrerelease: true }; + try { + return semver.compare(cleanedVersion, cleanOther, options); + } catch { + return looseAPI.sortVersions(cleanedVersion, cleanOther); + } +} + +function matches(version: string, range: string): boolean { + if (isVersion(version) && isVersion(range)) { + return true; + } + const cleanedVersion = cleanVersion(version); + const options = getOptions(range); + const cleanRange = cleanVersion(range); + return matchesWithOptions(cleanedVersion, cleanRange, options); +} + +function isCompatible(version: string, range: string): boolean { + if (isVersion(version) && isVersion(range)) { + return true; + } + const options = getOptions(range); + const compatibleVersion = makeVersion(version, options); + if (compatibleVersion) { + return !isLessThanRange(version, range); + } + return false; +} + +function isStable(version: string): boolean { + const cleanedVersion = cleanVersion(version); + const options = getOptions(version); + if ( + !options.includePrerelease && + semver.prerelease(cleanedVersion, options) + ) { + return false; + } + + return true; +} + +function minSatisfyingVersion( + versions: string[], + range: string +): string | null { + return findSatisfyingVersion(versions, range, MIN); +} + +function getSatisfyingVersion( + versions: string[], + range: string +): string | null { + return findSatisfyingVersion(versions, range, MAX); +} + +function getNewValue({ + currentValue, + rangeStrategy, + currentVersion, + newVersion, +}: NewValueConfig): string | null { + const cleanRange = cleanVersion(currentValue); + if (isVersion(currentValue) || rangeStrategy === 'pin') { + return newVersion; + } + const options = getOptions(currentValue); + let newValue: any = ''; + + if (rangeStrategy === 'widen') { + newValue = widenRange( + { currentValue: cleanRange, rangeStrategy, currentVersion, newVersion }, + options + ); + } else if (rangeStrategy === 'bump') { + newValue = bumpRange( + { currentValue: cleanRange, rangeStrategy, currentVersion, newVersion }, + options + ); + } else { + newValue = replaceRange({ + currentValue: cleanRange, + rangeStrategy, + currentVersion, + newVersion, + }); + } + + if (newValue) { + return currentValue.replace(cleanRange, newValue); + } + + return null; +} + +export const api: VersioningApi = { + equals, + getMajor, + getMinor, + getNewValue, + getPatch, + isCompatible, + isGreaterThan, + isLessThanRange, + isSingleVersion: isVersion, + isStable, + isValid, + isVersion, + matches, + getSatisfyingVersion, + minSatisfyingVersion, + sortVersions, +}; + +export default api; diff --git a/lib/versioning/conan/range.ts b/lib/versioning/conan/range.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ac598a8b4cbe215c725f3c81847c82585cd822a --- /dev/null +++ b/lib/versioning/conan/range.ts @@ -0,0 +1,345 @@ +import * as semver from 'semver'; +import { SemVer, parseRange } from 'semver-utils'; +import { logger } from '../../logger'; +import type { NewValueConfig } from '../types'; +import { + cleanVersion, + containsOperators, + getOptions, + makeVersion, + matchesWithOptions, +} from './common'; + +// always include prereleases +export function getMajor(version: string): null | number { + const cleanedVersion = cleanVersion(version); + const options = getOptions(version); + options.includePrerelease = true; + const cleanerVersion = makeVersion(cleanedVersion, options); + if (typeof cleanerVersion === 'string') { + return Number(cleanerVersion.split('.')[0]); + } + return null; +} + +// always include prereleases +export function getMinor(version: string): null | number { + const cleanedVersion = cleanVersion(version); + const options = getOptions(version); + options.includePrerelease = true; + const cleanerVersion = makeVersion(cleanedVersion, options); + if (typeof cleanerVersion === 'string') { + return Number(cleanerVersion.split('.')[1]); + } + return null; +} + +// always include prereleases +export function getPatch(version: string): null | number { + const cleanedVersion = cleanVersion(version); + const options = getOptions(version); + options.includePrerelease = true; + const cleanerVersion = makeVersion(cleanedVersion, options); + + if (typeof cleanerVersion === 'string') { + const newVersion = semver.valid( + semver.coerce(cleanedVersion, options), + options + ); + return Number(newVersion?.split('.')[2]); + } + return null; +} + +export function fixParsedRange(range: string): any { + const ordValues = []; + + // don't bump or'd single version values + const originalSplit = range.split(' '); + for (let i = 0; i < originalSplit.length; i += 1) { + if ( + !containsOperators(originalSplit[i]) && + !originalSplit[i].includes('||') + ) { + if (i !== 0 && originalSplit[i - 1].includes('||')) { + ordValues.push(`|| ${originalSplit[i]}`); + } else if (i !== originalSplit.length && originalSplit[i + 1] === '||') { + ordValues.push(`${originalSplit[i]} ||`); + } + } else { + ordValues.push(originalSplit[i]); + } + } + + const parsedRange = parseRange(range); + const cleanRange = range.replace(/([<=>^~])( )?/g, ''); + const splitRange = cleanRange.split(' '); + const semverRange: SemVer[] = []; + + for (let i = 0; i < splitRange.length; i += 1) { + if (!splitRange[i].includes('||')) { + const splitVersion = splitRange[i].split('.'); + const major = splitVersion[0]; + const minor = splitVersion[1]; + const patch = splitVersion[2]; + const operator = ordValues[i].includes('||') + ? '||' + : parsedRange[i].operator; + const NewSemVer: SemVer = { + major, + }; + + let full = `${operator || ''}${major}`; + if (minor) { + NewSemVer.minor = minor; + full = `${full}.${minor}`; + if (patch) { + NewSemVer.patch = patch; + full = `${full}.${patch}`; + } + } + if (operator) { + NewSemVer.operator = operator; + full = range.includes(`${operator} `) + ? `${operator} ${full.replace(operator, '')}` + : `${operator}${full.replace(operator, '')}`; + } + + full = ordValues[i].includes('||') ? ordValues[i] : full; + + NewSemVer.semver = full; + + semverRange.push(NewSemVer); + } + } + return semverRange; +} + +export function replaceRange({ + currentValue, + newVersion, +}: NewValueConfig): string { + const parsedRange = parseRange(currentValue); + const element = parsedRange[parsedRange.length - 1]; + const toVersionMajor = getMajor(newVersion); + const toVersionMinor = getMinor(newVersion); + const toVersionPatch = getPatch(newVersion); + const suffix = semver.prerelease(newVersion) + ? '-' + String(semver.prerelease(newVersion)?.[0]) + : ''; + + if (element.operator === '~>') { + return `~> ${toVersionMajor}.${toVersionMinor}.0`; + } + if (element.operator === '=') { + return `=${newVersion}`; + } + if (element.operator === '~') { + if (suffix.length) { + return `~${toVersionMajor}.${toVersionMinor}.${toVersionPatch}${suffix}`; + } + return `~${toVersionMajor}.${toVersionMinor}.0`; + } + if (element.operator === '<=') { + let res; + if (element.patch || suffix.length) { + res = `<=${newVersion}`; + } else if (element.minor) { + res = `<=${toVersionMajor}.${toVersionMinor}`; + } else { + res = `<=${toVersionMajor}`; + } + if (currentValue.includes('<= ')) { + res = res.replace('<=', '<= '); + } + return res; + } + if (element.operator === '<' && toVersionMajor) { + let res; + if (currentValue.endsWith('.0.0')) { + const newMajor = toVersionMajor + 1; + res = `<${newMajor}.0.0`; + } else if (element.patch) { + res = `<${semver.inc(newVersion, 'patch')}`; + } else if (element.minor && toVersionMinor) { + res = `<${toVersionMajor}.${toVersionMinor + 1}`; + } else { + res = `<${toVersionMajor + 1}`; + } + if (currentValue.includes('< ')) { + res = res.replace(/</g, '< '); + } + return res; + } + if (element.operator === '>') { + let res; + if (currentValue.endsWith('.0.0') && toVersionMajor) { + const newMajor = toVersionMajor + 1; + res = `>${newMajor}.0.0`; + } else if (element.patch) { + res = `>${toVersionMajor}.${toVersionMinor}.${toVersionPatch}`; + } else if (element.minor) { + res = `>${toVersionMajor}.${toVersionMinor}`; + } else { + res = `>${toVersionMajor}`; + } + if (currentValue.includes('> ')) { + res = res.replace(/</g, '> '); + } + return res; + } + if (!element.operator) { + if (element.minor) { + if (element.minor === 'x') { + return `${toVersionMajor}.x`; + } + if (element.minor === '*') { + return `${toVersionMajor}.*`; + } + if (element.patch === 'x') { + return `${toVersionMajor}.${toVersionMinor}.x`; + } + if (element.patch === '*') { + return `${toVersionMajor}.${toVersionMinor}.*`; + } + return `${newVersion}`; + } + return `${toVersionMajor}`; + } + return newVersion; +} + +export function widenRange( + { currentValue, currentVersion, newVersion }: NewValueConfig, + options: semver.Options +): string | null { + const parsedRange = parseRange(currentValue); + const element = parsedRange[parsedRange.length - 1]; + + if (matchesWithOptions(newVersion, currentValue, options)) { + return currentValue; + } + const newValue = replaceRange({ + currentValue, + rangeStrategy: 'replace', + currentVersion, + newVersion, + }); + if (element.operator?.startsWith('<')) { + const splitCurrent = currentValue.split(element.operator); + splitCurrent.pop(); + return splitCurrent.join(element.operator) + newValue; + } + if (parsedRange.length > 1) { + const previousElement = parsedRange[parsedRange.length - 2]; + if (previousElement.operator === '-') { + const splitCurrent = currentValue.split('-'); + splitCurrent.pop(); + return splitCurrent.join('-') + '- ' + newValue; + } + if (element.operator?.startsWith('>')) { + logger.warn(`Complex ranges ending in greater than are not supported`); + return null; + } + } + return `${currentValue} || ${newValue}`; +} + +export function bumpRange( + { currentValue, currentVersion, newVersion }: NewValueConfig, + options: semver.Options +): string | null { + if (!containsOperators(currentValue) && currentValue.includes('||')) { + return widenRange( + { + currentValue, + rangeStrategy: 'widen', + currentVersion, + newVersion, + }, + options + ); + } + const parsedRange = parseRange(currentValue); + const element = parsedRange[parsedRange.length - 1]; + + const toVersionMajor = getMajor(newVersion); + const toVersionMinor = getMinor(newVersion); + const suffix = semver.prerelease(newVersion) + ? '-' + String(semver.prerelease(newVersion)?.[0]) + : ''; + + if (parsedRange.length === 1) { + if (!element.operator) { + return replaceRange({ + currentValue, + rangeStrategy: 'replace', + currentVersion, + newVersion, + }); + } + if (element.operator.startsWith('~')) { + const split = currentValue.split('.'); + if (suffix.length) { + return `${element.operator}${newVersion}`; + } + if (split.length === 1) { + // ~4 + return `${element.operator}${toVersionMajor}`; + } + if (split.length === 2) { + // ~4.1 + return `${element.operator}${toVersionMajor}.${toVersionMinor}`; + } + return `${element.operator}${newVersion}`; + } + if (element.operator === '=') { + return `=${newVersion}`; + } + if (element.operator === '>=') { + return currentValue.includes('>= ') + ? `>= ${newVersion}` + : `>=${newVersion}`; + } + if (element.operator.startsWith('<')) { + return currentValue; + } + } else { + const newRange = fixParsedRange(currentValue); + const versions = newRange.map((x: any) => { + // don't bump or'd single version values + if (x.operator === '||') { + return x.semver; + } + if (x.operator) { + const bumpedSubRange = bumpRange( + { + currentValue: x.semver, + rangeStrategy: 'bump', + currentVersion, + newVersion, + }, + options + ); + if ( + bumpedSubRange && + matchesWithOptions(newVersion, bumpedSubRange, options) + ) { + return bumpedSubRange; + } + } + + return replaceRange({ + currentValue: x.semver, + rangeStrategy: 'replace', + currentVersion, + newVersion, + }); + }); + return versions.filter((x: any) => x !== null && x !== '').join(' '); + } + logger.debug( + 'Unsupported range type for rangeStrategy=bump: ' + currentValue + ); + return null; +} diff --git a/lib/versioning/conan/readme.md b/lib/versioning/conan/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..cf539a8faf580ee8360c166b61d0bb93adbd2516 --- /dev/null +++ b/lib/versioning/conan/readme.md @@ -0,0 +1,19 @@ +Conan versioning supports [Semantic Versioning 2.0](https://semver.org) but some packages don't follow this specification. + +Conan implements [python-node-semver](https://github.com/podhmo/python-node-semver). + +More information can be found in the [Conan docs](https://docs.conan.io/en/latest/versioning/version_ranges.html#version-ranges) + +| syntax | description | +| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | +| `5.45` | Equivalent to `5.45` | +| `16.00` | Equivalent to `16.00` | +| `2.8.3` | Equivalent to `2.8.3` | +| `[>1.1 <2.1]` | Keep version within range | +| `[2.8]` | Equivalent to `=2.8` | +| `[~=3.0]` | Compatible, according to SemVer | +| `[>1.1 \|\| 0.8]` | Conditions can be OR'ed | +| `[1.2.7 \|\| >=1.2.9 <2.0.0]` | This range would match the versions `1.2.7`, `1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0` | +| `[>1.1 <2.1, include_prerelease=True]` | Would e.g. accept `2.0.0-pre.1` as match | +| `[~1.2.3, loose=False]` | Would only accept correct Semantic Versioning strings. E.g. version `1.2.3.4` would not be accepted | +| `[~1.2.3, loose=False, include_prerelease=True]` | Both options can be used for the same version range |