Skip to content

Added artifacts validation #377

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

Merged
merged 4 commits into from
Jul 4, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ allprojects {
version = rootProject.libs.versions.kotlinx.rpc.get()
}

println("[Core] kotlinx.rpc project version: $version, Kotlin version: $kotlinVersion, Compiler: $kotlinCompiler")
logger.lifecycle("[Core] kotlinx.rpc project version: $version, Kotlin version: $kotlinVersion, Compiler: $kotlinCompiler")

// If the prefix of the kPRC version is not Kotlin gradle plugin version – you have a problem :)
// Probably some dependency brings kotlin with the later version.
Expand Down
4 changes: 2 additions & 2 deletions compiler-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ allprojects {
}
}

println(
logger.lifecycle(
"[Compiler Plugin] kotlinx.rpc project version: $version, " +
"Kotlin version: $kotlinLangVersion, " +
"Compiler version: $kotlinCompilerVersion"
)

whenForIde {
println("[Compiler Plugin] For-ide project mode enabled")
logger.lifecycle("[Compiler Plugin] For-ide project mode enabled")
}
10 changes: 9 additions & 1 deletion docs/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ Before pushing, run (maybe separately):
```

Beware, that `detekt` doesn't fail the build, but outputs messages into the console.
Makes sense to run it separately. You can also see generated reports
Makes sense to run it separately. You can also see generated reports

Also, artifact checks: `./validatePublishedArtifacts.sh -s`.
See the [section](#tasks-to-know-about) below.

### How to work with the compiler plugin

Expand Down Expand Up @@ -486,6 +489,11 @@ usually after Kotlin version update.
- `clean` - everything
- `cleanTest` - JVM test results
- `cleanAllTests` - KMP test results
- `validatePublishedArtifacts` task and more importantly `./validatePublishedArtifacts.sh` script.

They are used to validate published artifacts and ensure you didn't delete or published something accidentally.

Available options: `--dump` - update files, `-s` - no Gradle output except for errors, `-v` - verbose output.

## Other

Expand Down
2 changes: 1 addition & 1 deletion dokka-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
group = "org.jetbrains.kotlinx"
version = libs.versions.kotlinx.rpc.get()

println("[Dokka Plugin] kotlinx.rpc project version: $version, Kotlin version: ${libs.versions.kotlin.lang.get()}")
logger.lifecycle("[Dokka Plugin] kotlinx.rpc project version: $version, Kotlin version: ${libs.versions.kotlin.lang.get()}")

kotlin {
jvmToolchain(8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import gradle.kotlin.dsl.accessors._46680087f5e33e6a2d850d9e9b86aaa7.main
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import util.csm.ProcessCsmTemplate
import util.other.libs
import kotlin.io.path.createDirectories

val kotlin = the<KotlinJvmProjectExtension>()

val templatesDir = kotlin.sourceSets.main.map {
val mainSourceSet = kotlin.sourceSets.named("main")
val templatesDir = mainSourceSet.map {
it.kotlin.srcDirs.single { dir -> dir.name == "kotlin" }.toPath().parent.resolve("templates")
}

Expand All @@ -28,6 +28,6 @@ val processCsmTemplates =
sourcesDir,
)

kotlin.sourceSets.main {
mainSourceSet.configure {
kotlin.srcDirs(processCsmTemplates.map { it.sourcesDir })
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.gradle.kotlin.dsl.registering
import util.*
import util.other.getSensitiveProperty
import util.other.isPublicModule
import util.tasks.ValidatePublishedArtifactsTask

val isGradlePlugin = project.name == "gradle-plugin"
val publishingExtension = project.extensions.findByType<PublishingExtension>()
Expand All @@ -28,7 +29,6 @@ if (isPublicModule) {

fun PublishingExtension.configurePublication() {
repositories {
configureSonatypeRepository()
configureSpaceRepository()
configureForIdeRepository()
configureLocalDevRepository()
Expand Down Expand Up @@ -138,15 +138,6 @@ fun RepositoryHandler.configureLocalDevRepository() {
}
}

fun RepositoryHandler.configureSonatypeRepository() {
configureRepository(project) {
username = "libs.sonatype.user"
password = "libs.sonatype.password"
name = "sonatype"
url = sonatypeRepositoryUri
}
}

val sonatypeRepositoryUri: String?
get() {
val repositoryId: String = project.getSensitiveProperty("libs.repository.id")
Expand All @@ -166,6 +157,10 @@ fun configureEmptyJavadocArtifact(): TaskProvider<Jar?> {
}

fun MavenPublication.signPublicationIfKeyPresent() {
if (gradle.startParameter.taskNames.contains(ValidatePublishedArtifactsTask.NAME)) {
return
}

val keyId = project.getSensitiveProperty("libs.sign.key.id")
val signingKey = project.getSensitiveProperty("libs.sign.key.private")
val signingKeyPassphrase = project.getSensitiveProperty("libs.sign.passphrase")
Expand Down
20 changes: 17 additions & 3 deletions gradle-conventions/src/main/kotlin/conventions-root.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

import util.other.isPublicModule
import util.other.libs
import util.other.maybeNamed
import util.tasks.ValidatePublishedArtifactsTask
import util.tasks.configureNpm
import util.tasks.registerChangelogTask
import util.tasks.registerDumpPlatformTableTask
Expand All @@ -27,6 +30,17 @@ allprojects {
plugins.apply("project-report")
}

tasks.register<ValidatePublishedArtifactsTask>(ValidatePublishedArtifactsTask.NAME) {
dependsOn(subprojects.filter { it.isPublicModule })
}

// Remove then first Jvm Only public module is created
val publishMavenPublicationToBuildRepoRepository = "publishMavenPublicationToBuildRepoRepository"
tasks.maybeNamed(publishMavenPublicationToBuildRepoRepository)
?: tasks.register(publishMavenPublicationToBuildRepoRepository) {
group = PublishingPlugin.PUBLISH_TASK_GROUP
}

dokka {
val libVersion = libs.versions.kotlinx.rpc.get()

Expand Down Expand Up @@ -84,7 +98,7 @@ registerDumpPlatformTableTask()
registerVerifyPlatformTableTask()
registerChangelogTask()

fun Project.forEachSubproject(action: (String, Path, Path) -> Unit) {
fun Project.forEachIncludedProject(action: (String, Path, Path) -> Unit) {
val globalRootDir: String by extra
val root = Path.of(globalRootDir)
val rootProperties = root.resolve("gradle.properties").readText()
Expand All @@ -100,7 +114,7 @@ fun Project.forEachSubproject(action: (String, Path, Path) -> Unit) {
}

val updateProperties = tasks.register("updateProperties") {
forEachSubproject { rootProperties, _, subProjectProperties ->
forEachIncludedProject { rootProperties, _, subProjectProperties ->
if (!subProjectProperties.exists()) {
subProjectProperties.createFile()
}
Expand All @@ -114,7 +128,7 @@ gradle.afterProject {
return@afterProject
}

forEachSubproject { rootProperties, parent, subProjectProperties ->
forEachIncludedProject { rootProperties, parent, subProjectProperties ->
if (!subProjectProperties.exists() || subProjectProperties.readText() != rootProperties) {
throw GradleException(
"'gradle.properties' file in ${parent.name} included project is not up-to-date with root. " +
Expand Down
7 changes: 7 additions & 0 deletions gradle-conventions/src/main/kotlin/util/other/capitalized.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package util.other

fun String.capitalized() = replaceFirstChar(Char::titlecase)
16 changes: 16 additions & 0 deletions gradle-conventions/src/main/kotlin/util/other/maybeNamed.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package util.other

import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.NamedDomainObjectProvider

internal fun <T> NamedDomainObjectCollection<T>.maybeNamed(name: String): NamedDomainObjectProvider<T>? {
return if (name in names) named(name) else null
}

internal fun <T> NamedDomainObjectCollection<T>.maybeNamed(name: String, configure: T.() -> Unit) {
if (name in names) named(name).configure(configure)
}
2 changes: 2 additions & 0 deletions gradle-conventions/src/main/kotlin/util/targets/configure.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import util.kmp
import util.setPublicArtifactId
import kotlin.collections.map

private fun KotlinMultiplatformExtension.configureTargets(config: KmpConfig): List<KotlinTarget> {
val targets = mutableListOf<KotlinTarget>()

if (config.native) {
val nativeTargets = config.nativeTargets(this)
targets.addAll(nativeTargets)
config.project.configureNativePublication(nativeTargets)
}

if (config.jvm) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

package util.targets

import org.gradle.api.Project
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.plugins.PublishingPlugin
import org.gradle.kotlin.dsl.the
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.konan.target.Family
import util.other.capitalized
import util.other.isPublicModule

private const val APPLE = "publishApplePublication"
private const val LINUX = "publishLinuxPublication"
private const val WINDOWS = "publishWindowsPublication"

fun Project.configureNativePublication(nativeTargets: List<KotlinTarget>) {
if (!isPublicModule) {
return
}

val grouped = nativeTargets.filterIsInstance<KotlinNativeTarget>().groupBy {
val family = it.konanTarget.family

when {
family.isAppleFamily -> {
APPLE
}

family == Family.LINUX -> {
LINUX
}

family == Family.MINGW -> {
WINDOWS
}

else -> null
}
}

configureNativePublication(grouped, APPLE)
configureNativePublication(grouped, LINUX)
configureNativePublication(grouped, WINDOWS)
}

private fun Project.configureNativePublication(grouped: Map<String?, List<KotlinNativeTarget>>, groupName: String) {
val targets = grouped[groupName] ?: return

val repos = provider {
the<PublishingExtension>().repositories.map { it.name }
}

repos.get().forEach { repositoryName ->
tasks.register("${groupName}To${repositoryName.capitalized()}Repository").configure {
group = PublishingPlugin.PUBLISH_TASK_GROUP

dependsOn(targets.map {
"publish${it.name.capitalized()}PublicationTo${repositoryName.capitalized()}Repository"
})
}
}
}
Loading