diff --git a/.github/workflows/gradle-build.yml b/.github/workflows/gradle-build.yml index 6d009949..bbbab046 100644 --- a/.github/workflows/gradle-build.yml +++ b/.github/workflows/gradle-build.yml @@ -5,17 +5,23 @@ jobs: name: "Building" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: gradle/actions/wrapper-validation@v4 - - name: "Set up JDK 11" - uses: actions/setup-java@v4 + - uses: actions/checkout@v6 + - uses: gradle/actions/wrapper-validation@v5 + - name: "Set up JDK 17" + uses: actions/setup-java@v5 with: distribution: 'temurin' - java-version: '11' - - uses: gradle/actions/setup-gradle@v4 + java-version: '17' + - uses: gradle/actions/setup-gradle@v5 name: Setup Gradle - name: Check Fladle run: ./gradlew assembleDebug assembleDebugAndroidTest printYml check :fladle-plugin:check - name: Publish Snapshot if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }} - run: ./gradlew :fladle-plugin:publishAllPublicationsToMavenRepository -Pfladle.releaseMode -PsonatypeUsername=${{ secrets.SONATYPE_USERNAME }} -PsonatypePassword=${{ secrets.SONATYPE_PASSWORD }} + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.GPG_SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }} + run: ./gradlew :fladle-plugin:publishToMavenCentral --no-configuration-cache diff --git a/.github/workflows/gradle-release.yml b/.github/workflows/gradle-release.yml new file mode 100644 index 00000000..6565d5bb --- /dev/null +++ b/.github/workflows/gradle-release.yml @@ -0,0 +1,40 @@ +name: "Release" +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + release: + name: "Publish Release" + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-java@v5 + with: + java-version: "17" + distribution: "temurin" + - uses: gradle/actions/setup-gradle@v5 + - name: Publish to Maven Central + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.GPG_SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }} + run: ./gradlew :fladle-plugin:publishToMavenCentral --no-configuration-cache + - name: Publish to Gradle Plugin Portal + env: + GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} + GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_SIGNING_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.GPG_SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }} + run: ./gradlew :fladle-plugin:publishPlugins + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + run: gh release create "${{ github.ref_name }}" --generate-notes diff --git a/.github/workflows/mkdocs-deploy.yml b/.github/workflows/mkdocs-deploy.yml index 959ef67e..099a4d32 100644 --- a/.github/workflows/mkdocs-deploy.yml +++ b/.github/workflows/mkdocs-deploy.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout master - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Deploy docs uses: mhausenblas/mkdocs-deploy-gh-pages@1.26 diff --git a/android-library-no-tests/build.gradle.kts b/android-library-no-tests/build.gradle.kts index bed1b75d..76dda11f 100644 --- a/android-library-no-tests/build.gradle.kts +++ b/android-library-no-tests/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("com.android.library") - kotlin("android") } android { @@ -11,14 +10,14 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/build.gradle b/build.gradle index 4a0d6896..710a2a98 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,6 @@ buildscript { plugins { alias(libs.plugins.agp) apply false - alias(libs.plugins.kgp) apply false alias(libs.plugins.ben.manes.versions) id "com.osacky.fulladle" alias(libs.plugins.kotlinter) @@ -22,7 +21,7 @@ fladle { } tasks.wrapper.configure { - gradleVersion = '8.13' + gradleVersion = '9.4.0' } def isNonStable = { String version -> diff --git a/docs/changelog.md b/docs/changelog.md index c7095960..a97f61a9 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,18 @@ ## Unreleased +## 0.21.0 +* Minimum required Gradle version is now 9.1 +* Fixed support for Android Gradle Plugin version 9.0.1 + +## 0.20.0 +* Botched release. Do not use. + +## 0.19.0 +* Minimum required JVM version is now 17. +* Minimum supported Gradle version is now 7.3. +* Fix support for Gradle 9.0.0. [PR](https://github.com/runningcode/fladle/pull/452) Thanks [kevinguitar](https://github.com/kevinguitar) + ## 0.18.0 * Use non-deprecated device models and versions in default config. [PR](https://github.com/runningcode/fladle/pull/446) Thanks [Kaibolay](https://github.com/kaibolay) diff --git a/docs/releasing.md b/docs/releasing.md index 570fe6ce..10ec8351 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -36,18 +36,15 @@ git tag v{{ fladle.next_release }} git push origin v{{ fladle.next_release }} ``` -* Upload to Maven Central -``` bash -./gradlew :fladle-plugin:publishAllPublicationsToMavenRepository -Pfladle.releaseMode -Dorg.gradle.internal.publish.checksums.insecure=true -``` -* Upload to Gradle Plugin Portal -```bash -./gradlew :fladle-plugin:publishPlugins -Pfladle.releaseMode -Dorg.gradle.internal.publish.checksums.insecure=true -``` +Pushing the tag automatically triggers the [release workflow](https://github.com/runningcode/fladle/actions/workflows/gradle-release.yml) which: + +1. Publishes to Maven Central +2. Publishes to Gradle Plugin Portal +3. Creates a GitHub Release with auto-generated notes * Release to Maven Central - * Login to Sonatype OSS Nexus: [https://oss.sonatype.org/](https://oss.sonatype.org/) - * Click on **Staging Repositories** + * Login to Maven Central Repository: [https://central.sonatype.com/](https://central.sonatype.com/) + * Click on **Publish** * Merge the release branch to master ``` diff --git a/fladle-plugin/build.gradle.kts b/fladle-plugin/build.gradle.kts index d0bfac50..0f045edf 100644 --- a/fladle-plugin/build.gradle.kts +++ b/fladle-plugin/build.gradle.kts @@ -1,7 +1,7 @@ import org.gradle.api.tasks.testing.logging.TestLogEvent group = "com.osacky.flank.gradle" -version = "0.19.0" +version = "0.21.0" description = "Easily Scale your Android Instrumentation Tests with Firebase Test Lab with Flank" repositories { @@ -15,22 +15,21 @@ plugins { `java-gradle-plugin` alias(libs.plugins.gradle.plugin.publish) alias(libs.plugins.kotlinter) - `maven-publish` - signing + alias(libs.plugins.vanniktech.publish) } -// See https://github.com/slackhq/keeper/pull/11#issuecomment-579544375 for context -val isReleaseMode : Boolean = hasProperty("fladle.releaseMode") - dependencies { compileOnly(gradleApi()) - if (isReleaseMode) { - compileOnly(libs.agp) - } else { - implementation(libs.agp) + compileOnly(libs.agp) { + exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable") + exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-runner") } compileOnly(libs.gradle.enterprise) + // AGP must be on the runtime classpath so GradleTestKit's withPluginClasspath() + // can resolve the com.android.application and com.android.library plugins. + runtimeOnly(libs.agp) + testImplementation(gradleTestKit()) testImplementation(libs.junit) testImplementation(libs.truth) @@ -57,66 +56,37 @@ gradlePlugin { } } -val isReleaseBuild : Boolean = !version.toString().endsWith("SNAPSHOT") +java { + withJavadocJar() + withSourcesJar() +} -val sonatypeUsername : String? by project -val sonatypePassword : String? by project +mavenPublishing { + publishToMavenCentral() + signAllPublications() -publishing { - repositories { - repositories { - maven { - val releasesRepoUrl = uri("https://central.sonatype.com/api/v1/publisher/deployments/upload/") - val snapshotsRepoUrl = uri("https://central.sonatype.com/repository/maven-snapshots/") - url = if (isReleaseBuild) releasesRepoUrl else snapshotsRepoUrl - credentials { - username = sonatypeUsername - password = sonatypePassword - } + pom { + name.set("Fladle") + description.set(project.description) + url.set("https://github.com/runningcode/fladle") + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") } } - } - publications { - afterEvaluate { - named("fladlePluginMarkerMaven") { - pom.configureForFladle("Fladle") - } - - named("pluginMaven") { - pom.configureForFladle("Fladle") - } - named("fulladlePluginMarkerMaven") { - pom.configureForFladle("Fulladle") + developers { + developer { + id.set("runningcode") + name.set("Nelson Osacky") } } - } -} - -signing { - isRequired = isReleaseBuild -} - -fun org.gradle.api.publish.maven.MavenPom.configureForFladle(pluginName: String) { - name.set(pluginName) - description.set(project.description) - url.set("https://github.com/runningcode/fladle") - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + scm { + connection.set("scm:git:git://github.com/runningcode/fladle.git") + developerConnection.set("scm:git:ssh://github.com/runningcode/fladle.git") + url.set("https://github.com/runningcode/fladle") } } - developers { - developer { - id.set("runningcode") - name.set("Nelson Osacky") - } - } - scm { - connection.set("scm:git:git://github.com/runningcode/fladle.git") - developerConnection.set("scm:git:ssh://github.com/runningcode/fladle.git") - url.set("https://github.com/runningcode/fladle") - } } tasks.withType(Test::class.java).configureEach { @@ -132,17 +102,17 @@ tasks.withType(ValidatePlugins::class.java).configureEach { enableStricterValidation.set(true) } -// Ensure Java 11 Compatibility. See https://github.com/runningcode/fladle/issues/246 +// Ensure Java 17 Compatibility. See https://github.com/runningcode/fladle/issues/246 tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java).configureEach { - kotlinOptions { - jvmTarget = "11" - languageVersion = "1.7" - apiVersion = "1.7" + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) + apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0) } } java { toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) + languageVersion.set(JavaLanguageVersion.of(17)) } } diff --git a/fladle-plugin/settings.gradle.kts b/fladle-plugin/settings.gradle.kts index 528a0fa6..09608f5d 100644 --- a/fladle-plugin/settings.gradle.kts +++ b/fladle-plugin/settings.gradle.kts @@ -1,5 +1,9 @@ rootProject.name = "fladle" +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + dependencyResolutionManagement { versionCatalogs { create("libs") { diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladleConfig.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladleConfig.kt index 869a9938..d6721998 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladleConfig.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladleConfig.kt @@ -51,13 +51,11 @@ interface FladleConfig { @get:Input val testTargets: ListProperty + // The maximum number of shards. Value will be overwritten by [maxTestShards] if both used in configuration @Deprecated( message = "testShards is deprecated. Use maxTestShards instead", replaceWith = ReplaceWith("maxTestShards"), ) - /** - * The maximum number of shards. Value will be overwritten by [maxTestShards] if both used in configuration - */ @get:Input @get:Optional val testShards: Property @@ -473,7 +471,8 @@ interface FladleConfig { @Internal fun getPresentProperties() = - this::class.memberProperties + this::class + .memberProperties .filter { when (val prop = it.call(this)) { is Property<*> -> prop.isPresent diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt index ea878e0f..44873cd9 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FladlePluginDelegate.kt @@ -1,14 +1,15 @@ package com.osacky.flank.gradle -import com.android.build.gradle.AppExtension -import com.android.build.gradle.TestedExtension -import com.android.build.gradle.internal.tasks.factory.dependsOn -import com.android.builder.model.TestOptions +import com.android.build.api.dsl.ApplicationExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension +import com.android.build.api.variant.FilterConfiguration +import com.android.build.api.variant.HasAndroidTest import com.osacky.flank.gradle.validation.checkForExclusionUsage import com.osacky.flank.gradle.validation.validateOptionsUsed import org.gradle.api.GradleException import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.plugins.BasePluginExtension import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.create import org.gradle.util.GradleVersion @@ -24,7 +25,10 @@ class FladlePluginDelegate { target.tasks.register("flankAuth", FlankJavaExec::class.java) { doFirst { - target.layout.fladleDir.get().asFile.mkdirs() + target.layout.fladleDir + .get() + .asFile + .mkdirs() } classpath = project.fladleConfig args = listOf("auth", "login") @@ -34,7 +38,6 @@ class FladlePluginDelegate { } private fun checkMinimumGradleVersion() { - // Gradle 4.9 is required because we use the lazy task configuration API. if (GRADLE_MIN_VERSION > GradleVersion.current()) { throw GradleException("Fladle requires at minimum version $GRADLE_MIN_VERSION. Detected version ${GradleVersion.current()}.") } @@ -44,24 +47,22 @@ class FladlePluginDelegate { project: Project, base: FlankGradleExtension, ) { - if (GradleVersion.current() > GradleVersion.version("6.1")) { - base.flankVersion.finalizeValueOnRead() - base.flankCoordinates.finalizeValueOnRead() - base.serviceAccountCredentials.finalizeValueOnRead() + base.flankVersion.finalizeValueOnRead() + base.flankCoordinates.finalizeValueOnRead() + base.serviceAccountCredentials.finalizeValueOnRead() + + // Register onVariants callbacks before afterEvaluate for APK path detection + project.pluginManager.withPlugin("com.android.application") { + if (!base.debugApk.isPresent || !base.instrumentationApk.isPresent) { + findDebugAndInstrumentationApk(project, base) + } } + project.afterEvaluate { // Add Flank dependency to Fladle Configuration // Must be done afterEvaluate otherwise extension values will not be set. project.dependencies.add(FLADLE_CONFIG, "${base.flankCoordinates.get()}:${base.flankVersion.get()}") - // Only use automatic apk path detection for 'com.android.application' projects. - project.pluginManager.withPlugin("com.android.application") { - // This doesn't work properly for multiple configs since they likely are inheriting the config from root already. See #60 https://github.com/runningcode/fladle/issues/60 - if (!base.debugApk.isPresent || !base.instrumentationApk.isPresent) { - findDebugAndInstrumentationApk(project, base) - } - } - tasks.apply { createTasksForConfig(base, base, project, "") @@ -95,14 +96,21 @@ class FladlePluginDelegate { val writeConfigProps = register("writeConfigProps$name", YamlConfigWriterTask::class.java, base, config, name) - writeConfigProps.dependsOn(validateFladle) + writeConfigProps.configure { dependsOn(validateFladle) } register("printYml$name") { description = "Print the flank.yml file to the console." group = TASK_GROUP dependsOn(writeConfigProps) doLast { - println(writeConfigProps.get().fladleConfigFile.get().asFile.readText()) + println( + writeConfigProps + .get() + .fladleConfigFile + .get() + .asFile + .readText(), + ) } } @@ -110,7 +118,19 @@ class FladlePluginDelegate { if (useDefaultDir) setUpWorkingDir(configName) description = "Finds problems with the current configuration." classpath = project.fladleConfig - args = listOf("firebase", "test", "android", "doctor", "-c", writeConfigProps.get().fladleConfigFile.get().asFile.absolutePath) + args = + listOf( + "firebase", + "test", + "android", + "doctor", + "-c", + writeConfigProps + .get() + .fladleConfigFile + .get() + .asFile.absolutePath, + ) dependsOn(writeConfigProps) } @@ -122,13 +142,30 @@ class FladlePluginDelegate { args = if (project.hasProperty("dumpShards")) { listOf( - "firebase", "test", "android", "run", "-c", - writeConfigProps.get().fladleConfigFile.get().asFile.absolutePath, "--dump-shards", + "firebase", + "test", + "android", + "run", + "-c", + writeConfigProps + .get() + .fladleConfigFile + .get() + .asFile.absolutePath, + "--dump-shards", ) } else { listOf( - "firebase", "test", "android", "run", "-c", - writeConfigProps.get().fladleConfigFile.get().asFile.absolutePath, + "firebase", + "test", + "android", + "run", + "-c", + writeConfigProps + .get() + .fladleConfigFile + .get() + .asFile.absolutePath, ) } if (config.serviceAccountCredentials.isPresent) { @@ -136,17 +173,15 @@ class FladlePluginDelegate { } dependsOn(writeConfigProps) if (config.dependOnAssemble.isPresent && config.dependOnAssemble.get()) { - val testedExtension = - requireNotNull(project.extensions.findByType(TestedExtension::class.java)) { "Could not find TestedExtension in ${project.name}" } - testedExtension.testVariants.configureEach { - if (testedVariant.isExpectedVariant(config)) { - if (testedVariant.assembleProvider.isPresent) { - dependsOn(testedVariant.assembleProvider) - } - if (assembleProvider.isPresent) { - dependsOn(assembleProvider) - } - } + // Find assemble tasks by convention name pattern + val variantName = config.variant.orNull + if (variantName != null) { + val capitalizedVariant = variantName.capitalize() + dependsOn("assemble$capitalizedVariant") + dependsOn("assemble${capitalizedVariant}AndroidTest") + } else { + dependsOn("assembleDebug") + dependsOn("assembleDebugAndroidTest") } } if (config.localResultsDir.hasValue) { @@ -172,16 +207,17 @@ class FladlePluginDelegate { private fun automaticallyConfigureTestOrchestrator( project: Project, config: FladleConfig, - androidExtension: AppExtension, + androidExtension: ApplicationExtension, ) { project.afterEvaluate { + val execution = androidExtension.testOptions.execution.uppercase() val useOrchestrator = - androidExtension.testOptions.getExecutionEnum() == TestOptions.Execution.ANDROIDX_TEST_ORCHESTRATOR || - androidExtension.testOptions.getExecutionEnum() == TestOptions.Execution.ANDROID_TEST_ORCHESTRATOR + execution == "ANDROIDX_TEST_ORCHESTRATOR" || + execution == "ANDROID_TEST_ORCHESTRATOR" if (useOrchestrator) { log("Automatically detected the use of Android Test Orchestrator") + config.useOrchestrator.set(true) } - config.useOrchestrator.set(useOrchestrator) } } @@ -189,28 +225,77 @@ class FladlePluginDelegate { project: Project, config: FladleConfig, ) { - val baseExtension = - requireNotNull(project.extensions.findByType(AppExtension::class.java)) { "Could not find AppExtension in ${project.name}" } - automaticallyConfigureTestOrchestrator(project, config, baseExtension) - baseExtension.testVariants.configureEach { - val appVariant = testedVariant - outputs.configureEach test@{ - appVariant.outputs - .matching { it.isExpectedAbiOutput(config) } - .configureEach app@{ - if (appVariant.isExpectedVariant(config)) { - if (!config.debugApk.isPresent) { - // Don't set debug apk if not already set. #172 - project.log("Configuring fladle.debugApk from variant ${this@app.name}") - config.debugApk.set(this@app.outputFile.absolutePath) - } - if (!config.roboScript.isPresent && !config.instrumentationApk.isPresent && !config.sanityRobo.get()) { - // Don't set instrumentation apk if not already set. #172 - project.log("Configuring fladle.instrumentationApk from variant ${this@test.name}") - config.instrumentationApk.set(this@test.outputFile.absolutePath) - } - } + val androidExtension = + requireNotNull( + project.extensions.findByType(ApplicationExtension::class.java), + ) { "Could not find ApplicationExtension in ${project.name}" } + automaticallyConfigureTestOrchestrator(project, config, androidExtension) + + val androidComponents = + requireNotNull(project.extensions.findByType(ApplicationAndroidComponentsExtension::class.java)) { + "Could not find ApplicationAndroidComponentsExtension in ${project.name}" + } + + androidComponents.onVariants { variant -> + if (!variant.isExpectedVariant(config)) return@onVariants + val androidTest = (variant as? HasAndroidTest)?.androidTest ?: return@onVariants + + val buildType = variant.buildType ?: return@onVariants + val flavorName = variant.productFlavors.joinToString("") { it.second } + val flavorPath = variant.productFlavors.joinToString("/") { it.second } + val archivesName = + project.extensions + .getByType(BasePluginExtension::class.java) + .archivesName + .get() + val buildDir = project.layout.buildDirectory + + // Test APK path + val testApkDirPath = if (flavorPath.isNotEmpty()) "androidTest/$flavorPath/$buildType" else "androidTest/$buildType" + val testApkFileName = + if (flavorName.isNotEmpty()) { + "$archivesName-$flavorName-$buildType-androidTest.apk" + } else { + "$archivesName-$buildType-androidTest.apk" + } + val testApkPath = + buildDir + .file("outputs/apk/$testApkDirPath/$testApkFileName") + .get() + .asFile + .absolutePath + + variant.outputs.forEach { output -> + if (!output.isExpectedAbiOutput(config)) return@forEach + + val abiFilter = output.filters.firstOrNull { it.filterType == FilterConfiguration.FilterType.ABI } + val abiName = abiFilter?.identifier + + val appApkDirPath = if (flavorPath.isNotEmpty()) "$flavorPath/$buildType" else buildType + val appApkFileName = + buildString { + append(archivesName) + if (flavorName.isNotEmpty()) append("-$flavorName") + if (abiName != null) append("-$abiName") + append("-$buildType.apk") } + val appApkPath = + buildDir + .file("outputs/apk/$appApkDirPath/$appApkFileName") + .get() + .asFile + .absolutePath + + if (!config.debugApk.isPresent) { + // Don't set debug apk if not already set. #172 + project.log("Configuring fladle.debugApk from variant ${variant.name}") + config.debugApk.set(appApkPath) + } + if (!config.roboScript.isPresent && !config.instrumentationApk.isPresent && !config.sanityRobo.get()) { + // Don't set instrumentation apk if not already set. #172 + project.log("Configuring fladle.instrumentationApk from variant ${variant.name}") + config.instrumentationApk.set(testApkPath) + } } } } @@ -219,7 +304,7 @@ class FladlePluginDelegate { get() = configurations.getByName(FLADLE_CONFIG) companion object { - val GRADLE_MIN_VERSION: GradleVersion = GradleVersion.version("6.5") + val GRADLE_MIN_VERSION: GradleVersion = GradleVersion.version("9.1") const val TASK_GROUP = "fladle" const val FLADLE_CONFIG = "fladle" diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankExecutionTask.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankExecutionTask.kt index 168c5712..2518ff9d 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankExecutionTask.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankExecutionTask.kt @@ -8,7 +8,7 @@ import javax.inject.Inject @DisableCachingByDefault( because = "Flank executions are dependent on resources such as network connection and server and therefore cannot be cached.", ) -open class FlankExecutionTask +abstract class FlankExecutionTask @Inject constructor( projectLayout: ProjectLayout, @@ -22,7 +22,12 @@ open class FlankExecutionTask private fun checkFilesExist(base: FladleConfig) { if (base.serviceAccountCredentials.isPresent) { - check(base.serviceAccountCredentials.get().asFile.exists()) { + check( + base.serviceAccountCredentials + .get() + .asFile + .exists(), + ) { "serviceAccountCredential file doesn't exist ${base.serviceAccountCredentials.get()}" } } diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt index 19c0f938..25b496d1 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankGradleExtension.kt @@ -16,7 +16,9 @@ import javax.inject.Inject open class FlankGradleExtension @Inject - constructor(objects: ObjectFactory) : FladleConfig { + constructor( + objects: ObjectFactory, + ) : FladleConfig { companion object { const val FLANK_VERSION = "23.10.1" } diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankJavaExec.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankJavaExec.kt index f10ef850..21bb73aa 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankJavaExec.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FlankJavaExec.kt @@ -8,9 +8,11 @@ import javax.inject.Inject @DisableCachingByDefault( because = "Flank executions are dependent on resources such as network connection and server and therefore cannot be cached.", ) -open class FlankJavaExec +abstract class FlankJavaExec @Inject - constructor(projectLayout: ProjectLayout) : JavaExec() { + constructor( + projectLayout: ProjectLayout, + ) : JavaExec() { init { group = FladlePluginDelegate.TASK_GROUP mainClass.set("ftl.Main") diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladleModuleExtension.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladleModuleExtension.kt index 510f5f54..e6637bd1 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladleModuleExtension.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladleModuleExtension.kt @@ -9,7 +9,9 @@ import javax.inject.Inject open class FulladleModuleExtension @Inject - constructor(objects: ObjectFactory) { + constructor( + objects: ObjectFactory, + ) { /** * When set to false, Fulladle will not automatically add this module to additionalTestApks. * @@ -46,4 +48,10 @@ open class FulladleModuleExtension * can be a match. */ val variant: Property = objects.property().convention(null as String?) + + /** + * Variant APK info collected during configuration via onVariants callbacks. + * Used by FulladlePlugin at execution time to build YAML entries. + */ + internal val variantApks: MutableList = mutableListOf() } diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladlePlugin.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladlePlugin.kt index 568feebb..59be14be 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladlePlugin.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/FulladlePlugin.kt @@ -1,8 +1,12 @@ package com.osacky.flank.gradle -import com.android.build.gradle.TestedExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension +import com.android.build.api.variant.FilterConfiguration +import com.android.build.api.variant.HasAndroidTest +import com.android.build.api.variant.LibraryAndroidComponentsExtension import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.plugins.BasePluginExtension import org.gradle.kotlin.dsl.getByType /** @@ -18,23 +22,107 @@ class FulladlePlugin : Plugin { root.subprojects { // Yuck, cross project configuration extensions.create("fulladleModuleConfig", FulladleModuleExtension::class.java) + + // Register onVariants callbacks to capture APK info during configuration + pluginManager.withPlugin("com.android.application") { + val androidComponents = extensions.getByType(ApplicationAndroidComponentsExtension::class.java) + val ext = extensions.findByType(FulladleModuleExtension::class.java) ?: return@withPlugin + androidComponents.onVariants { variant -> + val androidTest = (variant as? HasAndroidTest)?.androidTest ?: return@onVariants + val buildType = variant.buildType ?: return@onVariants + val flavorName = variant.productFlavors.joinToString("") { it.second } + val flavorPath = variant.productFlavors.joinToString("/") { it.second } + val archivesName = extensions.getByType(BasePluginExtension::class.java).archivesName.get() + + variant.outputs.forEach { output -> + val abiFilter = output.filters.firstOrNull { it.filterType == FilterConfiguration.FilterType.ABI } + val abiName = abiFilter?.identifier + + val appApkDirPath = if (flavorPath.isNotEmpty()) "$flavorPath/$buildType" else buildType + val appApkFileName = + buildString { + append(archivesName) + if (flavorName.isNotEmpty()) append("-$flavorName") + if (abiName != null) append("-$abiName") + append("-$buildType.apk") + } + val appApkPath = + layout.buildDirectory + .file("outputs/apk/$appApkDirPath/$appApkFileName") + .get() + .asFile.absolutePath + + val testApkDirPath = + if (flavorPath.isNotEmpty()) "androidTest/$flavorPath/$buildType" else "androidTest/$buildType" + val testApkFileName = + if (flavorName.isNotEmpty()) { + "$archivesName-$flavorName-$buildType-androidTest.apk" + } else { + "$archivesName-$buildType-androidTest.apk" + } + val testApkPath = + layout.buildDirectory + .file("outputs/apk/$testApkDirPath/$testApkFileName") + .get() + .asFile.absolutePath + + ext.variantApks.add( + VariantApkInfo( + variantName = variant.name, + appApkPath = appApkPath, + testApkPath = testApkPath, + abiName = abiName, + ), + ) + } + } + } + + pluginManager.withPlugin("com.android.library") { + val androidComponents = extensions.getByType(LibraryAndroidComponentsExtension::class.java) + val ext = extensions.findByType(FulladleModuleExtension::class.java) ?: return@withPlugin + androidComponents.onVariants { variant -> + val androidTest = (variant as? HasAndroidTest)?.androidTest ?: return@onVariants + val buildType = variant.buildType ?: return@onVariants + val flavorName = variant.productFlavors.joinToString("") { it.second } + val flavorPath = variant.productFlavors.joinToString("/") { it.second } + val archivesName = extensions.getByType(BasePluginExtension::class.java).archivesName.get() + + val testApkDirPath = + if (flavorPath.isNotEmpty()) "androidTest/$flavorPath/$buildType" else "androidTest/$buildType" + val testApkFileName = + if (flavorName.isNotEmpty()) { + "$archivesName-$flavorName-$buildType-androidTest.apk" + } else { + "$archivesName-$buildType-androidTest.apk" + } + val testApkPath = + layout.buildDirectory + .file("outputs/apk/$testApkDirPath/$testApkFileName") + .get() + .asFile.absolutePath + + ext.variantApks.add( + VariantApkInfo( + variantName = variant.name, + appApkPath = null, + testApkPath = testApkPath, + abiName = null, + ), + ) + } + } } val fulladleConfigureTask = root.tasks.register("configureFulladle") { var modulesEnabled = false - /** - * we will first configure all app modules - * then configure all library modules - * we force this order of configuration because - * app modules are better candidates to become - * root level test/app APKs, since they produce - * app APKs - * if no app module had tests or was enabled - * we will choose a library module to become - * a root level module, in which case we will - * have to check if it has its debugApk set - */ + // We first configure all app modules, then configure all library modules. + // We force this order because app modules are better candidates to become + // root level test/app APKs, since they produce app APKs. + // If no app module had tests or was enabled, we will choose a library module + // to become a root level module, in which case we will have to check if it + // has its debugApk set. doLast { // first configure all app modules root.subprojects { @@ -86,82 +174,80 @@ fun configureModule( return } - val testedExtension = extensions.findByType(TestedExtension::class.java) ?: return // Only configure the first test variant per module. // Does anyone test more than one variant per module? var addedTestsForModule = false - testedExtension.testVariants.configureEach testVariant@{ - if (this.isExpectedVariantInModule(fulladleModuleExtension)) { - testedVariant.outputs - .matching { it.isExpectedAbiOutput(flankGradleExtension) } - .configureEach app@{ - if (addedTestsForModule) { - return@app - } - this@testVariant.outputs.configureEach test@{ - val yml = StringBuilder() - // If the debugApk isn't yet set, let's use this one. - if (!flankGradleExtension.debugApk.isPresent) { - if (project.isAndroidAppModule) { - // app modules produce app apks that we can consume - flankGradleExtension.debugApk.set(rootProject.provider { this@app.outputFile.absolutePath }) - } else if (project.isAndroidLibraryModule) { - // library modules do not produce an app apk and we'll use the one specified in fulladleModuleConfig block - // we need library modules to specify the app apk to test against, even if it's a dummy one - check(fulladleModuleExtension.debugApk.isPresent && fulladleModuleExtension.debugApk.orNull != null) { - "Library module ${project.path} did not specify a debug apk. Library modules do not " + - "generate a debug apk and one needs to be specified in the fulladleModuleConfig block\n" + - "This is a required parameter in FTL which remains unused for library modules under test, " + - "and you can use a dummy apk here" - } - flankGradleExtension.debugApk.set(rootProject.provider { fulladleModuleExtension.debugApk.get() }) - } - } else { - // Otherwise, let's just add it to the list. - if (project.isAndroidAppModule) { - yml.appendLine("- app: ${this@app.outputFile}") - } else if (project.isAndroidLibraryModule) { - // app apk is not required for library modules so only use if it's explicitly specified - if (fulladleModuleExtension.debugApk.orNull != null) { - yml.appendLine("- app: ${fulladleModuleExtension.debugApk.get()}") - } - } - } + for (variantInfo in fulladleModuleExtension.variantApks) { + if (addedTestsForModule) break - // If the instrumentation apk isn't yet set, let's use this one. - if (!flankGradleExtension.instrumentationApk.isPresent) { - flankGradleExtension.instrumentationApk.set(rootProject.provider { this@test.outputFile.absolutePath }) - } else { - // Otherwise, let's just add it to the list. - if (yml.isBlank()) { - // The first item in the list needs to start with a ` - `. - yml.appendLine("- test: ${this@test.outputFile}") - } else { - yml.appendLine(" test: ${this@test.outputFile}") - } - } + if (!variantInfo.isExpectedVariantInModule(fulladleModuleExtension)) continue - if (yml.isEmpty()) { - // this is the root module - // should not be added as additional test apk - overrideRootLevelConfigs(flankGradleExtension, fulladleModuleExtension) - } else { - yml.appendProperty(fulladleModuleExtension.maxTestShards, " max-test-shards") - yml.appendMapProperty( - fulladleModuleExtension.clientDetails, - " client-details", - ) { appendLine(" ${it.key}: ${it.value}") } - yml.appendMapProperty( - fulladleModuleExtension.environmentVariables, - " environment-variables", - ) { appendLine(" ${it.key}: ${it.value}") } - flankGradleExtension.additionalTestApks.add(yml.toString()) - } - addedTestsForModule = true - } + // Check ABI filter against the extension + if (flankGradleExtension.abi.isPresent && variantInfo.abiName != null && variantInfo.abiName != flankGradleExtension.abi.get()) continue + if (flankGradleExtension.abi.isPresent && variantInfo.abiName == null) { + // No ABI filter on this output - it's a match (universal) + } + + val yml = StringBuilder() + // If the debugApk isn't yet set, let's use this one. + if (!flankGradleExtension.debugApk.isPresent) { + if (project.isAndroidAppModule && variantInfo.appApkPath != null) { + // app modules produce app apks that we can consume + flankGradleExtension.debugApk.set(rootProject.provider { variantInfo.appApkPath }) + } else if (project.isAndroidLibraryModule) { + // library modules do not produce an app apk and we'll use the one specified in fulladleModuleConfig block + // we need library modules to specify the app apk to test against, even if it's a dummy one + check(fulladleModuleExtension.debugApk.isPresent && fulladleModuleExtension.debugApk.orNull != null) { + "Library module ${project.path} did not specify a debug apk. Library modules do not " + + "generate a debug apk and one needs to be specified in the fulladleModuleConfig block\n" + + "This is a required parameter in FTL which remains unused for library modules under test, " + + "and you can use a dummy apk here" } + flankGradleExtension.debugApk.set(rootProject.provider { fulladleModuleExtension.debugApk.get() }) + } + } else { + // Otherwise, let's just add it to the list. + if (project.isAndroidAppModule && variantInfo.appApkPath != null) { + yml.appendLine("- app: ${variantInfo.appApkPath}") + } else if (project.isAndroidLibraryModule) { + // app apk is not required for library modules so only use if it's explicitly specified + if (fulladleModuleExtension.debugApk.orNull != null) { + yml.appendLine("- app: ${fulladleModuleExtension.debugApk.get()}") + } + } + } + + // If the instrumentation apk isn't yet set, let's use this one. + if (!flankGradleExtension.instrumentationApk.isPresent) { + flankGradleExtension.instrumentationApk.set(rootProject.provider { variantInfo.testApkPath }) + } else { + // Otherwise, let's just add it to the list. + if (yml.isBlank()) { + // The first item in the list needs to start with a ` - `. + yml.appendLine("- test: ${variantInfo.testApkPath}") + } else { + yml.appendLine(" test: ${variantInfo.testApkPath}") + } + } + + if (yml.isEmpty()) { + // this is the root module + // should not be added as additional test apk + overrideRootLevelConfigs(flankGradleExtension, fulladleModuleExtension) + } else { + yml.appendProperty(fulladleModuleExtension.maxTestShards, " max-test-shards") + yml.appendMapProperty( + fulladleModuleExtension.clientDetails, + " client-details", + ) { appendLine(" ${it.key}: ${it.value}") } + yml.appendMapProperty( + fulladleModuleExtension.environmentVariables, + " environment-variables", + ) { appendLine(" ${it.key}: ${it.value}") } + flankGradleExtension.additionalTestApks.add(yml.toString()) } + addedTestsForModule = true } } @@ -180,16 +266,11 @@ val Project.hasAndroidTest: Boolean if (!fulladleModuleExtension.enabled.get()) { return false } - val testedExtension = extensions.findByType(TestedExtension::class.java) ?: return false - var testsFound = true - testedExtension.testVariants.configureEach testVariant@{ - if (!file("$projectDir/src/androidTest").exists()) { - println("Ignoring $name test variant in $path: No tests in $projectDir/src/androidTest") - testsFound = false - } - return@testVariant + if (!file("$projectDir/src/androidTest").exists()) { + println("Ignoring test variants in $path: No tests in $projectDir/src/androidTest") + return false } - return testsFound + return true } fun overrideRootLevelConfigs( diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/RequiredDeviceKeyMissingException.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/RequiredDeviceKeyMissingException.kt index 31427c11..7682930f 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/RequiredDeviceKeyMissingException.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/RequiredDeviceKeyMissingException.kt @@ -1,3 +1,5 @@ package com.osacky.flank.gradle -data class RequiredDeviceKeyMissingException(val key: String) : Exception("Device should have '$key' key set to a value.") +data class RequiredDeviceKeyMissingException( + val key: String, +) : Exception("Device should have '$key' key set to a value.") diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/SanityConfigValidation.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/SanityConfigValidation.kt index 26d91f4a..b26bcd5f 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/SanityConfigValidation.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/SanityConfigValidation.kt @@ -6,16 +6,22 @@ import java.lang.IllegalArgumentException fun checkIfSanityAndValidateConfigs(config: FladleConfig) = when (config) { - is FlankGradleExtension -> + is FlankGradleExtension -> { config.checkAndValidateConfig { option, name -> "Incorrect [$name] configuration. [$option] can't be used together with sanityRobo." } - is FladleConfigImpl -> + } + + is FladleConfigImpl -> { config.checkAndValidateConfig(config.name) { option, name -> "Incorrect [$name] configuration. [$option] can't be used together with sanityRobo. " + "To configure sanityRobo, add clearPropertiesForSanityRobo() to the [$name] configuration" } - else -> throw IllegalArgumentException("Unexpected configuration when validating parameters. Did not expect: $config.") + } + + else -> { + throw IllegalArgumentException("Unexpected configuration when validating parameters. Did not expect: $config.") + } } private fun FladleConfig.checkAndValidateConfig( @@ -35,5 +41,5 @@ private fun FladleConfig.checkAndValidateConfig( val Property.hasValue get() = orNull.isNullOrBlank().not() -private val ListProperty.hasValue +private val ListProperty.hasValue get() = getOrElse(emptyList()).isNotEmpty() diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/VariantApkInfo.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/VariantApkInfo.kt new file mode 100644 index 00000000..b69db0fa --- /dev/null +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/VariantApkInfo.kt @@ -0,0 +1,11 @@ +package com.osacky.flank.gradle + +data class VariantApkInfo( + val variantName: String, + val appApkPath: String?, + val testApkPath: String, + val abiName: String?, +) { + fun isExpectedVariantInModule(config: FulladleModuleExtension): Boolean = + !config.variant.isPresent || (config.variant.isPresent && variantName.contains(config.variant.get())) +} diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/Variants.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/Variants.kt index 630ed2ab..df732443 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/Variants.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/Variants.kt @@ -1,33 +1,34 @@ package com.osacky.flank.gradle -import com.android.build.VariantOutput -import com.android.build.gradle.api.BaseVariant -import com.android.build.gradle.api.BaseVariantOutput +import com.android.build.api.variant.FilterConfiguration +import com.android.build.api.variant.Variant +import com.android.build.api.variant.VariantOutput /** - * Returns true if this [BaseVariant] matches the variant specified in the [config]. + * Returns true if this [Variant] matches the variant specified in the [config]. * * If no variant is specified, all variants are considered a match. */ -fun BaseVariant.isExpectedVariant(config: FladleConfig) = +fun Variant.isExpectedVariant(config: FladleConfig) = !config.variant.isPresent || (config.variant.isPresent && config.variant.get() == this.name) /** - * Returns true if this [BaseVariantOutput] matches the ABI specified in the [config]. + * Returns true if this [VariantOutput] matches the ABI specified in the [config]. * - * If the config does not specify an ABI, or if the config specifies an ABI but the [BaseVariantOutput] + * If the config does not specify an ABI, or if the config specifies an ABI but the [VariantOutput] * is not filtered by ABI, it is considered a match. */ -fun BaseVariantOutput.isExpectedAbiOutput(config: FladleConfig): Boolean { +fun VariantOutput.isExpectedAbiOutput(config: FladleConfig): Boolean { + val abiFilters = filters.filter { it.filterType == FilterConfiguration.FilterType.ABI } return !config.abi.isPresent || - !filterTypes.contains(VariantOutput.FilterType.ABI.name) || - filters.single { it.filterType == VariantOutput.FilterType.ABI.name }.identifier == config.abi.get() + abiFilters.isEmpty() || + abiFilters.any { it.identifier == config.abi.get() } } /** - * Returns true if this [BaseVariant] matches the variant specified in the [config]. + * Returns true if this [Variant] matches the variant specified in the [config]. * * If no variant is specified, all variants are considered a match. */ -fun BaseVariant.isExpectedVariantInModule(config: FulladleModuleExtension) = +fun Variant.isExpectedVariantInModule(config: FulladleModuleExtension) = !config.variant.isPresent || (config.variant.isPresent && this.name.contains(config.variant.get())) diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlConfigWriterTask.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlConfigWriterTask.kt index 12373cbb..1d3b09e6 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlConfigWriterTask.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlConfigWriterTask.kt @@ -38,21 +38,18 @@ open class YamlConfigWriterTask @get:Input val additionalTestApks: ListProperty = - objects.listProperty(String::class.java) + objects + .listProperty(String::class.java) .convention(config.additionalTestApks) @OutputFile val fladleConfigFile: Provider = fladleDir.map { it.file("flank.yml") } @Internal - override fun getDescription(): String { - return "Writes a flank.yml file based on the current FlankGradleExtension configuration." - } + override fun getDescription(): String = "Writes a flank.yml file based on the current FlankGradleExtension configuration." @Internal - override fun getGroup(): String { - return FladlePluginDelegate.TASK_GROUP - } + override fun getGroup(): String = FladlePluginDelegate.TASK_GROUP @TaskAction fun writeFile() { diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlExtensions.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlExtensions.kt index 75d41a73..a80543bc 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlExtensions.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlExtensions.kt @@ -4,14 +4,14 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -fun StringBuilder.appendProperty( +fun StringBuilder.appendProperty( prop: Property, name: String, ) { if (prop.isPresent) appendLine(" $name: ${prop.get()}") } -fun StringBuilder.appendMapProperty( +fun StringBuilder.appendMapProperty( prop: MapProperty, name: String, custom: StringBuilder.(Map.Entry) -> Unit, @@ -22,7 +22,7 @@ fun StringBuilder.appendMapProperty( } } -fun StringBuilder.appendListProperty( +fun StringBuilder.appendListProperty( prop: ListProperty, name: String, custom: StringBuilder.(T) -> Unit, @@ -35,15 +35,16 @@ fun StringBuilder.appendListProperty( fun StringBuilder.appendAdditionalProperty(property: Property) { if (property.isPresent) { - property.get() + property + .get() .split("\n") .map { " $it" } .forEach { appendLine(it) } } } -val ListProperty.isPresentAndNotEmpty +val ListProperty.isPresentAndNotEmpty get() = isPresent && get().isNotEmpty() -val MapProperty.isPresentAndNotEmpty +val MapProperty.isPresentAndNotEmpty get() = isPresent && get().isNotEmpty() diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlWriter.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlWriter.kt index 2262148f..d2083f64 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlWriter.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/YamlWriter.kt @@ -126,7 +126,8 @@ internal class YamlWriter { } else { appendListProperty(config.roboDirectives, name = "robo-directives") { val value = - it.getOrElse(2) { "" } + it + .getOrElse(2) { "" } .let { stringValue -> if (stringValue.isBlank()) "\"\"" else stringValue } appendLine(" ${it[0]}:${it[1]}: $value") } diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/SinceFlank.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/SinceFlank.kt index 142b9713..f35e6222 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/SinceFlank.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/SinceFlank.kt @@ -1,3 +1,6 @@ package com.osacky.flank.gradle.validation -annotation class SinceFlank(val version: String, val hasDefaultValue: Boolean = false) +annotation class SinceFlank( + val version: String, + val hasDefaultValue: Boolean = false, +) diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/ValidateOptions.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/ValidateOptions.kt index 9fead49d..0a48b133 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/ValidateOptions.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/ValidateOptions.kt @@ -11,7 +11,8 @@ fun validateOptionsUsed( // if using snapshot version default to the latest known version of flank for validation checks val configFlankVersion = if (flank.toLowerCase().endsWith("snapshot")) FLANK_VERSION.toVersion() else flank.toVersion() - config.getPresentProperties() + config + .getPresentProperties() .mapNotNull { property -> properties[property.name]?.let { property to it } } .forEach { (property, version) -> if (version > configFlankVersion) { @@ -25,11 +26,18 @@ fun validateOptionsUsed( private fun String.toVersion() = VersionNumber.parse(this) private val properties = - FladleConfig::class.memberProperties + FladleConfig::class + .memberProperties .asSequence() .map { it to it.getter.annotations } // we also need to exclude properties with default values to preserve backward compatibility // to be fixed .filter { it.second.any { annotation -> annotation is SinceFlank && !annotation.hasDefaultValue } } - .map { it.first.name to it.second.filterIsInstance().first().version.toVersion() } - .toMap() + .map { + it.first.name to + it.second + .filterIsInstance() + .first() + .version + .toVersion() + }.toMap() diff --git a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/VersionNumber.kt b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/VersionNumber.kt index d17b4b3e..90d5d9cb 100644 --- a/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/VersionNumber.kt +++ b/fladle-plugin/src/main/java/com/osacky/flank/gradle/validation/VersionNumber.kt @@ -40,13 +40,13 @@ class VersionNumber private constructor( if (patch != other.patch) { return patch - other.patch } - return qualifier.orEmpty().lowercase() + return qualifier + .orEmpty() + .lowercase() .compareTo(other.qualifier.orEmpty().lowercase()) } - override fun equals(other: Any?): Boolean { - return other is VersionNumber && compareTo(other) == 0 - } + override fun equals(other: Any?): Boolean = other is VersionNumber && compareTo(other) == 0 override fun hashCode(): Int { var result = major @@ -57,9 +57,7 @@ class VersionNumber private constructor( return result } - override fun toString(): String { - return scheme.format(this) - } + override fun toString(): String = scheme.format(this) /** * Returns the version number scheme. @@ -70,7 +68,9 @@ class VersionNumber private constructor( fun format(versionNumber: VersionNumber): String } - private abstract class AbstractScheme protected constructor(val depth: Int) : Scheme { + private abstract class AbstractScheme protected constructor( + val depth: Int, + ) : Scheme { override fun parse(versionString: String): VersionNumber { if (versionString.isEmpty()) { return UNKNOWN @@ -109,16 +109,15 @@ class VersionNumber private constructor( return UNKNOWN } - private class Scanner(val str: String) { + private class Scanner( + val str: String, + ) { var pos: Int = 0 - fun hasDigit(): Boolean { - return pos < str.length && Character.isDigit(str.get(pos)) - } + fun hasDigit(): Boolean = pos < str.length && Character.isDigit(str.get(pos)) - fun isSeparatorAndDigit(vararg separators: Char): Boolean { - return pos < str.length - 1 && oneOf(*separators) && Character.isDigit(str.get(pos + 1)) - } + fun isSeparatorAndDigit(vararg separators: Char): Boolean = + pos < str.length - 1 && oneOf(*separators) && Character.isDigit(str.get(pos + 1)) fun oneOf(vararg separators: Char): Boolean { val current = str.get(pos) @@ -148,22 +147,19 @@ class VersionNumber private constructor( pos++ } - fun remainder(): String? { - return if (pos == str.length) null else str.substring(pos) - } + fun remainder(): String? = if (pos == str.length) null else str.substring(pos) } } private class DefaultScheme : AbstractScheme(3) { - override fun format(versionNumber: VersionNumber): String { - return String.format( + override fun format(versionNumber: VersionNumber): String = + String.format( VERSION_TEMPLATE, versionNumber.major, versionNumber.minor, versionNumber.micro, if (versionNumber.qualifier == null) "" else "-" + versionNumber.qualifier, ) - } companion object { private const val VERSION_TEMPLATE = "%d.%d.%d%s" @@ -178,8 +174,8 @@ class VersionNumber private constructor( fun version( major: Int, minor: Int = 0, - ): VersionNumber { - return VersionNumber( + ): VersionNumber = + VersionNumber( major = major, minor = minor, micro = 0, @@ -187,10 +183,7 @@ class VersionNumber private constructor( qualifier = null, scheme = DEFAULT_SCHEME, ) - } - fun parse(versionString: String): VersionNumber { - return DEFAULT_SCHEME.parse(versionString) - } + fun parse(versionString: String): VersionNumber = DEFAULT_SCHEME.parse(versionString) } } diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt index 8b7a732f..dcb28cd3 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/MultipleConfigsTest.kt @@ -38,7 +38,8 @@ class MultipleConfigsTest { testProjectRoot.newFile("flank-gradle-service.json").writeText("{}") val result = - GradleRunner.create() + GradleRunner + .create() .withPluginClasspath() .withArguments("writeConfigPropsOrange", "--stacktrace") .forwardOutput() @@ -76,7 +77,8 @@ class MultipleConfigsTest { ) val regularConfig = - GradleRunner.create() + GradleRunner + .create() .withPluginClasspath() .withArguments("writeConfigProps") .forwardOutput() diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/AutoConfigureFladleTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/AutoConfigureFladleTest.kt index a4c870ae..848eb540 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/AutoConfigureFladleTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/AutoConfigureFladleTest.kt @@ -39,7 +39,8 @@ class AutoConfigureFladleTest { testProjectRoot.setupFixture(fixtureName) val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withArguments("assembleDebug", "assembleDebugAndroidTest", "printYml", "--stacktrace") diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/ConfigurationCacheTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/ConfigurationCacheTest.kt index 2f9b5582..83cbf547 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/ConfigurationCacheTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/ConfigurationCacheTest.kt @@ -115,7 +115,7 @@ class ConfigurationCacheTest { settings.writeText( """ plugins { - id 'com.gradle.enterprise' version '3.7' + id 'com.gradle.develocity' version '4.3' } """.trimIndent(), ) @@ -131,11 +131,11 @@ class ConfigurationCacheTest { assertThat(secondResult.output).contains("Reusing configuration cache.") } - private fun configCachingRunner(arg: String): GradleRunner { - return GradleRunner.create() + private fun configCachingRunner(arg: String): GradleRunner = + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .forwardOutput() .withArguments(arg, "--configuration-cache") - } } diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt index 66f8cd8f..d95df33f 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FlankGradlePluginIntegrationTest.kt @@ -11,8 +11,8 @@ class FlankGradlePluginIntegrationTest { @get:Rule var testProjectRoot = TemporaryFolder() - val minSupportGradleVersion = "6.5" - val oldVersion = "6.4" + val minSupportGradleVersion = "9.1.0" + val oldVersion = "9.0.0" fun writeBuildGradle(build: String) { testProjectRoot.writeBuildDotGradle(build) @@ -27,16 +27,17 @@ class FlankGradlePluginIntegrationTest { """.trimMargin(), ) val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(oldVersion) .buildAndFail() - assertThat(result.output).contains("Fladle requires at minimum version Gradle 6.5. Detected version Gradle 6.4") + assertThat(result.output).contains("Fladle requires at minimum version Gradle 9.1. Detected version Gradle 9.0.0") } @Test - fun testGradleSevenOh() { + fun testGradleNineOne() { writeBuildGradle( """plugins { | id "com.osacky.fladle" @@ -44,10 +45,11 @@ class FlankGradlePluginIntegrationTest { """.trimMargin(), ) val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() - .withGradleVersion("7.0") + .withGradleVersion("9.1.0") .build() assertThat(result.output).contains("SUCCESS") @@ -61,7 +63,8 @@ class FlankGradlePluginIntegrationTest { |} """.trimMargin(), ) - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(minSupportGradleVersion) @@ -82,7 +85,8 @@ class FlankGradlePluginIntegrationTest { |} """.trimMargin(), ) - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(minSupportGradleVersion) @@ -103,7 +107,8 @@ class FlankGradlePluginIntegrationTest { """.trimMargin(), ) val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(minSupportGradleVersion) @@ -131,7 +136,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.newFile("foo").writeText("{}") val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(minSupportGradleVersion) @@ -155,7 +161,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.newFile("foo").writeText("{}") val result = - GradleRunner.create() + GradleRunner + .create() .withProjectDir(testProjectRoot.root) .withPluginClasspath() .withGradleVersion(minSupportGradleVersion) @@ -182,7 +189,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.writeEmptyServiceCredential() val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withGradleVersion(minSupportGradleVersion) .withArguments("printYml") .buildAndFail() @@ -209,7 +217,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.writeEmptyServiceCredential() val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withGradleVersion(minSupportGradleVersion) .withArguments("printYml") .buildAndFail() @@ -236,7 +245,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.writeEmptyServiceCredential() val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withGradleVersion(minSupportGradleVersion) .withArguments("printYml") .buildAndFail() @@ -264,7 +274,8 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.writeEmptyServiceCredential() val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withGradleVersion(minSupportGradleVersion) .withArguments("printYml") .buildAndFail() @@ -273,7 +284,7 @@ class FlankGradlePluginIntegrationTest { } @Test - fun testGradleSevenCompat() { + fun testGradleEightCompat() { writeBuildGradle( """plugins { id "com.osacky.fladle" @@ -291,8 +302,9 @@ class FlankGradlePluginIntegrationTest { ) testProjectRoot.writeEmptyServiceCredential() val result = - testProjectRoot.gradleRunner() - .withGradleVersion("7.0-rc-1") + testProjectRoot + .gradleRunner() + .withGradleVersion("9.1.0") .withArguments("printYmlFooConfig") .build() assertThat(result.task(":printYmlFooConfig")!!.outcome).isEqualTo(TaskOutcome.SUCCESS) diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FulladlePluginIntegrationTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FulladlePluginIntegrationTest.kt index 6706b2e2..7d2a3ecf 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FulladlePluginIntegrationTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/FulladlePluginIntegrationTest.kt @@ -10,7 +10,7 @@ class FulladlePluginIntegrationTest { @get:Rule var testProjectRoot = TemporaryFolder() - val agpDependency: String = "com.android.tools.build:gradle:4.2.1" + val agpDependency: String = "com.android.tools.build:gradle:9.0.1" fun writeBuildGradle(build: String) { val file = testProjectRoot.newFile("build.gradle") @@ -26,7 +26,8 @@ class FulladlePluginIntegrationTest { """.trimMargin(), ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments("help") .build() assertThat(result.output).contains("SUCCESS") @@ -88,7 +89,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -189,7 +191,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -271,7 +274,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -395,7 +399,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -446,10 +451,9 @@ class FulladlePluginIntegrationTest { testProjectRoot.newFile("settings.gradle").writeText( """ include '$appFixture' - include '$libraryFixture' include '$flavourProject' include '$flavourLibrary' - + dependencyResolutionManagement { repositories { mavenCentral() @@ -468,17 +472,17 @@ class FulladlePluginIntegrationTest { repositories { google() } - + dependencies { classpath '$agpDependency' } } - + plugins { id "com.osacky.fulladle" } - - + + fladle { serviceAccountCredentials = project.layout.projectDirectory.file("android-project/flank-gradle-5cf02dc90531.json") } @@ -486,7 +490,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -576,7 +581,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() assertThat(result.output).doesNotContain("max-test-shards: 4") @@ -632,7 +638,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .buildAndFail() @@ -708,7 +715,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .buildAndFail() @@ -797,7 +805,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -881,7 +890,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() @@ -967,7 +977,8 @@ class FulladlePluginIntegrationTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments(":printYml") .build() diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt index e9f83355..6ad7a89c 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/TestFixtures.kt @@ -5,7 +5,11 @@ import org.junit.rules.TemporaryFolder import java.io.File fun TemporaryFolder.setupFixture(fixtureName: String) { - File(this::class.java.classLoader.getResource(fixtureName)!!.file).copyRecursively(newFile(fixtureName), true) + File( + this::class.java.classLoader + .getResource(fixtureName)!! + .file, + ).copyRecursively(newFile(fixtureName), true) } internal fun TemporaryFolder.writeBuildDotGradle(buildScript: String) = @@ -13,7 +17,8 @@ internal fun TemporaryFolder.writeBuildDotGradle(buildScript: String) = .writeText(buildScript) fun TemporaryFolder.gradleRunner() = - GradleRunner.create() + GradleRunner + .create() .withPluginClasspath() .forwardOutput() .withProjectDir(root) diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/VariantTests.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/VariantTests.kt index c0f9a0c5..29f40468 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/VariantTests.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/integration/VariantTests.kt @@ -67,15 +67,13 @@ class VariantTests { assertThat(result.output).doesNotContain(":assembleVanillaRelease") assertThat(result.output).doesNotContain(":assembleChocolate") - /** - * See #60 https://github.com/runningcode/fladle/issues/60 - testProjectRoot.writeEmptyServiceCredential() - val resultPrint = testProjectRoot.gradleRunner() - .withArguments("printYmlVanilla") - .build() - assertThat(resultPrint.output).contains("build/outputs/apk/vanilla/debug/chocovanilla-vanilla-debug.apk") - assertThat(resultPrint.output).contains("build/outputs/apk/androidTest/vanilla/debug/chocovanilla-vanilla-debug-androidTest.apk") - **/ + // See #60 https://github.com/runningcode/fladle/issues/60 + // testProjectRoot.writeEmptyServiceCredential() + // val resultPrint = testProjectRoot.gradleRunner() + // .withArguments("printYmlVanilla") + // .build() + // assertThat(resultPrint.output).contains("build/outputs/apk/vanilla/debug/chocovanilla-vanilla-debug.apk") + // assertThat(resultPrint.output).contains("build/outputs/apk/androidTest/vanilla/debug/chocovanilla-vanilla-debug-androidTest.apk") } @Test @@ -106,6 +104,8 @@ class VariantTests { |include ':android-project' """.trimMargin(), ) + testProjectRoot.newFile("local.properties").writeText("sdk.dir=${androidHome()}\n") + testProjectRoot.newFile("gradle.properties").writeText("android.useAndroidX=true") testProjectRoot.setupFixture("android-project") val flavors = if (withFlavors) { @@ -191,7 +191,8 @@ class VariantTests { if (dryRun) { arguments.add("--dry-run") } - return testProjectRoot.gradleRunner() + return testProjectRoot + .gradleRunner() .withArguments(arguments) .build() } diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateExclusionsTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateExclusionsTest.kt index 0b5d05b4..4ffb9517 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateExclusionsTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateExclusionsTest.kt @@ -32,7 +32,8 @@ class ValidateExclusionsTest { ) val result = - testProjectRoot.gradleRunner() + testProjectRoot + .gradleRunner() .withArguments("printYml") .buildAndFail() diff --git a/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateOptionsTest.kt b/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateOptionsTest.kt index 8ef828cd..0800d233 100644 --- a/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateOptionsTest.kt +++ b/fladle-plugin/src/test/java/com/osacky/flank/gradle/validation/ValidateOptionsTest.kt @@ -16,7 +16,12 @@ class ValidateOptionsTest { @get:Rule var testProjectRoot = TemporaryFolder() - private val objects = ProjectBuilder.builder().withName("project").build().objects + private val objects = + ProjectBuilder + .builder() + .withName("project") + .build() + .objects private lateinit var config: FladleConfig @Before diff --git a/gradle.properties b/gradle.properties index b2732dd2..b9267d76 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,8 +15,6 @@ org.gradle.jvmargs=-Xmx1536m # Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=false kotlin.code.style=official diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 00000000..5b343e54 --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,13 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/ecd23fd7707c683afbcd6052998cb6a9/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/0b98aec810298c2c1d7fdac5dac37910/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/658299a896470fbb3103ba3a430ee227/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/23adb857f3cb3cbe28750bc7faa7abc0/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/932015f6361ccaead0c6d9b8717ed96e/redirect +toolchainVendor=JETBRAINS +toolchainVersion=21 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9064b167..9c952c41 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,16 @@ ## Generated by $ ./gradlew refreshVersionsCatalog [plugins] +foojay = { id = "org.gradle.toolchains.foojay-resolver-convention", version = "1.0.0"} ben-manes-versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -kotlinter = { id = "org.jmailen.kotlinter", version = "4.0.0" } +kotlinter = { id = "org.jmailen.kotlinter", version = "5.4.2" } -gradle-plugin-publish = {id = "com.gradle.plugin-publish", version = "1.3.1" } +gradle-plugin-publish = {id = "com.gradle.plugin-publish", version = "2.1.1" } + +vanniktech-publish = { id = "com.vanniktech.maven.publish", version = "0.36.0" } -kgp = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin"} agp = { id = "com.android.application", version.ref = "agp-version"} [versions] @@ -27,8 +29,8 @@ androidx-test-rules = "1.7.0" junit-version = "4.13.2" -kotlin = "2.0.21" -agp-version = "7.4.2" +agp-version = "9.0.1" + flank-version = "23.10.1" [libraries] @@ -51,8 +53,6 @@ flank = { module = "com.github.flank:flank", version.ref = "flank-version" } junit = { group = "junit", name = "junit", version.ref = "junit-version" } -kotlin-stdlib-jdk7 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlin" } - gradle-enterprise = { module = "com.gradle:develocity-gradle-plugin", version = "3.19.2" } -truth = "com.google.truth:truth:1.4.4" +truth = "com.google.truth:truth:1.4.5" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136..d997cfc6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b1..dbc3ce4a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf13..0262dcbd 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -170,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -203,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 7101f8e4..e509b2dd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/mkdocs.yml b/mkdocs.yml index e20000ff..be9b1e1d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,8 +4,8 @@ extra: fladle: - current_release: '0.19.0' - next_release: '0.19.1' + current_release: '0.20.0' + next_release: '0.20.1' flank_version: '23.10.1' site_name: Fladle diff --git a/sample-android-library/build.gradle.kts b/sample-android-library/build.gradle.kts index 751c6fca..63a998cb 100644 --- a/sample-android-library/build.gradle.kts +++ b/sample-android-library/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id("com.android.library") - kotlin("android") } fulladleModuleConfig { @@ -25,14 +24,14 @@ android { } testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR" compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/sample-android-library/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt b/sample-android-library/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt index ab896993..0b6fe002 100644 --- a/sample-android-library/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt +++ b/sample-android-library/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt @@ -12,7 +12,5 @@ class ExampleInstrumentedTest { } @Test - fun runAndFail() { - throw RuntimeException("Test failed") - } + fun runAndFail(): Unit = throw RuntimeException("Test failed") } diff --git a/sample-flavors-kotlin/build.gradle.kts b/sample-flavors-kotlin/build.gradle.kts index 551677fc..2b131a90 100644 --- a/sample-flavors-kotlin/build.gradle.kts +++ b/sample-flavors-kotlin/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id ("com.android.application") - kotlin("android") id ("com.osacky.fladle") } @@ -15,8 +14,8 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR" @@ -34,7 +33,7 @@ android { java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/sample-flavors-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt b/sample-flavors-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt index 5d25f62c..efa6aae8 100644 --- a/sample-flavors-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt +++ b/sample-flavors-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt @@ -23,7 +23,5 @@ class ExampleInstrumentedTest { } @Test - fun runAndFail() { - throw RuntimeException("Test failed") - } + fun runAndFail(): Unit = throw RuntimeException("Test failed") } diff --git a/sample-kotlin/build.gradle.kts b/sample-kotlin/build.gradle.kts index 1e08d49e..5d729cec 100644 --- a/sample-kotlin/build.gradle.kts +++ b/sample-kotlin/build.gradle.kts @@ -1,6 +1,5 @@ plugins { id ("com.android.application") - kotlin("android") id ("com.osacky.fladle") } @@ -15,15 +14,15 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR" } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/sample-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt b/sample-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt index 57d1a72f..cec17543 100644 --- a/sample-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt +++ b/sample-kotlin/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt @@ -22,7 +22,5 @@ class ExampleInstrumentedTest { } @Test - fun runAndFail() { - throw RuntimeException("Test failed") - } + fun runAndFail(): Unit = throw RuntimeException("Test failed") } diff --git a/sample/build.gradle b/sample/build.gradle index c2fc7529..71b98804 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,5 +1,4 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' apply plugin: 'com.osacky.fladle' android { @@ -17,14 +16,14 @@ android { execution 'ANDROIDX_TEST_ORCHESTRATOR' } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } } java { toolchain { - languageVersion = JavaLanguageVersion.of(11) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/sample/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt b/sample/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt index 2587b288..f71566f5 100644 --- a/sample/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt +++ b/sample/src/androidTest/java/com/osacky/flank/gradle/sample/ExampleInstrumentedTest.kt @@ -22,7 +22,5 @@ class ExampleInstrumentedTest { } @Test - fun runAndFail() { - throw RuntimeException("Test failed") - } + fun runAndFail(): Unit = throw RuntimeException("Test failed") } diff --git a/settings.gradle b/settings.gradle index 1fc5400d..e6b4450a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,7 +7,8 @@ pluginManagement { } plugins { - id "com.gradle.develocity" version "4.1" + id "org.gradle.toolchains.foojay-resolver-convention" version "1.0.0" + id "com.gradle.develocity" version "4.3.2" } include ':android-library-no-tests'