Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the plugin compatible with kotlin-only projects, add more tests #14

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
ktlint_compose_unstable-collections = disabled

[*.xml]
indent_size = 4
ij_xml_space_inside_empty_tag = true
79 changes: 66 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -23,31 +30,77 @@ 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:

```groovy
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.
Binary file added images/generated_code_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/generated_code_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions licensee-for-android/api/licensee-for-android.api
Original file line number Diff line number Diff line change
@@ -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 <init> ()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 <init> ()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 <init> (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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Boolean> = objectFactory.property(default = false)

Expand All @@ -18,15 +19,14 @@ public open class LicenseeForAndroidExtension(objectFactory: ObjectFactory) {
public val generatedPackageName: Property<String> = 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<Boolean> = objectFactory.property(default = true)
public val enableResourceGeneration: Property<Boolean> = 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<String> = objectFactory.property(default = "licensee_artifacts.json")
public val resourceFileName: Property<String> = 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.
Expand All @@ -39,3 +39,7 @@ public open class LicenseeForAndroidExtension(objectFactory: ObjectFactory) {
internal inline fun <reified T> ObjectFactory.property(default: T? = null): Property<T> = property(T::class.java).apply {
convention(default)
}

internal inline fun <reified T> ObjectFactory.setProperty(default: Set<T>? = null): SetProperty<T> = setProperty(T::class.java).apply {
convention(default)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Project> {

Expand All @@ -21,6 +22,13 @@ public class LicenseeForAndroidPlugin : Plugin<Project> {
configureAndroidPlugin(extension)
}
}

listOf("org.jetbrains.kotlin.jvm")
.forEach { pluginId ->
pluginManager.withPlugin(pluginId) {
project.afterEvaluate { configureKotlinPlugin(extension) }
}
}
}
}

Expand All @@ -37,18 +45,21 @@ public class LicenseeForAndroidPlugin : Plugin<Project> {
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) }
}

Expand All @@ -71,4 +82,48 @@ public class LicenseeForAndroidPlugin : Plugin<Project> {
}
}
}

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) }
}
}
}
12 changes: 6 additions & 6 deletions sample/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ licensee {

licenseeForAndroid {
enableKotlinCodeGeneration = true
enableAndroidAssetGeneration = true
enableResourceGeneration = true
}
android {
namespace "io.githhub.usefulness.licensee.android.app"
Expand All @@ -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()
Expand Down
18 changes: 9 additions & 9 deletions sample/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Gross"
tools:targetApi="31">
tools:targetApi="31"
>
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Gross">
android:theme="@style/Theme.Gross"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand All @@ -25,4 +25,4 @@
</activity>
</application>

</manifest>
</manifest>
Loading