From 1b94b5de8e4913e205a8c4231d5424583a7d9c0c Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 17 Oct 2021 17:15:26 +0200 Subject: [PATCH 01/10] sort libraries --- CHANGELOG.md | 1 + build.gradle.kts | 1 + buildSrc/src/main/kotlin/Deps.kt | 1 + pom.properties | 2 +- .../LicensePluginJavaMultiProjectShould.kt | 2 +- .../LicensePluginMultiplatformShould.kt | 32 +++---- .../kotlin/com/cmgapps/license/Extensions.kt | 4 +- .../com/cmgapps/license/LicensesPlugin.kt | 5 +- .../com/cmgapps/license/LicensesTask.kt | 30 +++---- .../com/cmgapps/license/model/Models.kt | 34 +++++++- .../cmgapps/license/reporter/HtmlReport.kt | 8 +- .../cmgapps/license/reporter/JsonReport.kt | 4 +- .../license/reporter/MarkdownReport.kt | 36 ++++---- .../cmgapps/license/reporter/TextReport.kt | 85 ++++++++++--------- .../com/cmgapps/license/reporter/XmlDsl.kt | 10 +-- .../com/cmgapps/license/reporter/XmlReport.kt | 2 +- .../com/cmgapps/license/LicensesTaskShould.kt | 35 ++++++++ .../cmgapps/license/helper/LibrariesHelper.kt | 3 +- .../license/reporter/CsvReportShould.kt | 7 +- .../license/reporter/HtmlReportShould.kt | 3 +- .../group/another/2.0.0/another-2.0.0.aar | 0 .../group/another/2.0.0/another-2.0.0.pom | 39 +++++++++ .../maven/group/other/1.0.0/other-1.0.0.aar | 0 .../maven/group/other/1.0.0/other-1.0.0.pom | 39 +++++++++ 24 files changed, 266 insertions(+), 117 deletions(-) create mode 100644 src/test/resources/maven/group/another/2.0.0/another-2.0.0.aar create mode 100644 src/test/resources/maven/group/another/2.0.0/another-2.0.0.pom create mode 100644 src/test/resources/maven/group/other/1.0.0/other-1.0.0.aar create mode 100644 src/test/resources/maven/group/other/1.0.0/other-1.0.0.pom diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ad193e..6525b76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added ### Changed +- sort dependencies by name and version ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 0860053..bf995b8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -325,6 +325,7 @@ dependencies { implementation(kotlin("stdlib-jdk8", Deps.kotlinVersion)) implementation(Deps.mavenModel) + implementation(Deps.mavenArtifact) implementation(Deps.kotlinSerialization) implementation(Deps.apacheCommonsCsv) diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index 793b5e0..3d162ad 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -29,6 +29,7 @@ object Deps { const val kotlinMultiplatformPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" const val apacheCommonsCsv = "org.apache.commons:commons-csv:1.9.0" const val mavenModel = "org.apache.maven:maven-model:3.8.3" + const val mavenArtifact = "org.apache.maven:maven-artifact:3.8.3" const val jUnit = "org.junit.jupiter:junit-jupiter:5.8.1" const val hamcrest = "org.hamcrest:hamcrest:2.2" const val ktlint = "com.pinterest:ktlint:0.42.1" diff --git a/pom.properties b/pom.properties index 2d0da4e..e544f38 100644 --- a/pom.properties +++ b/pom.properties @@ -14,7 +14,7 @@ # limitations under the License. # group=com.cmgapps -versionName=4.0.0 +versionName=4.1.0-SNAPSHOT pomName=Gradle Licenses Plugin pomArtifactId=gradle-licenses-plugin pomDescription=Gradle plugin that provides a task to generate a license report of your project. diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt index d7c07fb..8a2979f 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt @@ -163,10 +163,10 @@ class LicensePluginJavaMultiProjectShould { "" + "" + "

Notice for packages:

" + + "

Some license

http://website.tld/
" + "
" +
                     getFileContent("apache-2.0.txt") +
                     "
" + - "

Some license

