kotest icon indicating copy to clipboard operation
kotest copied to clipboard

IncompatibleClassChangeError with Kotlin 2.0.20-Beta2 for native (iOS) targets

Open JesusMcCloud opened this issue 1 year ago • 35 comments

Which version of Kotest are you using Kotest 5.9.1

Hi!

We ran into an issue testing our KMP codebase against Kotlin 2.0.20-Beta2 (Beta1 works, 2.0.10-RC also works). Kotest fails to start the iOS tests due to an IncompatibleClassChangeError. Here's the output of out CI pipeline triggering it.

JesusMcCloud avatar Jul 18 '24 07:07 JesusMcCloud

Thanks! Looks like a change in the Kotlin compiler that requires updating the Kotest compiler plugin.

e: java.lang.IncompatibleClassChangeError: Found class org.jetbrains.kotlin.ir.declarations.IrFactory, but interface was expected
	at io.kotest.framework.multiplatform.embeddablecompiler.NativeTransformer.generateLauncher(NativeTransformer.kt:46)
	at io.kotest.framework.multiplatform.embeddablecompiler.Transformer.visitModuleFragment(Transformer.kt:65)
	at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitModuleFragment(IrElementTransformerVoid.kt:113)
	at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitModuleFragment(IrElementTransformerVoid.kt:19)
	at org.jetbrains.kotlin.ir.declarations.IrModuleFragment.accept(IrModuleFragment.kt:33)
	at org.jetbrains.kotlin.ir.declarations.IrModuleFragment.transform(IrModuleFragment.kt:36)
	at io.kotest.framework.multiplatform.embeddablecompiler.SpecIrGenerationExtension.generate(SpecIrGenerationExtension.kt:23)
	at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.applyIrGenerationExtensions(convertToIr.kt:437)
	at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.runActualizationPipeline(convertToIr.kt:246)
	at org.jetbrains.kotlin.fir.pipeline.Fir2IrPipeline.convertToIrAndActualize(convertToIr.kt:130)
	at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize(convertToIr.kt:99)
	at org.jetbrains.kotlin.fir.pipeline.ConvertToIrKt.convertToIrAndActualize$default(convertToIr.kt:72)
	at org.jetbrains.kotlin.backend.konan.Fir2IrKt.fir2Ir(Fir2Ir.kt:99)

OliverO2 avatar Jul 18 '24 10:07 OliverO2

The latest snapshot might have this fixed @JesusMcCloud

sksamuel avatar Aug 06 '24 23:08 sksamuel

it is indeed fixed with latest 6.0.0 SNAPSHOT. Thank you very much!

Still keeping this one open until 6.0.0 is released. Feel free to close at your own discretion.

JesusMcCloud avatar Aug 15 '24 19:08 JesusMcCloud

Are there plans to backport the fix to 5.9.x?

YSakhno avatar Aug 29 '24 00:08 YSakhno

Are there plans to backport the fix to 5.9.x?

We've just switched to using 6.0.0-SNAPSHOT. Works like a charm even on complex KMP projects!

JesusMcCloud avatar Aug 29 '24 06:08 JesusMcCloud

Could it be possible to publish a version with this fix? Even if it's a 6.0.0-alpha.1 or similar, it doesn't have to be stable, I just can't depend on -SNAPSHOT versions because they are mutable.

CLOVIS-AI avatar Sep 03 '24 16:09 CLOVIS-AI

I am also going to lend my voice to asking for a release for the fix for this breaking bug. Especially since kotest does not work with the latest stable version of Kotlin without it. I cannot use a constantly changing snapshot library to test production code.

alyssa-nash avatar Sep 03 '24 16:09 alyssa-nash

In the meantime, we're using snapshot version 6.0.0-20240905.065253-61 as a test dependency. This version works for iOS, JVM, Android and is not mutable.

JesusMcCloud avatar Sep 05 '24 11:09 JesusMcCloud

I apologize if I am missing something, but I am getting Failed to resolve: io.kotest:kotest-property:6.0.0-20240905.065253-61 errors. When I look on s01.oss.sonatype.org I see the usual structure is 6.0.0.(some number)-morenumbers. The highest snapshot in the directory is 6.0.0-1564 which still provides the original error since it predates the fix. Is there a better way to look through snapshots?

alyssa-nash avatar Sep 05 '24 17:09 alyssa-nash

@alyssa-nash maybe you are not using a recent enough gradle version? if you look into the repo, it is there.

JesusMcCloud avatar Sep 05 '24 17:09 JesusMcCloud

Gradle needs a special setup to access snapshot artifacts.

This is what I'm using to access the snapshots repo for the Kotest Gradle plugin:

In settings.gradle.kts:

@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
    pluginManagement {
        repositories {
            specialRepositories()
            gradlePluginPortal()
        }
    }
    repositories {
        mavenCentral()
        specialRepositories()
    }
}

fun RepositoryHandler.specialRepositories() {
    maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
        name = "MavenCentralSnapshots"
        mavenContent { snapshotsOnly() }
    }
}

In gradle/libs.versions.toml:

[versions]

# https://github.com/kotest/kotest/releases
io-kotest = "5.9.1"
io-kotest-gradle-plugin = "6.0.0-20240905.065253-61"

# https://github.com/JetBrains/kotlin/releases
org-jetbrains-kotlin = "2.0.20"

[libraries]

io-kotest-kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "io-kotest" }
io-kotest-kotest-framework-engine = { module = "io.kotest:kotest-framework-engine", version.ref = "io-kotest" }

[plugins]

io-kotest-multiplatform = { id = "io.kotest.multiplatform", version.ref = "io-kotest-gradle-plugin" }
org-jetbrains-kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "org-jetbrains-kotlin" }

In build.gradle.kts:

plugins {
    alias(libs.plugins.org.jetbrains.kotlin.multiplatform)
    alias(libs.plugins.io.kotest.multiplatform)
}

kotlin {
    linuxX64 {
        binaries.executable()
    }

    sourceSets {
        val commonTest by getting {
            dependencies {
                implementation(libs.io.kotest.kotest.framework.engine)
                implementation(libs.io.kotest.kotest.assertions.core)
            }
        }
    }
}

Does that help?

OliverO2 avatar Sep 05 '24 18:09 OliverO2

I have never thought of NOT keeping the gradle plugin and the test dependencies in sync, but here it seems to be a viable strategy.

JesusMcCloud avatar Sep 05 '24 18:09 JesusMcCloud

Thank you @OliverO2 and @JesusMcCloud. My issue was that some of the artifacts do not match. For instance kotest-property uses 6.0.0-20240905.065253-62, while some like kotest-framework-engine uses 6.0.0-20240905.065253-61. But I tried what @OliverO2 suggested and am using 5.9.1 for the test dependencies and keeping the gradle plugin to an immutable snapshot and it works like a charm.

alyssa-nash avatar Sep 05 '24 19:09 alyssa-nash

Thanks for the feedback! Happy to hear that we have arrived at a viable solution.

Kotest 6.0 development is pretty dynamic with no release date in sight, so sticking to 5.9.1 for the library artifacts is best for stability, while the 6.0.0-xxx Gradle/compiler plugin supports the Kotlin 2.0.20 compiler. Best of both worlds, I'd say.

Unfortunately, new Kotlin versions can break the APIs used by compiler plugins at any time without advance notice. In this case, it was just a compiler class becoming an interface (a source-compatible binary incompatibility). This situation will be with us until the Kotlin compiler team figures out how to provide sufficiently stable compiler APIs.

OliverO2 avatar Sep 05 '24 20:09 OliverO2

This workaround doesn't seem to work for me.

Plugin [id: 'io.kotest.multiplatform', version: '6.0.0-20240905.065253-61'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Included Builds (None of the included builds contain this plugin)
- Plugin Repositories (could not resolve plugin artifact 'io.kotest.multiplatform:io.kotest.multiplatform.gradle.plugin:6.0.0-20240905.065253-61')
  Searched in the following repositories:
    Gradle Central Plugin Repository
    MavenCentralSnapshots(https://s01.oss.sonatype.org/content/repositories/snapshots/)
    MavenRepo

And, indeed, there is no such version in the Central snapshots repository: https://s01.oss.sonatype.org/content/repositories/snapshots/io/kotest/multiplatform/io.kotest.multiplatform.gradle.plugin/

I can't find where that version is?

Edit. Ah, it's here. But why would Gradle search there?

CLOVIS-AI avatar Sep 10 '24 11:09 CLOVIS-AI

I'd like to add my voice to those asking for a backported fix prior to the 6.0 release of the library. Setting up an artifactory remote to pull a snapshot is not an option at my company. This is currently blocking all Kotlin language fixes on KMP projects that use Kotest.

Spirarel avatar Sep 12 '24 21:09 Spirarel

Can someone who managed to get the workaround working explain what they did? It doesn't work for me, as I explained in my previous message :/

CLOVIS-AI avatar Sep 16 '24 20:09 CLOVIS-AI

I don't have it in an isolated project, but the combination of pinning a specific snapshot version for the plugin, alongside 5.9.1 for kotest dependencies works perfectly well in our conventions plugin. We simply set the kotest plugin version to a specific snapshot and everything else (like kotest-framework-engine, etc.) to 5.9.1.

JesusMcCloud avatar Sep 17 '24 20:09 JesusMcCloud

https://github.com/wgpu4k/wgpu4k For this project, I've been using the latests v6 snapshots. So far, I haven't encountered any instability, although there's been a significant increase in download size with each new snapshot build.

ygdrasil-io avatar Sep 17 '24 22:09 ygdrasil-io

https://github.com/wgpu4k/wgpu4k For this project, I've been using the latests v6 snapshots. So far, I haven't encountered any instability, although there's been a significant increase in download size with each new snapshot build.

yes, but this is always the latest snapshot. it is not a fixed buildrev.

JesusMcCloud avatar Sep 18 '24 09:09 JesusMcCloud

I can't help with company policy, but for those still looking how to make this work: Have you tried to use the exact configuration I posted above?

OliverO2 avatar Sep 18 '24 10:09 OliverO2

@CLOVIS-AI: @OliverO2's solution is what the conventions plugin does, wrt. kotest.

I just remembered: we do have everything self-contained in one project as well. Here, we did exactly what @OliverO2 suggested, and it works like a charm! As far as I am concerned, he provided the solution.

JesusMcCloud avatar Sep 18 '24 10:09 JesusMcCloud

I can also confirm this solution to be working for Kotlin 2.1.0-Beta1

JesusMcCloud avatar Sep 18 '24 11:09 JesusMcCloud

6.0.0-20240905.065253-61 was just depublished. now it's broken again

JesusMcCloud avatar Sep 19 '24 15:09 JesusMcCloud

would it be possible to have one snapshot build with this fix published more permanently or backport the fix to a 5.9.2 release? every time a snapshot gets depublished, the chore of updating every project starts anew.

JesusMcCloud avatar Sep 20 '24 06:09 JesusMcCloud

I don't do releases, so I'm not the one to decide how to proceed. What I can tell is:

  • This is not a "fix" that could be "backported". It is a recompilation of the Kotest compiler plugin.
  • The current build structure uses the same Kotlin version for the library and the compiler plugin. So just updating the Kotlin version to have a fresh compiler plugin would force all Kotest users to use Kotlin 2.0.20 for the library by default. This may not work for everyone. Libraries are usually conservative and do not force newer dependencies upon users for a reason.
  • Kotest does not currently have a release strategy in place which would maintain several version branches simultaneously. We work on master and publish a new release when it is ready.

Hopefully that helps to understand why resolving this case to everyone's satisfaction is not as straightforward as one might think. If we had unlimited resources, we'd be in a better position, of course.

OliverO2 avatar Sep 20 '24 16:09 OliverO2

We could publish a 6.0.0.M1 that would be permanent while making clear its prerelease

sksamuel avatar Sep 20 '24 17:09 sksamuel

Please do! <3

CLOVIS-AI avatar Sep 20 '24 20:09 CLOVIS-AI

I am unpinning the snapshot version in all of our projects, because pinning is no use anyway, given snapshots disappear within a week. So the idea, to depend on an immutable snapshot is good, but execution will never work for longer than a week.

I fully understand resources are limited, but again. just one 6.0.0 preview version of the gradle plugin would be highly appreciated!

JesusMcCloud avatar Sep 26 '24 05:09 JesusMcCloud

@sksamuel Do you have new information on that pre-release version's availability? We have multiple repositories that are stuck with broken versions for more than two months now.

CLOVIS-AI avatar Sep 26 '24 09:09 CLOVIS-AI