Skip to content

Commit

Permalink
Merge pull request #81 from rspieldenner/global_lock_not_ignored
Browse files Browse the repository at this point in the history
Global lock not ignored
  • Loading branch information
rspieldenner committed Dec 10, 2015
2 parents e78d8f7 + ebcb5b0 commit de4c49e
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 54 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
4.1.3 / 2015-12-10
==================

* BUGFIX: Fix for plugin not ignoring existing globalLock when generating a new one
* BUGFIX: Properly detect tasks when they are shortened or fully qualified to a specific project

4.1.2 / 2015-11-19
==================

Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ To include, add the following to your build.gradle
If newer than gradle 2.1 you may use

plugins {
id 'nebula.dependency-lock' version '4.1.2'
id 'nebula.dependency-lock' version '4.1.3'
}

*or*
Expand All @@ -34,7 +34,7 @@ If newer than gradle 2.1 you may use
repositories { jcenter() }

dependencies {
classpath 'com.netflix.nebula:gradle-dependency-lock-plugin:4.1.2'
classpath 'com.netflix.nebula:gradle-dependency-lock-plugin:4.1.3'
}
}

Expand Down Expand Up @@ -92,7 +92,7 @@ Update lock (the lock must still be saved/committed):
*Properties*

* lockFile - This field takes a String. The default is `dependencies.lock`. This filename will be what is generated by `generateLock` and read when locking dependencies.
* configurationNames - This field takes a List<String>. These will be the configurations that are read when locking. Defaults to all configurations.
* configurationNames - This field takes a List<String>. These will be the configurations that are written to the lock file when locking. Defaults to all configurations.
* dependencyFilter - This field can be assigned a Closure that is used to filter the set of top-level dependencies as they are retrieved from the configurations. This happens before overrides are applied and before any dependencies are skipped. The Closure must accept the dependency's `group`, `name`, and `version` as its 3 parameters. The default implementation returns `true`, meaning all dependencies are used.
* updateDependencies - This field takes a List<String> denoting the dependencies that should be updated when the `updateLock` task is run. If any dependencies are specified via the `--dependencies` option, this field is ignored. If any dependencies are listed during execution of the `updateLock` task either via the `--dependencies` option or this field, the `dependencyFilter` is bypassed.
* skippedDependencies - This field takes a List<String>. Defaults to empty. This list is used to list dependencies as ones that will never be locked. Strings should be of the format `<group>:<artifact>`
Expand All @@ -104,7 +104,6 @@ The following values are the defaults. If they work for you, you can skip config
dependencyLock {
lockFile = 'dependencies.lock'
globalLockFile = 'global.lock'
configurationNames = ['testRuntime']
dependencyFilter = { String group, String name, String version -> true }
updateDependencies = []
skippedDependencies = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@ import org.gradle.api.artifacts.Dependency
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.tasks.Delete
import org.gradle.util.NameMatcher

import static nebula.plugin.dependencylock.tasks.GenerateLockTask.getConfigurationsFromConfigurationNames

class DependencyLockPlugin implements Plugin<Project> {
public static final String GLOBAL_LOCK_CONFIG = '_global_'

private static Logger logger = Logging.getLogger(DependencyLockPlugin)
public static final String GENERATE_GLOBAL_LOCK_TASK_NAME = 'generateGlobalLock'
public static final String UPDATE_GLOBAL_LOCK_TASK_NAME = 'updateGlobalLock'
public static final String GENERATE_LOCK_TASK_NAME = 'generateLock'
public static final String UPDATE_LOCK_TASK_NAME = 'updateLock'
Project project

@Override
Expand All @@ -51,14 +56,13 @@ class DependencyLockPlugin implements Plugin<Project> {

Map overrides = loadOverrides()

GenerateLockTask genLockTask = project.tasks.create('generateLock', GenerateLockTask)
GenerateLockTask genLockTask = project.tasks.create(GENERATE_LOCK_TASK_NAME, GenerateLockTask)
configureLockTask(genLockTask, clLockFileName, extension, overrides)
if (project.hasProperty('dependencyLock.useGeneratedLock')) {
clLockFileName = genLockTask.getDependenciesLock().path
logger.lifecycle(clLockFileName)
}

UpdateLockTask updateLockTask = project.tasks.create('updateLock', UpdateLockTask)
UpdateLockTask updateLockTask = project.tasks.create(UPDATE_LOCK_TASK_NAME, UpdateLockTask)
configureLockTask(updateLockTask, clLockFileName, extension, overrides)
configureUpdateTask(updateLockTask, extension)

Expand All @@ -74,12 +78,12 @@ class DependencyLockPlugin implements Plugin<Project> {
GenerateLockTask globalLockTask
UpdateLockTask globalUpdateLock
if (project == project.rootProject) {
globalLockTask = project.tasks.create('generateGlobalLock', GenerateLockTask)
globalLockTask = project.tasks.create(GENERATE_GLOBAL_LOCK_TASK_NAME, GenerateLockTask)
if (project.hasProperty('dependencyLock.useGeneratedGlobalLock')) {
globalLockFileName = globalLockTask.getDependenciesLock().path
}
configureGlobalLockTask(globalLockTask, globalLockFileName, extension, overrides)
globalUpdateLock = project.tasks.create('updateGlobalLock', UpdateLockTask)
globalUpdateLock = project.tasks.create(UPDATE_GLOBAL_LOCK_TASK_NAME, UpdateLockTask)
configureGlobalLockTask(globalUpdateLock, globalLockFileName, extension, overrides)
configureUpdateTask(globalUpdateLock, extension)
globalSave = configureGlobalSaveTask(globalLockFileName, globalLockTask, globalUpdateLock, extension)
Expand All @@ -88,46 +92,17 @@ class DependencyLockPlugin implements Plugin<Project> {

configureCommitTask(clLockFileName, globalLockFileName, saveTask, extension, commitExtension, globalSave)

def applyLockToResolutionStrategy = {
if (extension.configurationNames.empty) {
extension.configurationNames = project.configurations.collect { it.name }
}

File dependenciesLock
File globalLock = new File(project.rootProject.projectDir, globalLockFileName ?: extension.globalLockFile)
if (globalLock.exists()) {
dependenciesLock = globalLock
} else {
dependenciesLock = new File(project.projectDir, clLockFileName ?: extension.lockFile)
}

def taskNames = project.gradle.startParameter.taskNames

boolean hasGlobalLockTask = false
if (project == project.rootProject) {
hasGlobalLockTask = taskNames.contains(globalLockTask.name) || taskNames.contains(globalUpdateLock.name)

}

if (dependenciesLock.exists() && !shouldIgnoreDependencyLock() && !taskNames.contains(genLockTask.name) &&
!taskNames.contains(updateLockTask.name) && !hasGlobalLockTask) {
applyLock(dependenciesLock, overrides)
} else if (!shouldIgnoreDependencyLock()) {
applyOverrides(overrides)
}
}

def lockAfterEvaluating = project.hasProperty('dependencyLock.lockAfterEvaluating') ? Boolean.parseBoolean(project['dependencyLock.lockAfterEvaluating']) : extension.lockAfterEvaluating
if (lockAfterEvaluating) {
logger.info("Applying dependency lock in afterEvaluate block")
project.afterEvaluate applyLockToResolutionStrategy
logger.info('Applying dependency lock in afterEvaluate block')
project.afterEvaluate { applyLockToResolutionStrategy(extension, overrides, globalLockFileName, clLockFileName) }
} else {
logger.info("Applying dependency lock as is (outside afterEvaluate block)")
applyLockToResolutionStrategy()
logger.info('Applying dependency lock as is (outside afterEvaluate block)')
applyLockToResolutionStrategy(extension, overrides, globalLockFileName, clLockFileName)
}

project.gradle.taskGraph.whenReady { taskGraph ->
def hasLockingTask = taskGraph.hasTask(genLockTask) || taskGraph.hasTask(updateLockTask)
def hasLockingTask = taskGraph.hasTask(genLockTask) || taskGraph.hasTask(updateLockTask) || ((project == project.rootProject) && (taskGraph.hasTask(globalLockTask) || taskGraph.hasTask(globalUpdateLock)))
if (hasLockingTask) {
project.configurations.all {
resolutionStrategy {
Expand All @@ -142,6 +117,52 @@ class DependencyLockPlugin implements Plugin<Project> {
}
}

private void applyLockToResolutionStrategy(DependencyLockExtension extension, Map overrides, String globalLockFileName, String clLockFileName) {
if (extension.configurationNames.empty) {
extension.configurationNames = project.configurations.collect { it.name }
}

File dependenciesLock
File globalLock = new File(project.rootProject.projectDir, globalLockFileName ?: extension.globalLockFile)
if (globalLock.exists()) {
dependenciesLock = globalLock
} else {
dependenciesLock = new File(project.projectDir, clLockFileName ?: extension.lockFile)
}

def taskNames = project.gradle.startParameter.taskNames

if (dependenciesLock.exists() && !shouldIgnoreDependencyLock() && !hasGenerationTask(taskNames)) {
applyLock(dependenciesLock, overrides)
} else if (!shouldIgnoreDependencyLock()) {
applyOverrides(overrides)
}
}

private boolean hasGenerationTask(Collection<String> cliTasks) {
def matcher = new NameMatcher()
def found = cliTasks.find { cliTaskName ->
def tokens = cliTaskName.split(':')
def taskName = tokens.last()
def generatesPresent = matcher.find(taskName, [GENERATE_LOCK_TASK_NAME, GENERATE_GLOBAL_LOCK_TASK_NAME,
UPDATE_LOCK_TASK_NAME, UPDATE_GLOBAL_LOCK_TASK_NAME])

generatesPresent && taskRunOnThisProject(tokens)
}

found != null
}

private boolean taskRunOnThisProject(String[] tokens) {
if (tokens.size() == 1) { // task run globally
return true
} else if (tokens.size() == 2 && tokens[0] == '') { // running fully qualified on root project
return project == project.rootProject
} else { // the task is being run on a specific project
return project.name == tokens[-2]
}
}

private void configureCommitTask(String clLockFileName, String globalLockFileName, SaveLockTask saveTask, DependencyLockExtension lockExtension,
DependencyLockCommitExtension commitExtension, SaveLockTask globalSaveTask = null) {
project.plugins.withType(ScmPlugin) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import nebula.plugin.dependencylock.dependencyfixture.Fixture
import nebula.test.IntegrationSpec
import org.ajoberstar.grgit.Grgit
import org.ajoberstar.grgit.operation.ResetOp
import org.gradle.execution.TaskSelectionException
import org.gradle.internal.exceptions.LocationAwareException

class DependencyLockCommitLauncherSpec extends IntegrationSpec {
def setup() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def result = runTasksSuccessfully('dependencies')

then:
println result.standardOutput
result.standardOutput.contains 'test.example:foo:1.0.1 -> 1.0.0'
}

Expand All @@ -222,7 +221,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def result = runTasksSuccessfully('gL', 'dependencies')

then:
println result.standardOutput
!result.standardOutput.contains('test.example:foo:1.0.1 -> 1.0.0')
}

Expand All @@ -237,10 +235,78 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def result = runTasksSuccessfully(':generateLock', 'dependencies')

then:
println result.standardOutput
!result.standardOutput.contains('test.example:foo:1.0.1 -> 1.0.0')
}

@Issue('#79')
def 'lock file is applied on subprojects not being locked while generating lock with qualified task name'() {
setupCommonMultiproject()
new File(projectDir, 'sub1/dependencies.lock').text = PRE_DIFF_FOO_LOCK
new File(projectDir, 'sub2/dependencies.lock').text = PRE_DIFF_FOO_LOCK

when:
def result = runTasksSuccessfully('sub1:generateLock', ':sub2:dependencies')

then:
result.standardOutput.contains('test.example:foo:1.+ -> 1.0.0')
}

@Issue('#79')
def 'lock file ignored in multiproject on specific project with no leading :'() {
setupCommonMultiproject()
new File(projectDir, 'sub1/dependencies.lock').text = PRE_DIFF_FOO_LOCK
new File(projectDir, 'sub2/dependencies.lock').text = PRE_DIFF_FOO_LOCK

when:
def result = runTasksSuccessfully('sub1:generateLock', 'sub1:dependencies')

then:
!result.standardOutput.contains('test.example:foo:2.0.0 -> 1.0.0')
}

@Issue('#79')
def 'lock file ignored in nested multiproject when generating locks'() {
def middleDir = addSubproject('middle')
def sub0Dir = new File(middleDir, 'sub0')
sub0Dir.mkdirs()
new File(sub0Dir, 'build.gradle').text = """\
apply plugin: 'java'
dependencies {
compile 'test.example:foo:2.0.0'
}
""".stripIndent()
new File(sub0Dir, 'dependencies.lock').text = PRE_DIFF_FOO_LOCK
def sub1Dir = new File(middleDir, 'sub1')
sub1Dir.mkdirs()
new File(sub1Dir, 'build.gradle').text = """\
apply plugin: 'java'
dependencies {
compile 'test.example:foo:1.+'
}
""".stripIndent()

buildFile << """\
allprojects {
${applyPlugin(DependencyLockPlugin)}
group = 'test'
}
subprojects {
repositories { maven { url '${Fixture.repo}' } }
}
""".stripIndent()

settingsFile << '''\
include ':middle:sub0'
include ':middle:sub1'
'''.stripIndent()

when:
def result = runTasksSuccessfully(':middle:sub0:generateLock', ':middle:sub0:dependencies')

then:
!result.standardOutput.contains('test.example:foo:2.0.0 -> 1.0.0')
}

def 'override lock file is applied'() {
def dependenciesLock = new File(projectDir, 'dependencies.lock')
dependenciesLock << OLD_FOO_LOCK
Expand Down Expand Up @@ -452,7 +518,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def s = runTasksSuccessfully('-PdependencyLock.overrideFile=test.lock', 'generateLock', 'saveLock')

then:
println s.standardOutput
new File(projectDir, 'dependencies.lock').text == NEW_FOO_LOCK
}

Expand Down Expand Up @@ -548,7 +613,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def aa = runTasksSuccessfully('-PdependencyLock.overrideFile=override.lock', 'generateLock', 'saveLock')

then:
println aa.standardOutput
String lockText1 = '''\
{
"compile": {
Expand Down Expand Up @@ -691,7 +755,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def s = runTasksSuccessfully('generateGlobalLock')

then:
println s.standardOutput
String globalLockText = '''\
{
"_global_": {
Expand Down Expand Up @@ -852,7 +915,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
def s = runTasksSuccessfully('generateGlobalLock')

then:
println s.standardOutput
String globalLockText = '''\
{
"_global_": {
Expand Down Expand Up @@ -904,8 +966,6 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
}
}'''.stripIndent()

println s.standardOutput

new File(projectDir, 'global.lock').text == globalLockText
}

Expand Down Expand Up @@ -991,6 +1051,52 @@ class DependencyLockLauncherSpec extends IntegrationSpec {
new File(projectDir, 'sub2/dependencies.lock').text == lockText2
}

def 'generateGlobalLock ignores existing global lock file'() {
setupCommonMultiproject()
new File(projectDir, 'global.lock').text = '''\
{
"_global_": {
"test.example:foo": {
"locked": "1.0.1",
"transitive": [
"test:sub1",
"test:sub2"
]
},
"test:sub1": {
"project": true
},
"test:sub2": {
"project": true
}
}
}'''.stripIndent()
String globalLockText = '''\
{
"_global_": {
"test.example:foo": {
"locked": "2.0.0",
"transitive": [
"test:sub1",
"test:sub2"
]
},
"test:sub1": {
"project": true
},
"test:sub2": {
"project": true
}
}
}'''.stripIndent()

when:
def r = runTasksSuccessfully('generateGlobalLock')

then:
new File(projectDir, 'build/global.lock').text == globalLockText
}

def 'throw exception when saving global lock, if individual locks are present'() {
setupCommonMultiproject()
runTasksSuccessfully('generateLock', 'saveLock')
Expand Down

0 comments on commit de4c49e

Please sign in to comment.