Skip to content

Add E2E integration test for Gradle plugin#160

Open
kirich1409 wants to merge 1 commit intomainfrom
test/gradle-plugin-e2e
Open

Add E2E integration test for Gradle plugin#160
kirich1409 wants to merge 1 commit intomainfrom
test/gradle-plugin-e2e

Conversation

@kirich1409
Copy link
Copy Markdown
Contributor

Summary

  • Add FeaturedPluginIntegrationTest using Gradle TestKit with a minimal Android app fixture
  • Test verifies generateProguardRules produces correct -assumevalues rules for boolean local flags
  • Test verifies assembleRelease auto-wires the generated ProGuard file via the Variant API
  • Add testPluginClasspath configuration to inject AGP into the TestKit subprocess classpath
  • Add fixture project at src/test/fixtures/android-project/ with minimal Android setup

Tests are skipped when ANDROID_HOME/ANDROID_SDK_ROOT is not set.

Depends on #155

Test plan

  • Run ./gradlew :featured-gradle-plugin:test with ANDROID_HOME set
  • Verify tests pass on CI (Android SDK is available)
  • Verify tests are gracefully skipped when no Android SDK is present

🤖 Generated with Claude Code

Add FeaturedPluginIntegrationTest that uses Gradle TestKit with a minimal
Android application fixture to verify:
- generateProguardRules produces correct -assumevalues rules
- assembleRelease auto-wires the generated proguard file via Variant API

Tests are skipped when ANDROID_HOME is not set. The testPluginClasspath
configuration injects AGP into the TestKit subprocess classpath.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 10, 2026 11:59
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add E2E integration test for Gradle plugin with Android fixture

🧪 Tests

Grey Divider

Walkthroughs

Description
• Add end-to-end integration test for Gradle plugin using TestKit
• Test verifies ProGuard rules generation with correct -assumevalues blocks
• Test verifies assembleRelease auto-wires generated ProGuard file via AGP Variant API
• Add minimal Android application fixture for integration testing
• Configure testPluginClasspath to inject AGP into TestKit subprocess
Diagram
flowchart LR
  A["Test Configuration"] -->|injects AGP| B["testPluginClasspath"]
  B -->|appended to| C["pluginUnderTestMetadata"]
  C -->|loaded in| D["GradleRunner TestKit"]
  D -->|executes| E["Android Fixture Project"]
  E -->|verifies| F["ProGuard Rules Generation"]
  E -->|verifies| G["assembleRelease Integration"]
Loading

Grey Divider

File Changes

1. featured-gradle-plugin/build.gradle.kts ⚙️ Configuration changes +17/-0

Configure AGP injection for TestKit subprocess

• Create testPluginClasspath configuration to resolve AGP dependency
• Configure pluginUnderTestMetadata task to include testPluginClasspath jars
• Add AGP 9.1.0 as testPluginClasspath dependency for TestKit subprocess injection
• Add comments explaining why AGP must be injected separately from runtimeClasspath

featured-gradle-plugin/build.gradle.kts


2. featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts 🧪 Tests +29/-0

Minimal Android application fixture for testing

• Apply Android application plugin and Featured plugin
• Configure Android namespace, SDK versions (compileSdk 36, minSdk 24, targetSdk 36)
• Enable minification for release build with default ProGuard file
• Declare dark_mode boolean local flag in Featured plugin configuration

featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts


3. featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts ⚙️ Configuration changes +31/-0

Fixture project repository and plugin configuration

• Configure pluginManagement repositories for AGP and plugin resolution
• Configure dependencyResolutionManagement with Google Maven and Maven Central
• Set root project name to android-project
• Include repository filters for Android, Google, and AndroidX artifacts

featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts


View more (2)
4. featured-gradle-plugin/src/test/fixtures/android-project/src/main/AndroidManifest.xml 🧪 Tests +1/-0

Minimal Android manifest for fixture

• Create minimal Android manifest file required by AGP compilation

featured-gradle-plugin/src/test/fixtures/android-project/src/main/AndroidManifest.xml


5. featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt 🧪 Tests +198/-0

End-to-end integration test for Gradle plugin

• Create FeaturedPluginIntegrationTest class using Gradle TestKit for end-to-end testing
• Test generateProguardRules task produces correct -assumevalues rules for boolean flags
• Test assembleRelease auto-wires generated ProGuard file and completes successfully
• Skip tests when ANDROID_HOME or ANDROID_SDK_ROOT environment variables are not set
• Implement fixture copying, SDK directory resolution, and GradleRunner configuration
• Verify ProGuard output contains expected extension class FQN and method signatures

featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review bot commented Apr 10, 2026

Code Review by Qodo

