• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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