Skip to content

Commit

Permalink
Merge pull request #250 from nebula-plugins/DependencyLockExtension-l…
Browse files Browse the repository at this point in the history
…azy-api

DependencyLockExtension: Introduce lazy APIs
  • Loading branch information
rpalcolea authored Oct 31, 2023
2 parents d564e17 + d027dd7 commit fe4705c
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 133 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ tasks.named('compileKotlin') {

test.dependsOn jar

tasks.withType(Test) {
tasks.withType(Test).configureEach {
testLogging {
events "PASSED", "FAILED", "SKIPPED"
afterSuite { desc, result ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,37 @@
*/
package nebula.plugin.dependencylock

class DependencyLockExtension {
String lockFile = 'dependencies.lock'
String globalLockFile = 'global.lock'
Set<String> configurationNames = [] as Set
Set<String> skippedConfigurationNamesPrefixes = [] as Set
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty

abstract class DependencyLockExtension {
DependencyLockExtension() {
lockFile.convention('dependencies.lock')
globalLockFile.convention('global.lock')
configurationNames.convention([])
skippedConfigurationNamesPrefixes.convention([])
updateDependencies.convention([])
skippedDependencies.convention([])
includeTransitives.convention(false)
lockAfterEvaluating.convention(true)
updateDependenciesFailOnInvalidCoordinates.convention(true)
updateDependenciesFailOnSimultaneousTaskUsage.convention(true)
updateDependenciesFailOnNonSpecifiedDependenciesToUpdate.convention(true)
additionalConfigurationsToLock.convention([])
}

abstract Property<String> getLockFile()
abstract Property<String> getGlobalLockFile()
abstract SetProperty<String> getConfigurationNames()
abstract SetProperty<String> getSkippedConfigurationNamesPrefixes()
abstract SetProperty<String> getUpdateDependencies()
abstract SetProperty<String> getSkippedDependencies()
abstract Property<Boolean> getIncludeTransitives()
abstract Property<Boolean> getLockAfterEvaluating()
abstract Property<Boolean> getUpdateDependenciesFailOnInvalidCoordinates()
abstract Property<Boolean> getUpdateDependenciesFailOnSimultaneousTaskUsage()
abstract Property<Boolean> getUpdateDependenciesFailOnNonSpecifiedDependenciesToUpdate()
abstract SetProperty<String> getAdditionalConfigurationsToLock()

Closure dependencyFilter = { String group, String name, String version -> true }
Set<String> updateDependencies = [] as Set
Set<String> skippedDependencies = [] as Set
boolean includeTransitives = false
boolean lockAfterEvaluating = true
boolean updateDependenciesFailOnInvalidCoordinates = true
boolean updateDependenciesFailOnSimultaneousTaskUsage = true
boolean updateDependenciesFailOnNonSpecifiedDependenciesToUpdate = true
Set<String> additionalConfigurationsToLock = [] as Set
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,19 @@ class DependencyLockTaskConfigurer {
}

private File getProjectDirLockFile(String lockFilename, DependencyLockExtension extension) {
new File(project.projectDir, lockFilename ?: extension.lockFile)
new File(project.projectDir, lockFilename ?: extension.lockFile.get())
}

private File getBuildDirLockFile(String lockFilename, DependencyLockExtension extension) {
new File(project.layout.buildDirectory.getAsFile().get(), lockFilename ?: extension.lockFile)
new File(project.layout.buildDirectory.getAsFile().get(), lockFilename ?: extension.lockFile.get())
}

private File getProjectDirGlobalLockFile(String lockFilename, DependencyLockExtension extension) {
new File(project.projectDir, lockFilename ?: extension.globalLockFile)
new File(project.projectDir, lockFilename ?: extension.globalLockFile.get())
}

private File getBuildDirGlobalLockFile(String lockFilename, DependencyLockExtension extension) {
new File(project.layout.buildDirectory.getAsFile().get(), lockFilename ?: extension.globalLockFile)
new File(project.layout.buildDirectory.getAsFile().get(), lockFilename ?: extension.globalLockFile.get())
}

private void configureCommitTask(String clLockFileName, String globalLockFileName, TaskProvider<SaveLockTask> saveTask, DependencyLockExtension lockExtension,
Expand Down Expand Up @@ -143,8 +143,8 @@ class DependencyLockTaskConfigurer {

private List<String> getPatternsToCommit(String clLockFileName, String globalLockFileName, DependencyLockExtension lockExtension ) {
List<String> patterns = []
patterns.add(clLockFileName ?: lockExtension.lockFile)
patterns.add(globalLockFileName ?: lockExtension.globalLockFile)
patterns.add(clLockFileName ?: lockExtension.lockFile.get())
patterns.add(globalLockFileName ?: lockExtension.globalLockFile.get())
return patterns
}

Expand Down Expand Up @@ -211,8 +211,8 @@ class DependencyLockTaskConfigurer {
lockTask.configure {
it.conventionMapping.with {
dependenciesLock = { getBuildDirLockFile(lockFilename, extension) }
configurationNames = { extension.configurationNames }
skippedConfigurationNames = { extension.skippedConfigurationNamesPrefixes }
configurationNames = { extension.configurationNames.get() }
skippedConfigurationNames = { extension.skippedConfigurationNamesPrefixes.get() }
}
}

Expand All @@ -222,9 +222,9 @@ class DependencyLockTaskConfigurer {
private void setupLockConventionMapping(TaskProvider<GenerateLockTask> task, DependencyLockExtension extension, Map overrideMap) {
task.configure { generateTask ->
generateTask.conventionMapping.with {
skippedDependencies = { extension.skippedDependencies }
skippedDependencies = { extension.skippedDependencies.get() }
includeTransitives = {
project.hasProperty('dependencyLock.includeTransitives') ? Boolean.parseBoolean(project['dependencyLock.includeTransitives'] as String) : extension.includeTransitives
project.hasProperty('dependencyLock.includeTransitives') ? Boolean.parseBoolean(project['dependencyLock.includeTransitives'] as String) : extension.includeTransitives.get()
}
filter = { extension.dependencyFilter }
overrides = { overrideMap }
Expand All @@ -245,15 +245,15 @@ class DependencyLockTaskConfigurer {
def subprojects = project.subprojects.collect { subproject ->
def ext = subproject.getExtensions().findByType(DependencyLockExtension)
if (ext != null) {
Collection<Configuration> lockableConfigurations = lockableConfigurations(project, subproject, ext.configurationNames, extension.skippedConfigurationNamesPrefixes)
Collection<Configuration> configurations = filterNonLockableConfigurationsAndProvideWarningsForGlobalLockSubproject(subproject, ext.configurationNames, lockableConfigurations)
Collection<Configuration> lockableConfigurations = lockableConfigurations(project, subproject, ext.configurationNames.get(), extension.skippedConfigurationNamesPrefixes.get())
Collection<Configuration> configurations = filterNonLockableConfigurationsAndProvideWarningsForGlobalLockSubproject(subproject, ext.configurationNames.get(), lockableConfigurations)
Configuration aggregate = subproject.configurations.create("aggregateConfiguration")
aggregate.setCanBeConsumed(true)
aggregate.setCanBeResolved(true)
configurations
.findAll { configuration ->
!configurationsToSkipForGlobalLockPrefixes.any { String prefix -> configuration.name.startsWith(prefix) }
&& !extension.skippedConfigurationNamesPrefixes.any { String prefix -> configuration.name.startsWith(prefix) }
&& !extension.skippedConfigurationNamesPrefixes.get().any { String prefix -> configuration.name.startsWith(prefix) }
}
.each { configuration ->
aggregate.extendsFrom(configuration)
Expand All @@ -267,7 +267,7 @@ class DependencyLockTaskConfigurer {
def conf = project.configurations.detachedConfiguration(subprojectsArray)
project.allprojects.each { it.configurations.add(conf) }

[conf] + lockableConfigurations(project, project, extension.configurationNames, extension.skippedConfigurationNamesPrefixes)
[conf] + lockableConfigurations(project, project, extension.configurationNames.get(), extension.skippedConfigurationNamesPrefixes.get())
}
}
}
Expand All @@ -278,20 +278,20 @@ class DependencyLockTaskConfigurer {
private TaskProvider<MigrateToCoreLocksTask> configureMigrateToCoreLocksTask(DependencyLockExtension extension) {
def migrateLockedDepsToCoreLocksTask = project.tasks.register(MIGRATE_LOCKED_DEPS_TO_CORE_LOCKS_TASK_NAME, MigrateLockedDepsToCoreLocksTask)
def migrateToCoreLocksTask = project.tasks.register(MIGRATE_TO_CORE_LOCKS_TASK_NAME, MigrateToCoreLocksTask)
def lockFile = new File(project.projectDir, extension.lockFile)
def lockFile = new File(project.projectDir, extension.lockFile.get())
def dependencyLock = new File(project.projectDir, "gradle.lockfile")

migrateLockedDepsToCoreLocksTask.configure {
it.conventionMapping.with {
configurationNames = { extension.configurationNames }
configurationNames = { extension.configurationNames.get() }
inputLockFile = { lockFile }
outputLock = { dependencyLock }
}
}

migrateToCoreLocksTask.configure {
it.conventionMapping.with {
configurationNames = { extension.configurationNames }
configurationNames = { extension.configurationNames.get() }
outputLock = { dependencyLock }
}
it.dependsOn project.tasks.named(MIGRATE_LOCKED_DEPS_TO_CORE_LOCKS_TASK_NAME)
Expand Down Expand Up @@ -331,11 +331,11 @@ class DependencyLockTaskConfigurer {

diffLockTask.configure { diffTask ->
diffTask.mustRunAfter(project.tasks.named(GENERATE_LOCK_TASK_NAME), project.tasks.named(UPDATE_LOCK_TASK_NAME))
def existing = new File(project.projectDir, lockFileName ?: extension.lockFile)
def existing = new File(project.projectDir, lockFileName ?: extension.lockFile.get())
if (existing.exists()) {
diffTask.existingLockFile = existing
}
diffTask.updatedLockFile = new File(project.layout.buildDirectory.getAsFile().get(), lockFileName ?: extension.lockFile)
diffTask.updatedLockFile = new File(project.layout.buildDirectory.getAsFile().get(), lockFileName ?: extension.lockFile.get())
}

project.tasks.named(SAVE_LOCK_TASK_NAME).configure { save ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class GenerateLockTask extends AbstractLockTask {
void lock() {
if (DependencyLockingFeatureFlags.isCoreLockingEnabled()) {
def dependencyLockExtension = project.extensions.findByType(DependencyLockExtension)
def globalLockFile = new File(project.projectDir, dependencyLockExtension.globalLockFile)
def globalLockFile = new File(project.projectDir, dependencyLockExtension.globalLockFile.get())
if (globalLockFile.exists()) {
throw new BuildCancelledException("Legacy global locks are not supported with core locking.\n" +
"Please remove global locks.\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class UpdateLockTask extends GenerateLockTask {
void lock() {
if (DependencyLockingFeatureFlags.isCoreLockingEnabled()) {
def dependencyLockExtension = project.extensions.findByType(DependencyLockExtension)
def globalLockFile = new File(project.projectDir, dependencyLockExtension.globalLockFile)
def globalLockFile = new File(project.projectDir, dependencyLockExtension.globalLockFile.get())
if (globalLockFile.exists()) {
throw new BuildCancelledException("Legacy global locks are not supported with core locking.\n" +
"Please remove global locks.\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class CoreLockingHelper {
def additionalConfigurationsToLockViaProperty = project.hasProperty(ADDITIONAL_CONFIGS_TO_LOCK)
? (project[ADDITIONAL_CONFIGS_TO_LOCK] as String).split(",") as Set<String>
: []
def additionalConfigurationsToLockViaExtension = dependencyLockExtension.additionalConfigurationsToLock as Set<String>
def additionalConfigurationsToLockViaExtension = dependencyLockExtension.additionalConfigurationsToLock.get() as Set<String>
def additionalConfigNames = additionalConfigurationsToLockViaProperty + additionalConfigurationsToLockViaExtension
additionalConfigNames
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ class DependencyLockPlugin : Plugin<Project> {
if (DependencyLockingFeatureFlags.isCoreLockingEnabled()) {
LOGGER.info("${project.name}: coreLockingSupport feature enabled")
val coreLockingHelper = CoreLockingHelper(project)
coreLockingHelper.lockSelectedConfigurations(extension.configurationNames)
coreLockingHelper.lockSelectedConfigurations(extension.configurationNames.get())

coreLockingHelper.disableCachingWhenUpdatingDependencies()
coreLockingHelper.notifyWhenUsingOfflineMode()

val lockFile = File(project.projectDir, extension.lockFile)
val lockFile = File(project.projectDir, extension.lockFile.get())

if (lockFile.exists()) {
if (startParameter.isWriteDependencyLocks) {
Expand All @@ -138,7 +138,7 @@ class DependencyLockPlugin : Plugin<Project> {
val taskNames = startParameter.taskNames
val hasUpdateTask = hasUpdateTask(taskNames)
val hasGenerationTask = hasGenerationTask(taskNames)
val globalLockFile = File(project.projectDir, extension.globalLockFile)
val globalLockFile = File(project.projectDir, extension.globalLockFile.get())

if (globalLockFile.exists() && !hasGenerationTask && !hasUpdateTask) {
// do not fail for generation or update tasks here. It's more readable when the task itself fails.
Expand All @@ -147,7 +147,7 @@ class DependencyLockPlugin : Plugin<Project> {
" - Legacy global lock: ${globalLockFile.absolutePath}")
}
} else {
val lockAfterEvaluating = if (project.hasProperty(LOCK_AFTER_EVALUATING)) project.property(LOCK_AFTER_EVALUATING).toString().toBoolean() else extension.lockAfterEvaluating
val lockAfterEvaluating = if (project.hasProperty(LOCK_AFTER_EVALUATING)) project.property(LOCK_AFTER_EVALUATING).toString().toBoolean() else extension.lockAfterEvaluating.get()
if (lockAfterEvaluating) {
LOGGER.info("Delaying dependency lock apply until beforeResolve ($LOCK_AFTER_EVALUATING set to true)")
} else {
Expand Down Expand Up @@ -186,17 +186,17 @@ class DependencyLockPlugin : Plugin<Project> {
}

private fun maybeApplyLock(conf: Configuration, extension: DependencyLockExtension, overrides: Map<*, *>, globalLockFileName: String?, lockFilename: String?) {
val shouldIgnoreLock = (extension.skippedConfigurationNamesPrefixes + DependencyLockTaskConfigurer.configurationsToSkipForGlobalLockPrefixes).any {
val shouldIgnoreLock = (extension.skippedConfigurationNamesPrefixes.get() + DependencyLockTaskConfigurer.configurationsToSkipForGlobalLockPrefixes).any {
prefix -> conf.name.startsWith(prefix) && !conf.name.contains("resolutionRules")
}
if(shouldIgnoreLock) {
return
}
val globalLock = File(project.rootProject.projectDir, globalLockFileName ?: extension.globalLockFile)
val globalLock = File(project.rootProject.projectDir, globalLockFileName ?: extension.globalLockFile.get())
val dependenciesLock = if (globalLock.exists()) {
globalLock
} else {
File(project.projectDir, lockFilename ?: extension.lockFile)
File(project.projectDir, lockFilename ?: extension.lockFile.get())
}

lockUsed = dependenciesLock.name
Expand All @@ -206,7 +206,7 @@ class DependencyLockPlugin : Plugin<Project> {
val taskNames = project.gradle.startParameter.taskNames
val hasUpdateTask = hasUpdateTask(taskNames)

val updates = if (project.hasProperty(UPDATE_DEPENDENCIES)) parseUpdates(project.property(UPDATE_DEPENDENCIES) as String) else extension.updateDependencies
val updates = if (project.hasProperty(UPDATE_DEPENDENCIES)) parseUpdates(project.property(UPDATE_DEPENDENCIES) as String) else extension.updateDependencies.get()
UpdateDependenciesValidator.validate(
updates, overrides, hasUpdateTask,
hasTask(taskNames, GENERATION_TASK_NAMES - UPDATE_TASK_NAMES),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class UpdateDependenciesValidator {
val validateCoordinates =
if (project.hasProperty(VALIDATE_DEPENDENCY_COORDINATES)) project.property(
VALIDATE_DEPENDENCY_COORDINATES
).toString().toBoolean() else extension.updateDependenciesFailOnInvalidCoordinates
).toString().toBoolean() else extension.updateDependenciesFailOnInvalidCoordinates.get()
val validateSimultaneousTasks =
if (project.hasProperty(VALIDATE_SIMULTANEOUS_TASKS)) project.property(
VALIDATE_SIMULTANEOUS_TASKS
).toString().toBoolean() else extension.updateDependenciesFailOnSimultaneousTaskUsage
).toString().toBoolean() else extension.updateDependenciesFailOnSimultaneousTaskUsage.get()
val validateSpecifiedDependenciesToUpdate =
if (project.hasProperty(VALIDATE_SPECIFIED_DEPENDENCIES_TO_UPDATE)) project.property(
VALIDATE_SPECIFIED_DEPENDENCIES_TO_UPDATE
).toString().toBoolean() else extension.updateDependenciesFailOnNonSpecifiedDependenciesToUpdate
).toString().toBoolean() else extension.updateDependenciesFailOnNonSpecifiedDependenciesToUpdate.get()

validateCoordinates(updateDependencies, validateCoordinates)
validateSimultaneousTasks(hasUpdateTask, hasGenerateTask, validateSimultaneousTasks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import nebula.test.ProjectSpec

class UpdateDependenciesValidatorSpec extends ProjectSpec {
private static final HashMap<Object, Object> emptyMap = new HashMap<Object, Object>()
private static final DependencyLockExtension extension = DependencyLockExtension.newInstance()
private DependencyLockExtension extension
private static final String pluginName = 'com.netflix.nebula.dependency-lock'

def setup() {
project.apply plugin: pluginName
extension = project.extensions.findByType(DependencyLockExtension)
}

def 'should not fail if valid coordinates'() {
Expand Down
Loading

0 comments on commit fe4705c

Please sign in to comment.