Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gradle): Add basic Gradle Kotlin DSL support #4086

Merged
merged 2 commits into from
Aug 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/config/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1644,7 +1644,7 @@ const options = [
stage: 'package',
type: 'object',
default: {
fileMatch: ['\\.gradle$', '(^|/)gradle.properties$'],
fileMatch: ['\\.gradle(\\.kts)?$', '(^|/)gradle.properties$'],
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
2 changes: 1 addition & 1 deletion renovate-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@
"description": "Configuration object for build.gradle files",
"type": "object",
"default": {
"fileMatch": ["\\.gradle$", "(^|/)gradle.properties$"],
"fileMatch": ["\\.gradle(\\.kts)?$", "(^|/)gradle.properties$"],
"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