diff --git a/lib/manager/gradle/index.ts b/lib/manager/gradle/index.ts index 2ff7ebc90e9a58f6a9c6cc5326e8f3af5d8ab229..64f72bd8ef3880bf0967ab1b15cc0883819f6a29 100644 --- a/lib/manager/gradle/index.ts +++ b/lib/manager/gradle/index.ts @@ -1,4 +1,6 @@ import { exists } from 'fs-extra'; +import upath from 'upath'; + import { exec } from '../../util/exec'; import { logger } from '../../logger'; @@ -22,24 +24,38 @@ export async function extractAllPackageFiles( config: ExtractConfig, packageFiles: string[] ): Promise<PackageFile[] | null> { - if ( - !packageFiles.some(packageFile => - ['build.gradle', 'build.gradle.kts'].includes(packageFile) - ) - ) { + let rootBuildGradle: string | undefined; + for (const packageFile of packageFiles) { + if (['build.gradle', 'build.gradle.kts'].includes(packageFile)) { + rootBuildGradle = packageFile; + break; + } + + // If there is gradlew in the same directory, the directory should be a Gradle project root + const dirname = upath.dirname(packageFile); + const gradlewPath = upath.join(dirname, 'gradlew'); + const gradlewExists = await exists( + upath.join(config.localDir, gradlewPath) + ); + if (gradlewExists) { + rootBuildGradle = packageFile; + break; + } + } + if (!rootBuildGradle) { logger.warn('No root build.gradle nor build.gradle.kts found - skipping'); return null; } logger.info('Extracting dependencies from all gradle files'); - await createRenovateGradlePlugin(config.localDir); - await executeGradle(config); + const cwd = upath.join(config.localDir, upath.dirname(rootBuildGradle)); + + await createRenovateGradlePlugin(cwd); + await executeGradle(config, cwd); init(); - const dependencies = await extractDependenciesFromUpdatesReport( - config.localDir - ); + const dependencies = await extractDependenciesFromUpdatesReport(cwd); if (dependencies.length === 0) { return []; } @@ -83,18 +99,18 @@ function buildGradleDependency(config: Upgrade): GradleDependency { return { group: config.depGroup, name: config.name, version: config.version }; } -async function executeGradle(config: ExtractConfig) { +async function executeGradle(config: ExtractConfig, cwd: string) { let stdout: string; let stderr: string; const gradleTimeout = config.gradle && config.gradle.timeout ? config.gradle.timeout * 1000 : undefined; - const cmd = await getGradleCommandLine(config); + const cmd = await getGradleCommandLine(config, cwd); try { logger.debug({ cmd }, 'Start gradle command'); ({ stdout, stderr } = await exec(cmd, { - cwd: config.localDir, + cwd, timeout: gradleTimeout, })); } catch (err) { @@ -117,11 +133,14 @@ async function executeGradle(config: ExtractConfig) { logger.info('Gradle report complete'); } -async function getGradleCommandLine(config: ExtractConfig): Promise<string> { +async function getGradleCommandLine( + config: ExtractConfig, + cwd: string +): Promise<string> { let cmd: string; - const gradlewExists = await exists(config.localDir + '/gradlew'); + const gradlewExists = await exists(upath.join(cwd, 'gradlew')); if (config.binarySource === 'docker') { - cmd = `docker run --rm -v ${config.localDir}:${config.localDir} -w ${config.localDir} renovate/gradle gradle`; + cmd = `docker run --rm -v ${cwd}:${cwd} -w ${cwd} renovate/gradle gradle`; } else if (gradlewExists) { cmd = 'sh gradlew'; } else { diff --git a/test/manager/gradle/__snapshots__/index.spec.ts.snap b/test/manager/gradle/__snapshots__/index.spec.ts.snap index c3751811704d9e6376a653d095e5cedf6552833c..44d2e1ec23bc823c03d0d9d1174ad29365f1cd40 100644 --- a/test/manager/gradle/__snapshots__/index.spec.ts.snap +++ b/test/manager/gradle/__snapshots__/index.spec.ts.snap @@ -79,6 +79,48 @@ Array [ ] `; +exports[`manager/gradle extractPackageFile should return gradle dependencies for build.gradle in subdirectories if there is gradlew in the same directory 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": "foo/build.gradle", + }, +] +`; + exports[`manager/gradle extractPackageFile should return gradle.kts dependencies 1`] = ` Array [ Object { diff --git a/test/manager/gradle/index.spec.ts b/test/manager/gradle/index.spec.ts index 88b3074d996ed8fe447dfa314aa789e4f197a916..1e4d60c6df9525384c8836c931589d78278da60c 100644 --- a/test/manager/gradle/index.spec.ts +++ b/test/manager/gradle/index.spec.ts @@ -117,7 +117,9 @@ describe('manager/gradle', () => { }); }); - it('should return null and gradle should not be executed if no build.gradle', async () => { + it('should return null and gradle should not be executed if no root build.gradle', async () => { + fs.exists.mockResolvedValue(false); + const packageFiles = ['foo/build.gradle']; expect( await manager.extractAllPackageFiles(config, packageFiles) @@ -126,6 +128,13 @@ describe('manager/gradle', () => { expect(exec).toHaveBeenCalledTimes(0); }); + it('should return gradle dependencies for build.gradle in subdirectories if there is gradlew in the same directory', async () => { + const dependencies = await manager.extractAllPackageFiles(config, [ + 'foo/build.gradle', + ]); + expect(dependencies).toMatchSnapshot(); + }); + it('should configure the renovate report plugin', async () => { await manager.extractAllPackageFiles(config, ['build.gradle']);