From d2bd81950d6256e0231a026b35104a180226d473 Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 10:41:17 -0500 Subject: [PATCH 1/8] Bumping version to next SNAPSHOT for development --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 8f3b981..4d9bd8f 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.5" +version := "0.7.6-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 72b5ff3573e4338bc1eee6034990592fe616641c Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 10:51:23 -0500 Subject: [PATCH 2/8] Wired up CSV task for generating the string and one for printing it to the console --- src/main/scala/net/virtualvoid/sbt/graph/Csv.scala | 7 +++++++ src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/Csv.scala diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala new file mode 100644 index 0000000..071a33e --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala @@ -0,0 +1,7 @@ +package net.virtualvoid.sbt.graph + +object Csv { + def toCsv(graph: IvyGraphMLDependencies.ModuleGraph):String = { + "Hello" + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 3fcafff..fd5af7d 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -52,8 +52,11 @@ object Plugin extends sbt.Plugin { "A task which returns the location of the ivy report file for a given configuration (default `compile`).") val ignoreMissingUpdate = update in ivyReport val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library", - "Specifies if scala dependency should be filtered in dependency-* output" - ) + "Specifies if scala dependency should be filtered in dependency-* output") + val asciiCsv = TaskKey[String]("dependency-csv-string", + "Returns a string containing the CSV-formatted report of all dependencies including transitives.") + val dependencyCsv = TaskKey[Unit]("dependency-csv", + "Prints the CSV-formatted report of all dependencies to the console.") val licenseInfo = TaskKey[Unit]("dependency-license-info", "Aggregates and shows information about the licenses of dependencies") @@ -128,6 +131,8 @@ object Plugin extends sbt.Plugin { dependencyDotNodeLabel := { (organisation: String, name: String, version: String) => """<%s
%s
%s>""".format(organisation, name, version) }, + asciiCsv <<= moduleGraph.map(Csv.toCsv), + dependencyCsv <<= print(asciiCsv), whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) From 73bbb39eb1ee0cc70259b7262a5b3aa4f9293a6a Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 10:59:15 -0500 Subject: [PATCH 3/8] Wired up a task to write CSV to file --- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index fd5af7d..d2e672a 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -35,7 +35,7 @@ object Plugin extends sbt.Plugin { val dependencyDotHeader = SettingKey[String]("dependency-dot-header", "The header of the dot file. (e.g. to set your preferred node shapes)") val dependencyDot = TaskKey[File]("dependency-dot", - "Creates a dot file containing the dpendency-graph for a project") + "Creates a dot file containing the dependency-graph for a project") val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", @@ -57,6 +57,10 @@ object Plugin extends sbt.Plugin { "Returns a string containing the CSV-formatted report of all dependencies including transitives.") val dependencyCsv = TaskKey[Unit]("dependency-csv", "Prints the CSV-formatted report of all dependencies to the console.") + val dependencyCsvFile = SettingKey[File]("dependency-csv-file", + "The location the CSV file should be generated at.") + val dependencyCsvToFile = TaskKey[File]("dependency-csv-to-file", + "Creates a CSV file containing the dependency report at the location configured in dependency-csv-file SettingKey.") val licenseInfo = TaskKey[Unit]("dependency-license-info", "Aggregates and shows information about the licenses of dependencies") @@ -133,6 +137,8 @@ object Plugin extends sbt.Plugin { }, asciiCsv <<= moduleGraph.map(Csv.toCsv), dependencyCsv <<= print(asciiCsv), + dependencyCsvFile <<= target / "dependencies-%s.csv".format(config.toString), + dependencyCsvToFile <<= dependencyCsvToFileTask, whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) @@ -158,6 +164,12 @@ object Plugin extends sbt.Plugin { streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } + def dependencyCsvToFileTask = + (asciiCsv, dependencyCsvFile, streams) map { (csv, resultFile, streams) => + sbt.IO.write(resultFile, csv) + streams.log.info("Wrote dependency csv to '%s'" format resultFile) + resultFile + } def absoluteReportPath = (file: File) => file.getAbsolutePath def print(key: TaskKey[String]) = From d914e6b70d912983fe64ef0bb384cc24813b1c35 Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 11:12:28 -0500 Subject: [PATCH 4/8] Printing basic module info in alphabetical order by org and name --- src/main/scala/net/virtualvoid/sbt/graph/Csv.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala index 071a33e..9b283e1 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala @@ -2,6 +2,12 @@ package net.virtualvoid.sbt.graph object Csv { def toCsv(graph: IvyGraphMLDependencies.ModuleGraph):String = { - "Hello" + graph.modules.toList.sortBy { case (id, module) => + (id.organisation, id.name) + } +// .map { case (id, module) => +// +// } + .map(_._1.idString).mkString("\n") } } From 880cb2f58df73b025651bfd1f11ac0a43872716f Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 11:22:53 -0500 Subject: [PATCH 5/8] CSV is now actually a CSV, includes license, filters out evicted versions --- src/main/scala/net/virtualvoid/sbt/graph/Csv.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala index 9b283e1..8a1ebbb 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala @@ -5,9 +5,14 @@ object Csv { graph.modules.toList.sortBy { case (id, module) => (id.organisation, id.name) } -// .map { case (id, module) => -// -// } - .map(_._1.idString).mkString("\n") + .filter { case (id, module) => + module.evictedByVersion.isEmpty + } + .map { case (id, module) => + val license = '"'+module.license.getOrElse("")+'"' // Surround with quotes because some have commas + List(id.organisation, id.name, id.version, license) + .mkString(",") + } + .mkString("\n") } } From 2673468042f07da07b66444c1d94f258acb1c8cf Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 11:33:08 -0500 Subject: [PATCH 6/8] Adding option to only include 3rd-party dependencies in CSV report --- src/main/scala/net/virtualvoid/sbt/graph/Csv.scala | 5 ++++- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala index 8a1ebbb..4edff71 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Csv.scala @@ -1,10 +1,13 @@ package net.virtualvoid.sbt.graph object Csv { - def toCsv(graph: IvyGraphMLDependencies.ModuleGraph):String = { + def toCsv(graph: IvyGraphMLDependencies.ModuleGraph, excludeOrg:Option[String]):String = { graph.modules.toList.sortBy { case (id, module) => (id.organisation, id.name) } + .filterNot { case (id, module) => + Some(id.organisation) == excludeOrg + } .filter { case (id, module) => module.evictedByVersion.isEmpty } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index d2e672a..abe5d01 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -57,6 +57,8 @@ object Plugin extends sbt.Plugin { "Returns a string containing the CSV-formatted report of all dependencies including transitives.") val dependencyCsv = TaskKey[Unit]("dependency-csv", "Prints the CSV-formatted report of all dependencies to the console.") + val dependencyCsv3rdOnly = SettingKey[Boolean]("dependency-csv-3rd-only", + "Set to true to only include 3rd-party dependencies in the CSV report, based on the configured 'organization' SettingKey. (default: true)") val dependencyCsvFile = SettingKey[File]("dependency-csv-file", "The location the CSV file should be generated at.") val dependencyCsvToFile = TaskKey[File]("dependency-csv-to-file", @@ -135,8 +137,9 @@ object Plugin extends sbt.Plugin { dependencyDotNodeLabel := { (organisation: String, name: String, version: String) => """<%s
%s
%s>""".format(organisation, name, version) }, - asciiCsv <<= moduleGraph.map(Csv.toCsv), + asciiCsv <<= asciiCsvTask, dependencyCsv <<= print(asciiCsv), + dependencyCsv3rdOnly := true, dependencyCsvFile <<= target / "dependencies-%s.csv".format(config.toString), dependencyCsvToFile <<= dependencyCsvToFileTask, whatDependsOn <<= InputTask(artifactIdParser) { module => @@ -164,6 +167,11 @@ object Plugin extends sbt.Plugin { streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } + def asciiCsvTask = + (moduleGraph, organization, dependencyCsv3rdOnly).map { (graph, org, thirdOnly) => + val thirdOption = if(thirdOnly) Some(org) else None + Csv.toCsv(graph, thirdOption) + } def dependencyCsvToFileTask = (asciiCsv, dependencyCsvFile, streams) map { (csv, resultFile, streams) => sbt.IO.write(resultFile, csv) From f5487f05e88e121107ef61f881d345655ae1d5d4 Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 11:38:44 -0500 Subject: [PATCH 7/8] Updating README with usage instructions for the CSV-formatted report --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ca1bee..a225faa 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,10 @@ Tasks * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. * `dependency-license-info`: show dependencies grouped by declared license - * `ivy-report`: let's ivy generate the resolution report for you project. Use + * `ivy-report`: lets ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report + * `dependency-csv`: Shows a CSV-formatted report of dependencies used in this project. + * `dependency-csv-to-file`: Writes the same CSV-formatted report to the configured file. All tasks can be scoped to a configuration to get the report for a specific configuration. `test:dependency-graph`, for example, prints the dependencies in the `test` configuration. If you don't specify any configuration, `compile` is @@ -55,6 +57,9 @@ Configuration settings * `dependencyDotHeader`: a setting to customize the header of the dot file (e.g. to set your preferred node shapes). * `dependencyDotNodeLabel`: defines the format of a node label (default set to `[organisation]
[name]
[version]`) + * `dependencyCsv3rdOnly`: a setting which when set to true (the default) excludes same-party dependencies from the report. + This is determined by comparing this project's `organization` setting to the same for the given dependency. + * `dependencyCsvFile`: a setting which allows configuring the output path of `dependency-csv-to-file`. E.g. in `build.sbt` you can change configuration settings like this: From ad674192290c230e1e17720d18658581f293c8cd Mon Sep 17 00:00:00 2001 From: Joe Barnes Date: Mon, 13 Apr 2015 11:48:10 -0500 Subject: [PATCH 8/8] Updating README with a note on the intent/purpose of the CSV file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a225faa..142a623 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Tasks * `dependency-license-info`: show dependencies grouped by declared license * `ivy-report`: lets ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report - * `dependency-csv`: Shows a CSV-formatted report of dependencies used in this project. + * `dependency-csv`: Shows a CSV-formatted report of dependencies used in this project suitable for review by your company's legal department. * `dependency-csv-to-file`: Writes the same CSV-formatted report to the configured file. All tasks can be scoped to a configuration to get the report for a specific configuration. `test:dependency-graph`,