I need help untangling what's wrong with <fix(deps...
# scripting
p
I need help untangling what's wrong with fix(deps): update ktor monorepo to v3.1.0. Calling
.github/workflows/end-to-end-tests.main.kts
here: https://github.com/typesafegithub/github-workflows-kt/actions/runs/13436465865/job/37545104505?pr=1830 causes:
java.lang.NoClassDefFoundError: kotlinx/io/unsafe/UnsafeBufferOperations
. So far I checked that: • I cannot reproduce it locally (purged all caches, used Java 11) - reproduced it by setting a GitHub token, only then the problematic code path is executed • if I remove
@file:DependsOn("io.github.typesafegithub:action-updates-checker:3.2.1-SNAPSHOT")
and any pieces that depend on functions from it, it works - so this package is to blame •
UnsafeBufferOperations
was introduced in kotlinx-io 0.5.0 • ktor started using kotlinx-io starting 3.1.0 in this commit Something must still depend on kotlinx-io older than 0.5.0, but I cannot pin it down...
1
how do I check how Scripting resolves the versions of transitive dependencies?
I checked that after running the same logic as on GitHub, my Maven Local has kotlinx-io 0.4.0, 0.5.4 and 0.6.0
v
how do I check how Scripting resolves the versions of transitive dependencies?
You don't really want to know. 😄
p
ah, it's this problem...
how do I solve it for good? can it be solved?
v
Make sure the version you want comes first on the class loader, by either moving the dependency that depends on it to above the dependency that depends on the previous version, or just add a dependency on the later version explicitly, but also above the dependency that brings in the older version.
👍 1
p
agrhh, adding
Copy code
@file:Repository("<https://repo.maven.apache.org/maven2/>")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.6.0")
above
Copy code
@file:DependsOn("io.github.typesafegithub:action-updates-checker:3.2.1-SNAPSHOT")
just changed the error message to
Copy code
java.lang.NoSuchMethodError: 'kotlinx.io.Segment kotlinx.io.Buffer.writableSegment(int)'
looking at
./gradlew action-update-checker:dependencies
, looks like kotlinx.serialization is to blame - it still depends on kotlinx-io 0.4.0, and apparently the changes between the versions are breaking enough to make the explicit override not work
so in one part of the dependency graph, ktor depends on kotlinx-io 0.6.0:
Copy code
+--- io.ktor:ktor-io:3.1.0
|    \--- io.ktor:ktor-io-jvm:3.1.0
|         +--- org.slf4j:slf4j-api:2.0.16
|         +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1 (*)
|         +--- org.jetbrains.kotlinx:kotlinx-io-core:0.6.0
but on the other, on 0.4.0:
Copy code
io.ktor:ktor-serialization-kotlinx-json:3.1.0
\--- io.ktor:ktor-serialization-kotlinx-json-jvm:3.1.0
     +--- org.slf4j:slf4j-api:2.0.16
     +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1 (*)
     +--- io.ktor:ktor-http:3.1.0 (*)
     +--- io.ktor:ktor-serialization-kotlinx:3.1.0
     |    \--- io.ktor:ktor-serialization-kotlinx-jvm:3.1.0
     |         +--- org.slf4j:slf4j-api:2.0.16
     |         +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1 (*)
     |         +--- io.ktor:ktor-http:3.1.0 (*)
     |         +--- io.ktor:ktor-serialization:3.1.0 (*)
     |         +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.8.0 (*)
     |         \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.10 (*)
     +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0 (*)
     +--- org.jetbrains.kotlinx:kotlinx-serialization-json-io:1.8.0
     |    \--- org.jetbrains.kotlinx:kotlinx-serialization-json-io-jvm:1.8.0
     |         +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.8.0 (*)
     |         +--- org.jetbrains.kotlin:kotlin-stdlib:2.1.0 -> 2.1.10 (*)
     |         +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.8.0 (*)
     |         +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0 (*)
     |         \--- org.jetbrains.kotlinx:kotlinx-io-core:0.4.0 -> 0.6.0 (*)
I think
-> 0.6.0 (*)
means that Gradle somehow deals with it, although I don't know how, and Scripting doesn't
I'll see how hard it is to bump kotlinx-io in kotlinx.serialization, it will have to be done sooner or later anyway
v
Gradle does conflict resolution and by default uses the later version. The scripting does not. It resolves each of the dependencies in the script individually and arranges them as described in the comment I linked.
👍 1
Within one dependency and it's transitives I guess it uses that non-sense nearest-wins logic from Maven world, as it uses Aether for the resolution which is the Maven resolution engine.
👍 1
You probably have to exclude the dependency additionally from that dependency.
It would be better if the scripting used the Gradle resolution engine which works with much more sense and would also support Gradle Module Metadata.
👍 1
p
You probably have to exclude the dependency additionally from that dependency.
I tried
Copy code
implementation(projects.sharedInternal) {
        exclude("org.jetbrains.kotlinx", "kotlinx-io-core")
    }
but it doesn't work, I'm lost... I've never fought that hard with dependencies. Could you hint me more on how to sort it out?
my goal is to fix (resolve the versions) the module: https://github.com/typesafegithub/github-workflows-kt/blob/main/action-updates-checker/build.gradle.kts so that no changes are needed in the consuming script
as a side note, the action-updates-checker is probably not really popular... I thought about asking if removing it would make some people sad. However, this whole issue intrigued me enough so that I want to learn how to deal with such issues
v
I tried ... but it doesn't work
I meant in the script. If you want to fix it in that build, I think you should there add an explicit dependency on
kotlinx-io-core
. Because currently you have for the 0.6.0
Copy code
action-updates-checker
 -> github-workflows-kt 
  -> shared-internal 
   -> io.ktor:ktor-client-core 
    -> io.ktor:ktor-client-core-jvm 
     -> io.ktor:ktor-http 
      -> io.ktor:ktor-http-jvm 
       -> io.ktor:ktor-utils 
        -> io.ktor:ktor-utils-jvm 
         -> io.ktor:ktor-io 
          -> io.ktor:ktor-io-jvm 
           -> org.jetbrains.kotlinx:kotlinx-io-core:0.6.0 
            -> org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.6.0
and for the 0.4.0
Copy code
action-updates-checker
 -> github-workflows-kt
  -> shared-internal
   -> io.ktor:ktor-serialization-kotlinx-json
    -> io.ktor:ktor-serialization-kotlinx-json-jvm
     -> org.jetbrains.kotlinx:kotlinx-serialization-json-io
      -> org.jetbrains.kotlinx:kotlinx-serialization-json-io-jvm
       -> org.jetbrains.kotlinx:kotlinx-io-core:0.4.0
        -> org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.4.0
so the path to the 0.4.0 is shorter and thus wins following the non-sense Maven logic while Gradle does proper conflict resolution and uses the newer. So to tame the aether resolver, you have to provide a shorter path for 0.6.0. As the common hook-point is
shared-internal
, I'd say you should there add a
runtimeOnly
dependency on 0.6.0, then the path to it is shorter than to the 0.4.0 and Aether should use that.
🙇 1
p
👌 1