Skip to content

Add Jetpack Compose compilation unit to the project #257

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

Merged
merged 13 commits into from
Dec 19, 2021
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
40 changes: 39 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
name: (Plugin) Test
command: cd plugin && ./gradlew :android-junit5:check --stacktrace --no-daemon

- run:
name: (Instrumentation) Prepare local.properties
command: |
touch instrumentation/local.properties
echo "junit5.includeCompose = false" > instrumentation/local.properties
- run:
name: (Instrumentation) Download Dependencies
command: cd instrumentation && ./gradlew androidDependencies --no-daemon
Expand All @@ -45,6 +50,24 @@ jobs:
name: (Instrumentation) Test
command: cd instrumentation && ./gradlew :core:check :runner:check --stacktrace --no-daemon

- run:
name: (Compose) Prepare local.properties
command: |
touch instrumentation/local.properties
echo "junit5.includeCompose = true" > instrumentation/local.properties

- run:
name: (Compose) Download Dependencies
command: cd instrumentation && ./gradlew androidDependencies --no-daemon
- run:
name: (Compose) Build
command: |
cd instrumentation
./gradlew :compose:assemble :compose:assembleDebugAndroidTest --stacktrace --no-daemon
- run:
name: (Compose) Test
command: cd instrumentation && ./gradlew :compose:check --stacktrace --no-daemon

- save_cache:
<<: *cache_key
paths:
Expand Down Expand Up @@ -95,6 +118,9 @@ jobs:
- store_artifacts:
path: instrumentation/runner/build/reports
destination: instrumentation-runner
- store_artifacts:
path: instrumentation/compose/build/reports
destination: instrumentation-compose

deploy:
<<: *defaults
Expand All @@ -109,7 +135,16 @@ jobs:
command: cd plugin && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace --no-daemon
- run:
name: (Instrumentation) Build & Deploy
command: cd instrumentation && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace --no-daemon
command: |
cd instrumentation
echo "junit5.includeCompose = false" > local.properties
./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace --no-daemon
- run:
name: (Compose) Build & Deploy
command: |
cd instrumentation
echo "junit5.includeCompose = true" > local.properties
./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --stacktrace --no-daemon
- store_artifacts:
path: plugin/android-junit5/build/publications
destination: plugin/publications/snapshots
Expand All @@ -119,6 +154,9 @@ jobs:
- store_artifacts:
path: instrumentation/runner/build/publications
destination: instrumentation-runner/publications/snapshots
- store_artifacts:
path: instrumentation/compose/build/publications
destination: instrumentation-compose/publications/snapshots

workflows:
version: 2
Expand Down
15 changes: 13 additions & 2 deletions build-logic/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

object libs {
object versions {
const val kotlin = "1.5.21"
const val kotlin = "1.5.31"
const val junitJupiter = "5.8.0"
const val junitVintage = "5.8.0"
const val junitPlatform = "1.8.0"
const val truth = "1.1.3"
const val androidXTest = "1.4.0"
const val compose = "1.0.5"
}

object plugins {
val android = "com.android.tools.build:gradle:${SupportedAgp.values().first().version}"
fun android(version: SupportedAgp) = "com.android.tools.build:gradle:${version.version}"
const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin}"
const val shadow = "com.github.jengelman.gradle.plugins:shadow:6.1.0"
const val dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.5.0"
}

// Libraries
const val kotlinStdLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}"
const val kotlinCoroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1"
const val javaSemver = "com.github.zafarkhaja:java-semver:0.9.0"

const val junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:${versions.junitJupiter}"
Expand All @@ -28,6 +30,11 @@ object libs {
const val junitPlatformCommons = "org.junit.platform:junit-platform-commons:${versions.junitPlatform}"
const val junitPlatformRunner = "org.junit.platform:junit-platform-runner:${versions.junitPlatform}"

const val composeUi = "androidx.compose.ui:ui:${versions.compose}"
const val composeUiTooling = "androidx.compose.ui:ui-tooling:${versions.compose}"
const val composeFoundation = "androidx.compose.foundation:foundation:${versions.compose}"
const val composeMaterial = "androidx.compose.material:material:${versions.compose}"

// Testing
const val junit4 = "junit:junit:4.13.2"
const val korte = "com.soywiz.korlibs.korte:korte:2.2.0"
Expand All @@ -41,4 +48,8 @@ object libs {
const val androidXTestRunner = "androidx.test:runner:${versions.androidXTest}"
const val androidXTestMonitor = "androidx.test:monitor:${versions.androidXTest}"
const val espressoCore = "androidx.test.espresso:espresso-core:3.4.0"

const val composeUiTest = "androidx.compose.ui:ui-test:${versions.compose}"
const val composeUiTestJUnit4 = "androidx.compose.ui:ui-test-junit4:${versions.compose}"
const val composeUiTestManifest = "androidx.compose.ui:ui-test-manifest:${versions.compose}"
}
72 changes: 43 additions & 29 deletions build-logic/src/main/kotlin/Deployment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ fun Project.configureDeployment(deployConfig: Deployed) {
throw IllegalStateException("This method can not be called on the root project")
}

// Deployment of modules needs to be conditionally locked.
// If the project is set to Compose mode, only the Compose modules may be deployed.
// On the other hand, if the project is set to Default mode, only the ordinary
// instrumentation modules are deployed. This has to do with the restrictions
// of the Nexus Publishing plugin, which must use the same group and version declaration
// for all modules. It's impossible to use Version A for instrumentation modules and Version B
// for Compose modules at the same time, hence this conditional.
if (shouldSkipDeployment(deployConfig)) {
return
}

val credentials = DeployedCredentials(this)

// Configure root project (this only happens once
Expand Down Expand Up @@ -113,6 +124,16 @@ fun Project.configureDeployment(deployConfig: Deployed) {

/* Private */

private fun Project.shouldSkipDeployment(deployConfig: Deployed): Boolean {
return if (this.isComposeIncluded) {
// If Compose is included, any non-compose module should be skipped
deployConfig != Artifacts.Instrumentation.Compose
} else {
// If Compose is disabled, any compose module should be skipped
deployConfig == Artifacts.Instrumentation.Compose
}
}

private fun Project.configureRootDeployment(deployConfig: Deployed, credentials: DeployedCredentials) {
if (this != rootProject) {
throw IllegalStateException("This method can only be called on the root project")
Expand Down Expand Up @@ -173,18 +194,27 @@ private fun MavenPublication.applyPublicationDetails(
.none { it.name().toString().endsWith("dependencies") }
) {
val dependenciesNode = appendNode("dependencies")
val dependencies =
project.configurations.getByName("implementation").allDependencies +
project.configurations.getByName("runtimeOnly").allDependencies

val compileDeps = project.configurations.getByName("api").allDependencies
val runtimeDeps = project.configurations.getByName("implementation").allDependencies +
project.configurations.getByName("runtimeOnly").allDependencies -
compileDeps

val dependencies = mapOf(
"runtime" to runtimeDeps,
"compile" to compileDeps
)

dependencies
.filter { it.name != "unspecified" }
.forEach {
with(dependenciesNode.appendNode("dependency")) {
appendNode("groupId", it.group)
appendNode("artifactId", it.name)
appendNode("version", it.version)
appendNode("scope", "runtime")
.mapValues { entry -> entry.value.filter { it.name != "unspecified" } }
.forEach { (scope, dependencies) ->
dependencies.forEach {
with(dependenciesNode.appendNode("dependency")) {
appendNode("groupId", it.group)
appendNode("artifactId", it.name)
appendNode("version", it.version)
appendNode("scope", scope)
}
}
}
}
Expand Down Expand Up @@ -261,11 +291,9 @@ private class AndroidDsl(project: Project) {
val java = JavaDsl(delegate)

class JavaDsl(main: Any) {
private val delegate = main.javaClass.getDeclaredMethod("getJava").invoke(main)

val srcDirs: Set<File> = delegate.javaClass
.getDeclaredMethod("getSrcDirs")
.invoke(delegate) as Set<File>
val srcDirs = main.javaClass
.getDeclaredMethod("getJavaDirectories")
.invoke(main) as Set<File>
}
}
}
Expand Down Expand Up @@ -300,20 +328,6 @@ private fun Project.signing(action: SigningExtension.() -> Unit) {

// Nexus Staging & Publishing Plugins facade

//private fun Project.nexusStaging(
// packageGroup: String,
// stagingProfileId: String?,
// username: String?,
// password: String?
//) {
// rootProject.extensions.getByName("nexusStaging").withGroovyBuilder {
// setProperty("packageGroup", packageGroup)
// setProperty("stagingProfileId", stagingProfileId)
// setProperty("username", username)
// setProperty("password", password)
// }
//}

private fun Project.nexusPublishing(
packageGroup: String,
stagingProfileId: String?,
Expand Down
29 changes: 22 additions & 7 deletions build-logic/src/main/kotlin/Environment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ enum class SupportedAgp(
AGP_7_1("7.1.0-beta05", gradle = "7.2"),
AGP_7_2("7.2.0-alpha06", gradle = "7.3");

companion object {
val oldest = values().first()
}

val shortVersion: String = run {
// Extract first two components of the Maven dependency's version string.
val components = version.split('.')
Expand All @@ -29,13 +33,14 @@ enum class SupportedAgp(
}

object Android {
const val compileSdkVersion = "android-28"
const val compileSdkVersion = 30
const val javaMaxHeapSize = "3g"

const val targetSdkVersion = 28
const val targetSdkVersion = 30
const val sampleMinSdkVersion = 14
val testRunnerMinSdkVersion = (Artifacts.Instrumentation.Runner.platform as Platform.Android).minSdk
val testCoreMinSdkVersion = (Artifacts.Instrumentation.Core.platform as Platform.Android).minSdk
val testRunnerMinSdkVersion = (Artifacts.Instrumentation.Runner.platform as Android).minSdk
val testCoreMinSdkVersion = (Artifacts.Instrumentation.Core.platform as Android).minSdk
val testComposeMinSdkVersion = (Artifacts.Instrumentation.Compose.platform as Android).minSdk
}


Expand Down Expand Up @@ -92,9 +97,9 @@ object Artifacts {
* Instrumentation Test artifacts
*/
object Instrumentation {
private val groupId = "de.mannodermaus.junit5"
private val currentVersion = "1.3.1-SNAPSHOT"
val latestStableVersion = "1.3.0"
private const val groupId = "de.mannodermaus.junit5"
private const val currentVersion = "1.3.1-SNAPSHOT"
const val latestStableVersion = "1.3.0"

val Core = Deployed(
platform = Android(minSdk = 14),
Expand All @@ -115,6 +120,16 @@ object Artifacts {
license = license,
description = "Runner for integration of instrumented Android tests with JUnit 5."
)

val Compose = Deployed(
platform = Android(minSdk = 21),
groupId = groupId,
artifactId = "android-test-compose",
currentVersion = "1.0.0-SNAPSHOT",
latestStableVersion = "0.1.0-SNAPSHOT",
license = license,
description = "Extensions for Jetpack Compose tests with JUnit 5."
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions build-logic/src/main/kotlin/Tasks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fun Project.configureTestResources() {
// for different versions of the Android Gradle Plugin
tasks.named("processTestResources", Copy::class.java).configure {
val tokens = mapOf(
"COMPILE_SDK_VERSION" to Android.compileSdkVersion,
"COMPILE_SDK_VERSION" to Android.compileSdkVersion.toString(),
"MIN_SDK_VERSION" to Android.sampleMinSdkVersion.toString(),
"TARGET_SDK_VERSION" to Android.targetSdkVersion.toString(),

Expand Down Expand Up @@ -56,7 +56,7 @@ fun Project.configureTestResources() {
"tests source code in Gradle functional tests against AGP ${plugin.version}"
extendsFrom(configurations.getByName("implementation"))

val agpDependency = libs.plugins.android.substringBeforeLast(":")
val agpDependency = libs.plugins.android(plugin).substringBeforeLast(":")
project.dependencies.add(this.name, "${agpDependency}:${plugin.version}")
}
}
Expand Down
9 changes: 9 additions & 0 deletions build-logic/src/main/kotlin/Utilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ fun Project.findLocalPluginJar(): File? {
return localPluginJar
}

/**
* Returns whether or not the Compose library module is included in the project.
* This depends on the presence of the :compose module, which is configured
* in settings.gradle.
*/
val Project.isComposeIncluded: Boolean get() {
return findProject(":compose") != null
}

/* File */

/**
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading