Skip to content

Commit

Permalink
Add flag to update only explicitly listed dependencies
Browse files Browse the repository at this point in the history
In many larger projects, users often want to update only specific dependencies
as updating everything at once may be too large of a change.  Provide such
functionality through a Gradle @option on the two task classes.

While this @option API exists only from 4.6 up, this is not a breaking change
for lower versions of Gradle as missing annotation types are simply ignored when
classes are being initialized (JLS §13.5.7).
  • Loading branch information
isker committed Jul 14, 2019
1 parent 8cf9c39 commit 35361c1
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 6 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ successfully updated.
will check the *.gradle files as they were when the gradle build started, which means that it can not pick up the
changes applied by `useLatestVersions`.

## Updating only specific dependencies
If your Gradle version is 4.6 or higher, you can pass the `--update-dependency` flag to `useLatestVersions` and
`useLatestVersionsCheck` with a value in the format `$GROUP:$NAME`. Multiple dependencies can be updated by passing
the flag multiple times.

```bash
# gradle useLatestVersions --update-dependency junit:junit --update-dependency com.google.guava:guava && gradle useLatestVersionsCheck --update-dependency junit:junit --update-dependency com.google.guava:guava
```

## Supported dependency formats

Dependencies stated in the following formats should cause the version to be successfully updated by the
Expand Down
23 changes: 21 additions & 2 deletions src/main/groovy/se/patrikerdes/UseLatestVersionsCheckTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ import groovy.json.JsonSlurper
import groovy.transform.CompileStatic
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.TaskAction

