diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 91ca28c..1948b90 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 675b421..2d80b69 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-rc-3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyBasePlugin.kt b/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyBasePlugin.kt index 07f2282..5eaa8b5 100644 --- a/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyBasePlugin.kt +++ b/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyBasePlugin.kt @@ -15,59 +15,16 @@ */ package com.netflix.nebula.dependencybase -import com.netflix.nebula.dependencybase.tasks.NebulaDependencyInsightReportTask -import groovy.lang.Closure import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.execution.TaskExecutionGraph class DependencyBasePlugin: Plugin { val dependencyManagement: DependencyManagement = DependencyManagement() - lateinit var insightTask: NebulaDependencyInsightReportTask override fun apply(project: Project) { - initializeDependencyBase(project) - enableForceCollection(project) - setupDependencyInsightEnhanced(project) - project.gradle.taskGraph.whenReady( groovyClosure { taskGraph : TaskExecutionGraph -> - if (!taskGraph.hasTask(insightTask)) { - dependencyManagement.disableMessageStore() - } - }) - } - - private fun initializeDependencyBase(project: Project) { + // We are leaving this around for backwards compatibility of people using this plugin project.extensions.extraProperties.set("nebulaDependencyBase", dependencyManagement) + dependencyManagement.disableMessageStore() } - private fun enableForceCollection(project: Project) { - project.configurations.all { conf -> - if (conf.state == Configuration.State.UNRESOLVED) { - conf.incoming.beforeResolve { - val forced = conf.resolutionStrategy.forcedModules - forced.forEach { force -> dependencyManagement.addForce(conf.name, "${force.group}:${force.name}") } - } - } - } - } - - private fun setupDependencyInsightEnhanced(project: Project) { - insightTask = project.tasks.create("dependencyInsightEnhanced", NebulaDependencyInsightReportTask::class.java) - insightTask.reasonLookup = dependencyManagement - project.afterEvaluate { - it.tasks.findByName("dependencyInsight").apply { - if (this == null) return@afterEvaluate - dependsOn(insightTask) - enabled = false - } - } - } -} - -inline fun S.groovyClosure(crossinline call: (a: T) -> Unit) = object : Closure(this) { - @Suppress("unused") - fun doCall(a: T) { - call(a) - } -} +} \ No newline at end of file diff --git a/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyManagement.kt b/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyManagement.kt index 95c7e56..ea63161 100644 --- a/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyManagement.kt +++ b/src/main/kotlin/com/netflix/nebula/dependencybase/DependencyManagement.kt @@ -22,6 +22,8 @@ class DependencyManagement { val pluginMessages: MutableSet = mutableSetOf() private var shouldStoreReason: Boolean = true + // Leaving these methods in place for backwards compatibility for projects calling them + fun addRecommendation(configuration: String, coordinate: String, version: String, source: String, plugin: String) { if (shouldStoreReason) reasons.add(Recommendation(configuration, coordinate, version, source)) } diff --git a/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt b/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt deleted file mode 100644 index 5dbc773..0000000 --- a/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2017 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.nebula.dependencybase.tasks - -import com.netflix.nebula.dependencybase.DependencyManagement -import org.gradle.api.InvalidUserDataException -import org.gradle.api.artifacts.component.ModuleComponentIdentifier -import org.gradle.api.artifacts.result.DependencyResult -import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator -import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.diagnostics.DependencyInsightReportTask -import org.gradle.api.tasks.diagnostics.internal.graph.DependencyGraphRenderer -import org.gradle.api.tasks.diagnostics.internal.graph.LegendRenderer -import org.gradle.api.tasks.diagnostics.internal.graph.NodeRenderer -import org.gradle.api.tasks.diagnostics.internal.graph.nodes.RenderableDependency -import org.gradle.api.tasks.diagnostics.internal.insight.DependencyInsightReporter -import org.gradle.internal.graph.GraphRenderer -import java.util.* -import org.gradle.internal.logging.text.StyledTextOutput.Style.* - - -/** - * Task extending {@link DependencyInsightReportTask} providing overridden report function to provide additional selection - * reasons. - */ -open class NebulaDependencyInsightReportTask : DependencyInsightReportTask() { - @Internal - lateinit var reasonLookup: DependencyManagement - - /** - * Copied verbatim from {@link DependencyInsightReportTask}, except for the marked changes. - */ - @TaskAction - override fun report() { - val reportTasks = project.tasks.withType(DependencyInsightReportTask::class.java) - val configuration = reportTasks.mapNotNull { it.configuration }.singleOrNull() - ?: throw InvalidUserDataException("Dependency insight report cannot be generated because the input configuration was not specified. " - + "\nIt can be specified from the command line, e.g: '" + path + " --configuration someConf --dependency someDep'") - - val dependencySpec = reportTasks.mapNotNull { it.dependencySpec }.singleOrNull() - ?: throw InvalidUserDataException("Dependency insight report cannot be generated because the dependency to show was not specified." - + "\nIt can be specified from the command line, e.g: '" + path + " --dependency someDep'") - - val output = textOutputFactory.create(javaClass) - val renderer = GraphRenderer(output) - - val result = configuration.incoming.resolutionResult - - val selectedDependencies = LinkedHashSet() - result.allDependencies { dependencyResult -> - if (dependencySpec.isSatisfiedBy(dependencyResult)) { - selectedDependencies.add(dependencyResult) - } - } - - if (selectedDependencies.isEmpty()) { - output.println("No dependencies matching given input were found in " + configuration.toString()) - return - } - - val reporter = DependencyInsightReporter() - val sortedDeps = try { - reporter.prepare(selectedDependencies, versionSelectorScheme, versionComparator, versionParser) - } catch (e: NoSuchMethodError) { - reporter.legacyPrepare(selectedDependencies, versionSelectorScheme, versionComparator) - } - - val nodeRenderer = NodeRenderer { target, node, alreadyRendered -> - val leaf = node.children.isEmpty() - target.text(if (leaf) configuration.name else node.name) - if (alreadyRendered && !leaf) { - target.withStyle(Info).text(" (*)") - } - } - - val legendRenderer = LegendRenderer(output) - val dependencyGraphRenderer = DependencyGraphRenderer(renderer, nodeRenderer, legendRenderer) - - var i = 1 - for (dependency in sortedDeps) { - renderer.visit({ out -> - out.withStyle(Identifier).text(dependency.name) - - // Nebula enhancements start here - val hasDescription = dependency.description != null && dependency.description.isNotEmpty() - if (hasDescription) { - val reason = reasonLookup.getReason(configuration.name, calculateCoordinateFromId(dependency.id)) - out.withStyle(Description).text(" ($reason)") - } - // Nebula enhancements end here - - when (dependency.resolutionState) { - RenderableDependency.ResolutionState.FAILED -> out.withStyle(Failure).text(" FAILED") - RenderableDependency.ResolutionState.UNRESOLVED -> out.withStyle(Failure).text(" (n)") - else -> { - } - } - }, true) - dependencyGraphRenderer.render(dependency) - val last = i++ == sortedDeps.size - if (!last) { - output.println() - } - - } - - // Nebula enhancements start here - val globalMessages = reasonLookup.getGlobalMessages() - if (globalMessages.isNotEmpty()) { - output.println() - output.println(globalMessages) - } - // Nebula enhancements end here - - legendRenderer.printLegend() - } - - fun calculateCoordinateFromId(id: Any): String { - when (id) { - is ModuleComponentIdentifier -> return "${id.group}:${id.module}" - } - return "" - } - - @Suppress("UNCHECKED_CAST") - private fun DependencyInsightReporter.legacyPrepare(input: Collection, versionSelectorScheme: VersionSelectorScheme, versionComparator: VersionComparator): Collection { - return javaClass.getMethod("prepare", Collection::class.java, VersionSelectorScheme::class.java, VersionComparator::class.java) - .invoke(this, input, versionSelectorScheme, versionComparator) as Collection - } -} diff --git a/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy b/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy deleted file mode 100644 index 02da05b..0000000 --- a/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2017 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.nebula.dependencybase - -import nebula.test.IntegrationSpec -import nebula.test.dependencies.DependencyGraphBuilder -import nebula.test.dependencies.GradleDependencyGenerator - -class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationSpec { - def "recommend versions of dependencies are explained in dependencyInsight"() { - given: - setup1Dependency() - - when: - def results = runTasks("dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - results.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" - } - - def "forces reported"() { - given: - setup1DependencyForce() - - when: - def results = runTasks("dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - results.standardOutput.contains "test.nebula:foo:1.0.0 (forced, recommend 2.0.0 via NebulaTest)" - } - - def "multiproject sees recommendations"() { - given: - setupMultiproject() - - when: - def onefoo = runTasks(":one:dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - onefoo.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" - - when: - def twofoo = runTasks(":two:dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - twofoo.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" - - when: - def twobar = runTasks(":two:dependencyInsight", "--configuration", "compileClasspath", "--dependency", "bar") - - then: - twobar.standardOutput.contains "test.nebula:bar:2.0.0 (recommend 2.0.0 via NebulaTest)" - } - - def "detect complete substitute foo to bar and give insight"() { - given: - def graph = new DependencyGraphBuilder() - .addModule("test.nebula:foo:1.0.0") - .addModule("test.nebula:bar:2.0.0") - .build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - buildFile << """\ - plugins { - id "java" - } - - apply plugin: "nebula.dependency-base" - - repositories { - ${generator.mavenRepositoryBlock} - } - - configurations.all { - resolutionStrategy { - eachDependency { details -> - if (details.requested.group == "test.nebula" && details.requested.name == "foo") { - details.useTarget "test.nebula:bar:2.0.0" - } - } - } - } - - project.nebulaDependencyBase.addReason("compileClasspath", "test.nebula:bar", "possible replacement of test.nebula:foo", "test") - - dependencies { - compile "test.nebula:foo:1.0.0" - } - """.stripIndent() - - when: - def results = runTasks("dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - results.standardOutput.contains "test.nebula:bar:2.0.0 (possible replacement of test.nebula:foo)" - } - - def "only collect dependency insight if dependencyInsight is on task graph"() { - given: - setup1Dependency() - - buildFile << """\ - task messageCount { - doLast { - println "Message count: \${project.nebulaDependencyBase.reasons.size()}" - } - } - """.stripIndent() - - when: - def results = runTasks("dependencies", "--configuration", "compileClasspath", "messageCount") - - then: - results.standardOutput.contains "Message count: 0" - } - - def setup1Dependency() { - def graph = new DependencyGraphBuilder().addModule("test.nebula:foo:1.0.0").build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - - buildFile << """\ - plugins { - id "java" - } - - apply plugin: "nebula.dependency-base" - - repositories { - ${generator.mavenRepositoryBlock} - } - - configurations.all { - resolutionStrategy { - eachDependency { details -> - if (details.requested.group == "test.nebula" && details.requested.name == "foo") { - details.useVersion "1.0.0" - } - } - } - } - - project.nebulaDependencyBase.addRecommendation("compileClasspath", "test.nebula:foo", "1.0.0", "NebulaTest", "test") - - dependencies { - compile "test.nebula:foo" - } - """.stripIndent() - } - - def setup1DependencyForce() { - def graph = new DependencyGraphBuilder() - .addModule("test.nebula:foo:1.0.0") - .addModule("test.nebula:foo:2.0.0") - .build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - - buildFile << """\ - plugins { - id "java" - } - apply plugin: "nebula.dependency-base" - - repositories { - ${generator.mavenRepositoryBlock} - } - - project.nebulaDependencyBase.addRecommendation("compileClasspath", "test.nebula:foo", "2.0.0", "NebulaTest", "test") - - configurations.all { - resolutionStrategy { - force "test.nebula:foo:1.0.0" - } - } - - dependencies { - compile "test.nebula:foo" - } - """.stripIndent() - } - - def setupMultiproject() { - def graph = new DependencyGraphBuilder() - .addModule("test.nebula:foo:1.0.0") - .addModule("test.nebula:bar:2.0.0") - .build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - - buildFile << """\ - apply plugin: "nebula.dependency-base" - - subprojects { - apply plugin: "nebula.dependency-base" - apply plugin: "java" - - configurations.all { - resolutionStrategy { - eachDependency { details -> - if (details.requested.group == "test.nebula" && details.requested.name == "foo") { - details.useVersion "1.0.0" - } - if (details.requested.group == "test.nebula" && details.requested.name == "bar") { - details.useVersion "2.0.0" - } - } - } - } - - project.nebulaDependencyBase.addRecommendation("compileClasspath", "test.nebula:foo", "1.0.0", "NebulaTest", "test") - project.nebulaDependencyBase.addRecommendation("compileClasspath", "test.nebula:bar", "2.0.0", "NebulaTest", "test") - - repositories { - ${generator.mavenRepositoryBlock} - } - } - """.stripIndent() - - addSubproject("one", """\ - dependencies { - compile "test.nebula:foo" - } - """.stripIndent()) - addSubproject("two", """\ - dependencies { - compile project(":one") - compile "test.nebula:bar" - } - """.stripIndent()) - } -} diff --git a/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy b/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy deleted file mode 100644 index 4feb4fb..0000000 --- a/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2017 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.nebula.dependencybase.tasks - -import nebula.test.IntegrationSpec -import nebula.test.dependencies.DependencyGraphBuilder -import nebula.test.dependencies.GradleDependencyGenerator - -class NebulaDependencyInsightReportTaskSpec extends IntegrationSpec { - def "generate a dependencyInsight report with more than just chosen by rule"() { - def graph = new DependencyGraphBuilder().addModule("test.nebula:foo:1.0.0") - .addModule("test.nebula:foo:1.1.0") - .build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - - - buildFile << """\ - plugins { - id "java" - } - apply plugin: 'nebula.dependency-base' - - repositories { - ${generator.mavenRepositoryBlock} - } - - configurations.all { - resolutionStrategy { - force "test.nebula:foo:1.0.0" - } - } - - dependencies { - compile "test.nebula:foo:1.+" - } - """.stripIndent() - - when: - def result = runTasks("dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - result.standardOutput.contains "test.nebula:foo:1.0.0 (forced)" - } - - def "display global info message"() { - def graph = new DependencyGraphBuilder().addModule("test.nebula:foo:1.0.0") - .addModule("test.nebula:foo:1.1.0") - .build() - def generator = new GradleDependencyGenerator(graph) - generator.generateTestMavenRepo() - - - buildFile << """\ - plugins { - id "java" - } - apply plugin: 'nebula.dependency-base' - - repositories { - ${generator.mavenRepositoryBlock} - } - - project.nebulaDependencyBase.addPluginMessage("test plugin message") - project.nebulaDependencyBase.addPluginMessage("and another") - - dependencies { - compile "test.nebula:foo:1.+" - } - """.stripIndent() - - when: - def result = runTasks("dependencyInsight", "--configuration", "compileClasspath", "--dependency", "foo") - - then: - result.standardOutput.contains "test plugin message${System.lineSeparator()}and another" - } -}