diff --git a/.travis.yml b/.travis.yml index 30973cb3..32378539 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ -language: java +language: android +android: + components: + - build-tools-20.0.0 + - android-20 sudo: false jdk: - oraclejdk7 diff --git a/build.gradle b/build.gradle index cd9795be..ba51bf29 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ buildscript { repositories { jcenter() } } // Some plugin dependencies (namely J plugins { id 'com.gradle.plugin-publish' version '0.9.4' - id 'nebula.plugin-plugin' version '4.1.0' + id 'nebula.plugin-plugin' version '4.4.0' id 'org.ysb33r.gradletest' version '0.5.4' } @@ -71,3 +71,4 @@ gradleTest.dependsOn(jar) gradleTest.doFirst { project.version = project.version.toString() } + diff --git a/src/main/groovy/nebula/plugin/dependencylock/DependencyLockPlugin.groovy b/src/main/groovy/nebula/plugin/dependencylock/DependencyLockPlugin.groovy index 96aa9c29..2ba73d0b 100644 --- a/src/main/groovy/nebula/plugin/dependencylock/DependencyLockPlugin.groovy +++ b/src/main/groovy/nebula/plugin/dependencylock/DependencyLockPlugin.groovy @@ -26,7 +26,6 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency -import org.gradle.api.artifacts.ResolutionStrategy import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.api.tasks.Delete @@ -35,154 +34,97 @@ import org.gradle.util.NameMatcher import static nebula.plugin.dependencylock.tasks.GenerateLockTask.getConfigurationsFromConfigurationNames class DependencyLockPlugin implements Plugin { - public static final String GLOBAL_LOCK_CONFIG = '_global_' + private static final Logger LOGGER = Logging.getLogger(DependencyLockPlugin) + + private static final String EXTENSION_NAME = 'dependencyLock' + private static final String COMMIT_EXTENSION_NAME = 'commitDependencyLock' + private static final String GLOBAL_LOCK_FILE = 'dependencyLock.globalLockFile' + private static final String LOCK_FILE = 'dependencyLock.lockFile' + private static final String LOCK_AFTER_EVALUATING = 'dependencyLock.lockAfterEvaluating' + private static final String USE_GENERATED_LOCK = 'dependencyLock.useGeneratedLock' + private static final String USE_GENERATED_GLOBAL_LOCK = 'dependencyLock.useGeneratedGlobalLock' + private static final String UPDATE_DEPENDENCIES = 'dependencyLock.updateDependencies' + private static final String OVERRIDE_FILE = 'dependencyLock.overrideFile' + private static final String OVERRIDE = 'dependencyLock.override' + + private static final List GENERATION_TASK_NAMES = [GENERATE_LOCK_TASK_NAME, GENERATE_GLOBAL_LOCK_TASK_NAME, + UPDATE_LOCK_TASK_NAME, UPDATE_GLOBAL_LOCK_TASK_NAME] + private static final List UPDATE_TASK_NAMES = [UPDATE_LOCK_TASK_NAME, UPDATE_GLOBAL_LOCK_TASK_NAME] - private static Logger logger = Logging.getLogger(DependencyLockPlugin) + public static final String GLOBAL_LOCK_CONFIG = '_global_' 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 - UpdateLockTask updateLockTask - UpdateLockTask globalUpdateLock + Project project @Override void apply(Project project) { this.project = project - String clLockFileName = project.hasProperty('dependencyLock.lockFile') ? project['dependencyLock.lockFile'] : null - DependencyLockExtension extension = project.extensions.create('dependencyLock', DependencyLockExtension) + DependencyLockExtension extension = project.extensions.create(EXTENSION_NAME, DependencyLockExtension) DependencyLockCommitExtension commitExtension = project.rootProject.extensions.findByType(DependencyLockCommitExtension) if (!commitExtension) { - commitExtension = project.rootProject.extensions.create('commitDependencyLock', DependencyLockCommitExtension) + commitExtension = project.rootProject.extensions.create(COMMIT_EXTENSION_NAME, DependencyLockCommitExtension) } Map overrides = loadOverrides() + String globalLockFilename = project.hasProperty(GLOBAL_LOCK_FILE) ? project[GLOBAL_LOCK_FILE] : null + String lockFilename = configureTasks(globalLockFilename, extension, commitExtension, overrides) - GenerateLockTask genLockTask = project.tasks.create(GENERATE_LOCK_TASK_NAME, GenerateLockTask) - configureLockTask(genLockTask, clLockFileName, extension, overrides) - if (project.hasProperty('dependencyLock.useGeneratedLock')) { - clLockFileName = genLockTask.getDependenciesLock().path + def lockAfterEvaluating = project.hasProperty(LOCK_AFTER_EVALUATING) ? Boolean.parseBoolean(project[LOCK_AFTER_EVALUATING] as String) : extension.lockAfterEvaluating + if (lockAfterEvaluating) { + LOGGER.info("Delaying dependency lock apply until beforeResolve ($LOCK_AFTER_EVALUATING set to true)") + } else { + LOGGER.info("Applying dependency lock during plugin apply ($LOCK_AFTER_EVALUATING set to false)") } - updateLockTask = project.tasks.create(UPDATE_LOCK_TASK_NAME, UpdateLockTask) - configureLockTask(updateLockTask, clLockFileName, extension, overrides) + project.configurations.all({ conf -> + if (lockAfterEvaluating) { + conf.incoming.beforeResolve { + maybeApplyLock(conf, extension, overrides, globalLockFilename, lockFilename) + } + } else { + maybeApplyLock(conf, extension, overrides, globalLockFilename, lockFilename) + } + }) + } + + private String configureTasks(String globalLockFilename, DependencyLockExtension extension, DependencyLockCommitExtension commitExtension, Map overrides) { + String lockFilename = project.hasProperty(LOCK_FILE) ? project[LOCK_FILE] : null - //DiffLockTask diffLockTask = project.tasks.create('diffLock', DiffLockTask) - //configureDiffTask(diffLockTask, genLockTask, clLockFileName) + GenerateLockTask genLockTask = project.tasks.create(GENERATE_LOCK_TASK_NAME, GenerateLockTask) + configureLockTask(genLockTask, lockFilename, extension, overrides) + if (project.hasProperty(USE_GENERATED_LOCK)) { + lockFilename = genLockTask.getDependenciesLock().path + } - SaveLockTask saveTask = configureSaveTask(clLockFileName, genLockTask, updateLockTask, extension) + UpdateLockTask updateLockTask = project.tasks.create(UPDATE_LOCK_TASK_NAME, UpdateLockTask) + configureLockTask(updateLockTask, lockFilename, extension, overrides) + + SaveLockTask saveTask = configureSaveTask(lockFilename, genLockTask, updateLockTask, extension) createDeleteLock(saveTask) // configure global lock only on rootProject SaveLockTask globalSave = null - String globalLockFileName = project.hasProperty('dependencyLock.globalLockFile') ? project['dependencyLock.globalLockFile'] : null GenerateLockTask globalLockTask + UpdateLockTask globalUpdateLock if (project == project.rootProject) { globalLockTask = project.tasks.create(GENERATE_GLOBAL_LOCK_TASK_NAME, GenerateLockTask) - if (project.hasProperty('dependencyLock.useGeneratedGlobalLock')) { - globalLockFileName = globalLockTask.getDependenciesLock().path + if (project.hasProperty(USE_GENERATED_GLOBAL_LOCK)) { + globalLockFilename = globalLockTask.getDependenciesLock().path } - configureGlobalLockTask(globalLockTask, globalLockFileName, extension, overrides) + configureGlobalLockTask(globalLockTask, globalLockFilename, extension, overrides) globalUpdateLock = project.tasks.create(UPDATE_GLOBAL_LOCK_TASK_NAME, UpdateLockTask) - configureGlobalLockTask(globalUpdateLock, globalLockFileName, extension, overrides) - globalSave = configureGlobalSaveTask(globalLockFileName, globalLockTask, globalUpdateLock, extension) + configureGlobalLockTask(globalUpdateLock, globalLockFilename, extension, overrides) + globalSave = configureGlobalSaveTask(globalLockFilename, globalLockTask, globalUpdateLock, extension) createDeleteGlobalLock(globalSave) } - configureCommitTask(clLockFileName, globalLockFileName, saveTask, extension, commitExtension, globalSave) - - def lockAfterEvaluating = project.hasProperty('dependencyLock.lockAfterEvaluating') ? Boolean.parseBoolean(project['dependencyLock.lockAfterEvaluating'] as String) : extension.lockAfterEvaluating - if (lockAfterEvaluating) { - 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(extension, overrides, globalLockFileName, clLockFileName) - } - - project.gradle.taskGraph.whenReady { taskGraph -> - def hasLockingTask = taskGraph.hasTask(genLockTask) || taskGraph.hasTask(updateLockTask) || ((project == project.rootProject) && (taskGraph.hasTask(globalLockTask) || taskGraph.hasTask(globalUpdateLock))) - if (hasLockingTask) { - project.configurations.all({ - resolutionStrategy { - cacheDynamicVersionsFor 0, 'seconds' - cacheChangingModulesFor 0, 'seconds' - } - }) - if (!shouldIgnoreDependencyLock()) { - applyOverrides(overrides) - } - } - } - } - - private void applyLockToResolutionStrategy(DependencyLockExtension extension, Map overrides, String globalLockFileName, String clLockFileName) { - if (extension.configurationNames.empty) { - extension.configurationNames = project.configurations.toSet().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 (dependenciesLock.exists() && !shouldIgnoreDependencyLock() && hasUpdateTask(taskNames)) { - def updates = project.hasProperty('dependencyLock.updateDependencies') ? parseUpdates(project.property('dependencyLock.updateDependencies') as String) : extension.updateDependencies - applyLock(dependenciesLock, overrides, updates) - } else if (!shouldIgnoreDependencyLock()) { - applyOverrides(overrides) - } - } - - private boolean hasGenerationTask(Collection cliTasks) { - def taskNames = [GENERATE_LOCK_TASK_NAME, GENERATE_GLOBAL_LOCK_TASK_NAME, - UPDATE_LOCK_TASK_NAME, UPDATE_GLOBAL_LOCK_TASK_NAME] + configureCommitTask(lockFilename, globalLockFilename, saveTask, extension, commitExtension, globalSave) - hasTask(cliTasks, taskNames) - } - - private boolean hasTask(Collection cliTasks, Collection taskNames) { - def matcher = new NameMatcher() - def found = cliTasks.find { cliTaskName -> - def tokens = cliTaskName.split(':') - def taskName = tokens.last() - def generatesPresent = matcher.find(taskName, taskNames) - - generatesPresent && taskRunOnThisProject(tokens) - } - - - found != null - } - - private boolean hasUpdateTask(Collection cliTasks) { - def taskNames = [UPDATE_LOCK_TASK_NAME, UPDATE_GLOBAL_LOCK_TASK_NAME] - hasTask(cliTasks, taskNames) - } - - 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 static Set parseUpdates(String updates) { - updates.tokenize(',') as Set + lockFilename } private void configureCommitTask(String clLockFileName, String globalLockFileName, SaveLockTask saveTask, DependencyLockExtension lockExtension, @@ -219,7 +161,7 @@ class DependencyLockPlugin implements Plugin { def patterns = lockFiles.collect { project.rootProject.projectDir.toURI().relativize(it.toURI()).path } - logger.info(patterns.toString()) + LOGGER.info(patterns.toString()) patterns } shouldCreateTag = { @@ -251,8 +193,8 @@ class DependencyLockPlugin implements Plugin { saveTask } - private - static void configureCommonSaveTask(SaveLockTask saveTask, GenerateLockTask lockTask, UpdateLockTask updateTask) { + private static void configureCommonSaveTask(SaveLockTask saveTask, GenerateLockTask lockTask, + UpdateLockTask updateTask) { saveTask.mustRunAfter lockTask, updateTask saveTask.outputs.upToDateWhen { if (saveTask.generatedLock.exists() && saveTask.outputLock.exists()) { @@ -263,7 +205,8 @@ class DependencyLockPlugin implements Plugin { } } - private SaveLockTask configureGlobalSaveTask(String globalLockFileName, GenerateLockTask globalLockTask, UpdateLockTask globalUpdateLockTask, DependencyLockExtension extension) { + private SaveLockTask configureGlobalSaveTask(String globalLockFileName, GenerateLockTask globalLockTask, + UpdateLockTask globalUpdateLockTask, DependencyLockExtension extension) { SaveLockTask globalSaveTask = project.tasks.create('saveGlobalLock', SaveLockTask) globalSaveTask.doFirst { project.subprojects.each { Project sub -> @@ -318,8 +261,9 @@ class DependencyLockPlugin implements Plugin { def subprojects = project.subprojects.collect { subproject -> def ext = subproject.getExtensions().findByType(DependencyLockExtension) if (ext != null) { - ext.configurationNames.collect { subconf -> - project.dependencies.create(project.dependencies.project(path: subproject.path, configuration: subconf)) + def configurations = getConfigurationsFromConfigurationNames(subproject, ext.configurationNames) + configurations.collect { configuration -> + project.dependencies.create(project.dependencies.project(path: subproject.path, configuration: configuration.name)) } } else { [project.dependencies.create(subproject)] @@ -348,33 +292,77 @@ class DependencyLockPlugin implements Plugin { } } - /*private configureDiffTask(DiffLockTask diffLockTask, GenerateLockTask generateLockTask, String lockFileName, DependencyLockExtension extension) { - diffLockTask.conventionMapping.with { - existingLock = { new File(project.projectDir, lockFileName ?: extension.lockFile) } + 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) + if (globalLock.exists()) { + dependenciesLock = globalLock + } else { + dependenciesLock = new File(project.projectDir, lockFilename ?: extension.lockFile) + } + + boolean appliedLock = false + if (!shouldIgnoreDependencyLock()) { + def taskNames = project.gradle.startParameter.taskNames + boolean hasGenerateTask = hasGenerationTask(taskNames) + if (dependenciesLock.exists()) { + if (!hasGenerateTask) { + applyLock(conf, dependenciesLock, overrides) + 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) + appliedLock = true + } + } + if (hasGenerateTask) { + conf.resolutionStrategy { + cacheDynamicVersionsFor 0, 'seconds' + cacheChangingModulesFor 0, 'seconds' + } + } + if (!appliedLock) { + applyOverrides(conf, overrides) + } } + } - diffLockTask.newLock = generateLockTask.dependenciesLock - diffLockTask.output = project.file('build/reports/dependencylock/lockdiff.txt') - }*/ + private boolean hasGenerationTask(Collection cliTasks) { + hasTask(cliTasks, GENERATION_TASK_NAMES) + } - void applyOverrides(Map overrides) { - if (project.hasProperty('dependencyLock.overrideFile')) { - logger.info("Using override file ${project['dependencyLock.overrideFile']} to lock dependencies") - } - if (project.hasProperty('dependencyLock.override')) { - logger.info("Using command line overrides ${project['dependencyLock.override']}") + private boolean hasUpdateTask(Collection cliTasks) { + hasTask(cliTasks, UPDATE_TASK_NAMES) + } + + private boolean hasTask(Collection cliTasks, Collection taskNames) { + def matcher = new NameMatcher() + def found = cliTasks.find { cliTaskName -> + def tokens = cliTaskName.split(':') + def taskName = tokens.last() + def generatesPresent = matcher.find(taskName, taskNames) + generatesPresent && taskRunOnThisProject(tokens) } - def overrideDeps = overrides.collect { "${it.key}:${it.value}" } - logger.debug(overrideDeps.toString()) + found != null + } - project.configurations.all({ Configuration conf -> - configureResolutionStrategy(conf.resolutionStrategy, overrideDeps) - }) + 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 static Set parseUpdates(String updates) { + updates.tokenize(',') as Set } - void applyLock(File dependenciesLock, Map overrides, Collection updates = []) { - logger.info("Using ${dependenciesLock.name} to lock dependencies") + void applyLock(Configuration conf, File dependenciesLock, Map overrides, Collection updates = []) { + LOGGER.info("Using ${dependenciesLock.name} to lock dependencies in $conf") def locks = loadLock(dependenciesLock) if (updates) { @@ -382,41 +370,53 @@ class DependencyLockPlugin implements Plugin { } // in the old format, all first level props were groupId:artifactId - def isDeprecatedFormat = !locks.isEmpty() && locks.every { it.key ==~ /[^:]+:.+/ } // in the old format, all first level props were groupId:artifactId + def isDeprecatedFormat = !locks.isEmpty() && locks.every { it.key ==~ /[^:]+:.+/ } + // in the old format, all first level props were groupId:artifactId if (isDeprecatedFormat) { - logger.warn("${dependenciesLock.name} is using a deprecated lock format. Support for this format may be removed in future versions.") + LOGGER.warn("${dependenciesLock.name} is using a deprecated lock format. Support for this format may be removed in future versions.") } - project.configurations.all({ Configuration conf -> - // In the old format of the lock file, there was only one locked setting. In that case, apply it on all configurations. - // In the new format, apply _global_ to all configurations or use the config name - def deps = isDeprecatedFormat ? locks : locks[GLOBAL_LOCK_CONFIG] ?: locks[conf.name] - if (deps) { - // Non-project locks are the top-level dependencies, and possibly transitive thereof, of this project which are - // locked by the lock file. There may also be dependencies on other projects. These are not captured here. - def nonProjectLocks = deps.findAll { it.value?.locked } - - // Override locks from the file with any of the user specified manual overrides. - def locked = nonProjectLocks.collect { - overrides.containsKey(it.key) ? "${it.key}:${overrides[it.key]}" : "${it.key}:${it.value.locked}" - } - - // If the user specifies an override that does not exist in the lock file, force that dependency anyway. - def unusedOverrides = overrides.findAll { !locks.containsKey(it.key) }.collect { - "${it.key}:${it.value}" - } + // In the old format of the lock file, there was only one locked setting. In that case, apply it on all configurations. + // In the new format, apply _global_ to all configurations or use the config name + def notations = isDeprecatedFormat ? locks : locks[GLOBAL_LOCK_CONFIG] ?: locks[conf.name] + if (notations) { + // Non-project locks are the top-level dependencies, and possibly transitive thereof, of this project which are + // locked by the lock file. There may also be dependencies on other projects. These are not captured here. + def nonProjectLocks = notations.findAll { it.value?.locked } - locked.addAll(unusedOverrides) - logger.debug('locked: {}', locked) + // Override locks from the file with any of the user specified manual overrides. + def locked = nonProjectLocks.collect { + overrides.containsKey(it.key) ? "${it.key}:${overrides[it.key]}" : "${it.key}:${it.value.locked}" + } - configureResolutionStrategy(conf.resolutionStrategy, locked) + // If the user specifies an override that does not exist in the lock file, force that dependency anyway. + def unusedOverrides = overrides.findAll { !locks.containsKey(it.key) }.collect { + "${it.key}:${it.value}" } - }) + + locked.addAll(unusedOverrides) + LOGGER.debug('locked: {}', locked) + + lockConfiguration(conf, locked) + } } - private void configureResolutionStrategy(ResolutionStrategy resolutionStrategy, List dependencyNotations) { + void applyOverrides(Configuration conf, Map overrides) { + if (project.hasProperty(OVERRIDE_FILE)) { + LOGGER.info("Using override file ${project[OVERRIDE_FILE]} to lock dependencies") + } + if (project.hasProperty(OVERRIDE)) { + LOGGER.info("Using command line overrides ${project[OVERRIDE]}") + } + + def overrideDeps = overrides.collect { "${it.key}:${it.value}" } + LOGGER.debug('overrides: {}', overrideDeps) + lockConfiguration(conf, overrideDeps) + } + + private void lockConfiguration(Configuration conf, List dependencyNotations) { def dependencies = dependencyNotations.collect { project.dependencies.create(it) } - resolutionStrategy.eachDependency { details -> + conf.resolutionStrategy.eachDependency { details -> dependencies.each { dep -> if (details.requested.group == dep.group && details.requested.name == dep.name) { details.useTarget group: details.requested.group, name: details.requested.name, version: dep.version @@ -428,7 +428,6 @@ class DependencyLockPlugin implements Plugin { private boolean shouldIgnoreDependencyLock() { if (project.hasProperty('dependencyLock.ignore')) { def prop = project.property('dependencyLock.ignore') - (prop instanceof String) ? prop.toBoolean() : prop.asBoolean() } else { false @@ -438,21 +437,18 @@ class DependencyLockPlugin implements Plugin { private Map loadOverrides() { // Overrides are dependencies that trump the lock file. Map overrides = [:] - if (shouldIgnoreDependencyLock()) { - return overrides - } // Load overrides from a file if the user has specified one via a property. - if (project.hasProperty('dependencyLock.overrideFile')) { - File dependenciesLock = new File(project.rootDir, project['dependencyLock.overrideFile'] as String) + if (project.hasProperty(OVERRIDE_FILE)) { + File dependenciesLock = new File(project.rootDir, project[OVERRIDE_FILE] as String) def lockOverride = loadLock(dependenciesLock) def isDeprecatedFormat = lockOverride.any { it.value.getClass() != String && it.value.locked } // the old lock override files specified the version to override under the "locked" property if (isDeprecatedFormat) { - logger.warn("The override file ${dependenciesLock.name} is using a deprecated format. Support for this format may be removed in future versions.") + LOGGER.warn("The override file ${dependenciesLock.name} is using a deprecated format. Support for this format may be removed in future versions.") } lockOverride.each { overrides[it.key] = isDeprecatedFormat ? it.value.locked : it.value } - logger.debug "Override file loaded: ${project['dependencyLock.overrideFile']}" + LOGGER.debug "Override file loaded: ${project[OVERRIDE_FILE]}" } // Allow the user to specify overrides via a property as well. @@ -460,7 +456,7 @@ class DependencyLockPlugin implements Plugin { project['dependencyLock.override'].tokenize(',').each { def (group, artifact, version) = it.tokenize(':') overrides["${group}:${artifact}".toString()] = version - logger.debug "Override added for: ${it}" + LOGGER.debug "Override added for: ${it}" } } @@ -471,8 +467,8 @@ class DependencyLockPlugin implements Plugin { try { return new JsonSlurper().parseText(lock.text) } catch (ex) { - logger.debug('Unreadable json file: ' + lock.text) - logger.error('JSON unreadable') + LOGGER.debug('Unreadable json file: ' + lock.text) + LOGGER.error('JSON unreadable') throw new GradleException("${lock.name} is unreadable or invalid json, terminating run", ex) } } diff --git a/src/main/groovy/nebula/plugin/dependencylock/tasks/GenerateLockTask.groovy b/src/main/groovy/nebula/plugin/dependencylock/tasks/GenerateLockTask.groovy index 6757122a..8bfdd0d0 100644 --- a/src/main/groovy/nebula/plugin/dependencylock/tasks/GenerateLockTask.groovy +++ b/src/main/groovy/nebula/plugin/dependencylock/tasks/GenerateLockTask.groovy @@ -43,7 +43,11 @@ class GenerateLockTask extends AbstractLockTask { } public static Collection getConfigurationsFromConfigurationNames(Project project, Set configurationNames) { - configurationNames.collect { project.configurations.getByName(it) } + if (configurationNames.empty) { + project.configurations.asList() + } else { + configurationNames.collect { project.configurations.getByName(it) } + } } Map readDependenciesFromConfigurations(Collection confs) { diff --git a/src/test/groovy/nebula/plugin/dependencylock/DependencyLockLauncherSpec.groovy b/src/test/groovy/nebula/plugin/dependencylock/DependencyLockLauncherSpec.groovy index 7ecf8591..25ee49e0 100644 --- a/src/test/groovy/nebula/plugin/dependencylock/DependencyLockLauncherSpec.groovy +++ b/src/test/groovy/nebula/plugin/dependencylock/DependencyLockLauncherSpec.groovy @@ -22,7 +22,7 @@ import spock.lang.Issue class DependencyLockLauncherSpec extends IntegrationSpec { def setup() { - fork = true + fork = false } static final String SPECIFIC_BUILD_GRADLE = """\ @@ -369,7 +369,7 @@ class DependencyLockLauncherSpec extends IntegrationSpec { buildFile << BUILD_GRADLE when: - def result = runTasksWithFailure('build') + def result = runTasksWithFailure('dependencies') then: result.failure.cause.cause.message.contains('unreadable or invalid json') @@ -979,36 +979,7 @@ class DependencyLockLauncherSpec extends IntegrationSpec { new File(projectDir, 'build/dependencies.lock').text == updatedLock } - def 'eachDependency wins over force'() { - buildFile << """\ - apply plugin: 'java' - - repositories { maven { url '${Fixture.repo}' } } - - dependencies { - compile 'test.example:foo:latest.release' - } - - configurations.all { - resolutionStrategy { - eachDependency { details -> - if (details.requested.group == 'test.example' && details.requested.name == 'foo') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '1.0.1' - } - } - force 'test.example:foo:1.0.0' - } - } - """.stripIndent() - - when: - def result = runTasksSuccessfully('dependencies') - - then: - result.standardOutput.contains('\\--- test.example:foo:latest.release -> 1.0.1\n') - } - - @Issue("https://github.com/nebula-plugins/gradle-dependency-lock-plugin/issues/86") + @Issue('#86') def 'locks win over Spring dependency management'() { buildFile << """\ buildscript { @@ -1054,6 +1025,83 @@ class DependencyLockLauncherSpec extends IntegrationSpec { result.standardOutput.contains('\\--- com.hazelcast:hazelcast:3.6-RC1\n') } + @Issue('#95') + def 'locking applied to Android variant configurations'() { + buildFile << """\ + buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.0.0' + } + } + + apply plugin: 'nebula.dependency-lock' + apply plugin: 'com.android.application' + + repositories { + jcenter() + } + + android { + compileSdkVersion 20 + buildToolsVersion '20.0.0' + + defaultConfig { + applicationId "com.netflix.dependencylocktest" + minSdkVersion 15 + targetSdkVersion 23 + versionCode 1 + versionName '1.0' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + } + + gradle.addBuildListener(new BuildAdapter() { + void buildFinished(BuildResult result) { + def confsWithDependencies = project.configurations.findAll { !it.dependencies.empty }.collect { '"' + it.name + '"' } + println "configurations=" + confsWithDependencies + } + }) + + dependencies { + compile 'commons-io:commons-io:2.4' + } + """.stripIndent() + + when: + def generateResult = runTasksSuccessfully('generateLock', 'saveLock') + + then: 'all configurations are in the lock file' + def configList = generateResult.standardOutput.readLines().find{ it.startsWith("configurations=")}.split("configurations=")[1] + def configurations = Eval.me(configList) + def lockFile = new File(projectDir, 'dependencies.lock') + def json = new JsonSlurper().parseText(lockFile.text) + configurations.each { + assert json.keySet().contains(it) + } + + when: 'all configurations are locked to the specified version' + def originalLockFile = new File('dependencies.lock.orig') + lockFile.renameTo(originalLockFile) + lockFile.withWriter { w -> + originalLockFile.eachLine { line -> + w << line.replaceAll( '2\\.4', '2.3' ) + } + } + def dependenciesResult = runTasksSuccessfully('dependencies') + + then: + dependenciesResult.standardOutput.contains('\\--- commons-io:commons-io:2.4 -> 2.3\n') + !dependenciesResult.standardOutput.contains('\\--- commons-io:commons-io:2.4\n') + } + def 'deprecated lock format message is not output for an empty file'() { def dependenciesLock = new File(projectDir, 'dependencies.lock') dependenciesLock << """{}""" diff --git a/src/test/groovy/nebula/plugin/dependencylock/DependencyLockPluginIntegrationSpec.groovy b/src/test/groovy/nebula/plugin/dependencylock/DependencyLockPluginIntegrationSpec.groovy new file mode 100644 index 00000000..6bf958fb --- /dev/null +++ b/src/test/groovy/nebula/plugin/dependencylock/DependencyLockPluginIntegrationSpec.groovy @@ -0,0 +1,76 @@ +package nebula.plugin.dependencylock + +import nebula.plugin.dependencylock.dependencyfixture.Fixture +import nebula.test.IntegrationSpec + +class DependencyLockPluginIntegrationSpec extends IntegrationSpec { + def 'eachDependency wins over force'() { + buildFile << """\ + plugins { + id 'java' + } + + repositories { maven { url '${Fixture.repo}' } } + + dependencies { + compile 'test.example:foo:latest.release' + } + + configurations.all { + resolutionStrategy { + eachDependency { details -> + if (details.requested.group == 'test.example' && details.requested.name == 'foo') { + details.useTarget group: details.requested.group, name: details.requested.name, version: '1.0.1' + } + } + force 'test.example:foo:1.0.0' + } + } + """.stripIndent() + + when: + def result = runTasksSuccessfully('dependencies') + + then: + result.standardOutput.contains('\\--- test.example:foo:latest.release -> 1.0.1\n') + } + + def 'able to modify configuration in beforeResolve block'() { + buildFile << """ + plugins { + id 'java' + } + + repositories { maven { url '${Fixture.repo}' } } + + configurations.all { configuration -> + incoming.beforeResolve { + configuration.resolutionStrategy { + force 'test.example:foo:1.0.0' + eachDependency { details -> + if (details.requested.name == 'bar') { + details.useVersion '1.0.0' + } + } + } + } + } + + repositories { + jcenter() + } + + dependencies { + compile 'test.example:foo:latest.release' + compile 'test.example:bar:latest.release' + } + """.stripIndent() + + when: + def result = runTasksSuccessfully('dependencies') + + then: + result.standardOutput.contains('+--- test.example:foo:latest.release -> 1.0.0\n') + result.standardOutput.contains('\\--- test.example:bar:latest.release -> 1.0.0\n') + } +}