Skip to content

Commit

Permalink
feat(gradle): Add basic Gradle Kotlin DSL support
Browse files Browse the repository at this point in the history
  • Loading branch information
ikesyo committed Jul 29, 2019
1 parent 2fbed0e commit 7d64f88
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 8 deletions.
6 changes: 5 additions & 1 deletion lib/config/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,11 @@ const options = [
stage: 'package',
type: 'object',
default: {
fileMatch: ['\\.gradle$', '(^|/)gradle.properties$'],
fileMatch: [
'\\.gradle(\\.kts)?$',
'(^|/)gradle.properties$',
'(^|/)buildSrc/.*',
],
timeout: 300,
versionScheme: 'maven',
},
Expand Down
36 changes: 34 additions & 2 deletions lib/manager/gradle/build-gradle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export function collectVersionVariables(
moduleStringVariableExpressionVersionFormatMatch(dependency),
moduleStringVariableInterpolationVersionFormatMatch(dependency),
moduleMapVariableVersionFormatMatch(dependency),
moduleKotlinNamedArgumentVariableVersionFormatMatch(dependency),
];

for (const regex of regexes) {
Expand All @@ -86,8 +87,10 @@ function updateVersionLiterals(
) {
const regexes: RegExp[] = [
moduleStringVersionFormatMatch(dependency),
pluginStringVersionFormatMatch(dependency),
groovyPluginStringVersionFormatMatch(dependency),
kotlinPluginStringVersionFormatMatch(dependency),
moduleMapVersionFormatMatch(dependency),
moduleKotlinNamedArgumentVersionFormatMatch(dependency),
];
for (const regex of regexes) {
if (buildGradleContent.match(regex)) {
Expand All @@ -106,6 +109,7 @@ function updateLocalVariables(
moduleMapVariableVersionFormatMatch(dependency),
moduleStringVariableInterpolationVersionFormatMatch(dependency),
moduleStringVariableExpressionVersionFormatMatch(dependency),
moduleKotlinNamedArgumentVariableVersionFormatMatch(dependency),
];
for (const regex of regexes) {
const match = buildGradleContent.match(regex);
Expand Down Expand Up @@ -161,12 +165,18 @@ function moduleStringVersionFormatMatch(dependency: GradleDependency) {
);
}

function pluginStringVersionFormatMatch(dependency: GradleDependency) {
function groovyPluginStringVersionFormatMatch(dependency: GradleDependency) {
return new RegExp(
`(id\\s+["']${dependency.group}["']\\s+version\\s+["'])[^$].*?(["'])`
);
}

function kotlinPluginStringVersionFormatMatch(dependency: GradleDependency) {
return new RegExp(
`(id\\("${dependency.group}"\\)\\s+version\\s+")[^$].*?(")`
);
}

function moduleMapVersionFormatMatch(dependency: GradleDependency) {
// prettier-ignore
return new RegExp(
Expand All @@ -176,6 +186,17 @@ function moduleMapVersionFormatMatch(dependency: GradleDependency) {
);
}

function moduleKotlinNamedArgumentVersionFormatMatch(
dependency: GradleDependency
) {
// 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: GradleDependency) {
// prettier-ignore
return new RegExp(
Expand All @@ -185,6 +206,17 @@ function moduleMapVariableVersionFormatMatch(dependency: GradleDependency) {
);
}

function moduleKotlinNamedArgumentVariableVersionFormatMatch(
dependency: GradleDependency
) {
// 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: GradleDependency
) {
Expand Down
8 changes: 6 additions & 2 deletions lib/manager/gradle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ export async function extractAllPackageFiles(
config: ExtractConfig,
packageFiles: string[]
): Promise<PackageFile[]> {
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');
Expand Down
6 changes: 5 additions & 1 deletion renovate-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,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"
},
Expand Down
79 changes: 79 additions & 0 deletions test/manager/gradle/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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`] = `
Expand Down
58 changes: 58 additions & 0 deletions test/manager/gradle/build-gradle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 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" )
Expand Down Expand Up @@ -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 = 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
Expand Down Expand Up @@ -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',
};
collectVersionVariables([mysqlDependency], gradleFile);

const gradleWithVersionFile = 'val mysqlVersion = "6.0.5"';
const updatedGradleFile = 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" )';
Expand Down
37 changes: 37 additions & 0 deletions test/manager/gradle/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,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.mockResolvedValue(fsReal.readFileSync(
'test/datasource/gradle/_fixtures/updatesReportEmpty.json',
Expand Down Expand Up @@ -201,5 +209,34 @@ describe('manager/gradle', () => {
'id "com.github.ben-manes.versions" version "0.20.0"'
);
});

it('should update an existing plugin dependency with Kotlin DSL', () => {
const buildGradleContent = `
plugins {
id("com.github.ben-manes.versions") version "0.20.0"
}
`;
const upgrade = {
depGroup: 'com.github.ben-manes.versions',
name: 'com.github.ben-manes.versions.gradle.plugin',
version: '0.20.0',
newValue: '0.21.0',
};
const buildGradleContentUpdated = manager.updateDependency(
buildGradleContent,
upgrade
);

expect(buildGradleContent).not.toMatch(
'id("com.github.ben-manes.versions") version "0.21.0"'
);

expect(buildGradleContentUpdated).toMatch(
'id("com.github.ben-manes.versions") version "0.21.0"'
);
expect(buildGradleContentUpdated).not.toMatch(
'id("com.github.ben-manes.versions") version "0.20.0"'
);
});
});
});
4 changes: 2 additions & 2 deletions website/docs/java.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 7d64f88

Please sign in to comment.