• 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.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