diff --git a/.editorconfig b/.editorconfig index a6820b5..31cbd96 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,4 +12,8 @@ ktlint_code_style = intellij_idea ktlint_standard_property-naming = disabled ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 2 ktlint_function_naming_ignore_when_annotated_with = Composable -ktlint_compose_unstable-collections = disabled \ No newline at end of file +ktlint_compose_unstable-collections = disabled + +[*.xml] +indent_size = 4 +ij_xml_space_inside_empty_tag = true diff --git a/README.md b/README.md index 69a5745..ba10f22 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,13 @@ Turn raw [cashapp/licensee](https://github.com/cashapp/licensee) report into assets/Kotlin code that can be easily consumed from an Android app +### Features +- Access licenses report directly by a generated Kotlin code (accessible via static `io.github.usefulness.licensee.Licensee` object) +- Read _licensee_ report copied to projects assets directory in runtime (via `assetManager.open("licensee_artifacts.json")`) + +![example](images/generated_code_dark.png#gh-dark-mode-only) +![example](images/generated_code_light.png#gh-light-mode-only) + ### Installation Available on: @@ -23,12 +30,7 @@ plugins { } ``` - -### Features -- Access licenses report directly by a generated Kotlin code (accessible via static `io.github.usefulness.licensee.Licensee` object) -- Read _licensee_ report copied to projects assets directory in runtime (via `assetManager.open("licensee_artifacts.json")`) - -### Configuration +#### Configuration Options can be configured in the `licenseeForAndroid` extension: @@ -36,18 +38,69 @@ Options can be configured in the `licenseeForAndroid` extension: licenseeForAndroid { enableKotlinCodeGeneration = false generatedPackageName = "io.github.usefulness.licensee" - enableAndroidAssetGeneration = true - androidAssetFileName = "licensee_artifacts.json" + enableResourceGeneration = false + resourceFileName = "licensee_artifacts.json" singularVariantName = null } ``` -- `enableKotlinCodeGeneration` - Generates a static list of open source assets -- `generatedPackageName` - Generate Kotlin code under given package -- `enableAndroidAssetGeneration` - Enable asset generation. Will copy licensee report to android asset directory making it available as `androidAssetFileName` -- `androidAssetFileName` - The name of the asset file the licensee report gets copied to. -- `singularVariantName` - The name of the build variant that all variants will use to have always the same licensed, regardless of app variant. (i.e. "productionRelease") +- `enableKotlinCodeGeneration` - Enables generating a static list of open source assets. +- `generatedPackageName` - Generate kotlin code under given package +- `enableResourceGeneration` - Enables copying _licensee_ report to asset(Android)/resource(JVM) directory, making it available under 'resourceFileName' name. +- `resourceFileName` - The name of the asset/resource file the licensee report gets copied to. +- `singularVariantName` - The name of the build variant that all variants will use to have always the same licensed, regardless of app variant. (i.e. `"paidRelease"`) + +### Common recipes + +#### Generate licensee information from any module + +```groovy +plugins { + id("com.android.application") // or `com.android.library` + id("app.cash.licensee") + id("io.github.usefulness.licensee-for-android") +} + +licensee { + allow("Apache-2.0") +} + +licenseeForAndroid { + enableKotlinCodeGeneration = true + enableResourceGeneration = true +} +``` +#### Generate Kotlin code in Kotlin-only module using licensee output from a different module + +```groovy +plugins { + id("org.jetbrains.kotlin.jvm") // or any other module type + id("io.github.usefulness.licensee-for-android") apply(false) // do not generate licensee information for _this_ module +} + +// Register custom, source-generating task, use `:app`'s `productionRelease` variant +def licenseeTarget = layout.buildDirectory.map { it.dir("generated/licensee") } +tasks.register("generateLicenseeKotlinCode", CodeGenerationTask) { + it.inputFile.set( + project(":app").tasks.named("licenseeAndroidProductionRelease") + .flatMap { it.outputDir.file("artifacts.json") } + ) + it.outputDirectory.set(licenseeTarget) + it.packageName.set("io.github.usefulness.licensee") +} +// Make sources discoverable in IDE (https://youtrack.jetbrains.com/issue/KT-45161) +sourceSets.named("main") { + kotlin { + srcDir(licenseeTarget) + } +} + +// Make them run on every compilation +tasks.named("compileKotlin") { + dependsOn("generateCustomLicenseeKotlinCode") +} +``` ### Credits Huge thanks to [premex-ab/gross](https://github.com/premex-ab/gross) which this plugin forked from. diff --git a/images/generated_code_dark.png b/images/generated_code_dark.png new file mode 100644 index 0000000..e5664f7 Binary files /dev/null and b/images/generated_code_dark.png differ diff --git a/images/generated_code_light.png b/images/generated_code_light.png new file mode 100644 index 0000000..15d75ca Binary files /dev/null and b/images/generated_code_light.png differ diff --git a/licensee-for-android/api/licensee-for-android.api b/licensee-for-android/api/licensee-for-android.api index 4371d4d..6c05b4b 100644 --- a/licensee-for-android/api/licensee-for-android.api +++ b/licensee-for-android/api/licensee-for-android.api @@ -1,25 +1,25 @@ -public abstract class io/github/usefulness/licensee/AssetCopyTask : org/gradle/api/DefaultTask { +public abstract class io/github/usefulness/licensee/CodeGenerationTask : org/gradle/api/DefaultTask { public fun ()V public final fun action ()V public abstract fun getInputFile ()Lorg/gradle/api/file/RegularFileProperty; public abstract fun getOutputDirectory ()Lorg/gradle/api/file/DirectoryProperty; - public abstract fun getTargetFileName ()Lorg/gradle/api/provider/Property; + public abstract fun getPackageName ()Lorg/gradle/api/provider/Property; } -public abstract class io/github/usefulness/licensee/CodeGenerationTask : org/gradle/api/DefaultTask { +public abstract class io/github/usefulness/licensee/LicenseeFileCopyTask : org/gradle/api/DefaultTask { public fun ()V public final fun action ()V public abstract fun getInputFile ()Lorg/gradle/api/file/RegularFileProperty; public abstract fun getOutputDirectory ()Lorg/gradle/api/file/DirectoryProperty; - public abstract fun getPackageName ()Lorg/gradle/api/provider/Property; + public abstract fun getTargetFileName ()Lorg/gradle/api/provider/Property; } public class io/github/usefulness/licensee/LicenseeForAndroidExtension { public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getAndroidAssetFileName ()Lorg/gradle/api/provider/Property; - public final fun getEnableAndroidAssetGeneration ()Lorg/gradle/api/provider/Property; public final fun getEnableKotlinCodeGeneration ()Lorg/gradle/api/provider/Property; + public final fun getEnableResourceGeneration ()Lorg/gradle/api/provider/Property; public final fun getGeneratedPackageName ()Lorg/gradle/api/provider/Property; + public final fun getResourceFileName ()Lorg/gradle/api/provider/Property; public final fun getSingularVariantName ()Lorg/gradle/api/provider/Property; } diff --git a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/AssetCopyTask.kt b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeFileCopyTask.kt similarity index 94% rename from licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/AssetCopyTask.kt rename to licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeFileCopyTask.kt index 1d741be..11d9e23 100644 --- a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/AssetCopyTask.kt +++ b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeFileCopyTask.kt @@ -13,7 +13,7 @@ import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction @CacheableTask -public abstract class AssetCopyTask : DefaultTask() { +public abstract class LicenseeFileCopyTask : DefaultTask() { @get:OutputDirectory public abstract val outputDirectory: DirectoryProperty diff --git a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidExtension.kt b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidExtension.kt index b38c10c..dfb37d7 100644 --- a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidExtension.kt +++ b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidExtension.kt @@ -3,11 +3,12 @@ package io.github.usefulness.licensee import org.gradle.api.Incubating import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property +import org.gradle.api.provider.SetProperty public open class LicenseeForAndroidExtension(objectFactory: ObjectFactory) { /** - * Generates a static list of open source assets + * Enables generating a static list of open source assets. */ public val enableKotlinCodeGeneration: Property = objectFactory.property(default = false) @@ -18,15 +19,14 @@ public open class LicenseeForAndroidExtension(objectFactory: ObjectFactory) { public val generatedPackageName: Property = objectFactory.property(default = "io.github.usefulness.licensee") /** - * Enable asset generation. Will copy licensee report to - * android asset directory making it available as 'androidAssetFileName' + * Enables copying licensee report to asset(Android)/resource(JVM) directory, making it available under 'resourceFileName' name. */ - public val enableAndroidAssetGeneration: Property = objectFactory.property(default = true) + public val enableResourceGeneration: Property = objectFactory.property(default = false) /** - * The name of the asset file the licensee report gets copied to. + * The name of the asset/resource file the licensee report gets copied to. */ - public val androidAssetFileName: Property = objectFactory.property(default = "licensee_artifacts.json") + public val resourceFileName: Property = objectFactory.property(default = "licensee_artifacts.json") /** * The name of the build variant that all variants will use to have always the same licensed, regardless of app variant. @@ -39,3 +39,7 @@ public open class LicenseeForAndroidExtension(objectFactory: ObjectFactory) { internal inline fun ObjectFactory.property(default: T? = null): Property = property(T::class.java).apply { convention(default) } + +internal inline fun ObjectFactory.setProperty(default: Set? = null): SetProperty = setProperty(T::class.java).apply { + convention(default) +} diff --git a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidPlugin.kt b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidPlugin.kt index dfaa163..d55772a 100644 --- a/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidPlugin.kt +++ b/licensee-for-android/src/main/kotlin/io/github/usefulness/licensee/LicenseeForAndroidPlugin.kt @@ -4,6 +4,7 @@ import com.android.build.api.variant.AndroidComponentsExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.reporting.ReportingExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetContainer public class LicenseeForAndroidPlugin : Plugin { @@ -21,6 +22,13 @@ public class LicenseeForAndroidPlugin : Plugin { configureAndroidPlugin(extension) } } + + listOf("org.jetbrains.kotlin.jvm") + .forEach { pluginId -> + pluginManager.withPlugin(pluginId) { + project.afterEvaluate { configureKotlinPlugin(extension) } + } + } } } @@ -37,18 +45,21 @@ public class LicenseeForAndroidPlugin : Plugin { val licenseeTaskName = "licenseeAndroid$sourceCapitalized" val artifactsFile = reportingExtension.file("licensee/android$sourceCapitalized/artifacts.json") - if (extension.enableAndroidAssetGeneration.get()) { + + if (extension.enableResourceGeneration.get()) { val copyArtifactsTask = tasks.register( - "generate${sourceCapitalized}LicenseeAssetsFor$targetCapitalized", - AssetCopyTask::class.java, + "generate${sourceCapitalized}LicenseeResourceFor$targetCapitalized", + LicenseeFileCopyTask::class.java, ) { it.inputFile.set(artifactsFile) - it.targetFileName.set(extension.androidAssetFileName) + it.targetFileName.set(extension.resourceFileName) } + variant.sources.assets!!.addGeneratedSourceDirectory( taskProvider = copyArtifactsTask, - wiredWith = AssetCopyTask::outputDirectory, + wiredWith = LicenseeFileCopyTask::outputDirectory, ) + copyArtifactsTask.configure { it.dependsOn(licenseeTaskName) } } @@ -71,4 +82,48 @@ public class LicenseeForAndroidPlugin : Plugin { } } } + + private fun Project.configureKotlinPlugin(extension: LicenseeForAndroidExtension) { + val reportingExtension = extensions.getByType(ReportingExtension::class.java) + val kotlinExtension = project.extensions.getByType(KotlinSourceSetContainer::class.java) + val licenseeTaskName = "licensee" + + val artifactsFile = reportingExtension.file("licensee/artifacts.json") + if (extension.enableResourceGeneration.get()) { + val kotlinSourceSet = kotlinExtension.sourceSets.named("main").get().resources + val targetDirectory = layout.buildDirectory.map { it.dir("generated").dir("licenseeResources") } + + val copyArtifactsTask = tasks.register("generateLicenseeResource", LicenseeFileCopyTask::class.java) { + it.inputFile.set(artifactsFile) + it.targetFileName.set(extension.resourceFileName) + it.outputDirectory.set(targetDirectory) + } + kotlinSourceSet.srcDir(targetDirectory) + + copyArtifactsTask.configure { it.dependsOn(licenseeTaskName) } + + tasks.named("processResources") { + it.dependsOn(copyArtifactsTask) + } + } + + if (extension.enableKotlinCodeGeneration.get()) { + val targetDirectory = layout.buildDirectory.map { it.dir("generated").dir("licensee") } + val codeGenerationTask = tasks.register("generateLicenseeKotlinCode", CodeGenerationTask::class.java) { + it.inputFile.set(artifactsFile) + it.packageName.set(extension.generatedPackageName) + it.outputDirectory.set(targetDirectory) + } + + kotlinExtension.sourceSets.named("main") { + it.kotlin.srcDir(targetDirectory) + } + + tasks.named("compileKotlin") { + it.dependsOn(codeGenerationTask) + } + + codeGenerationTask.configure { it.dependsOn(licenseeTaskName) } + } + } } diff --git a/sample/app/build.gradle b/sample/app/build.gradle index 4c1f219..b72bdfa 100644 --- a/sample/app/build.gradle +++ b/sample/app/build.gradle @@ -10,7 +10,7 @@ licensee { licenseeForAndroid { enableKotlinCodeGeneration = true - enableAndroidAssetGeneration = true + enableResourceGeneration = true } android { namespace "io.githhub.usefulness.licensee.android.app" @@ -28,15 +28,15 @@ android { matchingFallbacks += ["debug"] } } - lint { - checkReleaseBuilds = false + buildFeatures { + compose = true + buildConfig = true } testOptions { unitTests.includeAndroidResources true } - buildFeatures { - compose = true - buildConfig = true + lint { + checkReleaseBuilds = false } composeOptions { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() diff --git a/sample/app/src/main/AndroidManifest.xml b/sample/app/src/main/AndroidManifest.xml index c2a6060..9757691 100644 --- a/sample/app/src/main/AndroidManifest.xml +++ b/sample/app/src/main/AndroidManifest.xml @@ -1,22 +1,22 @@ - + + tools:targetApi="31" + > + android:theme="@style/Theme.Gross" + > @@ -25,4 +25,4 @@ - \ No newline at end of file + diff --git a/sample/app/src/main/res/drawable/ic_launcher_background.xml b/sample/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9..aa30557 100644 --- a/sample/app/src/main/res/drawable/ic_launcher_background.xml +++ b/sample/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,205 @@ - + android:viewportHeight="108" + > + android:pathData="M0,0h108v108h-108z" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> + android:strokeColor="#33FFFFFF" + /> diff --git a/sample/app/src/main/res/drawable/ic_launcher_foreground.xml b/sample/app/src/main/res/drawable/ic_launcher_foreground.xml index 2b068d1..a9a4e8b 100644 --- a/sample/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/sample/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,9 +1,11 @@ - + android:viewportHeight="108" + > + android:type="linear" + > + android:offset="0.0" + /> + android:offset="1.0" + /> @@ -26,5 +31,6 @@ android:fillType="nonZero" android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" android:strokeWidth="1" - android:strokeColor="#00000000" /> - \ No newline at end of file + android:strokeColor="#00000000" + /> + diff --git a/sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 6f3b755..0000000 --- a/sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/sample/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/sample/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78..0000000 Binary files a/sample/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d..0000000 Binary files a/sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/sample/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d6..0000000 Binary files a/sample/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp deleted file mode 100644 index 62b611d..0000000 Binary files a/sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/sample/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a307..0000000 Binary files a/sample/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a695..0000000 Binary files a/sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77..0000000 Binary files a/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9287f50..0000000 Binary files a/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d642..0000000 Binary files a/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9126ae3..0000000 Binary files a/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/sample/app/src/main/res/mipmap/ic_launcher.xml similarity index 72% rename from sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to sample/app/src/main/res/mipmap/ic_launcher.xml index 6f3b755..77422e8 100644 --- a/sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/sample/app/src/main/res/mipmap/ic_launcher.xml @@ -1,6 +1,7 @@ - + - \ No newline at end of file + diff --git a/sample/app/src/main/res/values/strings.xml b/sample/app/src/main/res/values/strings.xml index ed25f78..3418db3 100644 --- a/sample/app/src/main/res/values/strings.xml +++ b/sample/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ - Gross + Licensee for Android Programmatic oss view - Asset baset oss view + Asset based oss view Error Loading - \ No newline at end of file + diff --git a/sample/app/src/main/res/xml/backup_rules.xml b/sample/app/src/main/res/xml/backup_rules.xml deleted file mode 100644 index fa0f996..0000000 --- a/sample/app/src/main/res/xml/backup_rules.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/sample/app/src/main/res/xml/data_extraction_rules.xml b/sample/app/src/main/res/xml/data_extraction_rules.xml deleted file mode 100644 index 9ee9997..0000000 --- a/sample/app/src/main/res/xml/data_extraction_rules.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 49954eb..203c44e 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.starter.application.android) apply false alias(libs.plugins.starter.library.android) apply false alias(libs.plugins.starter.library.kotlin) apply false + id("io.github.usefulness.ktlint-gradle-plugin") version "0.7.0" apply(false) } commonConfig { diff --git a/sample/core/build.gradle b/sample/core/build.gradle index df24a01..b20328e 100644 --- a/sample/core/build.gradle +++ b/sample/core/build.gradle @@ -1,6 +1,40 @@ +import io.github.usefulness.licensee.CodeGenerationTask + plugins { alias(libs.plugins.starter.library.kotlin) alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.app.cash.licensee) + id("io.github.usefulness.licensee-for-android") +} + +licensee { + allow("Apache-2.0") +} + +licenseeForAndroid { + enableKotlinCodeGeneration = true + enableResourceGeneration = true + generatedPackageName = "example.generated.from.kotlin.library" +} + +def licenseeTarget = layout.buildDirectory.map { it.dir("generated/licenseeCustom") } +tasks.register("generateCustomLicenseeKotlinCode", CodeGenerationTask) { + it.inputFile.set( + project(":app").tasks.named("licenseeAndroidDebug") + .flatMap { it.outputDir.file("artifacts.json") } + ) + it.outputDirectory.set(licenseeTarget) + it.packageName.set("example.generated.app_rules.from.kotlin.library") +} + +sourceSets.named("main") { + kotlin { + srcDir(licenseeTarget) + } +} + +tasks.named("compileKotlin") { + dependsOn("generateCustomLicenseeKotlinCode") } tasks.withType(Test).configureEach { diff --git a/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/PluginIntegrationTest.kt b/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/PluginIntegrationTest.kt new file mode 100644 index 0000000..d1ba623 --- /dev/null +++ b/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/PluginIntegrationTest.kt @@ -0,0 +1,29 @@ +package io.github.usefulness.licensee.core + +import example.generated.from.kotlin.library.Licensee as LibraryLicensee +import org.junit.jupiter.api.Test +import example.generated.app_rules.from.kotlin.library.Licensee as AppLicensee +import org.assertj.core.api.Assertions.assertThat + +class PluginIntegrationTest { + + @Test + fun checkAppLicenses() { + assertThat(AppLicensee.artifacts).isNotEmpty() + assertThat(AppLicensee.artifacts.filter { it.groupId == "androidx.viewpager2" && it.artifactId == "viewpager2" }).hasSize(1) + } + + @Test + fun checkLibraryLicenses() { + assertThat(LibraryLicensee.artifacts).isNotEmpty() + assertThat(LibraryLicensee.artifacts.filter { it.groupId == "androidx.viewpager2" }).hasSize(0) + assertThat(LibraryLicensee.artifacts.size).isNotEqualTo(AppLicensee.artifacts.size) + } + + @Test + fun checkLibraryResource() { + val fileContent = readResource("licensee_artifacts.json").decodeToString() + + check(fileContent.contains("com.squareup.okio")) + } +} diff --git a/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/ResourcesLoader.kt b/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/ResourcesLoader.kt new file mode 100644 index 0000000..5c6bdc5 --- /dev/null +++ b/sample/core/src/test/kotlin/io/github/usefulness/licensee/core/ResourcesLoader.kt @@ -0,0 +1,16 @@ +package io.github.usefulness.licensee.core + +import java.io.ByteArrayOutputStream + +private object ResourcesLoader + +internal fun readResource(resource: String) = getResourceStream(resource).use { stream -> + ByteArrayOutputStream().use { out -> + stream.copyTo(out) + out.toByteArray() + } +} + +internal fun getResourceStream(resource: String) = checkNotNull(ResourcesLoader::class.java.classLoader.getResourceAsStream(resource)) { + "Could not load resource $resource" +} diff --git a/sample/core/src/test/kotlin/se/premex/gross/oss/LicenseeParserTest.kt b/sample/core/src/test/kotlin/se/premex/gross/oss/LicenseeParserTest.kt deleted file mode 100644 index 96730df..0000000 --- a/sample/core/src/test/kotlin/se/premex/gross/oss/LicenseeParserTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -package se.premex.gross.oss - -import io.github.usefulness.licensee.core.LicenseeParser -import okio.buffer -import okio.source -import org.junit.jupiter.api.Test - -private const val ARTIFACTS_SMALL = """[ - { - "groupId": "androidx.activity", - "artifactId": "activity", - "version": "1.7.0", - "name": "Activity", - "spdxLicenses": [ - { - "identifier": "Apache-2.0", - "name": "Apache License 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0" - } - ], - "scm": { - "url": "https://cs.android.com/androidx/platform/frameworks/support" - } - } -]""" - -private const val ARTIFACTS_MEDIUM = """[ - { - "groupId": "androidx.activity", - "artifactId": "activity", - "version": "1.7.0", - "name": "Activity", - "spdxLicenses": [ - { - "identifier": "Apache-2.0", - "name": "Apache License 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0" - } - ], - "scm": { - "url": "https://cs.android.com/androidx/platform/frameworks/support" - } - }, - { - "groupId": "androidx.activity", - "artifactId": "activity-compose", - "version": "1.7.0", - "name": "Activity Compose", - "spdxLicenses": [ - { - "identifier": "Apache-2.0", - "name": "Apache License 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0" - } - ], - "scm": { - "url": "https://cs.android.com/androidx/platform/frameworks/support" - } - }, - { - "groupId": "androidx.activity", - "artifactId": "activity-ktx", - "version": "1.7.0", - "name": "Activity Kotlin Extensions", - "spdxLicenses": [ - { - "identifier": "Apache-2.0", - "name": "Apache License 2.0", - "url": "https://www.apache.org/licenses/LICENSE-2.0" - } - ], - "scm": { - "url": "https://cs.android.com/androidx/platform/frameworks/support" - } - } -]""" - -class LicenseeParserTest { - - @Test - fun testSmall() { - LicenseeParser.decode(ARTIFACTS_SMALL.byteInputStream().source().buffer()) - } - - @Test - fun testMedium() { - LicenseeParser.decode(ARTIFACTS_MEDIUM.byteInputStream().source().buffer()) - } -} diff --git a/sample/ui/build.gradle b/sample/ui/build.gradle index cbd3e9e..c0b57d7 100644 --- a/sample/ui/build.gradle +++ b/sample/ui/build.gradle @@ -1,6 +1,3 @@ -import app.cash.licensee.LicenseeTask -import io.github.usefulness.licensee.CodeGenerationTask - plugins { alias(libs.plugins.starter.library.android) alias(libs.plugins.app.cash.licensee) @@ -13,9 +10,9 @@ licensee { licenseeForAndroid { enableKotlinCodeGeneration = true - enableAndroidAssetGeneration = false - generatedPackageName = "example.generated.from.library" - androidAssetFileName = "library_asset.json" + generatedPackageName = "example.generated.from.android.library" + enableResourceGeneration = true + resourceFileName = "ui_library_asset.json" } android { @@ -28,6 +25,9 @@ android { buildFeatures { compose = true } + testOptions { + unitTests.includeAndroidResources true + } composeOptions { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } @@ -53,10 +53,13 @@ dependencies { implementation(libs.androidx.core.core.ktx) testRuntimeOnly(libs.junit.platform.launcher) - testRuntimeOnly(libs.junit.jupiter.engine) + testRuntimeOnly(libs.junit.vintage.engine) - testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit4) testImplementation(libs.assertj.core) + testImplementation(libs.androidx.test.core) + testImplementation(libs.org.robolectric.core) + testImplementation(libs.kotlinx.serialization.json.okio) ktlintRuleSet(libs.io.nlopez.compose) } diff --git a/sample/ui/src/test/kotlin/io/github/usefulness/licensee/LibraryIntegrationTest.kt b/sample/ui/src/test/kotlin/io/github/usefulness/licensee/LibraryIntegrationTest.kt new file mode 100644 index 0000000..7c90c56 --- /dev/null +++ b/sample/ui/src/test/kotlin/io/github/usefulness/licensee/LibraryIntegrationTest.kt @@ -0,0 +1,32 @@ +package io.github.usefulness.licensee + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import example.generated.from.android.library.Licensee +import io.github.usefulness.licensee.core.LicenseeParser +import okio.buffer +import okio.source +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class LibraryIntegrationTest { + + @Test + fun checkGeneratedCode() { + assertThat(Licensee.artifacts).isNotEmpty() + } + + @Test + fun checkResource() { + val context = ApplicationProvider.getApplicationContext() + + val source = context.assets.open("ui_library_asset.json").source().buffer() + val artifacts = LicenseeParser.decode(source) + + assertThat(artifacts).isNotEmpty() + assertThat(artifacts.filter { it.groupId == "androidx.activity" }).isNotEmpty() + } +} diff --git a/sample/ui/src/test/kotlin/io/github/usefulness/licensee/PluginLibaryIntegrationTest.kt b/sample/ui/src/test/kotlin/io/github/usefulness/licensee/PluginLibaryIntegrationTest.kt deleted file mode 100644 index fda7bb3..0000000 --- a/sample/ui/src/test/kotlin/io/github/usefulness/licensee/PluginLibaryIntegrationTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.usefulness.licensee - -import example.generated.from.library.Licensee -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class PluginLibaryIntegrationTest { - - @Test - fun checkGeneratedCode() { - assertThat(Licensee.artifacts).isNotEmpty() - } -}