Merge tag '0.14.4' am: daa6047d51

Original change: https://android-review.googlesource.com/c/platform/external/kotlinx.atomicfu/+/1511394

Change-Id: I3377f48223e6d5b42e386b6b12a48d60291cdf2b
diff --git a/CHANGES.md b/CHANGES.md
index 1cecd18..fe0edc4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,11 @@
 # Change log for kotlinx.atomicfu
 
+# Version 0.14.4
+
+* Fixed bug when Maven plugin wasn't published
+* Migrate to new Kotlin HMPP metadata for multiplatform projects 
+* Update Kotlin to 1.4.0
+
 # Version 0.14.3
 
 * Update to Kotlin 1.3.71.
diff --git a/METADATA b/METADATA
index 631a340..c25731d 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/Kotlin/kotlinx.atomicfu"
   }
-  version: "0.14.3"
+  version: "0.14.4"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 7
-    day: 10
+    month: 11
+    day: 25
   }
 }
diff --git a/atomicfu-gradle-plugin/build.gradle b/atomicfu-gradle-plugin/build.gradle
index 1736dc3..864e88e 100644
--- a/atomicfu-gradle-plugin/build.gradle
+++ b/atomicfu-gradle-plugin/build.gradle
@@ -33,7 +33,12 @@
 evaluationDependsOn(':atomicfu')
 def atomicfu = project(':atomicfu')
 def atomicfuJvmJarTask = atomicfu.tasks.getByName(atomicfu.kotlin.targets.jvm.artifactsTaskName)
-def atomicfuJsJarTask = atomicfu.tasks.getByName(atomicfu.kotlin.targets.js.artifactsTaskName)
+
+def jsLegacy = atomicfu.kotlin.targets.hasProperty("jsLegacy")
+        ? atomicfu.kotlin.targets.jsLegacy
+        : atomicfu.kotlin.targets.js
+def atomicfuJsJarTask = atomicfu.tasks.getByName(jsLegacy.artifactsTaskName)
+
 def atomicfuMetadataJarTask = atomicfu.tasks.getByName(atomicfu.kotlin.targets.metadata.artifactsTaskName)
 
 // Write the plugin's classpath to a file to share with the tests
diff --git a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt
index f803af9..bb619a5 100644
--- a/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt
+++ b/atomicfu-gradle-plugin/src/main/kotlin/kotlinx/atomicfu/plugin/gradle/AtomicFUGradlePlugin.kt
@@ -50,14 +50,6 @@
         )
         dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.JS, version))
     }
-    withPluginWhenEvaluatedDependencies("kotlin-native") { version ->
-        dependencies.add(IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.NATIVE, version))
-        dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.NATIVE, version))
-    }
-    withPluginWhenEvaluatedDependencies("kotlin-platform-common") { version ->
-        dependencies.add(COMPILE_ONLY_CONFIGURATION, getAtomicfuDependencyNotation(Platform.COMMON, version))
-        dependencies.add(TEST_IMPLEMENTATION_CONFIGURATION, getAtomicfuDependencyNotation(Platform.COMMON, version))
-    }
     withPluginWhenEvaluatedDependencies("kotlin-multiplatform") { version ->
         configureMultiplatformPluginDependencies(version)
     }
@@ -96,10 +88,10 @@
 }
 
 private enum class Platform(val suffix: String) {
-    JVM(""),
+    JVM("-jvm"),
     JS("-js"),
-    NATIVE("-native"),
-    COMMON("-common")
+    NATIVE(""),
+    MULTIPLATFORM("")
 }
 
 private enum class CompilationType { MAIN, TEST }