@CompileStatic
class UseLatestVersionsCheckTask extends DefaultTask {
@Option(option='update-dependency',
description = 'The same argument that was passed to useLatestVersions')
List<String> updateWhitelist = Collections.emptyList()

UseLatestVersionsCheckTask() {
description = 'Check if all available updates were successfully applied by the useLatestVersions task.'
group = 'Help'
Expand All @@ -31,12 +36,16 @@ class UseLatestVersionsCheckTask extends DefaultTask {
List<DependencyUpdate> wasUpdateable = getOutDatedDependencies(previousDependencyUpdatesJson)
List<DependencyUpdate> leftToUpdate = getOutDatedDependencies(currentDependencyUpdatesJson)

int failedCount = leftToUpdate.size()
int skippedCount = updateWhitelist.empty ? 0 :
leftToUpdate.count { !updateWhitelist.contains(it.groupAndName()) } as int
int failedCount = leftToUpdate.size() - skippedCount
if (failedCount > 0) {
println("useLatestVersions failed to update $failedCount ${deps(failedCount)} " +
'to the latest version:')
for (dependencyUpdate in leftToUpdate) {
println(' - ' + dependencyUpdate)
if (skippedCount == 0 || updateWhitelist.contains(dependencyUpdate.groupAndName())) {
println(' - ' + dependencyUpdate)
}
}
}

Expand All @@ -61,6 +70,16 @@ class UseLatestVersionsCheckTask extends DefaultTask {
}
}

if (skippedCount > 0) {
println("useLatestVersions skipped updating $skippedCount ${deps(skippedCount)} " +
'not in --dependency-update:')
for (dependencyLeftToUpdate in leftToUpdate) {
if (!updateWhitelist.contains(dependencyLeftToUpdate.groupAndName())) {
println(' - ' + dependencyLeftToUpdate)
}
}
}

if (updatedCount == 0 && failedCount == 0) {
println('useLatestVersions successfully did nothing; there was nothing to update')
}
Expand Down
16 changes: 12 additions & 4 deletions src/main/groovy/se/patrikerdes/UseLatestVersionsTask.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import static se.patrikerdes.Common.getOutDatedDependencies
import groovy.json.JsonSlurper
import groovy.transform.CompileStatic
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.options.Option
import org.gradle.api.tasks.TaskAction

import java.nio.file.Files
Expand All @@ -15,6 +16,10 @@ import java.util.regex.Pattern

@CompileStatic
class UseLatestVersionsTask extends DefaultTask {
@Option(option='update-dependency',
description = 'A whitelist of dependencies to update, in the format of group:name')
List<String> updateWhitelist = Collections.emptyList()

UseLatestVersionsTask() {
description = 'Updates module and plugin versions in all *.gradle and *.gradle.kts files to the latest ' +
'available versions.'
Expand Down Expand Up @@ -53,7 +58,10 @@ class UseLatestVersionsTask extends DefaultTask {

Object dependencyUpdatesJson = new JsonSlurper().parse(dependencyUpdatesJsonReportFile)

List<DependencyUpdate> dependecyUpdates = getOutDatedDependencies(dependencyUpdatesJson)
List<DependencyUpdate> dependencyUpdates = getOutDatedDependencies(dependencyUpdatesJson)
if (!updateWhitelist.empty) {
dependencyUpdates = dependencyUpdates.findAll { updateWhitelist.contains(it.groupAndName()) }
}

List<DependencyUpdate> dependencyStables = getCurrentDependencies(dependencyUpdatesJson)

Expand All @@ -64,9 +72,9 @@ class UseLatestVersionsTask extends DefaultTask {
gradleFileContents[dotGradleFileName] = currentGradleFileContents
}

updateModuleVersions(gradleFileContents, dotGradleFileNames, dependecyUpdates)
updatePluginVersions(gradleFileContents, dotGradleFileNames, dependecyUpdates)
updateVariables(gradleFileContents, dotGradleFileNames, dependecyUpdates, dependencyStables)
updateModuleVersions(gradleFileContents, dotGradleFileNames, dependencyUpdates)
updatePluginVersions(gradleFileContents, dotGradleFileNames, dependencyUpdates)
updateVariables(gradleFileContents, dotGradleFileNames, dependencyUpdates, dependencyStables)

// Write all files back
for (dotGradleFileName in dotGradleFileNames) {
Expand Down
28 changes: 28 additions & 0 deletions src/test/groovy/se/patrikerdes/BaseFunctionalTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ class BaseFunctionalTest extends Specification {
.build()
}

BuildResult useLatestVersionsOnly(String update) {
useLatestVersionsOnly([update])
}

BuildResult useLatestVersionsOnly(List<String> updates) {
List<String> arguments = ['useLatestVersions']
updates.each { arguments << '--update-dependency' << it }
GradleRunner.create()
.withProjectDir(testProjectDir.root)
.withArguments(arguments)
.withPluginClasspath()
.build()
}

BuildResult useLatestVersions(String gradleVersion) {
GradleRunner.create()
.withProjectDir(testProjectDir.root)
Expand Down Expand Up @@ -57,6 +71,20 @@ class BaseFunctionalTest extends Specification {
.buildAndFail()
}

BuildResult useLatestVersionsCheckOnly(String update) {
useLatestVersionsCheckOnly([update])
}

BuildResult useLatestVersionsCheckOnly(List<String> updates) {
List<String> arguments = ['useLatestVersionsCheck']
updates.each { arguments << '--update-dependency' << it }
GradleRunner.create()
.withProjectDir(testProjectDir.root)
.withArguments(arguments)
.withPluginClasspath()
.build()
}

BuildResult clean() {
GradleRunner.create()
.withProjectDir(testProjectDir.root)
Expand Down
32 changes: 32 additions & 0 deletions src/test/groovy/se/patrikerdes/CheckFunctionalTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,38 @@ class CheckFunctionalTest extends BaseFunctionalTest {
result.output.contains("- log4j:log4j [1.2.16 -> $CurrentVersions.LOG4J]")
}

void "useLatestVersionsCheck notes skipped updates due to not being in --update-dependency"() {
given:
buildFile << """
plugins {
id 'se.patrikerdes.use-latest-versions'
id 'com.github.ben-manes.versions' version '$CurrentVersions.VERSIONS'
}
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile "log4j:log4j:1.2.16"
testCompile "junit:junit:3.0"
}
"""

when:
useLatestVersionsOnly('log4j:log4j')
BuildResult result = useLatestVersionsCheckOnly('log4j:log4j')

then:
result.task(':useLatestVersionsCheck').outcome == SUCCESS
result.output.contains("""useLatestVersions successfully updated 1 dependency to the latest version:
- log4j:log4j [1.2.16 -> $CurrentVersions.LOG4J]""")
result.output.contains("""useLatestVersions skipped updating 1 dependency not in --dependency-update:
- junit:junit [3.0 -> $CurrentVersions.JUNIT]""")
}

void "useLatestVersionsCheck outputs a special message when there was nothing to update"() {
given:
buildFile << """
Expand Down
29 changes: 29 additions & 0 deletions src/test/groovy/se/patrikerdes/ModuleUpdatesFunctionalTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,33 @@ class ModuleUpdatesFunctionalTest extends BaseFunctionalTest {
updatedBuildFile.contains("dependency \"junit:junit:$CurrentVersions.JUNIT\"")
updatedBuildFile.contains("dependencySet(group: 'log4j', version: \"$CurrentVersions.LOG4J\")")
}
void "only updates whitelisted dependencies with --update-dependency"() {
given:
buildFile << """
plugins {
id 'se.patrikerdes.use-latest-versions'
id 'com.github.ben-manes.versions' version '$CurrentVersions.VERSIONS'
}

apply plugin: 'java'

repositories {
mavenCentral()
}

dependencies {
testCompile "junit:junit:4.0:javadoc@jar"
compile "log4j:log4j:1.2.16"
}
"""
when:
useLatestVersionsOnly('log4j:log4j')
String updatedBuildFile = buildFile.getText('UTF-8')
then:
updatedBuildFile.contains('testCompile \"junit:junit:4.0:javadoc@jar\"')
updatedBuildFile.contains("compile \"log4j:log4j:$CurrentVersions.LOG4J\"")
}
}

0 comments on commit 35361c1

Please sign in to comment.