diff --git a/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml deleted file mode 100644 index 62f98ea855c26c27e708bc944e9542923093f3b1..0000000000000000000000000000000000000000 --- a/lib/modules/manager/gradle/__fixtures__/2/libs.versions.toml +++ /dev/null @@ -1,17 +0,0 @@ -[versions] -kotlin = "1.5.21" -retro_fit = "2.8.2" - -[libraries] -okHttp = "com.squareup.okhttp3:okhttp:4.9.0" -okio = { module = "com.squareup.okio:okio", version = "2.8.0" } -picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" } -retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retro_fit" } -google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" } -google-firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } -google-firebase-messaging = "com.google.firebase:firebase-messaging" - -[plugins] -kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" } -kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -multiJvm = "org.danilopianini.multi-jvm-test-plugin:0.3.0" diff --git a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml deleted file mode 100644 index 7188d1a6c6b443901fa7708e9154c60c197d7b52..0000000000000000000000000000000000000000 --- a/lib/modules/manager/gradle/__fixtures__/3/libs.versions.toml +++ /dev/null @@ -1,10 +0,0 @@ -[versions] -# Releases: http://someWebsite.com/junit/1.4.9 -mocha-junit-reporter = "2.0.2" -# JUnit 1.4.9 is awesome! -junit = "1.4.9" - - -[libraries] -junit-legacy = { module = "junit:junit", version.ref = "junit" } -mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha.junit.reporter" } diff --git a/lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml b/lib/modules/manager/gradle/__fixtures__/libs.versions.toml similarity index 100% rename from lib/modules/manager/gradle/__fixtures__/1/libs.versions.toml rename to lib/modules/manager/gradle/__fixtures__/libs.versions.toml diff --git a/lib/modules/manager/gradle/extract.spec.ts b/lib/modules/manager/gradle/extract.spec.ts index 7a0900ddfc2b3c8383e695d54eaaad061c2e3d90..bd11d3a32ac66ccc0d20dd48dfb7070f6a326239 100644 --- a/lib/modules/manager/gradle/extract.spec.ts +++ b/lib/modules/manager/gradle/extract.spec.ts @@ -1,4 +1,4 @@ -import { codeBlock, stripIndent } from 'common-tags'; +import { codeBlock } from 'common-tags'; import { Fixtures } from '../../../../test/fixtures'; import { fs, logger, partial } from '../../../../test/util'; import type { ExtractConfig } from '../types'; @@ -499,7 +499,7 @@ describe('modules/manager/gradle/extract', () => { describe('version catalogs', () => { it('works with dependency catalogs', async () => { const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('1/libs.versions.toml'), + 'gradle/libs.versions.toml': Fixtures.get('libs.versions.toml'), }; mockFs(fsMock); @@ -614,118 +614,6 @@ describe('modules/manager/gradle/extract', () => { ]); }); - it('supports versions declared as single string', async () => { - const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('2/libs.versions.toml'), - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial<ExtractConfig>(), - Object.keys(fsMock), - ); - - expect(res).toMatchObject([ - { - packageFile: 'gradle/libs.versions.toml', - deps: [ - { - depName: 'com.squareup.okhttp3:okhttp', - currentValue: '4.9.0', - managerData: { - fileReplacePosition: 100, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.okio:okio', - currentValue: '2.8.0', - managerData: { - fileReplacePosition: 162, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.picasso:picasso', - currentValue: '2.5.1', - managerData: { - fileReplacePosition: 244, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'com.squareup.retrofit2:retrofit', - groupName: 'retro.fit', - currentValue: '2.8.2', - managerData: { - fileReplacePosition: 42, - packageFile: 'gradle/libs.versions.toml', - }, - }, - { - depName: 'google-firebase-analytics', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'google-firebase-crashlytics', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'google-firebase-messaging', - managerData: { - packageFile: 'gradle/libs.versions.toml', - }, - skipReason: 'unspecified-version', - }, - { - depName: 'org.jetbrains.kotlin.jvm', - depType: 'plugin', - currentValue: '1.5.21', - commitMessageTopic: 'plugin kotlinJvm', - packageName: - 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', - managerData: { - fileReplacePosition: 663, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - { - depName: 'org.jetbrains.kotlin.plugin.serialization', - depType: 'plugin', - currentValue: '1.5.21', - packageName: - 'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin', - managerData: { - fileReplacePosition: 21, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - { - depName: 'org.danilopianini.multi-jvm-test-plugin', - depType: 'plugin', - currentValue: '0.3.0', - commitMessageTopic: 'plugin multiJvm', - packageName: - 'org.danilopianini.multi-jvm-test-plugin:org.danilopianini.multi-jvm-test-plugin.gradle.plugin', - managerData: { - fileReplacePosition: 824, - packageFile: 'gradle/libs.versions.toml', - }, - registryUrls: ['https://plugins.gradle.org/m2/'], - }, - ], - }, - ]); - }); - it('ignores empty TOML file', async () => { const fsMock = { 'gradle/libs.versions.toml': '', @@ -739,97 +627,6 @@ describe('modules/manager/gradle/extract', () => { ), ).toBeNull(); }); - - it('deletes commit message for plugins with version reference', async () => { - const fsMock = { - 'gradle/libs.versions.toml': stripIndent` - [versions] - detekt = "1.18.1" - - [plugins] - detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } - - [libraries] - detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } - `, - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial<ExtractConfig>(), - Object.keys(fsMock), - ); - expect(res).toMatchObject([ - { - packageFile: 'gradle/libs.versions.toml', - deps: [ - { - depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', - groupName: 'detekt', - currentValue: '1.18.1', - managerData: { - fileReplacePosition: 21, - packageFile: 'gradle/libs.versions.toml', - }, - fileReplacePosition: 21, - }, - { - depType: 'plugin', - depName: 'io.gitlab.arturbosch.detekt', - packageName: - 'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin', - registryUrls: ['https://plugins.gradle.org/m2/'], - currentValue: '1.18.1', - managerData: { - fileReplacePosition: 21, - packageFile: 'gradle/libs.versions.toml', - }, - groupName: 'detekt', - fileReplacePosition: 21, - }, - ], - }, - ]); - }); - - it('changes the dependency version, not the comment version', async () => { - const fsMock = { - 'gradle/libs.versions.toml': Fixtures.get('3/libs.versions.toml'), - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial<ExtractConfig>(), - Object.keys(fsMock), - ); - expect(res).toMatchObject([ - { - packageFile: 'gradle/libs.versions.toml', - deps: [ - { - depName: 'junit:junit', - groupName: 'junit', - currentValue: '1.4.9', - managerData: { - fileReplacePosition: 124, - packageFile: 'gradle/libs.versions.toml', - }, - fileReplacePosition: 124, - }, - { - depName: 'mocha-junit:mocha-junit', - groupName: 'mocha.junit.reporter', - currentValue: '2.0.2', - managerData: { - fileReplacePosition: 82, - packageFile: 'gradle/libs.versions.toml', - }, - fileReplacePosition: 82, - }, - ], - }, - ]); - }); }); describe('apply from', () => { @@ -996,7 +793,7 @@ describe('modules/manager/gradle/extract', () => { it('parses versions files', async () => { const fsMock = { 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew --write-locks to regenerate this file org.apache.lucene:lucene-core:1.2.3 (10 constraints: 95be0c15) org.apache.lucene:lucene-codecs:1.2.3 (5 constraints: 1231231) @@ -1046,7 +843,7 @@ describe('modules/manager/gradle/extract', () => { it('plugin not used due to lockfile not a GCV lockfile', async () => { const fsMock = { 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` This is NOT a lock file `, }; @@ -1072,117 +869,5 @@ describe('modules/manager/gradle/extract', () => { ); expect(res).toBeNull(); }); - - it('supports multiple levels of glob', async () => { - const fsMock = { - 'versions.props': stripIndent` - org.apache.* = 4 - org.apache.lucene:* = 3 - org.apache.lucene:a.* = 2 - org.apache.lucene:a.b = 1 - org.apache.foo*:* = 5 - `, - 'versions.lock': stripIndent` - # Run ./gradlew --write-locks to regenerate this file - org.apache.solr:x.y:1 (10 constraints: 95be0c15) - org.apache.lucene:a.b:1 (10 constraints: 95be0c15) - org.apache.lucene:a.c:1 (10 constraints: 95be0c15) - org.apache.lucene:a.d:1 (10 constraints: 95be0c15) - org.apache.lucene:d:1 (10 constraints: 95be0c15) - org.apache.lucene:e.f:1 (10 constraints: 95be0c15) - org.apache.foo-bar:a:1 (10 constraints: 95be0c15) - `, - }; - mockFs(fsMock); - - const res = await extractAllPackageFiles( - partial<ExtractConfig>(), - Object.keys(fsMock), - ); - - // Each lock dep is only present once, with highest prio for exact prop match, then globs from longest to shortest - expect(res).toMatchObject([ - { - packageFile: 'versions.lock', - deps: [], - }, - { - packageFile: 'versions.props', - deps: [ - { - managerData: { - packageFile: 'versions.props', - fileReplacePosition: 91, - }, - depName: 'org.apache.lucene:a.b', - currentValue: '1', - lockedVersion: '1', - fileReplacePosition: 91, - depType: 'dependencies', - }, - { - managerData: { - packageFile: 'versions.props', - fileReplacePosition: 65, - }, - depName: 'org.apache.lucene:a.c', - currentValue: '2', - lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', - fileReplacePosition: 65, - depType: 'dependencies', - }, - { - managerData: { - packageFile: 'versions.props', - fileReplacePosition: 65, - }, - depName: 'org.apache.lucene:a.d', - currentValue: '2', - lockedVersion: '1', - groupName: 'org.apache.lucene:a.*', - fileReplacePosition: 65, - depType: 'dependencies', - }, - { - managerData: { - packageFile: 'versions.props', - fileReplacePosition: 39, - }, - depName: 'org.apache.lucene:d', - currentValue: '3', - lockedVersion: '1', - groupName: 'org.apache.lucene:*', - fileReplacePosition: 39, - depType: 'dependencies', - }, - { - managerData: { - packageFile: 'versions.props', - fileReplacePosition: 39, - }, - depName: 'org.apache.lucene:e.f', - currentValue: '3', - lockedVersion: '1', - groupName: 'org.apache.lucene:*', - fileReplacePosition: 39, - depType: 'dependencies', - }, - { - managerData: { - fileReplacePosition: 113, - packageFile: 'versions.props', - }, - depName: 'org.apache.foo-bar:a', - currentValue: '5', - lockedVersion: '1', - groupName: 'org.apache.foo*:*', - fileReplacePosition: 113, - depType: 'dependencies', - }, - ], - }, - ]); - }); }); }); diff --git a/lib/modules/manager/gradle/extract/catalog.spec.ts b/lib/modules/manager/gradle/extract/catalog.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1dc53281634a545be12c6bc27747a9d1fa46578 --- /dev/null +++ b/lib/modules/manager/gradle/extract/catalog.spec.ts @@ -0,0 +1,194 @@ +import { codeBlock } from 'common-tags'; +import { parseCatalog } from './catalog'; + +describe('modules/manager/gradle/extract/catalog', () => { + it('supports versions declared as single string', () => { + const input = codeBlock` + [versions] + kotlin = "1.5.21" + retro_fit = "2.8.2" + + [libraries] + okHttp = "com.squareup.okhttp3:okhttp:4.9.0" + okio = { module = "com.squareup.okio:okio", version = "2.8.0" } + picasso = { group = "com.squareup.picasso", name = "picasso", version = "2.5.1" } + retrofit2-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retro_fit" } + google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" } + google-firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics" } + google-firebase-messaging = "com.google.firebase:firebase-messaging" + + [plugins] + kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version = "1.5.21" } + kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + multiJvm = "org.danilopianini.multi-jvm-test-plugin:0.3.0" + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + expect(res).toStrictEqual([ + { + depName: 'com.squareup.okhttp3:okhttp', + currentValue: '4.9.0', + managerData: { + fileReplacePosition: 100, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.okio:okio', + currentValue: '2.8.0', + managerData: { + fileReplacePosition: 162, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.picasso:picasso', + currentValue: '2.5.1', + managerData: { + fileReplacePosition: 244, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'com.squareup.retrofit2:retrofit', + groupName: 'retro.fit', + currentValue: '2.8.2', + managerData: { + fileReplacePosition: 42, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'google-firebase-analytics', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'google-firebase-crashlytics', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'google-firebase-messaging', + managerData: { + packageFile: 'gradle/libs.versions.toml', + }, + skipReason: 'unspecified-version', + }, + { + depName: 'org.jetbrains.kotlin.jvm', + depType: 'plugin', + currentValue: '1.5.21', + commitMessageTopic: 'plugin kotlinJvm', + packageName: + 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin', + managerData: { + fileReplacePosition: 663, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'org.jetbrains.kotlin.plugin.serialization', + depType: 'plugin', + currentValue: '1.5.21', + groupName: 'kotlin', + packageName: + 'org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'org.danilopianini.multi-jvm-test-plugin', + depType: 'plugin', + currentValue: '0.3.0', + commitMessageTopic: 'plugin multiJvm', + packageName: + 'org.danilopianini.multi-jvm-test-plugin:org.danilopianini.multi-jvm-test-plugin.gradle.plugin', + managerData: { + fileReplacePosition: 824, + packageFile: 'gradle/libs.versions.toml', + }, + }, + ]); + }); + + it('deletes commit message for plugins with version reference', () => { + const input = codeBlock` + [versions] + detekt = "1.18.1" + + [plugins] + detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } + + [libraries] + detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + + expect(res).toStrictEqual([ + { + depName: 'io.gitlab.arturbosch.detekt:detekt-formatting', + groupName: 'detekt', + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depType: 'plugin', + depName: 'io.gitlab.arturbosch.detekt', + packageName: + 'io.gitlab.arturbosch.detekt:io.gitlab.arturbosch.detekt.gradle.plugin', + currentValue: '1.18.1', + managerData: { + fileReplacePosition: 21, + packageFile: 'gradle/libs.versions.toml', + }, + groupName: 'detekt', + }, + ]); + }); + + it('changes the dependency version, not the comment version', () => { + const input = codeBlock` + [versions] + # Releases: http://someWebsite.com/junit/1.4.9 + mocha-junit-reporter = "2.0.2" + # JUnit 1.4.9 is awesome! + junit = "1.4.9" + + + [libraries] + junit-legacy = { module = "junit:junit", version.ref = "junit" } + mocha-junit = { module = "mocha-junit:mocha-junit", version.ref = "mocha.junit.reporter" } + `; + const res = parseCatalog('gradle/libs.versions.toml', input); + + expect(res).toStrictEqual([ + { + depName: 'junit:junit', + groupName: 'junit', + currentValue: '1.4.9', + managerData: { + fileReplacePosition: 124, + packageFile: 'gradle/libs.versions.toml', + }, + }, + { + depName: 'mocha-junit:mocha-junit', + groupName: 'mocha.junit.reporter', + currentValue: '2.0.2', + managerData: { + fileReplacePosition: 82, + packageFile: 'gradle/libs.versions.toml', + }, + }, + ]); + }); +}); diff --git a/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts b/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts index 5ebaef86501b142d7dbb60b22b8a64c32e2ac277..fdde721e725453eeb5c7129895f20fffbd9faa89 100644 --- a/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts +++ b/lib/modules/manager/gradle/extract/consistent-versions-plugin.spec.ts @@ -1,16 +1,17 @@ -import { stripIndent } from 'common-tags'; +import { codeBlock } from 'common-tags'; import { + parseGcv, parseLockFile, parsePropsFile, usesGcv, } from './consistent-versions-plugin'; describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { - it('gradle-consistent-versions plugin works for sub folders', () => { + it('works for sub folders', () => { const fsMock = { 'mysub/build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'mysub/versions.props': `org.apache.lucene:* = 1.2.3`, - 'mysub/versions.lock': stripIndent` + 'mysub/versions.lock': codeBlock` # Run ./gradlew --write-locks to regenerate this file org.apache.lucene:lucene-core:1.2.3`, 'othersub/build.gradle.kts': `nothing here`, @@ -24,7 +25,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { const fsMock = { 'build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew writeVersionsLock to regenerate this file org.apache.lucene:lucene-core:1.2.3`, }; @@ -36,7 +37,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { const fsMock = { 'build.gradle.kts': `(this file contains) 'com.palantir.consistent-versions'`, 'versions.props': `org.apache.lucene:* = 1.2.3`, - 'versions.lock': stripIndent` + 'versions.lock': codeBlock` # Run ./gradlew writeVersionsLocks to regenerate this file org.apache.lucene:lucene-core:1.2.3`, }; @@ -44,7 +45,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(usesGcv('versions.props', fsMock)).toBeTrue(); }); - it('gradle-consistent-versions plugin correct position for CRLF and LF', () => { + it('correct position for CRLF and LF', () => { const crlfProps = parsePropsFile(`a.b:c.d=1\r\na.b:c.e=2`); expect(crlfProps).toBeArrayOfSize(2); expect(crlfProps[0].has('a.b:c.e')).toBeTrue(); @@ -56,8 +57,8 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(lfProps[0].get('a.b:c.e')).toMatchObject({ filePos: 18 }); }); - it('gradle-consistent-versions plugin test bogus input lines', () => { - const parsedProps = parsePropsFile(stripIndent` + it('test bogus input lines', () => { + const parsedProps = parsePropsFile(codeBlock` # comment:foo.bar = 1 123.foo:bar = 2 this has:spaces = 3 @@ -71,7 +72,7 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { expect(parsedProps[0]).toMatchObject({ size: 1 }); // no 7 is valid exact dep expect(parsedProps[1]).toMatchObject({ size: 1 }); // no 8 is valid glob dep - const parsedLock = parseLockFile(stripIndent` + const parsedLock = parseLockFile(codeBlock` # comment:foo.bar:1 (10 constraints: 95be0c15) 123.foo:bar:2 (10 constraints: 95be0c15) this has:spaces:3 (10 constraints: 95be0c15) @@ -92,4 +93,96 @@ describe('modules/manager/gradle/extract/consistent-versions-plugin', () => { depType: 'test', }); }); + + it('supports multiple levels of glob', () => { + const fsMock = { + 'versions.props': codeBlock` + org.apache.* = 4 + org.apache.lucene:* = 3 + org.apache.lucene:a.* = 2 + org.apache.lucene:a.b = 1 + org.apache.foo*:* = 5 + `, + 'versions.lock': codeBlock` + # Run ./gradlew --write-locks to regenerate this file + org.apache.solr:x.y:1 (10 constraints: 95be0c15) + org.apache.lucene:a.b:1 (10 constraints: 95be0c15) + org.apache.lucene:a.c:1 (10 constraints: 95be0c15) + org.apache.lucene:a.d:1 (10 constraints: 95be0c15) + org.apache.lucene:d:1 (10 constraints: 95be0c15) + org.apache.lucene:e.f:1 (10 constraints: 95be0c15) + org.apache.foo-bar:a:1 (10 constraints: 95be0c15) + `, + }; + const res = parseGcv('versions.props', fsMock); + + // Each lock dep is only present once, with highest prio for exact prop match, then globs from longest to shortest + expect(res).toStrictEqual([ + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 91, + }, + depName: 'org.apache.lucene:a.b', + currentValue: '1', + lockedVersion: '1', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.c', + currentValue: '2', + lockedVersion: '1', + groupName: 'org.apache.lucene:a.*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 65, + }, + depName: 'org.apache.lucene:a.d', + currentValue: '2', + lockedVersion: '1', + groupName: 'org.apache.lucene:a.*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:d', + currentValue: '3', + lockedVersion: '1', + groupName: 'org.apache.lucene:*', + depType: 'dependencies', + }, + { + managerData: { + packageFile: 'versions.props', + fileReplacePosition: 39, + }, + depName: 'org.apache.lucene:e.f', + currentValue: '3', + lockedVersion: '1', + groupName: 'org.apache.lucene:*', + depType: 'dependencies', + }, + { + managerData: { + fileReplacePosition: 113, + packageFile: 'versions.props', + }, + depName: 'org.apache.foo-bar:a', + currentValue: '5', + lockedVersion: '1', + groupName: 'org.apache.foo*:*', + depType: 'dependencies', + }, + ]); + }); }); diff --git a/lib/modules/manager/gradle/utils.spec.ts b/lib/modules/manager/gradle/utils.spec.ts index 1de059b86c62b95004db6a1551d62bbb6f5e65fb..d8879d0ebf2bd34c1d8805996922c1c832dd08c8 100644 --- a/lib/modules/manager/gradle/utils.spec.ts +++ b/lib/modules/manager/gradle/utils.spec.ts @@ -1,7 +1,13 @@ -import type { VariableRegistry } from './types'; +import type { PackageVariables, VariableRegistry } from './types'; import { getVars, isDependencyString, + isGradleBuildFile, + isGradleScriptFile, + isGradleVersionsFile, + isKotlinSourceFile, + isPropsFile, + isTOMLFile, parseDependencyString, reorderFiles, toAbsolutePath, @@ -10,66 +16,83 @@ import { } from './utils'; describe('modules/manager/gradle/utils', () => { - it('versionLikeSubstring', () => { - [ - '1.2.3', - '[1.0,2.0]', - '(,2.0[', - '2.1.1.RELEASE', - '1.0.+', - '2022-05-10_55', - ].forEach((input) => { - expect(versionLikeSubstring(input)).toEqual(input); - expect(versionLikeSubstring(`${input}'`)).toEqual(input); - expect(versionLikeSubstring(`${input}"`)).toEqual(input); - expect(versionLikeSubstring(`${input}\n`)).toEqual(input); - expect(versionLikeSubstring(`${input} `)).toEqual(input); - expect(versionLikeSubstring(`${input}$`)).toEqual(input); + describe('versionLikeSubstring', () => { + it('extracts the actual version', () => { + const inputs = [ + '1.2.3', + '[1.0,2.0]', + '(,2.0[', + '2.1.1.RELEASE', + '1.0.+', + '2022-05-10_55', + ]; + const suffixes = ['', "'", '"', '\n', ' ', '$']; + + for (const input of inputs) { + for (const suffix of suffixes) { + expect(versionLikeSubstring(`${input}${suffix}`)).toEqual(input); + } + } }); - expect(versionLikeSubstring('')).toBeNull(); - expect(versionLikeSubstring(undefined)).toBeNull(); - expect(versionLikeSubstring(null)).toBeNull(); - expect(versionLikeSubstring('foobar')).toBeNull(); - expect(versionLikeSubstring('latest')).toBeNull(); - }); - it('isDependencyString', () => { - expect(isDependencyString('foo:bar:1.2.3')).toBeTrue(); - expect(isDependencyString('foo.foo:bar.bar:1.2.3')).toBeTrue(); - expect(isDependencyString('foo:bar:baz:qux')).toBeFalse(); - expect(isDependencyString('foo.bar:baz:1.2.3')).toBeTrue(); - expect(isDependencyString('foo.bar:baz:1.2.3:linux-cpu-x86_64')).toBeTrue(); - expect(isDependencyString('foo.bar:baz:1.2.+')).toBeTrue(); - expect(isDependencyString('foo:bar:baz:qux:quux')).toBeFalse(); - expect(isDependencyString("foo:bar:1.2.3'")).toBeFalse(); - expect(isDependencyString('foo:bar:1.2.3"')).toBeFalse(); - expect(isDependencyString('-Xep:ParameterName:OFF')).toBeFalse(); - expect(isDependencyString('foo$bar:baz:1.2.+')).toBeFalse(); - expect(isDependencyString('scm:git:https://some.git')).toBeFalse(); + it('returns null for invalid inputs', () => { + const inputs = ['', undefined, null, 'foobar', 'latest']; + for (const input of inputs) { + expect(versionLikeSubstring(input)).toBeNull(); + } + }); }); - it('parseDependencyString', () => { - expect(parseDependencyString('foo:bar:1.2.3')).toMatchObject({ - depName: 'foo:bar', - currentValue: '1.2.3', + describe('isDependencyString', () => { + it.each` + input | output + ${'foo:bar:1.2.3'} | ${true} + ${'foo.foo:bar.bar:1.2.3'} | ${true} + ${'foo.bar:baz:1.2.3'} | ${true} + ${'foo.bar:baz:1.2.3:linux-cpu-x86_64'} | ${true} + ${'foo:bar:1.2.3@zip'} | ${true} + ${'foo:bar:x86@x86'} | ${true} + ${'foo.bar:baz:1.2.+'} | ${true} + ${'foo:bar:baz:qux'} | ${false} + ${'foo:bar:baz:qux:quux'} | ${false} + ${"foo:bar:1.2.3'"} | ${false} + ${'foo:bar:1.2.3"'} | ${false} + ${'-Xep:ParameterName:OFF'} | ${false} + ${'foo$bar:baz:1.2.+'} | ${false} + ${'scm:git:https://some.git'} | ${false} + ${'foo.bar:baz:1.2.3:linux-cpu$-x86_64'} | ${false} + ${'foo:bar:1.2.3@zip@foo'} | ${false} + `('$input', ({ input, output }) => { + expect(isDependencyString(input)).toBe(output); }); - expect(parseDependencyString('foo.foo:bar.bar:1.2.3')).toMatchObject({ - depName: 'foo.foo:bar.bar', - currentValue: '1.2.3', - }); - expect(parseDependencyString('foo.bar:baz:1.2.3')).toMatchObject({ - depName: 'foo.bar:baz', - currentValue: '1.2.3', - }); - expect(parseDependencyString('foo:bar:1.2.+')).toMatchObject({ - depName: 'foo:bar', - currentValue: '1.2.+', + }); + + describe('parseDependencyString', () => { + it.each` + input | output + ${'foo:bar:1.2.3'} | ${{ depName: 'foo:bar', currentValue: '1.2.3' }} + ${'foo.foo:bar.bar:1.2.3'} | ${{ depName: 'foo.foo:bar.bar', currentValue: '1.2.3' }} + ${'foo.bar:baz:1.2.3'} | ${{ depName: 'foo.bar:baz', currentValue: '1.2.3' }} + ${'foo:bar:1.2.+'} | ${{ depName: 'foo:bar', currentValue: '1.2.+' }} + ${'foo:bar:1.2.3@zip'} | ${{ depName: 'foo:bar', currentValue: '1.2.3', dataType: 'zip' }} + ${'foo:bar:baz:qux'} | ${null} + ${'foo:bar:baz:qux:quux'} | ${null} + ${"foo:bar:1.2.3'"} | ${null} + ${'foo:bar:1.2.3"'} | ${null} + ${'-Xep:ParameterName:OFF'} | ${null} + `('$input', ({ input, output }) => { + expect(parseDependencyString(input)).toEqual(output); }); - expect(parseDependencyString('foo:bar:baz:qux')).toBeNull(); - expect(parseDependencyString('foo:bar:baz:qux:quux')).toBeNull(); - expect(parseDependencyString("foo:bar:1.2.3'")).toBeNull(); - expect(parseDependencyString('foo:bar:1.2.3"')).toBeNull(); - expect(parseDependencyString('-Xep:ParameterName:OFF')).toBeNull(); + }); + + it('filetype checks', () => { + expect(isGradleScriptFile('/a/Somefile.gradle.kts')).toBeTrue(); + expect(isGradleScriptFile('/a/Somefile.gradle')).toBeTrue(); + expect(isGradleVersionsFile('/a/versions.gradle.kts')).toBeTrue(); + expect(isGradleBuildFile('/a/build.gradle')).toBeTrue(); + expect(isPropsFile('/a/gradle.properties')).toBeTrue(); + expect(isKotlinSourceFile('/a/Somefile.kt')).toBeTrue(); + expect(isTOMLFile('/a/Somefile.toml')).toBeTrue(); }); it('reorderFiles', () => { @@ -175,20 +198,33 @@ describe('modules/manager/gradle/utils', () => { }); }); - it('updateVars', () => { - const registry: VariableRegistry = { - [toAbsolutePath('/foo/bar/baz')]: { + describe('updateVars', () => { + it('empty registry', () => { + const registry: VariableRegistry = {}; + const newVars: PackageVariables = { + qux: { key: 'qux', value: 'qux' }, + }; + updateVars(registry, '/foo/bar/baz', newVars); + expect(registry).toStrictEqual({ '/foo/bar/baz': newVars }); + }); + + it('updates the registry', () => { + const registry: VariableRegistry = { + [toAbsolutePath('/foo/bar/baz')]: { + bar: { key: 'bar', value: 'bar' }, + baz: { key: 'baz', value: 'baz' }, + }, + }; + + updateVars(registry, '/foo/bar/baz', { + qux: { key: 'qux', value: 'qux' }, + }); + const res = getVars(registry, '/foo/bar/baz/build.gradle'); + expect(res).toStrictEqual({ bar: { key: 'bar', value: 'bar' }, baz: { key: 'baz', value: 'baz' }, - }, - }; - - updateVars(registry, '/foo/bar/baz', { qux: { key: 'qux', value: 'qux' } }); - const res = getVars(registry, '/foo/bar/baz/build.gradle'); - expect(res).toStrictEqual({ - bar: { key: 'bar', value: 'bar' }, - baz: { key: 'baz', value: 'baz' }, - qux: { key: 'qux', value: 'qux' }, + qux: { key: 'qux', value: 'qux' }, + }); }); }); });