@@ -243,10 +235,27 @@
 
 fun Project.configureMultiplatformPluginDependencies(version: String) {
     if (rootProject.findProperty("kotlin.mpp.enableGranularSourceSetsMetadata").toString().toBoolean()) {
-        val configurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets
+        val mainConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets
                 .getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
                 .compileOnlyConfigurationName
-        dependencies.add(configurationName, getAtomicfuDependencyNotation(Platform.NATIVE, version))
+        dependencies.add(mainConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version))
+
+        val testConfigurationName = project.extensions.getByType(KotlinMultiplatformExtension::class.java).sourceSets
+                .getByName(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
+                .implementationConfigurationName
+        dependencies.add(testConfigurationName, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version))
+
+        // For each source set that is only used in Native compilations, add an implementation dependency so that it
+        // gets published and is properly consumed as a transitive dependency:
+        sourceSetsByCompilation().forEach { (sourceSet, compilations) ->
+            val isSharedNativeSourceSet = compilations.all {
+                it.platformType == KotlinPlatformType.common || it.platformType == KotlinPlatformType.native
+            }
+            if (isSharedNativeSourceSet) {
+                val configuration = sourceSet.implementationConfigurationName
+                dependencies.add(configuration, getAtomicfuDependencyNotation(Platform.MULTIPLATFORM, version))
+            }
+        }
     } else {
         sourceSetsByCompilation().forEach { (sourceSet, compilations) ->
             val platformTypes = compilations.map { it.platformType }.toSet()
@@ -256,9 +265,9 @@
             val compilationType = compilationNames.single().compilationNameToType()
                     ?: return@forEach // skip unknown compilations
             val platform =
-                    if (platformTypes.size > 1) Platform.COMMON else // mix of platform types -> "common"
+                    if (platformTypes.size > 1) Platform.MULTIPLATFORM else // mix of platform types -> "common"
                         when (platformTypes.single()) {
-                            KotlinPlatformType.common -> Platform.COMMON
+                            KotlinPlatformType.common -> Platform.MULTIPLATFORM
                             KotlinPlatformType.jvm, KotlinPlatformType.androidJvm -> Platform.JVM
                             KotlinPlatformType.js -> Platform.JS
                             KotlinPlatformType.native -> Platform.NATIVE
@@ -392,12 +401,17 @@
 
 @CacheableTask
 open class AtomicFUTransformTask : ConventionTask() {
+    @PathSensitive(PathSensitivity.RELATIVE)
     @InputFiles
     lateinit var inputFiles: FileCollection
+
     @OutputDirectory
     lateinit var outputDir: File
+
+    @Classpath
     @InputFiles
     lateinit var classPath: FileCollection
+
     @Input
     var variant = "FU"
     @Input
@@ -418,8 +432,10 @@
 
 @CacheableTask
 open class AtomicFUTransformJsTask : ConventionTask() {
+    @PathSensitive(PathSensitivity.RELATIVE)
     @InputFiles
     lateinit var inputFiles: FileCollection
+
     @OutputDirectory
     lateinit var outputDir: File
     @Input
diff --git a/atomicfu/build.gradle b/atomicfu/build.gradle
index e5707b5..682c48a 100644
--- a/atomicfu/build.gradle
+++ b/atomicfu/build.gradle
@@ -22,14 +22,16 @@
         addNative(delegate.fromPreset(preset, preset.name))
     }
 
+    // JS -- always
+    js {
+        // TODO: Commented out because browser tests do not work on TeamCity
+        // browser()
+        nodejs()
+    }
+
     targets {
-        // JVM & JS -- always
+        // JVM -- always
         fromPreset(presets.jvm, 'jvm')
-        fromPreset(presets.js, 'js') {
-            // TODO: Commented out because browser tests do not work on TeamCity
-            // browser()
-            nodejs()
-        }
 
         if (project.ext.ideaActive) {
             addNative(fromPreset(project.ext.ideaPreset, 'native'))
@@ -113,22 +115,12 @@
         nativeMain.dependsOn(nativeInterop)
     }
 
-    afterEvaluate {
-        def nativeTarget = kotlin.targets.findByName("linuxX64")
-        def cinteropTask = tasks.named(kotlin.linuxX64().compilations["main"].cinterops[0].interopProcessingTaskName)
-        def cinteropKlib = cinteropTask.map { it.outputFile }
-        def fakeCinteropCompilation = kotlin.targets["metadata"].compilations[kotlin.sourceSets.nativeInterop.name]
-        def destination = fakeCinteropCompilation.compileKotlinTask.destinationDir
+    apply from: "$rootDir/gradle/interop-as-source-set-klib.gradle"
 
-        task copyCinteropKlib(type: Zip) {
-            from(zipTree(cinteropKlib).matching { it.exclude("targets/**") })
-            destinationDirectory.set(destination)
-            archiveFileName.set("${project.name}_${fakeCinteropCompilation.name}.klib")
-            dependsOn cinteropTask
-        }
-
-        fakeCinteropCompilation.output.classesDirs.from(files().builtBy(copyCinteropKlib))
-    }
+    registerInteropAsSourceSetOutput(
+            kotlin.linuxX64().compilations["main"].cinterops["interop"],
+            kotlin.sourceSets["nativeInterop"]
+    )
 }
 
 configurations {
@@ -145,7 +137,11 @@
 
 // ==== CONFIGURE JS =====
 
-tasks.withType(compileKotlinJs.getClass()) {
+def compileJsLegacy = tasks.hasProperty("compileKotlinJsLegacy")
+        ? compileKotlinJsLegacy
+        : compileKotlinJs
+
+tasks.withType(compileJsLegacy.getClass()) {
     kotlinOptions {
         moduleKind = "umd"
         sourceMap = true
@@ -153,7 +149,7 @@
     }
 }
 
-compileKotlinJs {
+compileJsLegacy.configure {
     kotlinOptions {
         // NOTE: Module base-name must be equal to the package name declared in package.json
         def baseName = "kotlinx-atomicfu"
@@ -162,7 +158,6 @@
 }
 
 apply from: file("$rootProject.projectDir/gradle/node-js.gradle")
-apply from: file("$rootProject.projectDir/gradle/test-mocha-js.gradle")
 apply from: file("$rootProject.projectDir/gradle/publish-npm-js.gradle")
 
 // Workaround the problem with Node downloading
@@ -174,17 +169,21 @@
     }
 }
 
-def transformedJsFile = compileTestKotlinJs.kotlinOptions.outputFile
-compileTestKotlinJs {
+def compileTestJsLegacy = tasks.hasProperty("compileTestKotlinJsLegacy")
+        ? compileTestKotlinJsLegacy
+        : compileTestKotlinJs
+
+def transformedJsFile = compileTestJsLegacy.kotlinOptions.outputFile
+compileTestJsLegacy.configure {
     kotlinOptions {
         // NOTE: Module base-name must be equal to the package name declared in package.json
         def baseName = "kotlinx-atomicfu"
         outputFile = new File(outputFile.parent, baseName + ".js")
     }
 }
-def originalJsFile = compileTestKotlinJs.kotlinOptions.outputFile
+def originalJsFile = compileTestJsLegacy.kotlinOptions.outputFile
 
-task transformJS(type: JavaExec, dependsOn: [compileTestKotlinJs]) {
+task transformJS(type: JavaExec, dependsOn: [compileTestJsLegacy]) {
     main = "kotlinx.atomicfu.transformer.AtomicFUTransformerJSKt"
     args = [originalJsFile, transformedJsFile]
     classpath = configurations.transformer
@@ -192,8 +191,8 @@
     outputs.file(transformedJsFile)
 }
 
-if (project.tasks.findByName('legacyjsNodeTest')) {
-    legacyjsNodeTest.dependsOn transformJS
+if (project.tasks.findByName('jsLegacyNodeTest')) {
+    jsLegacyNodeTest.dependsOn transformJS
 } else {
     jsNodeTest.dependsOn transformJS
 }
@@ -298,9 +297,15 @@
 
 afterEvaluate {
     publishing.publications {
-        jvm.artifactId = 'atomicfu'
-        js.artifactId = 'atomicfu-js'
         metadata.artifactId = 'atomicfu-common'
-        kotlinMultiplatform.artifactId = 'atomicfu-native'
+
+        kotlinMultiplatform {
+            apply from: "$rootDir/gradle/publish-mpp-root-module-in-platform.gradle"
+            publishPlatformArtifactsInRootModule(jvm)
+        }
     }
 }
+
+tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication"}.configureEach {
+    dependsOn(tasks["generatePomFileForJvmPublication"])
+}
diff --git a/gradle.properties b/gradle.properties
index d02e6ed..8a16358 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,10 +2,10 @@
 # Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 #
 
-version=0.14.3-SNAPSHOT
+version=0.14.4-SNAPSHOT
 group=org.jetbrains.kotlinx
 
-kotlin_version=1.3.71
+kotlin_version=1.4.0
 asm_version=7.2
 slf4j_version=1.8.0-alpha2
 junit_version=4.12
@@ -26,4 +26,8 @@
 kotlin.js.compiler=both
 
 kotlin.mpp.enableGranularSourceSetsMetadata=true
-kotlin.mpp.enableCompatibilityMetadataVariant=true
\ No newline at end of file
+kotlin.mpp.enableCompatibilityMetadataVariant=true
+
+# Workaround for Bintray treating .sha512 files as artifacts
+# https://github.com/gradle/gradle/issues/11412
+systemProp.org.gradle.internal.publish.checksums.insecure=true
diff --git a/gradle/interop-as-source-set-klib.gradle b/gradle/interop-as-source-set-klib.gradle
new file mode 100644
index 0000000..62f2b77
--- /dev/null
+++ b/gradle/interop-as-source-set-klib.gradle
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014-2020 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+project.ext.registerInteropAsSourceSetOutput = { interop, sourceSet ->
+    afterEvaluate {
+        def cinteropTask = tasks.named(interop.interopProcessingTaskName)
+        def cinteropKlib = cinteropTask.map { it.outputFile }
+        def fakeCinteropCompilation = kotlin.targets["metadata"].compilations[sourceSet.name]
+        def destination = fakeCinteropCompilation.compileKotlinTask.destinationDir
+
+        def tempDir = "$buildDir/tmp/${sourceSet.name}UnpackedInteropKlib"
+
+        def prepareKlibTaskProvider = tasks.register("prepare${sourceSet.name.capitalize()}InteropKlib", Sync) {
+            from(files(zipTree(cinteropKlib).matching {
+                exclude("targets/**", "default/targets/**")
+            }).builtBy(cinteropTask))
+
+            into(tempDir)
+
+            doLast {
+                def manifest140 = file("$tempDir/default/manifest")
+                def manifest1371 = file("$tempDir/manifest")
+                def manifest = manifest140.exists() ? manifest140 : manifest1371
+
+                def lines = manifest.readLines()
+                def modifiedLines = lines.collect { line ->
+                    line.startsWith("depends=") ? "depends=stdlib ${manifest == manifest140 ? 'org.jetbrains.kotlin.native.platform.posix' : 'posix'}" :
+                            line.startsWith("native_targets=") ? "native_targets=" :
+                                    line
+                }
+                manifest.text = modifiedLines.join("\n")
+            }
+        }
+
+        def copyCinteropTaskProvider = tasks.register("copy${sourceSet.name.capitalize()}CinteropKlib",  Zip) {
+            from(fileTree(tempDir).builtBy(prepareKlibTaskProvider))
+            destinationDirectory.set(destination)
+            archiveFileName.set("${project.name}_${fakeCinteropCompilation.name}.klib")
+            dependsOn cinteropTask
+        }
+
+        fakeCinteropCompilation.output.classesDirs.from(files().builtBy(copyCinteropTaskProvider))
+
+        kotlin.sourceSets.matching {
+            def visited = new HashSet()
+            def visit
+            visit = { s -> if (visited.add(s)) s.dependsOn.each { visit(it) } }
+            visit(it)
+            sourceSet in visited
+        }.all {
+            project.dependencies.add(implementationMetadataConfigurationName, files(cinteropKlib))
+        }
+    }
+}
diff --git a/gradle/node-js.gradle b/gradle/node-js.gradle
index f549c2e..6766dee 100644
--- a/gradle/node-js.gradle
+++ b/gradle/node-js.gradle
@@ -10,42 +10,3 @@
     download = true
     nodeModulesDir = file(buildDir)
 }
-
-// Configures testing for JS modules
-
-task prepareNodePackage(type: Copy) {
-   from("npm") {
-       include 'package.json'
-       expand (project.properties + [kotlinDependency: ""])
-   }
-   from("npm") {
-       exclude 'package.json'
-   }
-   into "$node.nodeModulesDir"
-}
-
-npmInstall.dependsOn prepareNodePackage
-
-task populateNodeModules(type: Copy, dependsOn: [compileKotlinJs]) {
-    from (compileKotlinJs.destinationDir) {
-        exclude '**/kotlinx-atomicfu/*'
-    }
-    into "$node.nodeModulesDir/node_modules"
-
-    afterEvaluate {
-        def runtimeClassPath = configurations.hasProperty("legacyjsTestRuntimeClasspath")
-                ? configurations.legacyjsTestRuntimeClasspath
-                : configurations.jsTestRuntimeClasspath
-
-        runtimeClassPath.each {
-            if (it.absolutePath.endsWith(".jar")) {
-                from zipTree(it.absolutePath).matching {
-                    include '*.js'
-                    include '*.js.map'
-                }
-            }
-        }
-    }
-}
-
-npmInstall.dependsOn populateNodeModules
diff --git a/gradle/publish-bintray.gradle b/gradle/publish-bintray.gradle
index ba5aca3..50f2590 100644
--- a/gradle/publish-bintray.gradle
+++ b/gradle/publish-bintray.gradle
@@ -34,7 +34,7 @@
             def user = 'kotlin'
             def repo = 'kotlinx'
             def name = 'kotlinx.atomicfu'
-            url = "https://api.bintray.com/maven/$user/$repo/$name/;publish=0"
+            url = "https://api.bintray.com/maven/$user/$repo/$name/;publish=0;override=0"
 
             credentials {
                 username = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
@@ -67,8 +67,8 @@
     publications.all {
         pom.withXml(configureMavenCentralMetadata)
 
-        // add empty javadocs (no need for MPP root publication which publishes only pom file)
-        if (it.name != 'kotlinMultiplatform') {
+        // add empty javadocs
+        if (it.name != "kotlinMultiplatform") { // The root module gets the JVM's javadoc JAR
             it.artifact(javadocJar)
         }
     }
diff --git a/gradle/publish-mpp-root-module-in-platform.gradle b/gradle/publish-mpp-root-module-in-platform.gradle
new file mode 100644
index 0000000..38b7f89
--- /dev/null
+++ b/gradle/publish-mpp-root-module-in-platform.gradle
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014-2020 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+
+/** Publish the platform JAR and POM so that consumers who depend on this module and can't read Gradle module
+   metadata can still get the platform artifact and transitive dependencies from the POM: */
+project.ext.publishPlatformArtifactsInRootModule = { platformPublication ->
+    afterEvaluate {
+        def platformPomBuilder = null
+
+        platformPublication.pom.withXml { platformPomBuilder = asString() }
+
+        publishing.publications.kotlinMultiplatform {
+            platformPublication.artifacts.forEach {
+                artifact(it)
+            }
+
+            pom.withXml {
+                def pomStringBuilder = asString()
+                pomStringBuilder.setLength(0)
+                // The platform POM needs its artifact ID replaced with the artifact ID of the root module:
+                def platformPomString = platformPomBuilder.toString()
+                platformPomString.eachLine { line ->
+                    if (!line.contains("<!--")) { // Remove the Gradle module metadata marker as it will be added anew
+                        pomStringBuilder.append(line.replace(platformPublication.artifactId, artifactId))
+                        pomStringBuilder.append("\n")
+                    }
+                }
+            }
+        }
+
+        tasks.matching { it.name == "generatePomFileForKotlinMultiplatformPublication"}.configureEach {
+            dependsOn(tasks["generatePomFileFor${platformPublication.name.capitalize()}Publication"])
+        }
+    }
+}
\ No newline at end of file
diff --git a/gradle/publish-npm-js.gradle b/gradle/publish-npm-js.gradle
index dc83aac..e6760a7 100644
--- a/gradle/publish-npm-js.gradle
+++ b/gradle/publish-npm-js.gradle
@@ -21,11 +21,15 @@
 def authToken = prop("kotlin.npmjs.auth.token", "")
 def dryRun = prop("dryRun", "false")
 
-task preparePublishNpm(type: Copy, dependsOn: [compileKotlinJs]) {
+def compileJsLegacy = tasks.hasProperty("compileKotlinJsLegacy")
+        ? compileKotlinJsLegacy
+        : compileKotlinJs
+
+task preparePublishNpm(type: Copy, dependsOn: [compileJsLegacy]) {
     from(npmTemplateDir) {
         expand (project.properties + [kotlinDependency: "\"kotlin\": \"$kotlin_version\""])
     }
-    from(compileKotlinJs.destinationDir)
+    from(compileJsLegacy.destinationDir)
     into npmDeployDir
 }
 
diff --git a/gradle/test-mocha-js.gradle b/gradle/test-mocha-js.gradle
deleted file mode 100644
index a4ca962..0000000
--- a/gradle/test-mocha-js.gradle
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2017-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
- */
-
-// -- Testing with Mocha under Node
-task installDependenciesMochaNode(type: NpmTask, dependsOn: [npmInstall]) {
-    args = ['install',
-            "mocha@$mocha_version",
-            "source-map-support@$source_map_support_version",
-            '--no-save']
-    if (project.hasProperty("teamcity")) args += [
-            "mocha-teamcity-reporter@$mocha_teamcity_reporter_version"]
-}
-
-task testMochaNode(type: NodeTask, dependsOn: [installDependenciesMochaNode]) {
-    script = file("$node.nodeModulesDir/node_modules/mocha/bin/mocha")
-    args = [file("$buildDir/classes/kotlin/js/test/atomicfu_test_transformed.js"), '--require', 'source-map-support/register']
-    if (project.hasProperty("teamcity")) args += ['--reporter', 'mocha-teamcity-reporter']
-    if (project.hasProperty("mochaTests")) args += ['--grep', "$mochaTests"]
-}
-
-// -- Testing with Mocha under headless Chrome
-
-task installDependenciesMochaChrome(type: NpmTask, dependsOn: [npmInstall]) {
-    args = ['install',
-            "mocha@$mocha_version",
-            "mocha-headless-chrome@$mocha_headless_chrome_version",
-            "kotlin@$kotlin_version",
-            "kotlin-test@$kotlin_version",
-            '--no-save']
-    if (project.hasProperty("teamcity")) args += [
-            "mocha-teamcity-reporter@$mocha_teamcity_reporter_version"]
-}
-
-def mochaChromeTestPage = file("$buildDir/test-page.html")
-
-task prepareMochaChrome(dependsOn: [compileTestKotlinJs, installDependenciesMochaChrome]) {
-    outputs.file(mochaChromeTestPage)
-}
-
-prepareMochaChrome.doLast {
-    mochaChromeTestPage.text = """<!DOCTYPE html>
-        <html>
-        <head>
-            <title>Mocha Tests</title>
-            <meta charset="utf-8">
-            <link rel="stylesheet" href="$node.nodeModulesDir/node_modules/mocha/mocha.css">
-        </head>
-        <body>
-        <div id="mocha"></div>
-        <script src="$node.nodeModulesDir/node_modules/mocha/mocha.js"></script>
-        <script>mocha.setup('bdd');</script>
-        <script src="$node.nodeModulesDir/node_modules/kotlin/kotlin.js"></script>
-        <script src="$node.nodeModulesDir/node_modules/kotlin-test/kotlin-test.js"></script>
-        <script src="$compileKotlinJs.outputFile"></script>
-        <script src="$compileTestKotlinJs.outputFile"></script>
-        <script>mocha.run();</script>
-        </body>
-        </html>
-    """
-}
-
-task testMochaChrome(type: NodeTask, dependsOn: prepareMochaChrome) {
-    script = file("$node.nodeModulesDir/node_modules/mocha-headless-chrome/bin/start")
-    args = [compileTestKotlinJs.outputFile, '--file', mochaChromeTestPage]
-    if (project.hasProperty("teamcity")) args += ['--reporter', 'mocha-teamcity-reporter']
-    if (project.hasProperty("mochaTests")) args += ['--grep', "$mochaTests"]
-}
-
-// todo: Commented out because mocha-headless-chrome does not work on TeamCity
-//test.dependsOn testMochaChrome
-
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index efb8228..4c83d2a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip