Skip to content

Commit

Permalink
Fix updating global locks with updateDependencies set
Browse files Browse the repository at this point in the history
Because dependencies are "transitive" in the global context, we need to ensure
that anything a project directly depends on is not excluded from the list of
forces.
  • Loading branch information
aughr committed May 14, 2016
1 parent 28b11b8 commit 2b37699
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,10 @@ class DependencyLockPlugin implements Plugin<Project> {
private void maybeApplyLock(Configuration conf, DependencyLockExtension extension, Map overrides, String globalLockFileName, String lockFilename) {
File dependenciesLock
File globalLock = new File(project.rootProject.projectDir, globalLockFileName ?: extension.globalLockFile)
boolean isGlobal = false
if (globalLock.exists()) {
dependenciesLock = globalLock
isGlobal = true
} else {
dependenciesLock = new File(project.projectDir, lockFilename ?: extension.lockFile)
}
Expand All @@ -307,11 +309,11 @@ class DependencyLockPlugin implements Plugin<Project> {
boolean hasGenerateTask = hasGenerationTask(taskNames)
if (dependenciesLock.exists()) {
if (!hasGenerateTask) {
applyLock(conf, dependenciesLock, overrides)
applyLock(conf, dependenciesLock, overrides, [], isGlobal)
appliedLock = true
} else if (hasUpdateTask(taskNames)) {
def updates = project.hasProperty(UPDATE_DEPENDENCIES) ? parseUpdates(project.property(UPDATE_DEPENDENCIES) as String) : extension.updateDependencies
applyLock(conf, dependenciesLock, overrides, updates)
applyLock(conf, dependenciesLock, overrides, updates, isGlobal)
appliedLock = true
}
}
Expand Down Expand Up @@ -361,12 +363,20 @@ class DependencyLockPlugin implements Plugin<Project> {
updates.tokenize(',') as Set
}

void applyLock(Configuration conf, File dependenciesLock, Map overrides, Collection<String> updates = []) {
private static boolean isTopLevel(info, deps, isGlobal) {
// If this is not listed as being depended on at all, it must be a top-level dependency
if (info.transitive == null) return true

// If a dependency is listed as being depended on by something that we know is a project, then it must be a top-level dependency
return isGlobal && info.transitive.any { deps[it]?.project }
}

void applyLock(Configuration conf, File dependenciesLock, Map overrides, Collection<String> updates = [], boolean isGlobal) {
LOGGER.info("Using ${dependenciesLock.name} to lock dependencies in $conf")
def locks = loadLock(dependenciesLock)

if (updates) {
locks = locks.collectEntries { configurationName, deps -> [(configurationName): deps.findAll { coord, info -> (info.transitive == null) && !updates.contains(coord) }] }
locks = locks.collectEntries { configurationName, deps -> [(configurationName): deps.findAll { coord, info -> isTopLevel(info, deps, isGlobal) && !updates.contains(coord) }] }
}

// in the old format, all first level props were groupId:artifactId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,95 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
!result.standardOutput.contains("is using a deprecated lock format")
}

def 'only the update dependency and its transitives are updated when using a global lock'() {
addSubproject('sub1', """\
dependencies {
compile 'test.example:bar:1.+'
compile 'test.example:qux:latest.release'
}
""".stripIndent())
buildFile << """\
allprojects {
${applyPlugin(DependencyLockPlugin)}
group = 'test'
}
subprojects {
apply plugin: 'java'
repositories { maven { url '${Fixture.repo}' } }
}
dependencyLock {
includeTransitives = true
}
""".stripIndent()

def lockFile = new File(projectDir, 'global.lock')
def lockText = '''\
{
"_global_": {
"test.example:bar": {
"locked": "1.0.0",
"requested": "1.+",
"transitive": [
"test:sub1"
]
},
"test.example:qux": {
"locked": "1.0.0",
"requested": "latest.release",
"transitive": [
"test:sub1"
]
},
"test.example:foo": {
"locked": "1.0.0",
"transitive": [
"test.example:bar",
"test.example:qux"
]
},
"test:sub1": {
"project": true
}
}
}'''.stripIndent()
lockFile.text = lockText

def updatedLock = '''\
{
"_global_": {
"test.example:bar": {
"locked": "1.1.0",
"transitive": [
"test:sub1"
]
},
"test.example:foo": {
"locked": "1.0.1",
"transitive": [
"test.example:bar",
"test.example:qux"
]
},
"test.example:qux": {
"locked": "1.0.0",
"transitive": [
"test:sub1"
]
},
"test:sub1": {
"project": true
}
}
}'''.stripIndent()

when:
def results = runTasksSuccessfully('updateGlobalLock', '-PdependencyLock.updateDependencies=test.example:bar')

then:
println results.standardOutput
new File(projectDir, 'build/global.lock').text == updatedLock
}

@Ignore
def 'diff the generated lock with the existing lock '() {
def dependenciesLock = new File(projectDir, 'dependencies.lock')
Expand Down

0 comments on commit 2b37699

Please sign in to comment.