From aeb4bc069bdafffc6a9818428ba82816120d4ba9 Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sun, 14 Jul 2019 18:01:36 +0900 Subject: [PATCH] feat(gradle): Add basic Gradle Kotlin DSL support --- lib/config/definitions.js | 6 +- lib/manager/gradle/build-gradle.js | 49 ++++++++++++ lib/manager/gradle/index.js | 8 +- renovate-schema.json | 6 +- .../gradle/__snapshots__/index.spec.js.snap | 79 +++++++++++++++++++ test/manager/gradle/build-gradle.spec.js | 58 ++++++++++++++ test/manager/gradle/index.spec.js | 8 ++ website/docs/java.md | 4 +- 8 files changed, 212 insertions(+), 6 deletions(-) diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 909f67ccf56cdbc..248960520d5147b 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -1633,7 +1633,11 @@ const options = [ stage: 'package', type: 'object', default: { - fileMatch: ['\\.gradle$', '(^|/)gradle.properties$'], + fileMatch: [ + '\\.gradle(\\.kts)?$', + '(^|/)gradle.properties$', + '(^|/)buildSrc/.*', + ], timeout: 300, versionScheme: 'maven', }, diff --git a/lib/manager/gradle/build-gradle.js b/lib/manager/gradle/build-gradle.js index 03fc6debc028fcf..53e984c83bfe68f 100644 --- a/lib/manager/gradle/build-gradle.js +++ b/lib/manager/gradle/build-gradle.js @@ -10,7 +10,9 @@ function updateGradleVersion(buildGradleContent, dependency, newVersion) { const updateFunctions = [ updateVersionStringFormat, updateVersionMapFormat, + updateVersionKotlinNamedArgumentFormat, updateVersionMapVariableFormat, + updateVersionKotlinNamedArgumentVariableFormat, updateVersionStringVariableFormat, updateVersionExpressionVariableFormat, updateGlobalVariables, @@ -43,6 +45,7 @@ function collectVersionVariables(dependencies, buildGradleContent) { moduleStringVariableExpressionVersionFormatMatch(dependency), moduleStringVariableInterpolationVersionFormatMatch(dependency), moduleMapVariableVersionFormatMatch(dependency), + moduleKotlinNamedArgumentVariableVersionFormatMatch(dependency), ]; for (const regex of regexes) { @@ -74,6 +77,18 @@ function updateVersionMapFormat(dependency, buildGradleContent, newVersion) { return null; } +function updateVersionKotlinNamedArgumentFormat( + dependency, + buildGradleContent, + newVersion +) { + const regex = moduleKotlinNamedArgumentVersionFormatMatch(dependency); + if (buildGradleContent.match(regex)) { + return buildGradleContent.replace(regex, `$1${newVersion}$2`); + } + return null; +} + function updateVersionMapVariableFormat( dependency, buildGradleContent, @@ -90,6 +105,22 @@ function updateVersionMapVariableFormat( return null; } +function updateVersionKotlinNamedArgumentVariableFormat( + dependency, + buildGradleContent, + newVersion +) { + const regex = moduleKotlinNamedArgumentVariableVersionFormatMatch(dependency); + const match = buildGradleContent.match(regex); + if (match) { + return buildGradleContent.replace( + variableDefinitionFormatMatch(match[1]), + `$1${newVersion}$3` + ); + } + return null; +} + function updateVersionStringVariableFormat( dependency, buildGradleContent, @@ -169,6 +200,15 @@ function moduleMapVersionFormatMatch(dependency) { ); } +function moduleKotlinNamedArgumentVersionFormatMatch(dependency) { + // prettier-ignore + return new RegExp( + `(group\\s*=\\s*"${dependency.group}"\\s*,\\s*` + + `name\\s*=\\s*"${dependency.name}"\\s*,\\s*` + + `version\\s*=\\s*").*?(")` + ); +} + function moduleMapVariableVersionFormatMatch(dependency) { // prettier-ignore return new RegExp( @@ -178,6 +218,15 @@ function moduleMapVariableVersionFormatMatch(dependency) { ); } +function moduleKotlinNamedArgumentVariableVersionFormatMatch(dependency) { + // prettier-ignore + return new RegExp( + `group\\s*=\\s*"${dependency.group}"\\s*,\\s*` + + `name\\s*=\\s*"${dependency.name}"\\s*,\\s*` + + `version\\s*=\\s*([^\\s"]+?)[\\s\\),]` + ); +} + function moduleStringVariableInterpolationVersionFormatMatch(dependency) { return new RegExp( `["']${dependency.group}:${dependency.name}:\\$([^{].*?)["']` diff --git a/lib/manager/gradle/index.js b/lib/manager/gradle/index.js index bfc1f8c43e94a27..af10d7bb61c6b62 100644 --- a/lib/manager/gradle/index.js +++ b/lib/manager/gradle/index.js @@ -10,8 +10,12 @@ const GRADLE_DEPENDENCY_REPORT_OPTIONS = const TIMEOUT_CODE = 143; async function extractAllPackageFiles(config, packageFiles) { - if (!packageFiles.some(packageFile => packageFile === 'build.gradle')) { - logger.warn('No root build.gradle found - skipping'); + if ( + !packageFiles.some(packageFile => + ['build.gradle', 'build.gradle.kts'].includes(packageFile) + ) + ) { + logger.warn('No root build.gradle nor build.gradle.kts found - skipping'); return null; } logger.info('Extracting dependencies from all gradle files'); diff --git a/renovate-schema.json b/renovate-schema.json index 52868c23f5e4a22..56f2c32d185b87c 100644 --- a/renovate-schema.json +++ b/renovate-schema.json @@ -1122,7 +1122,11 @@ "description": "Configuration object for build.gradle files", "type": "object", "default": { - "fileMatch": ["\\.gradle$", "(^|/)gradle.properties$"], + "fileMatch": [ + "\\.gradle(\\.kts)?$", + "(^|/)gradle.properties$", + "(^|/)buildSrc/.*" + ], "timeout": 300, "versionScheme": "maven" }, diff --git a/test/manager/gradle/__snapshots__/index.spec.js.snap b/test/manager/gradle/__snapshots__/index.spec.js.snap index be187adcdc2218b..c3751811704d9e6 100644 --- a/test/manager/gradle/__snapshots__/index.spec.js.snap +++ b/test/manager/gradle/__snapshots__/index.spec.js.snap @@ -79,6 +79,85 @@ Array [ ] `; +exports[`manager/gradle extractPackageFile should return gradle.kts dependencies 1`] = ` +Array [ + Object { + "datasource": "maven", + "deps": Array [ + Object { + "currentValue": null, + "depGroup": "org.springframework.boot", + "depName": "org.springframework.boot:spring-boot-starter-jersey", + "name": "spring-boot-starter-jersey", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + Object { + "currentValue": "1.0-groovy-2.4", + "depGroup": "org.spockframework", + "depName": "org.spockframework:spock-core", + "name": "spock-core", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + Object { + "currentValue": "3.1", + "depGroup": "cglib", + "depName": "cglib:cglib-nodep", + "name": "cglib-nodep", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + ], + "manager": "gradle", + "packageFile": "build.gradle.kts", + }, + Object { + "datasource": "maven", + "deps": Array [ + Object { + "currentValue": null, + "depGroup": "org.springframework.boot", + "depName": "org.springframework.boot:spring-boot-starter-jersey", + "name": "spring-boot-starter-jersey", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + Object { + "currentValue": "1.0-groovy-2.4", + "depGroup": "org.spockframework", + "depName": "org.spockframework:spock-core", + "name": "spock-core", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + Object { + "currentValue": "3.1", + "depGroup": "cglib", + "depName": "cglib:cglib-nodep", + "name": "cglib-nodep", + "registryUrls": Array [ + "https://repo.maven.apache.org/maven2/", + "https://jitpack.io", + ], + }, + ], + "manager": "gradle", + "packageFile": "subproject/build.gradle.kts", + }, +] +`; + exports[`manager/gradle extractPackageFile should throw registry failure if gradle execution fails 1`] = `[Error: registry-failure]`; exports[`manager/gradle extractPackageFile should use repositories only for current project 1`] = ` diff --git a/test/manager/gradle/build-gradle.spec.js b/test/manager/gradle/build-gradle.spec.js index 514973395a74eb9..5987ae15d586ad2 100644 --- a/test/manager/gradle/build-gradle.spec.js +++ b/test/manager/gradle/build-gradle.spec.js @@ -82,6 +82,22 @@ describe('lib/manager/gradle/updateGradleVersion', () => { ); }); + it('returns a file updated if the version defined as a Kotlin named argument is found', () => { + const gradleFile = `compile(group = "mysql" , + name = "mysql-connector-java", + version = "6.0.5")`; + const updatedGradleFile = gradle.updateGradleVersion( + gradleFile, + { group: 'mysql', name: 'mysql-connector-java', version: '6.0.5' }, + '7.0.0' + ); + expect(updatedGradleFile).toEqual( + `compile(group = "mysql" , + name = "mysql-connector-java", + version = "7.0.0")` + ); + }); + it('should returns a file updated if the version defined in a variable as a string is found', () => { const gradleFile = `String mysqlVersion= "6.0.5" runtime ( "mysql:mysql-connector-java:$mysqlVersion" ) @@ -130,6 +146,26 @@ describe('lib/manager/gradle/updateGradleVersion', () => { ); }); + it('should returns a file updated if the version defined in a variable as a Kotlin named argument is found', () => { + const gradleFile = `val mysqlVersion = "6.0.5" + compile(group = "mysql" , + name = "mysql-connector-java", + version = mysqlVersion) + `; + const updatedGradleFile = gradle.updateGradleVersion( + gradleFile, + { group: 'mysql', name: 'mysql-connector-java', version: '6.0.5' }, + '7.0.0' + ); + expect(updatedGradleFile).toEqual( + `val mysqlVersion = "7.0.0" + compile(group = "mysql" , + name = "mysql-connector-java", + version = mysqlVersion) + ` + ); + }); + it('should replace a external groovy variable assigned to a specific dependency', () => { const gradleFile = 'runtime ( "mysql:mysql-connector-java:${mysqlVersion}" )'; // eslint-disable-line no-template-curly-in-string @@ -192,6 +228,28 @@ describe('lib/manager/gradle/updateGradleVersion', () => { expect(updatedGradleFile).toEqual('String mysqlVersion = "7.0.0"'); }); + it('should replace a external variable assigned to a Kotlin named argument dependency', () => { + const gradleFile = `compile(group = "mysql" , + name = "mysql-connector-java", + version = mysqlVersion) + `; + const mysqlDependency = { + group: 'mysql', + depGroup: 'mysql', + name: 'mysql-connector-java', + version: '6.0.5', + }; + gradle.collectVersionVariables([mysqlDependency], gradleFile); + + const gradleWithVersionFile = 'val mysqlVersion = "6.0.5"'; + const updatedGradleFile = gradle.updateGradleVersion( + gradleWithVersionFile, + mysqlDependency, + '7.0.0' + ); + expect(updatedGradleFile).toEqual('val mysqlVersion = "7.0.0"'); + }); + it('should replace a external variable assigned to a interpolated dependency', () => { const gradleFile = 'runtime ( "mysql:mysql-connector-java:$mysqlVersion" )'; diff --git a/test/manager/gradle/index.spec.js b/test/manager/gradle/index.spec.js index 6575cb2e48b7e83..18600df4653c0a0 100644 --- a/test/manager/gradle/index.spec.js +++ b/test/manager/gradle/index.spec.js @@ -39,6 +39,14 @@ describe('manager/gradle', () => { expect(dependencies).toMatchSnapshot(); }); + it('should return gradle.kts dependencies', async () => { + const dependencies = await manager.extractAllPackageFiles(config, [ + 'build.gradle.kts', + 'subproject/build.gradle.kts', + ]); + expect(dependencies).toMatchSnapshot(); + }); + it('should return empty if there are no dependencies', async () => { fs.readFile.mockReturnValue( fsReal.readFileSync( diff --git a/website/docs/java.md b/website/docs/java.md index 36618ad8dad92fa..87be83fdca4f05c 100644 --- a/website/docs/java.md +++ b/website/docs/java.md @@ -13,11 +13,11 @@ Renovate detects versions specified as string `'group:artifact:version'` and as ### File Support -Renovate can update `build.gradle` files in the root of the repository and any `*.gradle` file inside any subdirectory as multi-project configurations. +Renovate can update `build.gradle`/`build.gradle.kts` files in the root of the repository and any `*.gradle`/`*.gradle.kts` file inside any subdirectory as multi-project configurations. Renovate does not support: -- Projects without a `build.gradle` file in the root of the repository. +- Projects without neither `build.gradle` nor `build.gradle.kts` file in the root of the repository. - Android projects that requires extra configuration to run. (e.g. setting the android SDK) ### How It Works