Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced Android support #18

Closed
shanshin opened this issue Oct 11, 2021 · 27 comments · Fixed by #295
Closed

Advanced Android support #18

shanshin opened this issue Oct 11, 2021 · 27 comments · Fixed by #295
Assignees
Labels
Kover DSL Kover Gradle Plugin S: in progress Status: implementing or design in process
Milestone

Comments

@shanshin
Copy link
Collaborator

shanshin commented Oct 11, 2021

It is necessary to improve the plugin API for convenient work with Android applications:

  • support for Android build types
  • support Android flavors
  • consider creating merge reports for each Build Type
@pvegh
Copy link

pvegh commented Nov 29, 2021

Cannot use this until then. It's not realistic for us currently.
<===========--> 86% EXECUTING [25m 16s]

@shanshin
Copy link
Collaborator Author

shanshin commented Dec 3, 2021

@pvegh, please, can you clarify how long it takes to build a project without applying a Kover, how many tests and classes are in the project.
Perhaps you have suggestions on what settings can be added to the plugin to reduce code instrumentation and speed up your build.

@pvegh
Copy link

pvegh commented Dec 6, 2021

Those details are not important, the problem is that ./gradlew koverHtmlReport is not variant specific.
Currently this one Gradle task builds the project in every possible variant, which means debug + release build types for all of paid, free, foo flavours.
Meaning it builds 6 times instead of just one (whatever is needed e.g. freeDebug for local or freeRelease for CI).

As soon as it runs for just the specified variant (e.g. ./gradlew koverHtmlReportFreeDebug), it will be a huge win instantly.

@SpertsyanKM
Copy link

SpertsyanKM commented Mar 31, 2022

@pvegh I've solved this issue by simply adding this configuration to android.testOptions.unitTests.all section in build.gradle.

kover {
    disabled = (name == "testReleaseUnitTest")
}

Maybe it will help you?

@shanshin shanshin added this to the Release 1.0.0 milestone Apr 8, 2022
@pvegh
Copy link

pvegh commented Apr 8, 2022

Thanks, it might help others.
I'm not interested in a workaround in which I must explicitly disable things one by one.
If I execute ./gradlew koverHtmlReportLocalDebug then exactly that should be executed, not every variant combination

@pvegh
Copy link

pvegh commented Apr 11, 2022

I see now that we removed kover from the project, because the wasted time was huge without variants correctly supported.

@pagsantos
Copy link

we have the same problem can we at least have the possibility to avoid certain flavors ?

@gerardoepitacio
Copy link

@shanshin Is there a way to see the contribution guidelines for this project?, I really wanted to learn how to write a gradle plugin to be able to improve this tool, I would really appreciate a guideline over that.

@NeoMindStd
Copy link

We need report tasks support to specific buildVariant.
Do you have any plans or schedules to support?

@shanshin
Copy link
Collaborator Author

@NeoMindStd, yes, right now we are developing a new version of the plugin API, after switching to which filtering by buildVariant and/or flavours will be added.

@shanshin
Copy link
Collaborator Author

@gerardoepitacio, at the moment there are no strict documents, you can create PR with your suggestions and bug fixes.
Because the project code is not stabilized at the moment, I would not recommend creating large PR. However, if you have ideas, you can create an issue with their description.

@samuelneff
Copy link

Could we get an update on the status of this issue? Is a fix under active development?

If not, do you have any pointers on how to fix it? Would development/PR be welcome? I looked into it quickly but I think I'd need a little guidance on where to start addressing it. I'd be happy to help though; this is a huge issue for us as we have two build types and six flavors.

@samuelneff
Copy link

Building off of @SpertsyanKM 's answer above, here is a more generic implementation that figures out the right flavor/build-type from the start tasks and works with projects that don't have Android and those with Android but without Kover.

It also will support a mix of projects with different flavors defined or no flavors defined.

