Skip to content

Commit

Permalink
add support for csv
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredsburrows committed Dec 29, 2020
1 parent ba6c01d commit 1f6ed0d
Show file tree
Hide file tree
Showing 16 changed files with 362 additions and 82 deletions.
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
This plugin provides a task to generate a HTML license report based on the
configuration. (eg. `licenseDebugReport` for all debug dependencies in an Android project).

Applying this to an Android or Java project will generate a the license
Applying this to an Android or Java project will generate the license
file(`open_source_licenses.html`) in the `<project>/build/reports/licenses/`.

Also, for Android projects the license HTML file will be copied to `<project>/src/main/assets/`.
Expand Down Expand Up @@ -67,7 +67,13 @@ dependencies {
}
```

**HTML:**
**CSV (minimized example):**
```csv
project,description,version,developers,url,year,licenses,license urls,dependency
Design,null,26.1.0,null,null,null,The Apache Software License,http://www.apache.org/licenses/LICENSE-2.0.txt,com.android.support:design:26.1.0
```

**HTML (minimized example):**
```html
<html>
<head>
Expand Down Expand Up @@ -112,10 +118,10 @@ dependencies {
Note, if no license information is found in the POM for a project, "No License Found" will be used.
Those will be listed first.
Other missing information is provided as default values that can be corrected from other sources.
Projects are grouped by license name - the licence text is only provided once.
Projects are grouped by license name and the licence text is only provided once.
Projects with multiple licenses are grouped as if those licenses were a single combined license.

**JSON:**
**JSON (full example):**
```json
[
{
Expand Down Expand Up @@ -167,19 +173,21 @@ Note, if no license information is found for a component, the `licenses` element

## Configuration
The plugin can be configured to generate specific reports and automatically copy the reports to the assets directory (Android projects only). The default behaviours are:
- Java projects: Generate both the HTML report and the JSON report.
- Android projects: Generate both the HTML report and the JSON report, and copy the HTML report to the assets directory.
- Java projects: Generate HTML, JSON and CSV reports.
- Android projects: Generate HTML, JSON and CSV reports, and copy the HTML report to the assets directory.

To override the defaults, add the `licenseReport` configuration closure to the build script.

```groovy
apply plugin: "com.jaredsburrows.license"
licenseReport {
generateCsvReport = false
generateHtmlReport = false
generateJsonReport = true
// These options are ignored for Java projects
copyHtmlReportToAssets = false
copyHtmlReportToAssets = true
copyJsonReportToAssets = false
}
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ dependencies {
testImplementation localGroovy()
testImplementation deps.spock, { exclude module: 'groovy-all' } // Use localGroovy()
testImplementation deps.xmlunit.matchers
testImplementation deps.commons.csv
}

apply from: 'gradle/compile.gradle'
Expand Down
11 changes: 7 additions & 4 deletions gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ ext.versions = [

ext.deps = [
'kotlin' : [
'stdlib' : [
'stdlib': [
'jdk': "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
],
'gradle' : [
'gradle': [
'plugin': "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
],
],
'kotlinx': [
'html': 'org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.2',
],
'gson': 'com.google.code.gson:gson:2.8.6',
'gson' : 'com.google.code.gson:gson:2.8.6',
'android': [
'tools': [
'build': [
Expand All @@ -26,5 +26,8 @@ ext.deps = [
'spock' : 'org.spockframework:spock-core:1.3-groovy-2.5',
'xmlunit': [
'matchers': 'org.xmlunit:xmlunit-matchers:2.8.2',
]
],
'commons': [
'csv': 'org.apache.commons:commons-csv:1.8',
],
]
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
6 changes: 6 additions & 0 deletions src/main/kotlin/com/jaredsburrows/license/LicensePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ class LicensePlugin : Plugin<Project> {
project.tasks.create(taskName, LicenseReportTask::class.java).apply {
description = "Outputs licenses report."
group = "Reporting"
csvFile = File(path + LicenseReportTask.CSV_EXT)
htmlFile = File(path + LicenseReportTask.HTML_EXT)
jsonFile = File(path + LicenseReportTask.JSON_EXT)
generateCsvReport = extension.generateCsvReport
generateHtmlReport = extension.generateHtmlReport
generateJsonReport = extension.generateJsonReport
copyCsvReportToAssets = false
copyHtmlReportToAssets = false
copyJsonReportToAssets = false
}
Expand All @@ -78,10 +81,13 @@ class LicensePlugin : Plugin<Project> {
project.tasks.create(taskName, LicenseReportTask::class.java).apply {
description = "Outputs licenses report for $name variant."
group = "Reporting"
csvFile = File(path + LicenseReportTask.CSV_EXT)
htmlFile = File(path + LicenseReportTask.HTML_EXT)
jsonFile = File(path + LicenseReportTask.JSON_EXT)
generateCsvReport = extension.generateCsvReport
generateHtmlReport = extension.generateHtmlReport
generateJsonReport = extension.generateJsonReport
copyCsvReportToAssets = extension.copyCsvReportToAssets
copyHtmlReportToAssets = extension.copyHtmlReportToAssets
copyJsonReportToAssets = extension.copyJsonReportToAssets
assetDirs = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ package com.jaredsburrows.license

/** Configuration options for the gradle license plugin. */
open class LicenseReportExtension { // extensions can't be final
/** Whether or not the Csv report should be generated. */
var generateCsvReport = true

/**
* Whether or not the Csv report should be copied to the Android assets directory. Ignored if the
* project is not an Android project. Has no effect if the Csv report is disabled.
*/
var copyCsvReportToAssets = true

/** Whether or not the HTML report should be generated. */
var generateHtmlReport = true

Expand All @@ -15,7 +24,7 @@ open class LicenseReportExtension { // extensions can't be final
var generateJsonReport = true

/**
* Whether or not the HTML report should be copied to the Android assets directory. Ignored if the
* Whether or not the JSON report should be copied to the Android assets directory. Ignored if the
* project is not an Android project. Has no effect if the JSON report is disabled.
*/
var copyJsonReportToAssets = false
Expand Down
127 changes: 90 additions & 37 deletions src/main/kotlin/com/jaredsburrows/license/LicenseReportTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.jaredsburrows.license.internal.ConsoleRenderer
import com.jaredsburrows.license.internal.pom.Developer
import com.jaredsburrows.license.internal.pom.License
import com.jaredsburrows.license.internal.pom.Project
import com.jaredsburrows.license.internal.report.CsvReport
import com.jaredsburrows.license.internal.report.HtmlReport
import com.jaredsburrows.license.internal.report.JsonReport
import groovy.util.Node
Expand All @@ -25,15 +26,15 @@ import java.net.URI
import java.net.URL
import java.util.UUID

/**
* A [Task] that creates HTML and JSON reports of the current projects dependencies.
*/
/** A [Task] that creates HTML and JSON reports of the current projects dependencies. */
open class LicenseReportTask : DefaultTask() { // tasks can't be final

@Internal var projects = arrayListOf<Project>()
@Input var assetDirs = listOf<File>()
@Input var generateCsvReport = false
@Input var generateHtmlReport = false
@Input var generateJsonReport = false
@Input var copyCsvReportToAssets = false
@Input var copyHtmlReportToAssets = false
@Input var copyJsonReportToAssets = false

Expand All @@ -43,6 +44,7 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
@Optional @Input
var variantName: String? = null
@Internal var productFlavors = listOf<ProductFlavor>()
@OutputFile lateinit var csvFile: File
@OutputFile lateinit var htmlFile: File
@OutputFile lateinit var jsonFile: File
private var pomConfiguration = "poms"
Expand All @@ -58,10 +60,19 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
initDependencies()
generatePOMInfo()

if (generateCsvReport) {
createCsvReport()

// If android project and copy enabled, copy to asset directory
if (!variantName.isNullOrEmpty() && copyCsvReportToAssets) {
copyCsvReport()
}
}

if (generateHtmlReport) {
createHtmlReport()

// If Android project and copy enabled, copy to asset directory
// If android project and copy enabled, copy to asset directory
if (!variantName.isNullOrEmpty() && copyHtmlReportToAssets) {
copyHtmlReport()
}
Expand All @@ -70,7 +81,7 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
if (generateJsonReport) {
createJsonReport()

// If Android project and copy enabled, copy to asset directory
// If android project and copy enabled, copy to asset directory
if (!variantName.isNullOrEmpty() && copyJsonReportToAssets) {
copyJsonReport()
}
Expand Down Expand Up @@ -243,9 +254,9 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
}

/** Generated HTML report. */
private fun createHtmlReport() {
private fun createCsvReport() {
// Remove existing file
htmlFile.apply {
csvFile.apply {
// Remove existing file
delete()

Expand All @@ -254,16 +265,39 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
createNewFile()

// Write report for file
bufferedWriter().use { it.write(HtmlReport(projects).toString()) }
bufferedWriter().use { it.write(CsvReport(projects).toString()) }
}

// Log output directory for user
logger.log(LogLevel.LIFECYCLE, "Wrote HTML report to ${ConsoleRenderer().asClickableFileUrl(htmlFile)}.")
logger.log(LogLevel.LIFECYCLE, "Wrote CSV report to ${ConsoleRenderer().asClickableFileUrl(csvFile)}.")
}

/** Generated JSON report. */
private fun createJsonReport() {
jsonFile.apply {
private fun copyCsvReport() {
// Iterate through all asset directories
assetDirs.forEach { directory ->
val licenseFile = File(directory.path, OPEN_SOURCE_LICENSES + CSV_EXT)

licenseFile.apply {
// Remove existing file
delete()

// Create new file
parentFile.mkdirs()
createNewFile()

// Copy HTML file to the assets directory
bufferedWriter().use { it.write(csvFile.readText()) }
}

// Log output directory for user
logger.log(LogLevel.LIFECYCLE, "Copied CSV report to ${ConsoleRenderer().asClickableFileUrl(licenseFile)}.")
}
}

/** Generated HTML report. */
private fun createHtmlReport() {
// Remove existing file
htmlFile.apply {
// Remove existing file
delete()

Expand All @@ -272,11 +306,11 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
createNewFile()

// Write report for file
bufferedWriter().use { it.write(JsonReport(projects).toString()) }
bufferedWriter().use { it.write(HtmlReport(projects).toString()) }
}

// Log output directory for user
logger.log(LogLevel.LIFECYCLE, "Wrote JSON report to ${ConsoleRenderer().asClickableFileUrl(jsonFile)}.")
logger.log(LogLevel.LIFECYCLE, "Wrote HTML report to ${ConsoleRenderer().asClickableFileUrl(htmlFile)}.")
}

private fun copyHtmlReport() {
Expand All @@ -301,6 +335,24 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
}
}

/** Generated JSON report. */
private fun createJsonReport() {
jsonFile.apply {
// Remove existing file
delete()

// Create directories
parentFile.mkdirs()
createNewFile()

// Write report for file
bufferedWriter().use { it.write(JsonReport(projects).toString()) }
}

// Log output directory for user
logger.log(LogLevel.LIFECYCLE, "Wrote JSON report to ${ConsoleRenderer().asClickableFileUrl(jsonFile)}.")
}

private fun copyJsonReport() {
// Iterate through all asset directories
assetDirs.forEach { directory ->
Expand Down Expand Up @@ -402,36 +454,37 @@ open class LicenseReportTask : DefaultTask() { // tasks can't be final
}.trim()
}

private fun File?.isNullOrEmpty(): Boolean = this == null || this.length() == 0L

private fun Node.getAt(name: String): NodeList {
val answer = NodeList()
val var3 = this.children().iterator()

while (var3.hasNext()) {
val child = var3.next()
if (child is Node) {
val childNodeName = child.name()
if (childNodeName is QName) {
if (childNodeName.matches(name)) {
answer.add(child)
}
} else if (name == childNodeName) {
answer.add(child)
}
}
}

return answer
}

companion object {
private val xmlParser = XmlParser(false, false)
private const val ANDROID_SUPPORT_GROUP_ID = "com.android.support"
private const val APACHE_LICENSE_NAME = "The Apache Software License"
private const val APACHE_LICENSE_URL = "http://www.apache.org/licenses/LICENSE-2.0.txt"
private const val OPEN_SOURCE_LICENSES = "open_source_licenses"
const val CSV_EXT = ".csv"
const val HTML_EXT = ".html"
const val JSON_EXT = ".json"
}
}

private fun File?.isNullOrEmpty(): Boolean = this == null || this.length() == 0L

private fun Node.getAt(name: String): NodeList {
val answer = NodeList()
val var3 = this.children().iterator()

while (var3.hasNext()) {
val child = var3.next()
if (child is Node) {
val childNodeName = child.name()
if (childNodeName is QName) {
if (childNodeName.matches(name)) {
answer.add(child)
}
} else if (name == childNodeName) {
answer.add(child)
}
}
}

return answer
}
Loading

0 comments on commit 1f6ed0d

Please sign in to comment.