1/* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 6import org.jetbrains.kotlin.config.KotlinCompilerVersion 7import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType 8import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile 9import org.jetbrains.kotlin.konan.target.HostManager 10import org.jetbrains.dokka.gradle.DokkaTaskPartial 11 12import static Projects.* 13 14apply plugin: 'jdk-convention' 15 16buildscript { 17 /* 18 * These property group is used to build kotlinx.coroutines against Kotlin compiler snapshot. 19 * How does it work: 20 * When build_snapshot_train is set to true, kotlin_version property is overridden with kotlin_snapshot_version, 21 * atomicfu_version is overwritten by TeamCity environment (AFU is built with snapshot and published to mavenLocal 22 * as previous step or the snapshot build). 23 * Additionally, mavenLocal and Sonatype snapshots are added to repository list and stress tests are disabled. 24 * DO NOT change the name of these properties without adapting kotlinx.train build chain. 25 */ 26 def prop = rootProject.properties['build_snapshot_train'] 27 ext.build_snapshot_train = prop != null && prop != "" 28 if (build_snapshot_train) { 29 ext.kotlin_version = rootProject.properties['kotlin_snapshot_version'] 30 if (kotlin_version == null) { 31 throw new IllegalArgumentException("'kotlin_snapshot_version' should be defined when building with snapshot compiler") 32 } 33 } 34 ext.native_targets_enabled = rootProject.properties['disable_native_targets'] == null 35 36 // Determine if any project dependency is using a snapshot version 37 ext.using_snapshot_version = build_snapshot_train 38 rootProject.properties.each { key, value -> 39 if (key.endsWith("_version") && value instanceof String && value.endsWith("-SNAPSHOT")) { 40 println("NOTE: USING SNAPSHOT VERSION: $key=$value") 41 ext.using_snapshot_version = true 42 } 43 } 44 45 repositories { 46 mavenCentral() 47 maven { url "https://plugins.gradle.org/m2/" } 48 maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } 49 mavenLocal() 50 } 51 52 dependencies { 53 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 54 classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" 55 classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version" 56 classpath "org.jetbrains.kotlinx:kotlinx-knit:$knit_version" 57 classpath "com.github.node-gradle:gradle-node-plugin:$gradle_node_version" 58 classpath "org.jetbrains.kotlinx:binary-compatibility-validator:$binary_compatibility_validator_version" 59 classpath "ru.vyarus:gradle-animalsniffer-plugin:1.5.4" // Android API check 60 classpath "org.jetbrains.kotlinx:kover:$kover_version" 61 62 // JMH plugins 63 classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.2" 64 } 65 66 CacheRedirector.configureBuildScript(buildscript, rootProject) 67} 68// todo:KLUDGE: Hierarchical project structures are not fully supported in IDEA, enable only for a regular built 69if (!Idea.active) { 70 ext.set("kotlin.mpp.enableGranularSourceSetsMetadata", "true") 71} 72 73// todo:KLUDGE: This is needed to workaround dependency resolution between Java and MPP modules 74def configureKotlinJvmPlatform(configuration) { 75 configuration.attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.jvm) 76} 77 78allprojects { 79 // the only place where HostManager could be instantiated 80 project.ext.hostManager = new HostManager() 81 def deployVersion = properties['DeployVersion'] 82 if (deployVersion != null) version = deployVersion 83 84 if (build_snapshot_train) { 85 ext.kotlin_version = rootProject.properties['kotlin_snapshot_version'] 86 println "Using Kotlin $kotlin_version for project $it" 87 88 def skipSnapshotChecks = rootProject.properties['skip_snapshot_checks'] != null 89 if (!skipSnapshotChecks && version != atomicfu_version) { 90 throw new IllegalStateException("Current deploy version is $version, but atomicfu version is not overridden ($atomicfu_version) for $it") 91 } 92 93 kotlin_version = rootProject.properties['kotlin_snapshot_version'] 94 } 95 96 ext.unpublished = unpublished 97 98 // This project property is set during nightly stress test 99 def stressTest = project.properties['stressTest'] 100 101 // Copy it to all test tasks 102 tasks.withType(Test) { 103 systemProperty 'stressTest', stressTest 104 } 105} 106 107apply plugin: "binary-compatibility-validator" 108apply plugin: "base" 109apply plugin: "kover-conventions" 110 111apiValidation { 112 ignoredProjects += unpublished + ["kotlinx-coroutines-bom"] 113 if (build_snapshot_train) { 114 ignoredProjects.remove("example-frontend-js") 115 ignoredProjects.add(coreModule) 116 } 117 ignoredPackages += "kotlinx.coroutines.internal" 118} 119 120// Configure repositories 121allprojects { 122 repositories { 123 /* 124 * google should be first in the repository list because some of the play services 125 * transitive dependencies was removed from jcenter, thus breaking gradle dependency resolution 126 */ 127 google() 128 mavenCentral() 129 maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" } 130 } 131} 132 133// needs to be before evaluationDependsOn due to weird Gradle ordering 134apply plugin: "animalsniffer-conventions" 135 136// Add dependency to core source sets. Core is configured in kx-core/build.gradle 137configure(subprojects.findAll { !sourceless.contains(it.name) && it.name != coreModule }) { 138 evaluationDependsOn(":$coreModule") 139 if (isMultiplatform(it)) { 140 apply plugin: "kotlin-multiplatform" 141 apply from: rootProject.file("gradle/compile-jvm-multiplatform.gradle") 142 apply from: rootProject.file("gradle/compile-common.gradle") 143 144 if (rootProject.ext["native_targets_enabled"] as Boolean) { 145 apply from: rootProject.file("gradle/compile-native-multiplatform.gradle") 146 } 147 148 apply from: rootProject.file("gradle/compile-js-multiplatform.gradle") 149 apply from: rootProject.file("gradle/publish-npm-js.gradle") 150 kotlin.sourceSets.commonMain.dependencies { 151 api project(":$coreModule") 152 } 153 kotlin.sourceSets.jvmTest.dependencies { 154 implementation project(":$coreModule").kotlin.targets.jvm.compilations.test.output.allOutputs 155 } 156 } else { 157 def platform = PlatformKt.platformOf(it) 158 apply plugin: "kotlin-${platform}-conventions" 159 dependencies { 160 api project(":$coreModule") 161 // the only way IDEA can resolve test classes 162 testImplementation project(":$coreModule").kotlin.targets.jvm.compilations.test.output.allOutputs 163 } 164 } 165} 166 167apply plugin: "bom-conventions" 168 169// Configure subprojects with Kotlin sources 170configure(subprojects.findAll { !sourceless.contains(it.name) }) { 171 // Use atomicfu plugin, it also adds all the necessary dependencies 172 apply plugin: 'kotlinx-atomicfu' 173 174 // Configure options for all Kotlin compilation tasks 175 tasks.withType(AbstractKotlinCompile).all { 176 kotlinOptions.freeCompilerArgs += OptInPreset.optInAnnotations.collect { "-Xopt-in=" + it } 177 kotlinOptions.freeCompilerArgs += "-progressive" 178 // Disable KT-36770 for RxJava2 integration 179 kotlinOptions.freeCompilerArgs += "-XXLanguage:-ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated" 180 // Remove null assertions to get smaller bytecode on Android 181 kotlinOptions.freeCompilerArgs += ["-Xno-param-assertions", "-Xno-receiver-assertions", "-Xno-call-assertions"] 182 } 183} 184 185if (build_snapshot_train) { 186 println "Hacking test tasks, removing stress and flaky tests" 187 allprojects { 188 tasks.withType(Test).all { 189 exclude '**/*LinearizabilityTest*' 190 exclude '**/*LFTest*' 191 exclude '**/*StressTest*' 192 exclude '**/*scheduling*' 193 exclude '**/*Timeout*' 194 exclude '**/*definitely/not/kotlinx*' 195 // Disable because of KT-11567 in 1.4 196 exclude '**/*CasesPublicAPITest*' 197 // Kotlin 198 exclude '**/*PrecompiledDebugProbesTest*' 199 } 200 } 201 202 println "Manifest of kotlin-compiler-embeddable.jar for coroutines" 203 configure(subprojects.findAll { it.name == coreModule }) { 204 configurations.matching { it.name == "kotlinCompilerClasspath" }.all { 205 resolvedConfiguration.getFiles().findAll { it.name.contains("kotlin-compiler-embeddable") }.each { 206 def manifest = zipTree(it).matching { 207 include 'META-INF/MANIFEST.MF' 208 }.getFiles().first() 209 210 manifest.readLines().each { 211 println it 212 } 213 } 214 } 215 } 216} 217 218// Redefine source sets because we are not using 'kotlin/main/fqn' folder convention 219configure(subprojects.findAll { 220 !sourceless.contains(it.name) && !isMultiplatform(it) && 221 it.name != "benchmarks" && 222 it.name != "example-frontend-js" 223}) { 224 // Pure JS and pure MPP doesn't have this notion and are configured separately 225 // TODO detect it via platformOf and migrate benchmarks to the same scheme 226 sourceSets { 227 main.kotlin.srcDirs = ['src'] 228 test.kotlin.srcDirs = ['test'] 229 main.resources.srcDirs = ['resources'] 230 test.resources.srcDirs = ['test-resources'] 231 } 232} 233 234def core_docs_url = "https://kotlinlang.org/api/kotlinx.coroutines/$coreModule/" 235def core_docs_file = "$projectDir/kotlinx-coroutines-core/build/dokka/htmlPartial/package-list" 236apply plugin: "org.jetbrains.dokka" 237 238configure(subprojects.findAll { !unpublished.contains(it.name) && it.name != coreModule }) { 239 if (it.name != 'kotlinx-coroutines-bom') { 240 apply from: rootProject.file('gradle/dokka.gradle.kts') 241 } 242 apply from: rootProject.file('gradle/publish.gradle') 243} 244 245configure(subprojects.findAll { !unpublished.contains(it.name) }) { 246 if (it.name != "kotlinx-coroutines-bom") { 247 if (it.name != coreModule) { 248 tasks.withType(DokkaTaskPartial.class) { 249 dokkaSourceSets.configureEach { 250 externalDocumentationLink { 251 url.set(new URL(core_docs_url)) 252 packageListUrl.set(new File(core_docs_file).toURI().toURL()) 253 } 254 } 255 } 256 } 257 } 258 259 def thisProject = it 260 if (thisProject.name in sourceless) { 261 return 262 } 263 264 def versionFileTask = thisProject.tasks.register("versionFileTask") { 265 def name = thisProject.name.replace("-", "_") 266 def versionFile = thisProject.layout.buildDirectory.file("${name}.version") 267 it.outputs.file(versionFile) 268 269 it.doLast { 270 versionFile.get().asFile.text = version.toString() 271 } 272 } 273 274 List<String> jarTasks 275 if (isMultiplatform(it)) { 276 jarTasks = ["jvmJar", "metadataJar"] 277 } else if (it.name == "kotlinx-coroutines-debug") { 278 // We shadow debug module instead of just packaging it 279 jarTasks = ["shadowJar"] 280 } else { 281 jarTasks = ["jar"] 282 } 283 284 for (name in jarTasks) { 285 thisProject.tasks.named(name, Jar) { 286 it.dependsOn versionFileTask 287 it.from(versionFileTask) { 288 into("META-INF") 289 } 290 } 291 } 292} 293 294// Report Kotlin compiler version when building project 295println("Using Kotlin compiler version: $KotlinCompilerVersion.VERSION") 296 297// --------------- Cache redirector --------------- 298 299allprojects { 300 CacheRedirector.configure(project) 301} 302 303// --------------- Configure sub-projects that are published --------------- 304 305def publishTasks = getTasksByName("publish", true) + getTasksByName("publishNpm", true) 306 307task deploy(dependsOn: publishTasks) 308 309clean.dependsOn gradle.includedBuilds.collect { it.task(':clean') } 310 311// --------------- Knit configuration --------------- 312 313apply plugin: 'kotlinx-knit' 314 315knit { 316 siteRoot = "https://kotlinlang.org/api/kotlinx.coroutines" 317 moduleRoots = [".", "integration", "reactive", "ui"] 318 moduleDocs = "build/dokka/htmlPartial" 319 dokkaMultiModuleRoot = "build/dokka/htmlMultiModule/" 320} 321 322knitPrepare.dependsOn getTasksByName("dokkaHtmlMultiModule", true) 323 324dependencies { 325 dokkaHtmlMultiModulePlugin("org.jetbrains.kotlinx:dokka-pathsaver-plugin:$knit_version") 326} 327 328// Opt-in for build scan in order to troubleshoot Gradle on TC 329if (hasProperty('buildScan')) { 330 buildScan { 331 termsOfServiceUrl = 'https://gradle.com/terms-of-service' 332 termsOfServiceAgree = 'yes' 333 } 334} 335 336/* 337 * kotlinx-coroutines-core dependency leaks into test runtime classpath via kotlin-compiler-embeddable 338 * and conflicts with our own test/runtime incompatibilities (e.g. when class is moved from a main to test), 339 * so we do substitution here 340 */ 341allprojects { subProject -> 342 subProject 343 .configurations 344 .matching { 345 // Excluding substituted project itself because of circular dependencies, but still do it 346 // for "*Test*" configurations 347 subProject.name != coreModule || it.name.contains("Test") 348 } 349 .configureEach { conf -> 350 conf.resolutionStrategy.dependencySubstitution { 351 substitute(module("org.jetbrains.kotlinx:$coreModule")) 352 .using(project(":$coreModule")) 353 .because("Because Kotlin compiler embeddable leaks coroutines into the runtime classpath, " + 354 "triggering all sort of incompatible class changes errors") 355 } 356 } 357} 358