diff --git a/CHANGELOG.md b/CHANGELOG.md index ad903a0..f2b4e8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.2.0 / 2017-03-15 +================== + +* Move to gradle 2.13 + 0.1.0 / 2017-03-13 ================== diff --git a/build.gradle b/build.gradle index 4fcc486..bffce7e 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,14 @@ contacts { } } +configurations.all { + resolutionStrategy { + force "com.netflix.nebula:nebula-test:4.4.2" + } +} + dependencies { - testCompile "com.netflix.nebula:nebula-test:5.+" + testCompile "com.netflix.nebula:nebula-test:4.4.2" } description = "A base plugin to improve dependency insight and handle all dependency applies" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 25432ce..377d4d2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip diff --git a/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt b/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt index cf2c147..45597fc 100644 --- a/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt +++ b/src/main/kotlin/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTask.kt @@ -16,53 +16,114 @@ package com.netflix.nebula.dependencybase.tasks import com.netflix.nebula.dependencybase.DependencyManagement -import org.gradle.api.Action +import org.gradle.api.DefaultTask import org.gradle.api.InvalidUserDataException +import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.result.DependencyResult +import org.gradle.api.artifacts.result.ResolutionResult +import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator +import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme +import org.gradle.api.internal.tasks.options.Option +import org.gradle.api.specs.Spec import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.diagnostics.DependencyInsightReportTask +import org.gradle.api.tasks.diagnostics.internal.dsl.DependencyResultSpecNotationConverter 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 org.gradle.internal.logging.text.StyledTextOutput -import java.util.* +import org.gradle.logging.StyledTextOutput +import org.gradle.logging.StyledTextOutputFactory +import javax.inject.Inject /** * Mostly a copy of DependencyInsightReportTask from gradle/gradle which is under a Apache 2.0 license. Modified to Kotlin. * Modified to provide more information on why a dependenecy version was selected. */ -open class NebulaDependencyInsightReportTask : DependencyInsightReportTask() { +open class NebulaDependencyInsightReportTask : DefaultTask() { var reasonLookup: DependencyManagement? = null + /** + * Configuration to look the dependency in + */ + var configuration: Configuration? = null + + /** + * Selects the dependency (or dependencies if multiple matches found) to show the report for. + */ + var dependencySpec: Spec? = null + + @Inject + open fun getTextOutputFactory(): StyledTextOutputFactory { + throw UnsupportedOperationException() + } + + @Inject + open fun getVersionSelectorScheme(): VersionSelectorScheme { + throw UnsupportedOperationException() + } + + @Inject + open fun getVersionComparator(): VersionComparator { + throw UnsupportedOperationException(); + } + + /** + * Configures the dependency to show the report for. + * Multiple notation formats are supported: Strings, instances of {@link Spec} + * and groovy closures. Spec and closure receive {@link DependencyResult} as parameter. + * Examples of String notation: 'org.slf4j:slf4j-api', 'slf4j-api', or simply: 'slf4j'. + * The input may potentially match multiple dependencies. + * See also {@link DependencyInsightReportTask#setDependencySpec(Spec)} + *

+ * This method is exposed to the command line interface. Example usage: + *

gradle dependencyInsight --dependency slf4j
+ * + * @param dependencyInsightNotation + */ + @Option(option = "dependency", description = "Shows the details of given dependency.") + fun setDependencySpec(dependencyInsightNotation: Any) { + val parser = DependencyResultSpecNotationConverter.parser() + this.dependencySpec = parser.parseNotation(dependencyInsightNotation) + } + + /** + * Sets the configuration (via name) to look the dependency in. + *

+ * This method is exposed to the command line interface. Example usage: + *

gradle dependencyInsight --configuration runtime --dependency slf4j
+ * + * @param configurationName + */ + @Option(option = "configuration", description = "Looks for the dependency in given configuration.") + fun setConfiguration(configurationName: String) { + this.configuration = project.configurations.getByName(configurationName) + } + @TaskAction - override fun report() { - val configuration = getConfiguration() ?: 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'") + fun report() { + val conf = configuration ?: + 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'") - if (dependencySpec == null) { + val depSpec = dependencySpec ?: 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'") - } - + + "\nIt can be specified from the command line, e.g: '$path --dependency someDep'") - val output = textOutputFactory.create(javaClass) - val renderer = GraphRenderer(output) + val output: StyledTextOutput = getTextOutputFactory().create(javaClass) + val renderer: GraphRenderer = GraphRenderer(output) - val result = configuration!!.getIncoming().getResolutionResult() + val result: ResolutionResult = conf.incoming.resolutionResult; - val selectedDependencies = LinkedHashSet() - result.allDependencies(Action { dependencyResult -> - if (dependencySpec.isSatisfiedBy(dependencyResult)) { - selectedDependencies.add(dependencyResult) + val selectedDependencies: MutableSet = mutableSetOf() + result.allDependencies { + if (depSpec.isSatisfiedBy(it)) { + selectedDependencies.add(it) } - }) + } if (selectedDependencies.isEmpty()) { - output.println("No dependencies matching given input were found in " + configuration.toString()) + output.println("No dependencies matching given input were found in ${conf}") return } @@ -70,42 +131,35 @@ open class NebulaDependencyInsightReportTask : DependencyInsightReportTask() { val nodeRenderer = NodeRenderer { target, node, alreadyRendered -> val leaf = node.children.isEmpty() - target.text(if (leaf) configuration!!.getName() else node.name) + target.text(if (leaf) conf.name else node.name) if (alreadyRendered && !leaf) { target.withStyle(StyledTextOutput.Style.Info).text(" (*)") } } - val legendRenderer = LegendRenderer(output) - val dependencyGraphRenderer = DependencyGraphRenderer(renderer, nodeRenderer, legendRenderer) + val dependencyGraphRenderer = DependencyGraphRenderer(renderer, nodeRenderer) var i = 1 for (dependency in sortedDeps) { - renderer.visit({ out -> - out.withStyle(StyledTextOutput.Style.Identifier).text(dependency.name) - + renderer.visit( { out -> + out.withStyle(StyledTextOutput.Style.Identifier).text(dependency.name); if (dependency.description?.isNotEmpty()?:false) { - out.withStyle(StyledTextOutput.Style.Description).text(" (${reasonLookup?.getReason(configuration.name, calculateCoordinateFromId(dependency.id))})") + out.withStyle(StyledTextOutput.Style.Description).text(" (${reasonLookup?.getReason(conf.name, calculateCoordinateFromId(dependency.id))})") } - - when (dependency.resolutionState) { - RenderableDependency.ResolutionState.FAILED -> out.withStyle(StyledTextOutput.Style.Failure).text(" FAILED") - RenderableDependency.ResolutionState.RESOLVED -> { - } - RenderableDependency.ResolutionState.UNRESOLVED -> out.withStyle(StyledTextOutput.Style.Failure).text(" (n)") + if (!dependency.isResolvable) { + out.withStyle(StyledTextOutput.Style.Failure).text(" FAILED") } - }, true) + }, true); dependencyGraphRenderer.render(dependency) val last = i++ == sortedDeps.size if (!last) { output.println() } - } output.println() output.println(reasonLookup?.getGlobalMessages()) - legendRenderer.printLegend() + dependencyGraphRenderer.printLegend() } fun calculateCoordinateFromId(id: Any): String { diff --git a/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy b/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy index 2c914d0..c94ea5e 100644 --- a/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy +++ b/src/test/groovy/com/netflix/nebula/dependencybase/RecommendationDependencyBasePluginIntegrationSpec.groovy @@ -15,11 +15,11 @@ */ package com.netflix.nebula.dependencybase -import nebula.test.IntegrationTestKitSpec +import nebula.test.IntegrationSpec import nebula.test.dependencies.DependencyGraphBuilder import nebula.test.dependencies.GradleDependencyGenerator -class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestKitSpec { +class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationSpec { def "recommend versions of dependencies are explained in dependencyInsightEnhanced"() { given: setup1Dependency() @@ -28,7 +28,9 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK def results = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - results.output.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" + println results?.standardError + println results?.standardOutput + results.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" } def "forces reported"() { @@ -39,7 +41,7 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK def results = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - results.output.contains "test.nebula:foo:1.0.0 (forced, recommend 2.0.0 via NebulaTest)" + results.standardOutput.contains "test.nebula:foo:1.0.0 (forced, recommend 2.0.0 via NebulaTest)" } def "multiproject sees recommendations"() { @@ -50,19 +52,19 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK def onefoo = runTasks(":one:dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - onefoo.output.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" + onefoo.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" when: def twofoo = runTasks(":two:dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - twofoo.output.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" + twofoo.standardOutput.contains "test.nebula:foo:1.0.0 (recommend 1.0.0 via NebulaTest)" when: def twobar = runTasks(":two:dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "bar") then: - twobar.output.contains "test.nebula:bar:2.0.0 (recommend 2.0.0 via NebulaTest)" + 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"() { @@ -74,10 +76,11 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK generator.generateTestMavenRepo() buildFile << """\ plugins { - id "nebula.dependency-base" id "java" } + apply plugin: "nebula.dependency-base" + repositories { ${generator.mavenRepositoryBlock} } @@ -95,7 +98,7 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK project.nebulaDependencyBase.addReason("compileClasspath", "test.nebula:bar", "possible replacement of test.nebula:foo", "test") dependencies { - implementation "test.nebula:foo:1.0.0" + compile "test.nebula:foo:1.0.0" } """.stripIndent() @@ -103,7 +106,7 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK def results = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - results.output.contains "test.nebula:bar:2.0.0 (possible replacement of test.nebula:foo)" + results.standardOutput.contains "test.nebula:bar:2.0.0 (possible replacement of test.nebula:foo)" } def setup1Dependency() { @@ -113,10 +116,11 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK buildFile << """\ plugins { - id "nebula.dependency-base" id "java" } + apply plugin: "nebula.dependency-base" + repositories { ${generator.mavenRepositoryBlock} } @@ -134,7 +138,7 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK project.nebulaDependencyBase.addRecommendation("compileClasspath", "test.nebula:foo", "1.0.0", "NebulaTest", "test") dependencies { - implementation "test.nebula:foo" + compile "test.nebula:foo" } """.stripIndent() } @@ -149,9 +153,9 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK buildFile << """\ plugins { - id "nebula.dependency-base" id "java" } + apply plugin: "nebula.dependency-base" repositories { ${generator.mavenRepositoryBlock} @@ -166,13 +170,12 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK } dependencies { - implementation "test.nebula:foo" + compile "test.nebula:foo" } """.stripIndent() } def setupMultiproject() { - keepFiles = true def graph = new DependencyGraphBuilder() .addModule("test.nebula:foo:1.0.0") .addModule("test.nebula:bar:2.0.0") @@ -181,9 +184,7 @@ class RecommendationDependencyBasePluginIntegrationSpec extends IntegrationTestK generator.generateTestMavenRepo() buildFile << """\ - plugins { - id "nebula.dependency-base" - } + apply plugin: "nebula.dependency-base" subprojects { apply plugin: "nebula.dependency-base" diff --git a/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy b/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy index 1246a4b..d4eecd3 100644 --- a/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy +++ b/src/test/groovy/com/netflix/nebula/dependencybase/tasks/NebulaDependencyInsightReportTaskSpec.groovy @@ -15,12 +15,11 @@ */ package com.netflix.nebula.dependencybase.tasks -import nebula.test.IntegrationTestKitSpec +import nebula.test.IntegrationSpec import nebula.test.dependencies.DependencyGraphBuilder import nebula.test.dependencies.GradleDependencyGenerator -import org.gradle.testkit.runner.BuildResult -class NebulaDependencyInsightReportTaskSpec extends IntegrationTestKitSpec { +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") @@ -32,8 +31,8 @@ class NebulaDependencyInsightReportTaskSpec extends IntegrationTestKitSpec { buildFile << """\ plugins { id "java" - id "nebula.dependency-base" } + apply plugin: 'nebula.dependency-base' repositories { ${generator.mavenRepositoryBlock} @@ -46,15 +45,15 @@ class NebulaDependencyInsightReportTaskSpec extends IntegrationTestKitSpec { } dependencies { - implementation "test.nebula:foo:1.+" + compile "test.nebula:foo:1.+" } """.stripIndent() when: - BuildResult result = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") + def result = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - result.output.contains "test.nebula:foo:1.0.0 (forced)" + result.standardOutput.contains "test.nebula:foo:1.0.0 (forced)" } def "display global info message"() { @@ -68,8 +67,8 @@ class NebulaDependencyInsightReportTaskSpec extends IntegrationTestKitSpec { buildFile << """\ plugins { id "java" - id "nebula.dependency-base" } + apply plugin: 'nebula.dependency-base' repositories { ${generator.mavenRepositoryBlock} @@ -79,14 +78,14 @@ class NebulaDependencyInsightReportTaskSpec extends IntegrationTestKitSpec { project.nebulaDependencyBase.addPluginMessage("and another") dependencies { - implementation "test.nebula:foo:1.+" + compile "test.nebula:foo:1.+" } """.stripIndent() when: - BuildResult result = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") + def result = runTasks("dependencyInsightEnhanced", "--configuration", "compileClasspath", "--dependency", "foo") then: - result.output.contains "test plugin message${System.lineSeparator()}and another" + result.standardOutput.contains "test plugin message${System.lineSeparator()}and another" } }