Skip to content

Commit

Permalink
Add DSL helpers to enable metrics and reports (#1627)
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton authored Dec 13, 2023
1 parent e242612 commit d1fc6d0
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
*/
package app.cash.redwood.gradle

import javax.inject.Inject
import org.gradle.api.model.ObjectFactory
import org.gradle.api.Action
import org.gradle.api.provider.Property

public abstract class RedwoodComposeExtension
@Inject constructor(objectFactory: ObjectFactory) {
public interface RedwoodComposeExtension {
/**
* The version of the JetBrains Compose compiler to use, or a Maven coordinate triple of
* the custom Compose compiler to use.
Expand All @@ -39,7 +37,48 @@ public abstract class RedwoodComposeExtension
* }
* ```
*/
public val kotlinCompilerPlugin: Property<String> =
objectFactory.property(String::class.java)
.convention(composeCompilerVersion)
public val kotlinCompilerPlugin: Property<String>

/**
* Configuration options that require extra care when used.
*
* @see DangerZone
*/
public fun dangerZone(body: Action<DangerZone>)

/**
* Configuration options that require extra care when used. Please read the documentation of
* each member carefully to understand how it affects your build.
*/
public interface DangerZone {
/**
* Enable the output of metrics from the Compose compiler.
*
* Text files will be written to `generated/redwood/compose-metrics/` in the project's build
* directory. See
* [the compiler documentation](https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md#reports-breakdown)
* for more information about the contents.
*
* **NOTE:** This should only be enabled during investigation as it breaks the use of
* Gradle's build cache for this project's Kotlin compilation tasks.
*
* @see enableReports
*/
public fun enableMetrics()

/**
* Enable the output of reports from the Compose compiler.
*
* Text files will be written to `generated/redwood/compose-reports/` in the project's build
* directory. See
* [the compiler documentation](https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md#reports-breakdown)
* for more information about the contents.
*
* **NOTE:** This should only be enabled during investigation as it breaks the use of
* Gradle's build cache for this project's Kotlin compilation tasks.
*
* @see enableMetrics
*/
public fun enableReports()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2023 Square, Inc.
*
* 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 app.cash.redwood.gradle

import app.cash.redwood.gradle.RedwoodComposeExtension.DangerZone
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

internal class RedwoodComposeExtensionImpl(
private val project: Project,
) : RedwoodComposeExtension, DangerZone {
private var metricsEnabled = false
private var reportsEnabled = false

// Explicit backing property avoids Gradle attempting to reflect on an implicit backing field.
override val kotlinCompilerPlugin: Property<String> get() = _kotlinCompilerPlugin

private val _kotlinCompilerPlugin = project.objects.property(String::class.java)
.convention(composeCompilerVersion)

override fun dangerZone(body: Action<DangerZone>) {
body.execute(this)
}

override fun enableMetrics() {
if (metricsEnabled) return
metricsEnabled = true

project.tasks.withType(KotlinCompile::class.java).configureEach {
val dir = project.redwoodReportDir("compose-metrics/${it.name}").get().asFile.absolutePath
it.compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=$dir",
)
}
}

override fun enableReports() {
if (reportsEnabled) return
reportsEnabled = true

project.tasks.withType(KotlinCompile::class.java).configureEach {
val dir = project.redwoodReportDir("compose-reports/${it.name}").get().asFile.absolutePath
it.compilerOptions.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=$dir",
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ public class RedwoodComposePlugin : KotlinCompilerPluginSupportPlugin {
override fun apply(target: Project) {
super.apply(target)

extension = target.extensions.create(EXTENSION_NAME, RedwoodComposeExtension::class.java)
extension = RedwoodComposeExtensionImpl(target)
target.extensions.add(
RedwoodComposeExtension::class.java,
EXTENSION_NAME,
extension,
)

target.plugins.withId("org.jetbrains.compose") {
throw IllegalStateException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public abstract class RedwoodGeneratorPlugin(
it.description = "Generate Redwood Kotlin sources"

it.toolClasspath.from(toolingConfiguration)
it.outputDir.set(project.layout.buildDirectory.dir("generated/redwood"))
it.outputDir.set(project.redwoodGeneratedDir("sources"))
it.generatorFlag.set(strategy.generatorFlag)
it.schemaType.set(extension.type)
it.classpath.from(schemaConfiguration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class RedwoodSchemaPlugin : Plugin<Project> {
it.description = "Generate parsed schema JSON"

it.toolClasspath.from(toolingConfiguration)
it.outputDir.set(project.layout.buildDirectory.dir("generated/redwood"))
it.outputDir.set(project.redwoodGeneratedDir("schema-json"))
it.schemaType.set(extension.type)
it.classpath.from(classpath, compilation.output.classesDirs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package app.cash.redwood.gradle

import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.reporting.ReportingExtension

internal fun Project.redwoodDependency(artifactId: String): Any {
// Indicates when the plugin is applied inside the Redwood repo to Redwood's own modules. This
Expand All @@ -28,3 +31,11 @@ internal fun Project.redwoodDependency(artifactId: String): Any {
"app.cash.redwood:$artifactId:$redwoodVersion"
}
}

internal fun Project.redwoodGeneratedDir(name: String): Provider<Directory> {
return layout.buildDirectory.dir("generated/redwood/$name")
}

internal fun Project.redwoodReportDir(name: String): Provider<Directory> {
return extensions.getByType(ReportingExtension::class.java).baseDirectory.dir("redwood/$name")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
buildscript {
dependencies {
classpath "app.cash.redwood:redwood-gradle-plugin:$redwoodVersion"
classpath libs.kotlin.gradlePlugin
}

repositories {
maven {
url "file://${rootDir.absolutePath}/../../../../../build/localMaven"
}
mavenCentral()
google()
}
}

apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'app.cash.redwood'

redwood {
dangerZone {
enableMetrics()
}
}

repositories {
maven {
url "file://${rootDir.absolutePath}/../../../../../build/localMaven"
}
mavenCentral()
google()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Square, Inc.
*
* 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.example

import androidx.compose.runtime.Composable

@Composable
fun double(value: Int): Int {
return value * 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
buildscript {
dependencies {
classpath "app.cash.redwood:redwood-gradle-plugin:$redwoodVersion"
classpath libs.kotlin.gradlePlugin
}

repositories {
maven {
url "file://${rootDir.absolutePath}/../../../../../build/localMaven"
}
mavenCentral()
google()
}
}

apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'app.cash.redwood'

redwood {
dangerZone {
enableReports()
}
}

repositories {
maven {
url "file://${rootDir.absolutePath}/../../../../../build/localMaven"
}
mavenCentral()
google()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Square, Inc.
*
* 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.example

import androidx.compose.runtime.Composable

@Composable
fun double(value: Int): Int {
return value * 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
*/
package app.cash.redwood.gradle

import assertk.all
import assertk.assertThat
import assertk.assertions.contains
import assertk.assertions.containsExactly
import assertk.assertions.containsOnly
import assertk.assertions.exists
import assertk.assertions.isEqualTo
import assertk.assertions.isNotEmpty
import assertk.assertions.isNotNull
import assertk.assertions.prop
import java.io.File
import org.gradle.testkit.runner.BuildTask
Expand Down Expand Up @@ -208,6 +212,34 @@ class FixtureTest {
)
}

@Test fun composeCompilerMetrics() {
val fixtureDir = File("src/test/fixture/compose-compiler-metrics")
fixtureGradleRunner(fixtureDir).build()
assertThat(fixtureDir.resolve("build/reports/redwood/compose-metrics/compileKotlin")).all {
exists()
prop("children", File::list)
.isNotNull()
.containsOnly(
"compose-compiler-metrics-module.json",
)
}
}

@Test fun composeCompilerReports() {
val fixtureDir = File("src/test/fixture/compose-compiler-reports")
fixtureGradleRunner(fixtureDir).build()
assertThat(fixtureDir.resolve("build/reports/redwood/compose-reports/compileKotlin")).all {
exists()
prop("children", File::list)
.isNotNull()
.containsOnly(
"compose-compiler-reports-classes.txt",
"compose-compiler-reports-composables.csv",
"compose-compiler-reports-composables.txt",
)
}
}

private fun fixtureGradleRunner(
fixtureDir: File,
vararg tasks: String = arrayOf("clean", "build"),
Expand Down

0 comments on commit d1fc6d0

Please sign in to comment.