Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ kotlin = "2.2.21"
dokka = "2.1.0"
jvmTarget = "17"
kotlinxCollectionsImmutable = "0.4.0"
kotlinxSerialization = "1.8.0"
kotlinxSerialization = "1.9.0"
kotlinBinaryCompatibility = "0.18.1"
lintApi = "31.13.0"
nexusPlugin = "0.34.0"
Expand All @@ -15,6 +15,7 @@ androidxComposeBom = "2025.10.01"
jetbrains-compose = "1.9.2"
compose-stability-analyzer = "0.5.2"
spotless = "6.21.0"
shadow = "8.1.1"

[libraries]
androidx-compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compiler" }
Expand Down Expand Up @@ -49,3 +50,4 @@ compose-stability-analyzer = { id = "com.github.skydoves.compose.stability.analy
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
nexus-plugin = { id = "com.vanniktech.maven.publish", version.ref = "nexusPlugin" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
39 changes: 39 additions & 0 deletions stability-compiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.jvm.tasks.Jar

plugins {
kotlin("jvm")
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.shadow)
alias(libs.plugins.nexus.plugin)
`maven-publish`
}

kotlin {
Expand Down Expand Up @@ -47,4 +52,38 @@ dependencies {
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

// Configure shadowJar to embed kotlinx.serialization
tasks.shadowJar {
archiveClassifier.set("all") // Use a classifier to avoid conflict with jar task

// Merge all runtime dependencies (including kotlinx-serialization)
// By default, shadow excludes nothing, so we need to explicitly configure
configurations = listOf(project.configurations.runtimeClasspath.get())

// Don't relocate - K/Native compiler needs original package names
// relocate("kotlinx.serialization", "...")

// Exclude unnecessary files
exclude("META-INF/maven/**")
exclude("META-INF/*.SF")
exclude("META-INF/*.DSA")
exclude("META-INF/*.RSA")
}

// Make jar task produce the shadowJar content
tasks.named<Jar>("jar") {
dependsOn(tasks.shadowJar)
// Copy shadowJar content after jar is built
doLast {
val shadowTask = tasks.shadowJar.get()
val shadowJarFile = shadowTask.archiveFile.get().asFile
val jarFile = archiveFile.get().asFile

if (shadowJarFile.exists()) {
shadowJarFile.copyTo(jarFile, overwrite = true)
logger.lifecycle("Replaced ${jarFile.name} with shadowJar content")
}
}
Comment on lines 70 to 81
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Jar replacement logic is fragile and non-standard.

Using doLast { ... } to overwrite the jar file with shadowJar content bypasses Gradle's task model and caching mechanisms, which can lead to non-deterministic builds and cache invalidation issues. This approach is not idiomatic for Gradle plugin development.

Consider these alternatives:

  • Configure shadowJar to output to the expected jar location instead.
  • Use Gradle's artifact management (publishArtifact) to declare shadowJar as the primary artifact.
  • Adjust the Maven publication configuration to reference shadowJar directly if used in publications.

Do you have a specific reason for the current approach, or would you prefer to refactor this to use standard Gradle patterns?

🤖 Prompt for AI Agents
In stability-compiler/build.gradle.kts around lines 76 to 88, the current doLast
block copies the shadowJar over the produced jar, which bypasses Gradle's task
model and caching; remove the doLast override and instead produce the shadow
artifact via standard Gradle semantics by one of: configure the shadowJar task
to write to the same archive location/name as the jar (set
archiveFileName/archiveClassifier appropriately and disable the default jar if
needed), or mark the shadowJar as the published/primary artifact (use
publications { ... artifact(tasks.shadowJar) { builtBy(tasks.shadowJar) } } or
publishArtifact=true) so Maven publications reference the shadow output
directly; after switching, delete the file-copying logic and ensure task
dependencies are set (e.g., jar.dependsOn shadowJar or builtBy) so builds remain
cacheable and deterministic.

}
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ public class StabilityAnalyzerGradlePlugin : KotlinCompilerPluginSupportPlugin {
val runtimeDependency = runtimeProject
?: "$GROUP_ID:$RUNTIME_ARTIFACT_ID:$VERSION"

// Add runtime to all compiler plugin classpath configurations (not general compiler classpath)
// Add runtime to all compiler plugin classpath configurations
// Note: kotlinx.serialization is now embedded in the compiler JAR via shadow plugin
project.configurations.configureEach {
if (name.contains("CompilerPluginClasspath", ignoreCase = true)) {
project.dependencies.add(name, runtimeDependency)
Expand Down