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