// NOTE: This code depends on having a map defined as `buildFlavorConfigs` with the flavors as keys. If you don't have this then you can run this code after everything else is evaluated and gather the flavor names from by looping through the projects first.

// We put these variable declarations inside the buildscript's `ext` block but they can be put locally right below the assignment code instead

startTaskNames = gradle.getStartParameter().getTaskRequests().collect { TaskExecutionRequest req -> req.args }.flatten()

flavorNames = buildFlavorConfigs.keySet().collect { String flavor ->
    flavor.substring(0, 1).toUpperCase() + flavor.substring(1)
}
buildTypes = ['Debug', 'Release']

List<String> selectedFlavors = flavorNames.findAll { flavorName ->
    startTaskNames.any { startTaskName ->
        startTaskName.contains(flavorName)
    }
}
List<String> selectedBuildTypes = buildTypes.findAll { buildType ->
    startTaskNames.any { startTaskName ->
        startTaskName.contains(buildType)
    }
}
selectedBuildType = selectedBuildTypes.size() == 1
        ? selectedBuildTypes[0]
        : buildTypes[0]

switch (selectedFlavors.size()) {
    case 0:
        selectedFlavor = selectedBuildType == 'Debug'
                ? 'Dev'
                : 'Prod'
        break

    case 1:
        selectedFlavor = selectedFlavors[0]
        break

    default:
        selectedFlavor = ''
        break
}

// This code we have in our top-level `build.config` file.

if (startTaskNames.any { it.startsWith('kover')}) {

    String allowedUnitTestNameWithFlavorAndBuild = "test${selectedFlavor}${selectedBuildType}UnitTest".toString()
    String allowedUnitTestNameWithBuildOnly = "test${selectedBuildType}UnitTest".toString()

    subprojects {
        afterEvaluate { project ->
            if (project.hasProperty("android")) {
                android.testOptions.unitTests.all {
                    if (project.hasProperty("kover")) {
                        if (name != allowedUnitTestNameWithFlavorAndBuild && name != allowedUnitTestNameWithBuildOnly) {
                            kover {
                                disabled = true
                            }
                        }
                    }
                }
            }
        }
    }
}

@shanshin
Copy link
Collaborator Author

shanshin commented Nov 8, 2022

@samuelneff, work is in progress now.
since this is not just a bug, but new features that were not originally laid in the plugin API, it took a redesign of the API for more convenient use in Android.

@shanshin
Copy link
Collaborator Author

shanshin commented Nov 8, 2022

@samuelneff, however, it would help us a lot to know how you build reports when there are several build types and flavors in the project.

Do you generate only one report by build type and all flavors, multiple reports at a time for different build types, or only individual reports for each build variant (build type + flavor)?

@G00fY2
Copy link

G00fY2 commented Nov 8, 2022

@samuelneff We have an Android project with a lot of variants (multiple flavors in different dimensions + multiple build types). We are currently using Jacoco without any issues. But even after disabling all test tasks expect for one variant we got attempted duplicate class definition exceptions when using Kover. So I guess there are more underlying issues which have to be fixed instead of only limiting the task execution.

@samuelneff
Copy link

work is in progress now.

🍾 🍾 🍾 😄 😄 😄 So happy to hear this. Thank you!!

since this is not just a bug, but new features

Different opinion on my side, but not important. So glad it's being addressed either way.

it would help us a lot to know how you build reports when there are several build types and flavors in the project

I'm happy to explain what we do and it's very possible that what we do is very unusual compared to how others use flavors and build-types. Any feedback on this that people care to share is appreciated (fine to send me a direct message to not clog up this thread with unrelated things, sam@serndesign.com. )

We have five flavors: Dev, Prod, Local, Mock, E2e. They are used for different use cases and are mutually exclusive. There is no reason we would ever run a build for more than one flavor at a time.

Our Flavors primarily are used to define which downstream server to hit. Production, shared development server, local in-development back end, or client-side mocks (no network calls at all). The e2e flavor also adds some extra utility code to support e2e testing.

So for an official build on our CI server we typically run a command like this:

./gradlew clean detekt testProdRelease koverXmlReport assembleProdRelease

and while working on the code we would usually run

./gradlew testDebugUnitTest koverXmlReport

I hope this is useful and am happy to help in any way I can--more info, early testing, whatever.

@samuelneff
Copy link

@G00fY2

We are currently using Jacoco without any issues

We actually have been running with Kover for about a year without realizing we had this issue. We always just wondered why our builds were so slow without making it a priority to look into it. It's pretty common in my experience for builds to be slower on CI than locally.

We only discovered the problem when we made a change to our build to surface errors as a giant annotation instead of being buried in the CI console output. Once we did that we immediately saw that all errors were showing up 12 times each.

@G00fY2
Copy link

G00fY2 commented Nov 9, 2022

@samuelneff If you don't have variant specific unit tests and only need to run to run them once, why not disable all tests except for one variant. This way you don't need to wait for changes to kover since there will only be one test task that can be executed:

android {
    androidComponents {
        beforeVariants { variantBuilder ->
            variantBuilder.enableUnitTest = variantBuilder.name == "MyVariantIwantTestsFor"
        }
    }
 }

@samuelneff
Copy link

@G00fY2 Thanks for the recommendation. I appreciate it, but am not sure it applies to our (unusual?) use case.

While we only build one variant at a time, we would want to run the unit tests regardless of what variant was run. If we always ran the same variant, like testDevDebugUnitTest then that would require compiling that variant regardless of which one we actually wanted to build. So we would often end up compiling twice, which is not necessary in our specific case and what I'm looking to avoid.

@hansenji
Copy link

hansenji commented Nov 9, 2022

My team is in a similar space as @samuelneff. We have a few build types that are mutually exclusive and running kover on all build types takes valuable of cpu time.

@sonrohan
Copy link

sonrohan commented Dec 5, 2022

+1 Support for this

@adrianlazaro8
Copy link

+1 for this advanced Android support. Thanks for your work!

@outadoc
Copy link

outadoc commented Jan 11, 2023

@G00fY2 Thank you for this snippet, it solves our exact needs, for both Kover and just configuring unit tests correctly overall! I'd been trying to figure this out for quite some time 🎉

@jweick
Copy link

jweick commented Jan 12, 2023

Hi,

i followed the discussion what can be done to avoid running all the buildType/variants when executing koverReport and tried a variant of a mentioned configuration option

kover {
disabled = (name == "testReleaseUnitTest")
enabled = name == "testDebugUnitTest"
}

to only run it on the testDebugUnitTest task.

That worked only partly, as something like testReleaseUnitTest was indeed not executed (log said it was SKIPPED), but related tasks like bundleReleaseClassesToCompileJar or compileReleaseUnitTestKotlin where executed.
And that should not happen, as the job just builds a debug-build.

Any ideas for a workaround until kover supports buildTypes/variants?

regards,
Jerg

UPDATE:
ok, i see i should be possible with G00fY2's last advice

android {
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.enableUnitTest = variantBuilder.name == "MyVariantIwantTestsFor"
}
}
}

but that seems not to be availably in a groovy build-script - or am i wrong?

@shanshin
Copy link
Collaborator Author

Resolved in 0.7.0-Alpha

@hamada147
Copy link

hamada147 commented Feb 15, 2024

I am using the KMP project that supports JVM and AndroidTarget with only two variants debug and release, and I'm still getting the same error above. Using Kover 0.7.5 with JaCoCo engine. If not using JaCoCo, it works with no issues.
If you need to reproduce the same issue, our repo is open sourced at Wallet SDK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Kover DSL Kover Gradle Plugin S: in progress Status: implementing or design in process
Projects
None yet
Development

Successfully merging a pull request may close this issue.