http://website.tld/
" + "" + "" ) diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt index b9513ba..17146ae 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt @@ -164,13 +164,13 @@ class LicensePluginMultiplatformShould { File("$reportFolder/$taskName/licenses.txt").readText().trim(), `is`( "Licenses\n" + - "├─ com.google.firebase:firebase-core:10.0.1\n" + + "├─ Fake dependency name:1.0.0\n" + + "│ ├─ License: Some license\n" + + "│ └─ URL: http://website.tld/\n" + "├─ Retrofit:2.3.0\n" + "│ ├─ License: Apache 2.0\n" + "│ └─ URL: http://www.apache.org/licenses/LICENSE-2.0.txt\n" + - "└─ Fake dependency name:1.0.0\n" + - " ├─ License: Some license\n" + - " └─ URL: http://website.tld/" + "└─ com.google.firebase:firebase-core:10.0.1" ) ) } @@ -230,10 +230,10 @@ class LicensePluginMultiplatformShould { File("$reportFolder/$taskName/licenses.txt").readText().trim(), `is`( "Licenses\n" + - "├─ com.google.firebase:firebase-core:10.0.1\n" + - "└─ Retrofit:2.3.0\n" + - " ├─ License: Apache 2.0\n" + - " └─ URL: http://www.apache.org/licenses/LICENSE-2.0.txt" + "├─ Retrofit:2.3.0\n" + + "│ ├─ License: Apache 2.0\n" + + "│ └─ URL: http://www.apache.org/licenses/LICENSE-2.0.txt\n" + + "└─ com.google.firebase:firebase-core:10.0.1" ) ) } @@ -282,10 +282,10 @@ class LicensePluginMultiplatformShould { File("$reportFolder/$taskName/licenses.txt").readText().trim(), `is`( "Licenses\n" + - "├─ com.google.firebase:firebase-core:10.0.1\n" + - "└─ Fake dependency name:1.0.0\n" + - " ├─ License: Some license\n" + - " └─ URL: http://website.tld/" + "├─ Fake dependency name:1.0.0\n" + + "│ ├─ License: Some license\n" + + "│ └─ URL: http://website.tld/\n" + + "└─ com.google.firebase:firebase-core:10.0.1" ) ) } @@ -334,10 +334,10 @@ class LicensePluginMultiplatformShould { File("$reportFolder/$taskName/licenses.txt").readText().trim(), `is`( "Licenses\n" + - "├─ com.google.firebase:firebase-core:10.0.1\n" + - "└─ Fake dependency name:1.0.0\n" + - " ├─ License: Some license\n" + - " └─ URL: http://website.tld/" + "├─ Fake dependency name:1.0.0\n" + + "│ ├─ License: Some license\n" + + "│ └─ URL: http://website.tld/\n" + + "└─ com.google.firebase:firebase-core:10.0.1" ) ) } diff --git a/src/main/kotlin/com/cmgapps/license/Extensions.kt b/src/main/kotlin/com/cmgapps/license/Extensions.kt index ee7b09a..aa3ba02 100644 --- a/src/main/kotlin/com/cmgapps/license/Extensions.kt +++ b/src/main/kotlin/com/cmgapps/license/Extensions.kt @@ -16,8 +16,6 @@ package com.cmgapps.license -import java.util.Locale - fun String.capitalize() = replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() + if (it.isLowerCase()) it.titlecase() else it.toString() } diff --git a/src/main/kotlin/com/cmgapps/license/LicensesPlugin.kt b/src/main/kotlin/com/cmgapps/license/LicensesPlugin.kt index 10576b3..57e5352 100644 --- a/src/main/kotlin/com/cmgapps/license/LicensesPlugin.kt +++ b/src/main/kotlin/com/cmgapps/license/LicensesPlugin.kt @@ -28,7 +28,6 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType -import java.util.Locale @Suppress("unused") class LicensesPlugin : Plugin { @@ -76,9 +75,7 @@ class LicensesPlugin : Plugin { @JvmStatic private fun configureAndroidProject(project: Project, extension: LicensesExtension) { getAndroidVariants(project)?.all { androidVariant -> - val taskName = "license" + androidVariant.name.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() - } + "Report" + val taskName = "license" + androidVariant.name.capitalize() + "Report" val configuration = Action { task -> task.addBasicConfiguration(extension) diff --git a/src/main/kotlin/com/cmgapps/license/LicensesTask.kt b/src/main/kotlin/com/cmgapps/license/LicensesTask.kt index 119faeb..3996dc0 100644 --- a/src/main/kotlin/com/cmgapps/license/LicensesTask.kt +++ b/src/main/kotlin/com/cmgapps/license/LicensesTask.kt @@ -33,6 +33,7 @@ import com.cmgapps.license.reporter.ReportType import com.cmgapps.license.reporter.TextReport import com.cmgapps.license.reporter.XmlReport import groovy.lang.Closure +import org.apache.maven.artifact.versioning.ComparableVersion import org.apache.maven.model.Model import org.apache.maven.model.Parent import org.apache.maven.model.io.xpp3.MavenXpp3Reader @@ -148,20 +149,21 @@ abstract class LicensesTask : DefaultTask() { val model = getPomModel(it.file) val licenses = findLicenses(model) - val version = findVersion(model) - val description = findDescription(model) if (licenses.isEmpty()) { logger.warn("${model.name} dependency does not have a license.") } + Library( model.name ?: "${model.groupId}:${model.artifactId}", - version, - description, + findVersion(model)?.let { ComparableVersion(it) } ?: ComparableVersion(""), + findDescription(model), licenses ) } + .sortedWith(Library.Comparator()) + .toList() } private fun getPomModel(file: File): Model = MavenXpp3Reader().run { @@ -213,17 +215,15 @@ abstract class LicensesTask : DefaultTask() { return getPomModel(pomFile) } - private fun findVersion(model: Model): String? { - return when { - model.version != null -> model.version - model.parent != null -> - if (model.parent.version != null) { - model.parent.version - } else { - findVersion(getParentPomFile(model.parent)) - } - else -> null - } + private fun findVersion(model: Model): String? = when { + model.version != null -> model.version + model.parent != null -> + if (model.parent.version != null) { + model.parent.version + } else { + findVersion(getParentPomFile(model.parent)) + } + else -> null } private fun findDescription(model: Model): String? { diff --git a/src/main/kotlin/com/cmgapps/license/model/Models.kt b/src/main/kotlin/com/cmgapps/license/model/Models.kt index 237981f..b7f39fa 100644 --- a/src/main/kotlin/com/cmgapps/license/model/Models.kt +++ b/src/main/kotlin/com/cmgapps/license/model/Models.kt @@ -16,10 +16,42 @@ package com.cmgapps.license.model +import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import org.apache.maven.artifact.versioning.ComparableVersion @Serializable data class License(val name: String, val url: String) @Serializable -data class Library(val name: String, val version: String?, val description: String?, val licenses: List) +data class Library( + val name: String, + @Serializable(ComparableVersionSerializer::class) + val version: ComparableVersion, + val description: String?, + val licenses: List +) { + companion object { + @Suppress("FunctionName") + @JvmStatic + fun Comparator(): Comparator = + Comparator.comparing(Library::name).thenComparing(Library::version, reverseOrder()) + } +} + +object ComparableVersionSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ComparableVersion", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): ComparableVersion { + return ComparableVersion(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: ComparableVersion) { + encoder.encodeString(value.toString()) + } +} diff --git a/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt index 981af7a..b2223f6 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt @@ -46,11 +46,9 @@ internal class HtmlReport( if (library.licenses.isNotEmpty()) { val key = library.licenses[0] - if (!licenseListMap.contains(key)) { - licenseListMap[key] = mutableListOf() - } - - licenseListMap[key]?.add(library) + licenseListMap[key] ?: mutableListOf().also { + licenseListMap[key] = it + }.add(library) } } diff --git a/src/main/kotlin/com/cmgapps/license/reporter/JsonReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/JsonReport.kt index ec0e7b4..f37df7f 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/JsonReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/JsonReport.kt @@ -26,7 +26,5 @@ internal class JsonReport(libraries: List) : Report(libraries) { prettyPrint = true } - override fun generate(): String { - return json.encodeToString(libraries) - } + override fun generate() = json.encodeToString(libraries) } diff --git a/src/main/kotlin/com/cmgapps/license/reporter/MarkdownReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/MarkdownReport.kt index b8119c0..8af9c27 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/MarkdownReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/MarkdownReport.kt @@ -19,25 +19,23 @@ package com.cmgapps.license.reporter import com.cmgapps.license.model.Library internal class MarkdownReport(libraries: List) : Report(libraries) { - override fun generate(): String { - return StringBuilder().apply { - append("# Open source licenses\n") - append("### Notice for packages:\n") - libraries.forEach { library -> - append(library.name) - append(' ') - append('_') - append(library.version) - append("_:") - library.licenses.forEach { license -> - append("\n* ") - append(license.name) - append(" (") - append(license.url) - append(")") - } - append("\n\n") + override fun generate() = buildString { + append("# Open source licenses\n") + append("### Notice for packages:\n") + libraries.forEach { library -> + append(library.name) + append(' ') + append('_') + append(library.version) + append("_:") + library.licenses.forEach { license -> + append("\n* ") + append(license.name) + append(" (") + append(license.url) + append(")") } - }.toString() + append("\n\n") + } } } diff --git a/src/main/kotlin/com/cmgapps/license/reporter/TextReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/TextReport.kt index 9ebe8b5..8842b78 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/TextReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/TextReport.kt @@ -17,52 +17,59 @@ package com.cmgapps.license.reporter import com.cmgapps.license.model.Library +import com.cmgapps.license.model.License internal class TextReport(libraries: List) : Report(libraries) { - override fun generate(): String { - return StringBuilder().apply { - append("Licenses\n") - val libLength = libraries.size - libraries.forEachIndexed { libIndex, library -> - if (libIndex < libLength - 1) { - append("$ITEM_PREFIX ") - } else { - append("$LAST_ITEM_PREFIX ") - } - append(library.name) - append(':') - append(library.version) - val licensesLength = library.licenses.size - library.licenses.forEachIndexed { index, license -> + override fun generate() = buildString { + append("Licenses\n") + val libLength = libraries.size + libraries.forEachIndexed { libIndex, library -> + appendPrefix(libIndex, libLength) + append(library.name) + append(':') + append(library.version) + appendLicenses(libIndex, libLength, library.licenses) + if (libIndex < libLength - 1) { + append('\n') + } + } + } - if (libIndex < libLength - 1) { - append(LINE_PREFIX) - } else { - append(LAST_LINE_PREFIX) - } + private fun StringBuilder.appendPrefix(index: Int, length: Int) { + if (index < length - 1) { + append("$ITEM_PREFIX ") + } else { + append("$LAST_ITEM_PREFIX ") + } + } - append("$ITEM_PREFIX License: ") - append(license.name) + private fun StringBuilder.appendLicenses(libIndex: Int, libLength: Int, licenses: List) { + val licensesLength = licenses.size - if (libIndex < libLength - 1) { - append(LINE_PREFIX) - } else { - append(LAST_LINE_PREFIX) - } + licenses.forEachIndexed { index, license -> + if (libIndex < libLength - 1) { + append(LINE_PREFIX) + } else { + append(LAST_LINE_PREFIX) + } + + append("$ITEM_PREFIX License: ") + append(license.name) + + if (libIndex < libLength - 1) { + append(LINE_PREFIX) + } else { + append(LAST_LINE_PREFIX) + } - if (index < licensesLength - 1) { - append(ITEM_PREFIX) - } else { - append(LAST_ITEM_PREFIX) - } - append(" URL: ") - append(license.url) - } - if (libIndex < libLength - 1) { - append('\n') - } + if (index < licensesLength - 1) { + append(ITEM_PREFIX) + } else { + append(LAST_ITEM_PREFIX) } - }.toString() + append(" URL: ") + append(license.url) + } } private companion object { diff --git a/src/main/kotlin/com/cmgapps/license/reporter/XmlDsl.kt b/src/main/kotlin/com/cmgapps/license/reporter/XmlDsl.kt index 67bd0a7..8c830e7 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/XmlDsl.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/XmlDsl.kt @@ -79,17 +79,15 @@ internal abstract class Tag(protected val name: String) : Element { } } - private fun renderAttributes(): String { - val builder = StringBuilder() + private fun renderAttributes(): String = buildString { for ((attr, value) in attributes) { - builder.append(" $attr=\"$value\"") + append(" $attr=\"$value\"") } - return builder.toString() } - fun toString(format: Boolean = true): String = StringBuilder().apply { + fun toString(format: Boolean = true): String = buildString { render(this, "", format) - }.toString() + } override fun toString(): String = toString(true) } diff --git a/src/main/kotlin/com/cmgapps/license/reporter/XmlReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/XmlReport.kt index 6d23738..14cad25 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/XmlReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/XmlReport.kt @@ -26,7 +26,7 @@ internal class XmlReport(libraries: List) : R +library.name } version { - +(library.version ?: "") + +(library.version.toString()) } description { diff --git a/src/test/kotlin/com/cmgapps/license/LicensesTaskShould.kt b/src/test/kotlin/com/cmgapps/license/LicensesTaskShould.kt index 30e4855..5234327 100644 --- a/src/test/kotlin/com/cmgapps/license/LicensesTaskShould.kt +++ b/src/test/kotlin/com/cmgapps/license/LicensesTaskShould.kt @@ -331,4 +331,39 @@ class LicensesTaskShould { assertThat(File(reportFolder).listFiles()?.size, `is`(7)) } + + @Test + fun `sort libraries`() { + val outputFile = File(reportFolder, "licenses.txt") + + project.dependencies.add("compile", "group:another:2.0.0") + project.dependencies.add("compile", "group:other:1.0.0") + val task = project.tasks.create("licensesReport", LicensesTask::class.java) { task -> + task.reports { + it.html.enabled = false + it.text { + it.enabled = true + it.destination = outputFile + } + } + } + + task.licensesReport() + + assertThat( + outputFile.readText(), + `is`( + "Licenses\n" + + "├─ Fake dependency another:2.0.0\n" + + "│ ├─ License: Some license\n" + + "│ └─ URL: http://website.tld/\n" + + "├─ Fake dependency name:1.0.0\n" + + "│ ├─ License: Some license\n" + + "│ └─ URL: http://website.tld/\n" + + "└─ Fake dependency other:1.0.0\n" + + " ├─ License: Some license\n" + + " └─ URL: http://website.tld/" + ) + ) + } } diff --git a/src/test/kotlin/com/cmgapps/license/helper/LibrariesHelper.kt b/src/test/kotlin/com/cmgapps/license/helper/LibrariesHelper.kt index 6860b2a..61f4ab3 100644 --- a/src/test/kotlin/com/cmgapps/license/helper/LibrariesHelper.kt +++ b/src/test/kotlin/com/cmgapps/license/helper/LibrariesHelper.kt @@ -18,13 +18,14 @@ package com.cmgapps.license.helper import com.cmgapps.license.model.Library import com.cmgapps.license.model.License +import org.apache.maven.artifact.versioning.ComparableVersion object LibrariesHelper { val libraries = listOf( Library( "Test lib 1", - "1.0", + ComparableVersion("1.0"), "proper description", listOf( License( diff --git a/src/test/kotlin/com/cmgapps/license/reporter/CsvReportShould.kt b/src/test/kotlin/com/cmgapps/license/reporter/CsvReportShould.kt index 42de652..2297da4 100644 --- a/src/test/kotlin/com/cmgapps/license/reporter/CsvReportShould.kt +++ b/src/test/kotlin/com/cmgapps/license/reporter/CsvReportShould.kt @@ -19,6 +19,7 @@ package com.cmgapps.license.reporter import com.cmgapps.license.helper.LibrariesHelper import com.cmgapps.license.model.Library import com.cmgapps.license.model.License +import org.apache.maven.artifact.versioning.ComparableVersion import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` import org.junit.jupiter.api.Test @@ -41,7 +42,11 @@ class CsvReportShould { fun `escape strings in report`() { val license = License("License name with a \" in it", "just a plain url") val library = - Library("Name with a , in it", "version with a \n in it", "description with \r in it", listOf(license)) + Library( + "Name with a , in it", + ComparableVersion("version with a \n in it"), + "description with \r in it", listOf(license) + ) val result = CsvReport(listOf(library)).generate() assertThat( diff --git a/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt b/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt index 842a52e..53f6981 100644 --- a/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt +++ b/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt @@ -19,6 +19,7 @@ package com.cmgapps.license.reporter import com.cmgapps.license.helper.LibrariesHelper import com.cmgapps.license.model.License import com.cmgapps.license.util.getFileContent +import org.apache.maven.artifact.versioning.ComparableVersion import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.hamcrest.MatcherAssert.assertThat @@ -72,7 +73,7 @@ class HtmlReportShould { listOf( LibraryModel( name = "Lib with invalid license", - version = "1.0.0", + version = ComparableVersion("1.0.0"), licenses = listOf( License(name = "foo", url = "http://www.license.foo") ), diff --git a/src/test/resources/maven/group/another/2.0.0/another-2.0.0.aar b/src/test/resources/maven/group/another/2.0.0/another-2.0.0.aar new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/maven/group/another/2.0.0/another-2.0.0.pom b/src/test/resources/maven/group/another/2.0.0/another-2.0.0.pom new file mode 100644 index 0000000..f92b873 --- /dev/null +++ b/src/test/resources/maven/group/another/2.0.0/another-2.0.0.pom @@ -0,0 +1,39 @@ + + + + + + 4.0.0 + group + another + 2.0.0 + aar + + + Fake dependency another + Fake dependency another description + https://github.com/user/repo + 2017 + + + Some license + http://website.tld/ + repo + + + + + id + name + + + + + + scm:git@github.com:user/repo.git + scm:git@github.com:user/repo.git + https://github.com/user/repo.git + + diff --git a/src/test/resources/maven/group/other/1.0.0/other-1.0.0.aar b/src/test/resources/maven/group/other/1.0.0/other-1.0.0.aar new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/maven/group/other/1.0.0/other-1.0.0.pom b/src/test/resources/maven/group/other/1.0.0/other-1.0.0.pom new file mode 100644 index 0000000..e16bb27 --- /dev/null +++ b/src/test/resources/maven/group/other/1.0.0/other-1.0.0.pom @@ -0,0 +1,39 @@ + + + + + + 4.0.0 + group + other + 1.0.0 + aar + + + Fake dependency other + Fake dependency other description + https://github.com/user/repo + 2017 + + + Some license + http://website.tld/ + repo + + + + + id + name + + + + + + scm:git@github.com:user/repo.git + scm:git@github.com:user/repo.git + https://github.com/user/repo.git + + From 45ff7d7f7cdc52ebe870e63b8bc341f56c63a5d0 Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 17 Oct 2021 19:44:21 +0200 Subject: [PATCH 02/10] add all library's licenses to html report --- .../cmgapps/license/reporter/HtmlReport.kt | 9 +- .../cmgapps/license/model/LibraryShould.kt | 156 ++++++++++++++++++ .../license/reporter/HtmlReportShould.kt | 6 + 3 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt diff --git a/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt b/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt index b2223f6..c4e257b 100644 --- a/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt +++ b/src/main/kotlin/com/cmgapps/license/reporter/HtmlReport.kt @@ -42,13 +42,8 @@ internal class HtmlReport( val licenseListMap = mutableMapOf>() libraries.forEach { library -> - - if (library.licenses.isNotEmpty()) { - val key = library.licenses[0] - - licenseListMap[key] ?: mutableListOf().also { - licenseListMap[key] = it - }.add(library) + library.licenses.forEach { license -> + licenseListMap[license] ?: mutableListOf().also { licenseListMap[license] = it }.add(library) } } diff --git a/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt b/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt new file mode 100644 index 0000000..144e953 --- /dev/null +++ b/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021. Christian Grach + * + * 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.cmgapps.license.model + +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import org.apache.maven.artifact.versioning.ComparableVersion +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.`is` +import org.hamcrest.Matchers.contains +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class LibraryShould { + + private lateinit var json: Json + + @BeforeEach + fun beforeEach() { + json = Json { prettyPrint = false } + } + + @Test + fun serialize() { + val jsonString = json.encodeToString( + Library( + name = "Lib name", + version = ComparableVersion("1.0.0-alpha-4"), + description = "description", + licenses = listOf(License("License name", "http://domain.com")) + ) + ) + assertThat( + jsonString, + `is`( + "{" + + "\"name\":\"Lib name\"," + + "\"version\":\"1.0.0-alpha-4\"," + + "\"description\":\"description\"," + + "\"licenses\":[" + + "{" + + "\"name\":\"License name\"," + + "\"url\":\"http://domain.com\"" + + "}" + + "]" + + "}" + ) + ) + } + + @Test + fun deserialize() { + val lib: Library = + json.decodeFromString( + "{" + + "\"name\":\"Lib name\"," + + "\"version\":\"1.0.0-alpha-4\"," + + "\"description\":\"description\"," + + "\"licenses\":[" + + "{" + + "\"name\":\"License name\"," + + "\"url\":\"http://domain.com\"" + + "}" + + "]" + + "}" + ) + assertThat( + lib, + `is`( + Library( + name = "Lib name", + version = ComparableVersion("1.0.0-alpha-4"), + description = "description", + licenses = listOf(License("License name", "http://domain.com")) + ) + ) + ) + } + + @Test + fun `round trip from class`() { + val lib = Library( + name = "Lib name", + version = ComparableVersion("1.0.0-alpha-4"), + description = "description", + licenses = listOf(License("License name", "http://domain.com")) + ) + assertThat(json.decodeFromString(json.encodeToString(lib)), `is`(lib)) + } + + @Test + fun `round trip from string`() { + val lib = "{" + + "\"name\":\"Lib name\"," + + "\"version\":\"1.0.0-alpha-4\"," + + "\"description\":\"description\"," + + "\"licenses\":[" + + "{" + + "\"name\":\"License name\"," + + "\"url\":\"http://domain.com\"" + + "}" + + "]" + + "}" + assertThat(json.encodeToString(json.decodeFromString(lib)), `is`(lib)) + } + + @Test + fun `sort by name and version`() { + val sortedList = listOf( + Library("B", ComparableVersion("1.0"), description = null, licenses = emptyList()), + Library("A", ComparableVersion("1.0"), description = "desc", licenses = emptyList()), + Library("A", ComparableVersion("2.0"), description = null, licenses = emptyList()), + Library("A", ComparableVersion("0.3-alpha4"), description = null, licenses = emptyList()), + Library( + "C", ComparableVersion("13"), description = "desc", licenses = listOf( + License( + "license", + "http://domain.tld" + ) + ) + ), + ).sortedWith(Library.Comparator()) + assertThat( + sortedList, + contains( + Library("A", ComparableVersion("2.0"), description = null, licenses = emptyList()), + Library("A", ComparableVersion("1.0"), description = "desc", licenses = emptyList()), + Library("A", ComparableVersion("0.3-alpha4"), description = null, licenses = emptyList()), + Library("B", ComparableVersion("1.0"), description = null, licenses = emptyList()), + Library( + "C", ComparableVersion("13"), description = "desc", licenses = listOf( + License( + "license", + "http://domain.tld" + ) + ) + ), + ) + ) + } +} diff --git a/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt b/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt index 53f6981..c56a2b9 100644 --- a/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt +++ b/src/test/kotlin/com/cmgapps/license/reporter/HtmlReportShould.kt @@ -59,6 +59,12 @@ class HtmlReportShould { "
" +
                     getFileContent("apache-2.0.txt") +
                     "
" + + "
    " + + "
  • Test lib 1
  • " + + "
" + + "
" +
+                    getFileContent("mit.txt") +
+                    "
" + "" + "" ) From 3ad816e31df06c085e79f3c5b0ac0762bb506364 Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 12:24:28 +0100 Subject: [PATCH 03/10] update dependencies --- build.gradle.kts | 55 ++--- buildSrc/src/main/kotlin/Deps.kt | 25 ++- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 ++++++++++++++--------- 4 files changed, 180 insertions(+), 159 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bf995b8..76987f3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,6 +16,7 @@ import com.cmgapps.gradle.logResults import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +import kotlinx.kover.api.VerificationValueType.COVERED_LINES_PERCENTAGE import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.util.Date import java.util.Properties @@ -25,13 +26,13 @@ plugins { `java-gradle-plugin` `maven-publish` signing - jacoco id("com.github.ben-manes.versions") version Deps.Plugins.versionsVersion kotlin("jvm") version Deps.kotlinVersion id("com.gradle.plugin-publish") version Deps.Plugins.pluginPublishVersion id("org.jetbrains.dokka") version Deps.Plugins.dokkaVersion kotlin("plugin.serialization") version Deps.kotlinVersion id("org.jetbrains.changelog") version Deps.Plugins.changelogPluginVersion + id("org.jetbrains.kotlinx.kover") version "0.4.4" } repositories { @@ -45,7 +46,7 @@ val functionalTestSourceSet: SourceSet = sourceSets.create("functionalTest") { srcDir("src/$sourceSetName/kotlin") } - compileClasspath += sourceSets.main.get().output + configurations.testRuntimeClasspath.get() + compileClasspath += sourceSets.main.get().output //+ configurations.testRuntimeClasspath.get() runtimeClasspath += output + compileClasspath } @@ -55,8 +56,6 @@ configurations { named("functionalTestImplementation") { extendsFrom(testImplementation.get()) } - - register("jacocoRuntime") } idea { @@ -188,25 +187,11 @@ changelog { version.set(versionName) } -jacoco { - toolVersion = Deps.jacocoAgentVersion -} - tasks { - val setupJacocoRuntime by registering(WriteProperties::class) { - outputFile = - functionalTestSourceSet.output.resourcesDir!!.resolve("testkit/testkit-gradle.properties") - property( - "org.gradle.jvmargs", - "-javaagent:${configurations["jacocoRuntime"].asPath}=destfile=$buildDir/jacoco/functionalTest.exec" - ) - } - val functionalTest by registering(Test::class) { group = "verification" testClassesDirs = functionalTestSourceSet.output.classesDirs classpath = functionalTestSourceSet.runtimeClasspath - dependsOn(setupJacocoRuntime) } val ktlint by registering(JavaExec::class) { @@ -221,26 +206,6 @@ tasks { dependsOn(functionalTest, ktlint) } - val jacocoExecData = fileTree("$buildDir/jacoco").include("*.exec") - - jacocoTestReport { - executionData(jacocoExecData) - dependsOn(test, functionalTest) - } - - jacocoTestCoverageVerification { - inputs.dir(buildDir.resolve("jacoco")) - executionData(jacocoExecData) - violationRules { - rule { - limit { - counter = "INSTRUCTION" - minimum = "0.8".toBigDecimal() - } - } - } - } - jar { manifest { attributes( @@ -287,7 +252,7 @@ tasks { wrapper { distributionType = Wrapper.DistributionType.ALL - gradleVersion = "7.2" + gradleVersion = "7.3.3" } val updateReadme by registering { @@ -313,6 +278,16 @@ tasks { patchChangelog { dependsOn(updateReadme) } + + koverVerify { + rule { + name = "Minimal Line coverage" + bound { + minValue = 80 + valueType = COVERED_LINES_PERCENTAGE + } + } + } } dependencies { @@ -343,6 +318,4 @@ dependencies { "functionalTestImplementation"(Deps.kotlinMultiplatformPlugin) "functionalTestImplementation"(gradleTestKit()) "functionalTestImplementation"(kotlinReflect) - - "jacocoRuntime"("org.jacoco:org.jacoco.agent:${jacoco.toolVersion}:runtime") } diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index 3d162ad..16e6078 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -15,24 +15,23 @@ */ object Deps { - const val kotlinVersion = "1.5.31" - const val jacocoAgentVersion = "0.8.7" + const val kotlinVersion = "1.6.10" object Plugins { - const val dokkaVersion = "1.5.31" - const val changelogPluginVersion = "1.3.0" - const val pluginPublishVersion = "0.16.0" - const val versionsVersion = "0.39.0" + const val dokkaVersion = "1.6.10" + const val changelogPluginVersion = "1.3.1" + const val pluginPublishVersion = "0.19.0" + const val versionsVersion = "0.40.0" } - const val androidGradlePlugin = "com.android.tools.build:gradle:7.0.2" + const val androidGradlePlugin = "com.android.tools.build:gradle:7.0.4" const val kotlinMultiplatformPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" const val apacheCommonsCsv = "org.apache.commons:commons-csv:1.9.0" - const val mavenModel = "org.apache.maven:maven-model:3.8.3" - const val mavenArtifact = "org.apache.maven:maven-artifact:3.8.3" - const val jUnit = "org.junit.jupiter:junit-jupiter:5.8.1" + const val mavenModel = "org.apache.maven:maven-model:3.8.4" + const val mavenArtifact = "org.apache.maven:maven-artifact:3.8.4" + const val jUnit = "org.junit.jupiter:junit-jupiter:5.8.2" const val hamcrest = "org.hamcrest:hamcrest:2.2" - const val ktlint = "com.pinterest:ktlint:0.42.1" - const val kotlinSerialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.0" - const val mockitoKotlin = "org.mockito.kotlin:mockito-kotlin:3.2.0" + const val ktlint = "com.pinterest:ktlint:0.43.2" + const val kotlinSerialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2" + const val mockitoKotlin = "org.mockito.kotlin:mockito-kotlin:4.0.0" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a0f7639..669386b 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-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" From 0368566924e022e2371ee12ec1a792816e08a424 Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:16:20 +0100 Subject: [PATCH 04/10] use kover --- build.gradle.kts | 22 ++++++++++--------- .../license/LicensePluginAndroidShould.kt | 2 -- .../LicensePluginJavaMultiProjectShould.kt | 2 -- .../license/LicensePluginJavaShould.kt | 2 -- .../LicensePluginMultiplatformShould.kt | 2 -- .../cmgapps/license/model/LibraryShould.kt | 14 ++++++++---- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 76987f3..ff9378b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,19 +45,13 @@ val functionalTestSourceSet: SourceSet = sourceSets.create("functionalTest") { java { srcDir("src/$sourceSetName/kotlin") } - - compileClasspath += sourceSets.main.get().output //+ configurations.testRuntimeClasspath.get() - runtimeClasspath += output + compileClasspath + resources { + srcDirs(sourceSets.main.get().resources.srcDirs) + } } val ktlint: Configuration by configurations.creating -configurations { - named("functionalTestImplementation") { - extendsFrom(testImplementation.get()) - } -} - idea { module { testSourceDirs = testSourceDirs + functionalTestSourceSet.allJava.srcDirs @@ -151,7 +145,7 @@ publishing { licenses { license { name.set("Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") } } } @@ -187,6 +181,10 @@ changelog { version.set(versionName) } +kover { + coverageEngine.set(kotlinx.kover.api.CoverageEngine.JACOCO) +} + tasks { val functionalTest by registering(Test::class) { group = "verification" @@ -314,8 +312,12 @@ dependencies { testImplementation(kotlinReflect) testImplementation(Deps.mockitoKotlin) + "functionalTestImplementation"(Deps.jUnit) { + exclude(group = "org.hamcrest") + } "functionalTestImplementation"(Deps.androidGradlePlugin) "functionalTestImplementation"(Deps.kotlinMultiplatformPlugin) + "functionalTestImplementation"(Deps.hamcrest) "functionalTestImplementation"(gradleTestKit()) "functionalTestImplementation"(kotlinReflect) } diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginAndroidShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginAndroidShould.kt index f228d4e..dee3a33 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginAndroidShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginAndroidShould.kt @@ -17,7 +17,6 @@ package com.cmgapps.license import com.cmgapps.license.util.plus -import com.cmgapps.license.util.withJaCoCo import com.cmgapps.license.util.write import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome @@ -83,7 +82,6 @@ class LicensePluginAndroidShould { gradleRunner = GradleRunner.create() .withProjectDir(testProjectDir.toFile()) - .withJaCoCo() } @Test diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt index 8a2979f..87e46f4 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaMultiProjectShould.kt @@ -18,7 +18,6 @@ package com.cmgapps.license import com.cmgapps.license.util.getFileContent import com.cmgapps.license.util.plus -import com.cmgapps.license.util.withJaCoCo import org.gradle.testkit.runner.GradleRunner import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` @@ -60,7 +59,6 @@ class LicensePluginJavaMultiProjectShould { .withProjectDir(testProjectDir.toFile()) .withArguments(":module1:licenseReport") .withPluginClasspath() - .withJaCoCo() } @Test diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaShould.kt index 3bee776..45a22bd 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginJavaShould.kt @@ -18,7 +18,6 @@ package com.cmgapps.license import com.cmgapps.license.util.getFileContent import com.cmgapps.license.util.plus -import com.cmgapps.license.util.withJaCoCo import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome import org.hamcrest.MatcherAssert.assertThat @@ -69,7 +68,6 @@ class LicensePluginJavaShould { .withProjectDir(testProjectDir.toFile()) .withArguments(":licenseReport") .withPluginClasspath() - .withJaCoCo() } @DisabledIfEnvironmentVariable(named = "CIRCLECI", matches = "true") diff --git a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt index 17146ae..e9cba15 100644 --- a/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt +++ b/src/functionalTest/kotlin/com/cmgapps/license/LicensePluginMultiplatformShould.kt @@ -17,7 +17,6 @@ package com.cmgapps.license import com.cmgapps.license.util.plus -import com.cmgapps.license.util.withJaCoCo import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome import org.hamcrest.MatcherAssert.assertThat @@ -89,7 +88,6 @@ class LicensePluginMultiplatformShould { gradleRunner = GradleRunner.create() .withProjectDir(testProjectDir.toFile()) - .withJaCoCo() } @Test diff --git a/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt b/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt index 144e953..b26a878 100644 --- a/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt +++ b/src/test/kotlin/com/cmgapps/license/model/LibraryShould.kt @@ -21,8 +21,8 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.apache.maven.artifact.versioning.ComparableVersion import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.`is` import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -100,7 +100,7 @@ internal class LibraryShould { description = "description", licenses = listOf(License("License name", "http://domain.com")) ) - assertThat(json.decodeFromString(json.encodeToString(lib)), `is`(lib)) + assertThat(json.decodeFromString(json.encodeToString(lib)), `is`(lib)) } @Test @@ -127,7 +127,10 @@ internal class LibraryShould { Library("A", ComparableVersion("2.0"), description = null, licenses = emptyList()), Library("A", ComparableVersion("0.3-alpha4"), description = null, licenses = emptyList()), Library( - "C", ComparableVersion("13"), description = "desc", licenses = listOf( + "C", + ComparableVersion("13"), + description = "desc", + licenses = listOf( License( "license", "http://domain.tld" @@ -143,7 +146,10 @@ internal class LibraryShould { Library("A", ComparableVersion("0.3-alpha4"), description = null, licenses = emptyList()), Library("B", ComparableVersion("1.0"), description = null, licenses = emptyList()), Library( - "C", ComparableVersion("13"), description = "desc", licenses = listOf( + "C", + ComparableVersion("13"), + description = "desc", + licenses = listOf( License( "license", "http://domain.tld" From 1fb8d2d1d28a8e28c73b493459bf89b75fd2168f Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:24:21 +0100 Subject: [PATCH 05/10] use github workflow --- .circleci/config.yml | 70 -------------------------------------- .github/workflows/main.yml | 47 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 70 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/main.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 6b7b9cf..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,70 +0,0 @@ -version: 2.1 - -executors: - android-executor: - docker: - - image: circleci/android:api-30 - auth: - username: chrimaeon - password: $DOCKERHUB_PASSWORD - environment: - TERM: "dumb" - JAVA_TOOL_OPTIONS: "-Xmx3g" - GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=false -Dorg.gradle.workers.max=2 -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false" - -commands: - restore_gradle_wrapper: - description: "Restores Gradle Wrapper from cache" - steps: - - restore_cache: - key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} - restore_gradle_cache: - description: "Restores Gradle Cache from cache" - steps: - - restore_cache: - key: v1-gradle-cache-{{ checksum "buildSrc/src/main/kotlin/Deps.kt" }}-{{ checksum "build.gradle.kts" }} - save_gradle_wrapper: - description: "Save Gradle Wrapper to cache" - steps: - - save_cache: - paths: - - ~/.gradle/wrapper - key: v1-gradle-wrapper-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} - save_gradle_cache: - description: "Save Gradle Cache to cache" - steps: - - save_cache: - paths: - - ~/.gradle/caches - key: v1-gradle-cache-{{ checksum "buildSrc/src/main/kotlin/Deps.kt" }}-{{ checksum "build.gradle.kts" }} - -jobs: - test: - executor: android-executor - resource_class: medium - steps: - - checkout - - restore_gradle_wrapper - - restore_gradle_cache - - run: - name: Run check task - command: ./gradlew check - - run: - name: Generate and verify code coverage and - command: ./gradlew jacocoTestReport - - save_gradle_wrapper - - save_gradle_cache - - store_test_results: - path: build/test-results/test - - store_test_results: - path: build/test-results/functionalTest - - store_artifacts: - path: build/reports - -workflows: - version: 2 - workflow: - jobs: - - test: - context: - - DockerHub diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..3be4de2 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,47 @@ +name: Build & Test + +on: + push: + branches: + - main + - develop + - 'release/**' + - 'hotfix/**' + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: zulu + java-version: 11 + - name: Gradle Cache + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + ~/.gradle/caches/build-cache-* + key: gradle-${{ hashFiles('**/build.gradle.kts', '**/Deps.kt') }} + - name: Gradle Wrapper Cache + uses: actions/cache@v2 + with: + path: ~/.gradle/wrapper + key: gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Download dependencies + run: ./gradlew dependencies + + - name: Build & Test + run: ./gradlew check koverHtmlReport koverVerify + + - name: Archive Test results + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: test-results + path: | + build/reports/* + build/test-results/* From 9ac38a8fc73ac281cad68b3071e575724d1762a6 Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:35:50 +0100 Subject: [PATCH 06/10] upload codecov --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3be4de2..2effc3c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,3 +45,5 @@ jobs: path: | build/reports/* build/test-results/* + + - uses: codecov/codecov-action@v2 From caa9ad2a189a2965385ec39531a108267052a0fd Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:40:33 +0100 Subject: [PATCH 07/10] update readme --- .github/workflows/main.yml | 3 ++- CHANGELOG.md | 2 +- README.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2effc3c..2cc7cce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,4 +46,5 @@ jobs: build/reports/* build/test-results/* - - uses: codecov/codecov-action@v2 + - name: Upload Codecov + uses: codecov/codecov-action@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6525b76..b6ffba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added ### Changed -- sort dependencies by name and version +- Sort dependencies by name and version ### Deprecated diff --git a/README.md b/README.md index 67c6818..387d6f3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Gradle Licenses Plugin [![CircleCI](https://circleci.com/gh/chrimaeon/gradle-licenses-plugin.svg?style=svg)](https://circleci.com/gh/chrimaeon/gradle-licenses-plugin) +# Gradle Licenses Plugin [![Build & Test](https://github.com/chrimaeon/gradle-licenses-plugin/actions/workflows/main.yml/badge.svg)](https://github.com/chrimaeon/gradle-licenses-plugin/actions/workflows/main.yml) [![codecov](https://codecov.io/gh/chrimaeon/gradle-licenses-plugin/branch/master/graph/badge.svg?token=XY0G488B3B)](https://codecov.io/gh/chrimaeon/gradle-licenses-plugin) [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg?style=for-the-badge)](http://www.apache.org/licenses/LICENSE-2.0) [![Gradle Plugin](https://img.shields.io/badge/Gradle-6.8%2B-%2302303A.svg?style=for-the-badge&logo=Gradle)](https://gradle.org/) From 43e938937eec7b0938ace179868c1ba8c97bb8ce Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:45:32 +0100 Subject: [PATCH 08/10] bump version number --- CHANGELOG.md | 20 +++++++++----------- README.md | 4 ++-- pom.properties | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6ffba5..ef6e232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ ### Added ### Changed -- Sort dependencies by name and version ### Deprecated @@ -14,14 +13,11 @@ ### Security -## [4.0.0] +## [4.1.0] ### Added -- Kotlin Multiplatform support - ### Changed - -- Extension property to set `enabled` and `destination` +- Sort dependencies by name and version ### Deprecated @@ -31,25 +27,27 @@ ### Security -## [3.3.0] +## [4.0.0] +### Added +- Kotlin Multiplatform support ### Changed +- Extension property to set `enabled` and `destination` +## [3.3.0] +### Changed - Update Android Gradle plugin to version 7+ - Warning when license has no mapping for html reports ## [3.2.0] - ### Added - - set task outputs to report files - add DSL to configure reports ### Changed - - use library to create CSV report ## [3.1.0] ### Changed - All public properties are now provided Properties -- Use Kotlin Serialization instead of Moshi +- Use Kotlin Serialization instead of Moshi \ No newline at end of file diff --git a/README.md b/README.md index 387d6f3..2ecb35c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Using the plugins DSL ```groovy plugins { - id "com.cmgapps.licenses" version "4.0.0" + id "com.cmgapps.licenses" version "4.1.0" } ``` @@ -26,7 +26,7 @@ buildscript { } dependencies { - classpath("com.cmgapps:gradle-licenses-plugin:4.0.0") + classpath("com.cmgapps:gradle-licenses-plugin:4.1.0") } } diff --git a/pom.properties b/pom.properties index e544f38..fd98790 100644 --- a/pom.properties +++ b/pom.properties @@ -14,7 +14,7 @@ # limitations under the License. # group=com.cmgapps -versionName=4.1.0-SNAPSHOT +versionName=4.1.0 pomName=Gradle Licenses Plugin pomArtifactId=gradle-licenses-plugin pomDescription=Gradle plugin that provides a task to generate a license report of your project. From d714c10b9db2bd80e04408c1619f0b5ca9f0e1e0 Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:45:38 +0100 Subject: [PATCH 09/10] add create release github workflow --- .github/workflows/create_release.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/create_release.yml diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml new file mode 100644 index 0000000..fed083a --- /dev/null +++ b/.github/workflows/create_release.yml @@ -0,0 +1,23 @@ +name: Create Github Release + +on: + push: + tags: + - '**' + workflow_dispatch: + +jobs: + create-github-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Create Release Notes + run: ./gradlew --quiet getChangelog --no-header > ./RELEASE_NOTES.md + - name: Create Release + uses: chrimaeon/github-create-release-action@0.2.0 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + tag_name: ${{ github.ref }} + body_file: ./RELEASE_NOTES.md + draft: false From 128e1bd31dba3fe82eb9a96a2deac30bbe2a8ceb Mon Sep 17 00:00:00 2001 From: Christian Grach Date: Sun, 2 Jan 2022 13:51:47 +0100 Subject: [PATCH 10/10] resolve creds file --- build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ff9378b..08995f5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -160,14 +160,14 @@ publishing { url = if (versionName.endsWith("SNAPSHOT")) snapshotUrl else releaseUrl val credentials = Properties().apply { - val credFile = file("./credentials.properties") + val credFile = projectDir.resolve("credentials.properties") if (credFile.exists()) { load(credFile.inputStream()) } } credentials { - username = credentials.getProperty("sonaUsername") - password = credentials.getProperty("sonaPassword") + username = credentials.getProperty("username") + password = credentials.getProperty("password") } } }