🐞 Bugs (3)   📘 Rule violations (2)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ≡ Correctness (1) ☼ Reliability (2)
📘\ ⚙ Maintainability (2)

Grey Divider


Action required

1. Hardcoded AGP in testPluginClasspath 📘
Description
The build script adds an AGP dependency with a literal version string (9.1.0) instead of sourcing
the version from the Gradle version catalog. This can lead to version drift and violates the
requirement to declare dependency versions centrally.
Code

featured-gradle-plugin/build.gradle.kts[74]

+    testPluginClasspath("com.android.tools.build:gradle:9.1.0")
Evidence
The compliance rule requires dependency versions to be referenced via the version catalog rather
than hardcoded. The added dependency declaration uses a literal version string in
testPluginClasspath("com.android.tools.build:gradle:9.1.0").

Rule 162994: Declare all dependency versions in Gradle version catalog
featured-gradle-plugin/build.gradle.kts[74-74]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A dependency version is hardcoded as `9.1.0` in `featured-gradle-plugin/build.gradle.kts`, violating the requirement to declare dependency versions in the Gradle version catalog.

## Issue Context
`gradle/libs.versions.toml` already defines `agp = "9.1.0"`, but the build script still hardcodes the version in the dependency coordinate.

## Fix Focus Areas
- featured-gradle-plugin/build.gradle.kts[74-74]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Fixture uses plugin version literal 📘
Description
The fixture project applies com.android.application with a hardcoded version (9.1.0) in `plugins
{}`. This violates the requirement to avoid literal version strings in Gradle build scripts.
Code

featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[2]

+    id("com.android.application") version "9.1.0"
Evidence
The compliance rule prohibits literal version strings in build scripts. The added fixture build
script contains id("com.android.application") version "9.1.0", which is a hardcoded version.

Rule 162994: Declare all dependency versions in Gradle version catalog
featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[2-2]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The TestKit fixture `build.gradle.kts` applies `com.android.application` with a hardcoded plugin version string (`9.1.0`).

## Issue Context
This fixture is used for TestKit E2E tests and should not hardcode versions in the build script. If AGP is injected via the TestKit classpath, the fixture can typically apply the plugin without specifying a version.

## Fix Focus Areas
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. assembleRelease not wired 🐞
Description
FeaturedPluginIntegrationTest asserts :generateProguardRules runs during assembleRelease, but
the Featured plugin currently only registers the task and does not wire it into AGP variants, and
the fixture does not include the generated .pro file in proguardFiles. This will cause the test
to fail because result.task(":generateProguardRules") will be null or not executed during
assembleRelease.
Code

featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[R79-84]

+        // generateProguardRules must have run as part of the release build.
+        val proguardOutcome = result.task(":generateProguardRules")?.outcome
+        assertTrue(
+            proguardOutcome == TaskOutcome.SUCCESS || proguardOutcome == TaskOutcome.UP_TO_DATE,
+            "Expected :generateProguardRules to participate in assembleRelease, got $proguardOutcome\n${result.output}",
+        )
Evidence
The test requires generateProguardRules to participate in assembleRelease. However,
FeaturedPlugin only registers generateProguardRules and does not configure any Android/variant
hooks or dependencies to connect it to assembleRelease. The fixture’s release build type also
only specifies the default ProGuard file and never references
build/featured/proguard-featured.pro, so AGP has no reason to run the generation task as part of
minification.

featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[72-97]
featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[37-58]
featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[99-111]
featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[15-22]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new E2E test expects `assembleRelease` to trigger `generateProguardRules`, but the plugin/fixture currently do not wire the generated ProGuard file into AGP’s release variant. This makes the test fail because `:generateProguardRules` will not be in the task graph for `assembleRelease`.

## Issue Context
- The plugin registers `generateProguardRules` and writes `build/featured/proguard-featured.pro`.
- The fixture’s `release` build type does not reference this file.
- There is no Android Components/Variant API integration in the plugin to add this file automatically.

## Fix Focus Areas
- featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[37-58]
- featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[99-111]
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[15-22]
- featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[72-97]

## What to change
1. Implement actual AGP integration in the Featured plugin so that for release variants it:
  - adds `build/featured/proguard-featured.pro` to the variant’s ProGuard/R8 configuration, and
  - ensures the relevant R8/minify task depends on `generateProguardRules` (or otherwise consumes its output via the Variant API).
2. Keep the fixture minimal (it should not manually add the file if the plugin is supposed to auto-wire it).
3. If auto-wiring is not intended yet, adjust the test and fixture accordingly (but then remove the “auto-wires” claim and the `assembleRelease` participation assertion).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. AGP double-resolution risk 🐞
Description
AGP is appended to the TestKit plugin classpath via pluginUnderTestMetadata, but the fixture still
applies com.android.application with an explicit version. This can cause Gradle plugin resolution
to fail because the plugin is already on the classpath while also being requested with a version.
Code

featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[R1-4]

+plugins {
+    id("com.android.application") version "9.1.0"
+    id("dev.androidbroadcast.featured")
+}
Evidence
The plugin module explicitly injects com.android.tools.build:gradle:9.1.0 into
pluginUnderTestMetadata, which is the classpath used by GradleRunner.withPluginClasspath() for
the subprocess. The fixture then requests com.android.application with version "9.1.0", which is
incompatible with the ‘plugin already on classpath’ application mode TestKit uses.

featured-gradle-plugin/build.gradle.kts[57-75]
featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[1-4]
featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts[1-15]
Best Practice: Gradle plugins DSL semantics

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
AGP is injected into the TestKit subprocess classpath via `pluginUnderTestMetadata`, but the fixture still requests the Android plugin with an explicit version. This can break Gradle’s plugin resolution (plugin already on classpath + versioned request).

## Issue Context
The goal of `testPluginClasspath` is to make AGP available in the TestKit subprocess without relying on external plugin resolution.

## Fix Focus Areas
- featured-gradle-plugin/build.gradle.kts[57-75]
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[1-4]
- featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts[1-15]

## What to change
- Prefer one mechanism:
 1) **Injected-classpath approach (recommended here):**
    - Change fixture to `plugins { id("com.android.application"); id("dev.androidbroadcast.featured") }` (no version for AGP).
    - Optionally simplify/remove `pluginManagement.repositories` if it’s no longer needed.
 OR
 2) **Repository resolution approach:**
    - Remove AGP from `testPluginClasspath` injection and keep the fixture’s versioned plugin request.

Ensure the chosen approach is consistent with the comments in the fixture/settings files.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Windows sdk.dir may break 🐞
Description
The integration test writes local.properties using sdkDir.absolutePath, which contains
backslashes on Windows and can be mis-parsed by Java .properties escaping rules. This can make the
test fail to locate the SDK on Windows environments.
Code

featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[R45-46]

+        // Write local.properties with sdk.dir so AGP can locate the Android SDK.
+        projectDir.resolve("local.properties").writeText("sdk.dir=${sdkDir!!.absolutePath}\n")
Evidence
local.properties is a Java properties file; writing a raw Windows path (e.g., C:\Android\Sdk)
without escaping backslashes can corrupt the parsed value. The test currently writes the path
verbatim.

featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[34-47]
Best Practice: Java Properties file format

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The test writes `sdk.dir` into `local.properties` without normalizing/escaping the path, which can break on Windows.

## Issue Context
`local.properties` is parsed as Java properties. Windows paths contain `\` which are escape characters in this format.

## Fix Focus Areas
- featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[34-47]

## What to change
- Write `sdk.dir` using a properties-safe path, e.g.:
 - `sdkDir.absolutePath.replace('\\', '/')` (forward slashes), or
 - escape backslashes: `sdkDir.absolutePath.replace("\\", "\\\\")`.
- Keep the newline terminator.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Tests & Coverage

Failed stage: Run ./gradlew test :core:koverVerify :providers:datastore:koverVerify :providers:sharedpreferences:koverVerify :providers:firebase:koverVerify :featured-compose:koverVerify :featured-registry:koverVerify :featured-testing:koverVerify [❌]

Failed test name: FeaturedPluginIntegrationTest > assembleRelease wires proguard rules and completes successfully

Failure summary:

The action failed because the Gradle test task :featured-gradle-plugin:test had a failing test and
exited with code 1.
- Failing test: FeaturedPluginIntegrationTest > assembleRelease wires proguard
rules and completes successfully failed with java.lang.AssertionError at
FeaturedPluginIntegrationTest.kt:81 (151 tests completed, 1 failed).
- As a result, Gradle reported:
Execution failed for task ':featured-gradle-plugin:test' and There were failing tests (test report
at featured-gradle-plugin/build/reports/tests/test/index.html).

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

160:  add-job-summary-as-pr-comment: never
161:  dependency-graph: disabled
162:  dependency-graph-continue-on-failure: true
163:  build-scan-publish: false
164:  validate-wrappers: false
165:  generate-job-summary: true
166:  gradle-home-cache-strict-match: false
167:  workflow-job-context: null
168:  github-token: ***
169:  env:
170:  JAVA_HOME: /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.10-7/x64
171:  JAVA_HOME_21_X64: /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk/21.0.10-7/x64
172:  ##[endgroup]
173:  Merged default JDK locations into /home/runner/.m2/toolchains.xml
174:  ##[group]Restore Gradle state from cache
175:  ##[warning]Failed to restore gradle-home-v1|Linux|test[b8a35c2f917259958c9abe8f2ff1b5ff]-5b3f5397e40da890a32d375047123eea3df72ace: Error: Cache service responded with 400
176:  Gradle User Home cache not found. Will initialize empty.
...

317:  This is a build performance and scalability issue.
318:  See https://github.com/gradle/gradle/issues/2298
319:  Run with --info for a stacktrace.
320:  Configuration 'jvmTestCompileClasspath' was resolved during configuration time.
321:  This is a build performance and scalability issue.
322:  See https://github.com/gradle/gradle/issues/2298
323:  Run with --info for a stacktrace.
324:  Configuration 'kotlinCompilerPluginClasspathJvmTest' was resolved during configuration time.
325:  This is a build performance and scalability issue.
326:  See https://github.com/gradle/gradle/issues/2298
327:  Run with --info for a stacktrace.
328:  Configuration 'koverJvmAgent' was resolved during configuration time.
329:  This is a build performance and scalability issue.
330:  See https://github.com/gradle/gradle/issues/2298
331:  Run with --info for a stacktrace.
332:  > Task :featured-detekt-rules:checkKotlinGradlePluginConfigurationErrors SKIPPED
333:  > Task :featured-gradle-plugin:checkKotlinGradlePluginConfigurationErrors SKIPPED
334:  > Task :featured-detekt-rules:processTestResources NO-SOURCE
335:  > Task :featured-gradle-plugin:pluginDescriptors
336:  > Task :featured-gradle-plugin:processResources
337:  > Task :featured-detekt-rules:processResources
338:  > Task :featured-lint-rules:checkKotlinGradlePluginConfigurationErrors SKIPPED
339:  > Task :featured-gradle-plugin:processTestResources NO-SOURCE
340:  > Task :featured-lint-rules:processResources NO-SOURCE
341:  > Task :featured-lint-rules:processTestResources NO-SOURCE
342:  > Task :core:kmpPartiallyResolvedDependenciesChecker
343:  > Task :core:checkKotlinGradlePluginConfigurationErrors SKIPPED
344:  > Task :featured-lint-rules:compileKotlin
...

401:  > Task :providers:firebase:generateDebugAssets UP-TO-DATE
402:  > Task :providers:firebase:mergeDebugAssets
403:  > Task :providers:firebase:mergeDebugUnitTestAssets
404:  > Task :providers:firebase:koverFindJar
405:  > Task :providers:firebase:processDebugJavaRes
406:  > Task :providers:firebase:processDebugUnitTestManifest
407:  > Task :providers:firebase:processDebugUnitTestResources
408:  > Task :core:compileKotlinJvm
409:  > Task :providers:firebase:packageDebugUnitTestForUnitTest
410:  > Task :providers:firebase:generateDebugUnitTestConfig
411:  > Task :core:compileJvmMainJava NO-SOURCE
412:  > Task :core:jvmProcessResources NO-SOURCE
413:  > Task :core:processJvmMainResources SKIPPED
414:  > Task :core:jvmMainClasses
415:  > Task :core:jvmJar
416:  > Task :providers:javaprefs:checkKotlinGradlePluginConfigurationErrors SKIPPED
417:  > Task :providers:javaprefs:compileKotlin
...

470:  > Task :providers:sharedpreferences:generateDebugAssets UP-TO-DATE
471:  > Task :providers:sharedpreferences:javaPreCompileDebugUnitTest FROM-CACHE
472:  > Task :providers:sharedpreferences:compileDebugUnitTestJavaWithJavac NO-SOURCE
473:  > Task :providers:sharedpreferences:koverFindJar
474:  > Task :providers:sharedpreferences:mergeDebugAssets
475:  > Task :providers:sharedpreferences:processDebugJavaRes
476:  > Task :providers:sharedpreferences:processDebugUnitTestJavaRes
477:  > Task :core:koverGenerateArtifactAndroid
478:  > Task :providers:sharedpreferences:mergeDebugUnitTestAssets
479:  > Task :providers:sharedpreferences:packageDebugUnitTestForUnitTest
480:  > Task :providers:sharedpreferences:generateDebugUnitTestConfig
481:  > Task :core:jvmTestProcessResources NO-SOURCE
482:  > Task :core:processJvmTestResources SKIPPED
483:  > Task :core:koverFindJar
484:  > Task :providers:datastore:kmpPartiallyResolvedDependenciesChecker
485:  > Task :providers:datastore:checkKotlinGradlePluginConfigurationErrors SKIPPED
486:  > Task :core:compileTestKotlinJvm
...

519:  > Task :providers:firebase:preReleaseBuild UP-TO-DATE
520:  > Task :providers:firebase:generateReleaseResources FROM-CACHE
521:  > Task :providers:firebase:packageReleaseResources
522:  > Task :providers:firebase:processReleaseNavigationResources FROM-CACHE
523:  > Task :providers:firebase:parseReleaseLocalResources FROM-CACHE
524:  > Task :providers:firebase:generateReleaseRFile FROM-CACHE
525:  > Task :providers:firebase:compileReleaseKotlin
526:  w: file:///home/runner/work/Featured/Featured/providers/firebase/src/main/kotlin/dev/androidbroadcast/featured/firebase/FirebaseConfigValueProvider.kt:75:41 No cast needed.
527:  > Task :providers:firebase:javaPreCompileRelease FROM-CACHE
528:  > Task :providers:firebase:compileReleaseJavaWithJavac NO-SOURCE
529:  > Task :providers:firebase:koverGenerateArtifactRelease
530:  > Task :providers:firebase:koverGenerateArtifact
531:  > Task :providers:firebase:koverCachedVerify
532:  > Task :providers:firebase:koverVerify
533:  > Task :featured-compose:kmpPartiallyResolvedDependenciesChecker
534:  > Task :featured-compose:checkKotlinGradlePluginConfigurationErrors SKIPPED
535:  > Task :featured-compose:convertXmlValueResourcesForAndroidMain NO-SOURCE
...

563:  > Task :featured-compose:jvmProcessResources
564:  > Task :featured-compose:processJvmMainResources SKIPPED
565:  > Task :featured-compose:convertXmlValueResourcesForCommonTest NO-SOURCE
566:  > Task :featured-compose:copyNonXmlValueResourcesForCommonTest NO-SOURCE
567:  > Task :featured-compose:prepareComposeResourcesTaskForCommonTest NO-SOURCE
568:  > Task :featured-compose:generateResourceAccessorsForCommonTest SKIPPED
569:  > Task :featured-compose:convertXmlValueResourcesForJvmTest NO-SOURCE
570:  > Task :featured-compose:copyNonXmlValueResourcesForJvmTest NO-SOURCE
571:  > Task :featured-compose:prepareComposeResourcesTaskForJvmTest NO-SOURCE
572:  > Task :featured-compose:generateResourceAccessorsForJvmTest SKIPPED
573:  > Task :featured-compose:assembleJvmTestResources
574:  > Task :featured-compose:jvmTestProcessResources
575:  > Task :featured-compose:processJvmTestResources SKIPPED
576:  > Task :featured-compose:koverFindJar
577:  > Task :featured-registry:kmpPartiallyResolvedDependenciesChecker
578:  > Task :featured-registry:checkKotlinGradlePluginConfigurationErrors SKIPPED
579:  > Task :featured-compose:compileKotlinJvm
...

594:  > Task :featured-compose:compileJvmTestJava NO-SOURCE
595:  > Task :featured-compose:jvmTestClasses
596:  > Task :featured-registry:compileTestKotlinJvm
597:  > Task :featured-registry:compileJvmTestJava NO-SOURCE
598:  > Task :featured-registry:jvmTestProcessResources NO-SOURCE
599:  > Task :featured-registry:processJvmTestResources SKIPPED
600:  > Task :featured-registry:jvmTestClasses
601:  > Task :featured-registry:koverFindJar
602:  > Task :providers:sharedpreferences:testDebugUnitTest
603:  > Task :featured-registry:jvmTest
604:  > Task :featured-registry:koverGenerateArtifactJvm
605:  > Task :featured-registry:koverGenerateArtifact
606:  > Task :featured-registry:koverCachedVerify
607:  > Task :featured-registry:koverVerify
608:  > Task :featured-testing:kmpPartiallyResolvedDependenciesChecker
609:  > Task :featured-testing:checkKotlinGradlePluginConfigurationErrors SKIPPED
610:  > Task :featured-testing:compileAndroidMain
...

625:  > Task :featured-testing:jvmJar
626:  > Task :featured-testing:compileTestKotlinJvm
627:  > Task :featured-testing:compileJvmTestJava NO-SOURCE
628:  > Task :featured-testing:jvmTestClasses
629:  > Task :featured-testing:jvmTest
630:  > Task :featured-testing:koverGenerateArtifactJvm
631:  > Task :featured-testing:koverGenerateArtifact
632:  > Task :featured-testing:koverCachedVerify
633:  > Task :featured-testing:koverVerify
634:  > Task :providers:sharedpreferences:test
635:  > Task :providers:sharedpreferences:koverGenerateArtifactDebug
636:  > Task :providers:sharedpreferences:koverGenerateArtifact
637:  > Task :providers:sharedpreferences:koverCachedVerify
638:  > Task :providers:sharedpreferences:koverVerify
639:  > Task :featured-gradle-plugin:test
640:  FeaturedPluginIntegrationTest > assembleRelease wires proguard rules and completes successfully FAILED
641:  java.lang.AssertionError at FeaturedPluginIntegrationTest.kt:81
642:  151 tests completed, 1 failed
643:  > Task :featured-gradle-plugin:test FAILED
644:  [Incubating] Problems report is available at: file:///home/runner/work/Featured/Featured/build/reports/problems/problems-report.html
645:  Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.
646:  You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
647:  For more on this, please refer to https://docs.gradle.org/9.4.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
648:  174 actionable tasks: 154 executed, 20 from cache
649:  FAILURE: Build failed with an exception.
650:  Configuration cache entry stored.
651:  * What went wrong:
652:  Execution failed for task ':featured-gradle-plugin:test'.
653:  > There were failing tests. See the report at: file:///home/runner/work/Featured/Featured/featured-gradle-plugin/build/reports/tests/test/index.html
654:  * Try:
655:  > Run with --scan to get full insights from a Build Scan (powered by Develocity).
656:  BUILD FAILED in 5m 16s
657:  ##[error]Process completed with exit code 1.
658:  ##[group]Run actions/upload-artifact@v7

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Gradle TestKit-based end-to-end integration test for :featured-gradle-plugin using a minimal Android app fixture, aiming to validate ProGuard rule generation and (intended) release-variant wiring.

Changes:

  • Introduce FeaturedPluginIntegrationTest that runs generateProguardRules and assembleRelease against a fixture Android app.
  • Add an Android fixture project under src/test/fixtures/android-project/.
  • Extend pluginUnderTestMetadata classpath via a new testPluginClasspath configuration (to inject AGP into the TestKit subprocess).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt New TestKit E2E test verifying ProGuard output and (intended) wiring into assembleRelease.
featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts Minimal Android app applying AGP + Featured plugin and declaring a boolean local flag.
featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts Fixture repositories/pluginManagement setup for TestKit build.
featured-gradle-plugin/src/test/fixtures/android-project/src/main/AndroidManifest.xml Minimal manifest for the fixture app.
featured-gradle-plugin/build.gradle.kts Adds testPluginClasspath and appends it to pluginUnderTestMetadata for TestKit.

Comment on lines +73 to +83
fun `assembleRelease wires proguard rules and completes successfully`() {
val result =
gradleRunner(projectDir)
.withArguments("assembleRelease", "--stacktrace")
.build()

// generateProguardRules must have run as part of the release build.
val proguardOutcome = result.task(":generateProguardRules")?.outcome
assertTrue(
proguardOutcome == TaskOutcome.SUCCESS || proguardOutcome == TaskOutcome.UP_TO_DATE,
"Expected :generateProguardRules to participate in assembleRelease, got $proguardOutcome\n${result.output}",
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assembleRelease test currently expects :generateProguardRules to run as part of the Android release build, but FeaturedPlugin only registers the generateProguardRules task and does not wire it into any Android variant/task graph (no Variant API wiring in FeaturedPlugin). As-is, assembleRelease in the fixture won't invoke generateProguardRules, so this test should fail unless the wiring code is included in this PR branch. Either include the wiring change (from the dependent PR) in this branch or change the fixture/build to explicitly add the generated .pro file to proguardFiles(...) and adjust the assertion accordingly.

Suggested change
fun `assembleRelease wires proguard rules and completes successfully`() {
val result =
gradleRunner(projectDir)
.withArguments("assembleRelease", "--stacktrace")
.build()
// generateProguardRules must have run as part of the release build.
val proguardOutcome = result.task(":generateProguardRules")?.outcome
assertTrue(
proguardOutcome == TaskOutcome.SUCCESS || proguardOutcome == TaskOutcome.UP_TO_DATE,
"Expected :generateProguardRules to participate in assembleRelease, got $proguardOutcome\n${result.output}",
fun `generateProguardRules and assembleRelease complete successfully`() {
val result =
gradleRunner(projectDir)
.withArguments("generateProguardRules", "assembleRelease", "--stacktrace")
.build()
// Explicitly invoke generateProguardRules before assembleRelease for the current plugin behavior.
val proguardOutcome = result.task(":generateProguardRules")?.outcome
assertTrue(
proguardOutcome == TaskOutcome.SUCCESS || proguardOutcome == TaskOutcome.UP_TO_DATE,
"Expected :generateProguardRules to succeed before assembleRelease, got $proguardOutcome\n${result.output}",

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +169
/**
* Resolves the fixture directory. The plugin module's project directory is either
* injected as the `user.dir` system property by Gradle's test task, or derived
* relative to this class file's location.
*/
private fun fixtureDir(): File {
// Gradle's test task sets user.dir to the module project directory.
val moduleDir = File(System.getProperty("user.dir"))
val candidate = moduleDir.resolve("src/test/fixtures/android-project")
require(candidate.isDirectory) {
"Fixture directory not found at ${candidate.absolutePath}. " +
"Expected it relative to module project dir: ${moduleDir.absolutePath}"
}
return candidate
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The KDoc for fixtureDir() says the module directory is either provided via user.dir or derived relative to this class file's location, but the implementation only uses System.getProperty("user.dir") and has no fallback. Either implement the described fallback (e.g., resolve via a classpath resource) or update the KDoc to match the actual behavior to avoid confusion and brittle test setup.

Copilot uses AI. Check for mistakes.
Comment on lines +175 to +179
* AGP is declared as `compileOnly` in this module — the applying build provides it at runtime.
* In the TestKit subprocess, AGP is loaded by the build's own classloader when `com.android.application`
* is applied from the fixture's `plugins {}` block (resolved from Google Maven). The Featured plugin
* code that references [com.android.build.api.variant.AndroidComponentsExtension] is loaded in the
* same classloader context, so no extra classpath injection is needed.
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gradleRunner() KDoc claims “no extra classpath injection is needed”, but this PR adds testPluginClasspath to inject AGP into pluginUnderTestMetadata. This comment is now misleading (and the classloader explanation is likely incorrect in TestKit). Please update the KDoc to reflect the actual mechanism being used so future changes don’t accidentally remove required classpath setup.

Suggested change
* AGP is declared as `compileOnly` in this module — the applying build provides it at runtime.
* In the TestKit subprocess, AGP is loaded by the build's own classloader when `com.android.application`
* is applied from the fixture's `plugins {}` block (resolved from Google Maven). The Featured plugin
* code that references [com.android.build.api.variant.AndroidComponentsExtension] is loaded in the
* same classloader context, so no extra classpath injection is needed.
* The runner uses [GradleRunner.withPluginClasspath] so TestKit loads the plugin-under-test from
* the generated `pluginUnderTestMetadata` classpath.
*
* This test setup also relies on additional classpath wiring for that metadata so AGP is available
* to the plugin under test, even though AGP is declared as `compileOnly` in this module. Keep that
* wiring in place when changing the test configuration; removing it can break access to
* [com.android.build.api.variant.AndroidComponentsExtension] during the TestKit build.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,29 @@
plugins {
id("com.android.application") version "9.1.0"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fixture applies com.android.application with an explicit version. With TestKit, this typically resolves/loads AGP via plugin resolution rather than from the injected withPluginClasspath() classpath, while this PR also injects com.android.tools.build:gradle into the plugin-under-test classpath. That combination can create classloader/type-identity issues (e.g., AndroidComponentsExtension loaded twice) and make Variant API lookups/casts fail. Prefer applying com.android.application without a version here so it uses the injected classpath, keeping AGP types consistent.

Suggested change
id("com.android.application") version "9.1.0"
id("com.android.application")

Copilot uses AI. Check for mistakes.
dependencies {
// Inject AGP into the TestKit subprocess via pluginUnderTestMetadata so that the Featured
// plugin can access AndroidComponentsExtension when wireProguardToVariants() is called.
testPluginClasspath("com.android.tools.build:gradle:9.1.0")
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AGP version is hard-coded as 9.1.0 in the new testPluginClasspath dependency. Since the repo already tracks the AGP version in the version catalog (libs.versions.agp), this should be sourced from there to avoid accidental drift (tests may break if the plugin’s compileOnly AGP version changes but this stays pinned).

Suggested change
testPluginClasspath("com.android.tools.build:gradle:9.1.0")
testPluginClasspath("com.android.tools.build:gradle:${libs.versions.agp.get()}")

Copilot uses AI. Check for mistakes.
dependencies {
// Inject AGP into the TestKit subprocess via pluginUnderTestMetadata so that the Featured
// plugin can access AndroidComponentsExtension when wireProguardToVariants() is called.
testPluginClasspath("com.android.tools.build:gradle:9.1.0")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Hardcoded agp in testpluginclasspath 📘 Rule violation ⚙ Maintainability

The build script adds an AGP dependency with a literal version string (9.1.0) instead of sourcing
the version from the Gradle version catalog. This can lead to version drift and violates the
requirement to declare dependency versions centrally.
Agent Prompt
## Issue description
A dependency version is hardcoded as `9.1.0` in `featured-gradle-plugin/build.gradle.kts`, violating the requirement to declare dependency versions in the Gradle version catalog.

## Issue Context
`gradle/libs.versions.toml` already defines `agp = "9.1.0"`, but the build script still hardcodes the version in the dependency coordinate.

## Fix Focus Areas
- featured-gradle-plugin/build.gradle.kts[74-74]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@@ -0,0 +1,29 @@
plugins {
id("com.android.application") version "9.1.0"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Fixture uses plugin version literal 📘 Rule violation ⚙ Maintainability

The fixture project applies com.android.application with a hardcoded version (9.1.0) in `plugins
{}`. This violates the requirement to avoid literal version strings in Gradle build scripts.
Agent Prompt
## Issue description
The TestKit fixture `build.gradle.kts` applies `com.android.application` with a hardcoded plugin version string (`9.1.0`).

## Issue Context
This fixture is used for TestKit E2E tests and should not hardcode versions in the build script. If AGP is injected via the TestKit classpath, the fixture can typically apply the plugin without specifying a version.

## Fix Focus Areas
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +79 to +84
// generateProguardRules must have run as part of the release build.
val proguardOutcome = result.task(":generateProguardRules")?.outcome
assertTrue(
proguardOutcome == TaskOutcome.SUCCESS || proguardOutcome == TaskOutcome.UP_TO_DATE,
"Expected :generateProguardRules to participate in assembleRelease, got $proguardOutcome\n${result.output}",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Assemblerelease not wired 🐞 Bug ≡ Correctness

FeaturedPluginIntegrationTest asserts :generateProguardRules runs during assembleRelease, but
the Featured plugin currently only registers the task and does not wire it into AGP variants, and
the fixture does not include the generated .pro file in proguardFiles. This will cause the test
to fail because result.task(":generateProguardRules") will be null or not executed during
assembleRelease.
Agent Prompt
## Issue description
The new E2E test expects `assembleRelease` to trigger `generateProguardRules`, but the plugin/fixture currently do not wire the generated ProGuard file into AGP’s release variant. This makes the test fail because `:generateProguardRules` will not be in the task graph for `assembleRelease`.

## Issue Context
- The plugin registers `generateProguardRules` and writes `build/featured/proguard-featured.pro`.
- The fixture’s `release` build type does not reference this file.
- There is no Android Components/Variant API integration in the plugin to add this file automatically.

## Fix Focus Areas
- featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[37-58]
- featured-gradle-plugin/src/main/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPlugin.kt[99-111]
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[15-22]
- featured-gradle-plugin/src/test/kotlin/dev/androidbroadcast/featured/gradle/FeaturedPluginIntegrationTest.kt[72-97]

## What to change
1. Implement actual AGP integration in the Featured plugin so that for release variants it:
   - adds `build/featured/proguard-featured.pro` to the variant’s ProGuard/R8 configuration, and
   - ensures the relevant R8/minify task depends on `generateProguardRules` (or otherwise consumes its output via the Variant API).
2. Keep the fixture minimal (it should not manually add the file if the plugin is supposed to auto-wire it).
3. If auto-wiring is not intended yet, adjust the test and fixture accordingly (but then remove the “auto-wires” claim and the `assembleRelease` participation assertion).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +4
plugins {
id("com.android.application") version "9.1.0"
id("dev.androidbroadcast.featured")
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Agp double-resolution risk 🐞 Bug ☼ Reliability

AGP is appended to the TestKit plugin classpath via pluginUnderTestMetadata, but the fixture still
applies com.android.application with an explicit version. This can cause Gradle plugin resolution
to fail because the plugin is already on the classpath while also being requested with a version.
Agent Prompt
## Issue description
AGP is injected into the TestKit subprocess classpath via `pluginUnderTestMetadata`, but the fixture still requests the Android plugin with an explicit version. This can break Gradle’s plugin resolution (plugin already on classpath + versioned request).

## Issue Context
The goal of `testPluginClasspath` is to make AGP available in the TestKit subprocess without relying on external plugin resolution.

## Fix Focus Areas
- featured-gradle-plugin/build.gradle.kts[57-75]
- featured-gradle-plugin/src/test/fixtures/android-project/build.gradle.kts[1-4]
- featured-gradle-plugin/src/test/fixtures/android-project/settings.gradle.kts[1-15]

## What to change
- Prefer one mechanism:
  1) **Injected-classpath approach (recommended here):**
     - Change fixture to `plugins { id("com.android.application"); id("dev.androidbroadcast.featured") }` (no version for AGP).
     - Optionally simplify/remove `pluginManagement.repositories` if it’s no longer needed.
  OR
  2) **Repository resolution approach:**
     - Remove AGP from `testPluginClasspath` injection and keep the fixture’s versioned plugin request.

Ensure the chosen approach is consistent with the comments in the fixture/settings files.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants