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

Introduce extensions module #309

Merged
merged 2 commits into from
Nov 4, 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
13 changes: 10 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defaults: &defaults
GRADLE_OPTS: -Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.daemon=false -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false

cache_key: &cache_key
key: jars-{{ checksum "plugin/build.gradle.kts" }}-{{ checksum "plugin/android-junit5/build.gradle.kts" }}-{{ checksum "plugin/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "instrumentation/build.gradle.kts" }}-{{ checksum "instrumentation/runner/build.gradle.kts" }}-{{ checksum "instrumentation/sample/build.gradle.kts" }}-{{ checksum "instrumentation/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "build-logic/src/main/kotlin/Environment.kt" }}-{{ checksum "build-logic/src/main/kotlin/Dependencies.kt" }}
key: jars-{{ checksum "plugin/build.gradle.kts" }}-{{ checksum "plugin/android-junit5/build.gradle.kts" }}-{{ checksum "plugin/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "instrumentation/build.gradle.kts" }}-{{ checksum "instrumentation/core/build.gradle.kts" }}-{{ checksum "instrumentation/compose/build.gradle.kts" }}-{{ checksum "instrumentation/extensions/build.gradle.kts" }}-{{ checksum "instrumentation/runner/build.gradle.kts" }}-{{ checksum "instrumentation/sample/build.gradle.kts" }}-{{ checksum "instrumentation/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "build-logic/src/main/kotlin/Environment.kt" }}-{{ checksum "build-logic/src/main/kotlin/Dependencies.kt" }}

commands:
construct_signing_key:
Expand Down Expand Up @@ -42,11 +42,12 @@ jobs:
./gradlew assembleRelease :core:assembleDebug \
:core:assembleDebugAndroidTest \
:compose:assembleDebugAndroidTest \
:extensions:assembleDebug \
:runner:assembleDebug \
:sample:assembleDebug --stacktrace
:sample:assembleDebug --stacktrace
- run:
name: (Instrumentation) Test
command: cd instrumentation && ./gradlew :core:check :runner:check :compose:check --stacktrace
command: cd instrumentation && ./gradlew :core:check :extensions:check :runner:check :compose:check --stacktrace

- save_cache:
<<: *cache_key
Expand Down Expand Up @@ -95,6 +96,9 @@ jobs:
- store_artifacts:
path: test-lab-results
destination: instrumentation-core/test-lab-results
- store_artifacts:
path: instrumentation/extensions/build/reports
destination: instrumentation-extensions
- store_artifacts:
path: instrumentation/runner/build/reports
destination: instrumentation-runner
Expand Down Expand Up @@ -126,6 +130,9 @@ jobs:
- store_artifacts:
path: instrumentation/core/build/publications
destination: instrumentation-core/publications/snapshots
- store_artifacts:
path: instrumentation/extensions/build/publications
destination: instrumentation-extensions/publications/snapshots
- store_artifacts:
path: instrumentation/runner/build/publications
destination: instrumentation-runner/publications/snapshots
Expand Down
21 changes: 0 additions & 21 deletions build-logic/src/main/kotlin/Deployment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@ 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 @@ -127,16 +116,6 @@ 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
88 changes: 49 additions & 39 deletions build-logic/src/main/kotlin/Environment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import Platform.Android
import Platform.Java
import org.gradle.api.Project
import java.io.File
import java.util.*
import java.util.Properties

enum class SupportedAgp(
val version: String,
val gradle: String? = null
val version: String,
val gradle: String? = null
) {
AGP_7_0("7.0.4", gradle = "7.0.2"),
AGP_7_1("7.1.3", gradle = "7.2"),
Expand Down Expand Up @@ -55,13 +55,13 @@ sealed class Platform(val name: String) {
* containing all sorts of configuration related to Maven coordinates, for instance.
*/
class Deployed internal constructor(
val platform: Platform,
val groupId: String,
val artifactId: String,
val currentVersion: String,
val latestStableVersion: String,
val description: String,
val license: String
val platform: Platform,
val groupId: String,
val artifactId: String,
val currentVersion: String,
val latestStableVersion: String,
val description: String,
val license: String
)

object Artifacts {
Expand All @@ -74,24 +74,24 @@ object Artifacts {
* Return null if none can be found
*/
fun from(project: Project) =
when (project.name) {
"core" -> Instrumentation.Core
"runner" -> Instrumentation.Runner
"android-junit5" -> Plugin
else -> null
}
when (project.name) {
"core" -> Instrumentation.Core
"runner" -> Instrumentation.Runner
"android-junit5" -> Plugin
else -> null
}

/**
* Gradle Plugin artifact
*/
val Plugin = Deployed(
platform = Java,
groupId = "de.mannodermaus.gradle.plugins",
artifactId = "android-junit5",
currentVersion = "1.10.0.0-SNAPSHOT",
latestStableVersion = "1.9.3.0",
license = license,
description = "Unit Testing with JUnit 5 for Android."
platform = Java,
groupId = "de.mannodermaus.gradle.plugins",
artifactId = "android-junit5",
currentVersion = "1.10.0.0-SNAPSHOT",
latestStableVersion = "1.9.3.0",
license = license,
description = "Unit Testing with JUnit 5 for Android."
)

/**
Expand All @@ -103,30 +103,40 @@ object Artifacts {
const val latestStableVersion = "1.3.0"

val Core = Deployed(
platform = Android(minSdk = 14),
groupId = groupId,
artifactId = "android-test-core",
currentVersion = currentVersion,
latestStableVersion = latestStableVersion,
license = license,
description = "Extensions for instrumented Android tests with JUnit 5."
platform = Android(minSdk = 14),
groupId = groupId,
artifactId = "android-test-core",
currentVersion = currentVersion,
latestStableVersion = latestStableVersion,
license = license,
description = "Extensions for instrumented Android tests with JUnit 5."
)

val Extensions = Deployed(
platform = Android(minSdk = 14),
groupId = groupId,
artifactId = "android-test-extensions",
currentVersion = currentVersion,
latestStableVersion = latestStableVersion,
license = license,
description = "Optional extensions for instrumented Android tests with JUnit 5."
)

val Runner = Deployed(
platform = Android(minSdk = 14),
groupId = groupId,
artifactId = "android-test-runner",
currentVersion = currentVersion,
latestStableVersion = latestStableVersion,
license = license,
description = "Runner for integration of instrumented Android tests with JUnit 5."
platform = Android(minSdk = 14),
groupId = groupId,
artifactId = "android-test-runner",
currentVersion = currentVersion,
latestStableVersion = latestStableVersion,
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",
currentVersion = currentVersion,
latestStableVersion = "1.0.0-SNAPSHOT",
license = license,
description = "Extensions for Jetpack Compose tests with JUnit 5."
Expand Down Expand Up @@ -166,5 +176,5 @@ class DeployedCredentials(private val project: Project) {
}

private fun Properties.getOrEnvvar(key: String): String? =
getProperty(key, System.getenv(key))
getProperty(key, System.getenv(key))
}
9 changes: 0 additions & 9 deletions build-logic/src/main/kotlin/Utilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,6 @@ 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.

1 change: 1 addition & 0 deletions instrumentation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Change Log
- Only autoconfigure JUnit 5 for instrumentation tests when the user explicitly adds junit-jupiter-api as a dependency
- Prevent noisy logs in Logcat complaining about unresolvable annotation classes (#306)
- Add support for parallel execution of non-UI instrumentation tests (#295)
- Introduce `android-test-extensions` artifact with optional extensions, starting with a port of JUnit 4's `GrantPermissionRule` (#251)

## 1.3.0 (2021-09-17)

Expand Down
10 changes: 10 additions & 0 deletions instrumentation/extensions/api/extensions.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public final class de/mannodermaus/junit5/extensions/GrantPermissionExtension : org/junit/jupiter/api/extension/BeforeEachCallback {
public static final field Companion Lde/mannodermaus/junit5/extensions/GrantPermissionExtension$Companion;
public fun beforeEach (Lorg/junit/jupiter/api/extension/ExtensionContext;)V
public static final fun grant ([Ljava/lang/String;)Lde/mannodermaus/junit5/extensions/GrantPermissionExtension;
}

public final class de/mannodermaus/junit5/extensions/GrantPermissionExtension$Companion {
public final fun grant ([Ljava/lang/String;)Lde/mannodermaus/junit5/extensions/GrantPermissionExtension;
}

93 changes: 93 additions & 0 deletions instrumentation/extensions/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import libs.plugins.android
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

buildscript {
repositories {
google()
mavenCentral()
sonatypeSnapshots()
}

dependencies {
val latest = Artifacts.Plugin.latestStableVersion
classpath("de.mannodermaus.gradle.plugins:android-junit5:$latest")
}
}

plugins {
id("com.android.library")
kotlin("android")
id("explicit-api-mode")
}

apply {
plugin("de.mannodermaus.android-junit5")
}

val javaVersion = JavaVersion.VERSION_1_8

android {
compileSdk = Android.compileSdkVersion

defaultConfig {
minSdk = Android.testRunnerMinSdkVersion
targetSdk = Android.targetSdkVersion
}

compileOptions {
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
}

buildFeatures {
buildConfig = false
resValues = false
}

lint {
// JUnit 4 refers to java.lang.management APIs, which are absent on Android.
warning("InvalidPackage")
}

packagingOptions {
resources.excludes.add("META-INF/LICENSE.md")
resources.excludes.add("META-INF/LICENSE-notice.md")
}

testOptions {
unitTests.isReturnDefaultValues = true
}
}

tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = javaVersion.toString()
}

tasks.withType<Test> {
failFast = true
testLogging {
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
exceptionFormat = TestExceptionFormat.FULL
}
}

configurations.all {
// The Instrumentation Test Runner uses the plugin,
// which in turn provides the Instrumentation Test Runner again -
// that's kind of deep.
// To avoid conflicts, prefer using the local classes
// and exclude the dependency from being pulled in externally.
exclude(module = Artifacts.Instrumentation.Extensions.artifactId)
}

dependencies {
implementation(libs.androidXTestRunner)
implementation(libs.junitJupiterApi)

testImplementation(project(":testutil"))
testRuntimeOnly(libs.junitJupiterEngine)
}

project.configureDeployment(Artifacts.Instrumentation.Extensions)
1 change: 1 addition & 0 deletions instrumentation/extensions/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="de.mannodermaus.junit5.extensions"/>
Loading
Loading