Gradle: Kotlin NodeJS tests runner for single target

#KT-30528
This commit is contained in:
Sergey Rostov
2019-03-20 13:18:29 +03:00
parent 04d8568fdc
commit d210255623
18 changed files with 318 additions and 225 deletions
@@ -27,30 +27,32 @@ class CodeConformanceTest : TestCase() {
private val JAVA_FILE_PATTERN = Pattern.compile(".+\\.java")
private val SOURCES_FILE_PATTERN = Pattern.compile("(.+\\.java|.+\\.kt|.+\\.js)")
private val EXCLUDED_FILES_AND_DIRS = listOf(
"android.tests.dependencies",
"buildSrc",
"core/reflection.jvm/src/kotlin/reflect/jvm/internal/pcollections",
"js/js.tests/.gradle",
"js/js.translator/testData/node_modules",
"libraries/kotlin.test/js/it/.gradle",
"libraries/kotlin.test/js/it/node_modules",
"libraries/stdlib/js/.gradle",
"libraries/stdlib/js/build",
"libraries/reflect/build",
"libraries/reflect/api/src/java9/java/kotlin/reflect/jvm/internal/impl",
"libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools",
"dependencies",
"js/js.translator/qunit/qunit.js",
"libraries/tools/kotlin-js-tests/src/test/web/qunit.js",
"out",
"dist",
"libraries/tools/kotlin-gradle-plugin-core/gradle_api_jar/build/tmp",
"libraries/tools/kotlin-maven-plugin/target",
"libraries/tools/kotlinp/src",
"compiler/testData/psi/kdoc",
"compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt",
"compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java",
"dependencies/protobuf/protobuf-relocated/build"
"android.tests.dependencies",
"buildSrc",
"core/reflection.jvm/src/kotlin/reflect/jvm/internal/pcollections",
"js/js.tests/.gradle",
"js/js.translator/testData/node_modules",
"libraries/kotlin.test/js/it/.gradle",
"libraries/kotlin.test/js/it/node_modules",
"libraries/stdlib/js/.gradle",
"libraries/stdlib/js/build",
"libraries/reflect/build",
"libraries/reflect/api/src/java9/java/kotlin/reflect/jvm/internal/impl",
"libraries/tools/binary-compatibility-validator/src/main/kotlin/org.jetbrains.kotlin.tools",
"dependencies",
"js/js.translator/qunit/qunit.js",
"libraries/tools/kotlin-js-tests/src/test/web/qunit.js",
"out",
"dist",
"libraries/tools/kotlin-gradle-plugin-core/gradle_api_jar/build/tmp",
"libraries/tools/kotlin-maven-plugin/target",
"libraries/tools/kotlinp/src",
"libraries/tools/kotlin-test-nodejs-runner/node_modules",
"libraries/tools/kotlin-test-nodejs-runner/.gradle",
"compiler/testData/psi/kdoc",
"compiler/tests/org/jetbrains/kotlin/code/CodeConformanceTest.kt",
"compiler/util/src/org/jetbrains/kotlin/config/MavenComparableVersion.java",
"dependencies/protobuf/protobuf-relocated/build"
).map(::File)
private val COPYRIGHT_EXCLUDED_FILES_AND_DIRS = listOf(
@@ -72,6 +74,8 @@ class CodeConformanceTest : TestCase() {
"libraries/stdlib/js/node_modules",
"libraries/tools/kotlin-maven-plugin-test/target",
"libraries/tools/kotlin-gradle-plugin-integration-tests/build",
"libraries/tools/kotlin-test-nodejs-runner/node_modules",
"libraries/tools/kotlin-test-nodejs-runner/.gradle",
"buildSrc/prepare-deps/build"
)
}
@@ -95,49 +99,49 @@ class CodeConformanceTest : TestCase() {
val atAuthorPattern = Pattern.compile("/\\*.+@author.+\\*/", Pattern.DOTALL)
val tests = listOf(
TestData(
"%d source files contain @author javadoc tag.\nPlease remove them or exclude in this test:\n%s",
{ source ->
// substring check is an optimization
"@author" in source && atAuthorPattern.matcher(source).find() &&
"ASM: a very small and fast Java bytecode manipulation framework" !in source
}
),
TestData(
"%d source files use something from com.beust.jcommander.internal package.\n" +
TestData(
"%d source files contain @author javadoc tag.\nPlease remove them or exclude in this test:\n%s",
{ source ->
// substring check is an optimization
"@author" in source && atAuthorPattern.matcher(source).find() &&
"ASM: a very small and fast Java bytecode manipulation framework" !in source
}
),
TestData(
"%d source files use something from com.beust.jcommander.internal package.\n" +
"This code won't work when there's no TestNG in the classpath of our IDEA plugin, " +
"because there's only an optional dependency on testng.jar.\n" +
"Most probably you meant to use Guava's Lists, Maps or Sets instead. " +
"Please change references in these files to com.google.common.collect:\n%s",
{ source ->
"com.beust.jcommander.internal" in source
}
),
TestData(
"%d source files contain references to package org.jetbrains.jet.\n" +
{ source ->
"com.beust.jcommander.internal" in source
}
),
TestData(
"%d source files contain references to package org.jetbrains.jet.\n" +
"Package org.jetbrains.jet is deprecated now in favor of org.jetbrains.kotlin. " +
"Please consider changing the package in these files:\n%s",
{ source ->
"org.jetbrains.jet" in source
}
),
TestData(
"%d source files contain references to package kotlin.reflect.jvm.internal.impl.\n" +
{ source ->
"org.jetbrains.jet" in source
}
),
TestData(
"%d source files contain references to package kotlin.reflect.jvm.internal.impl.\n" +
"This package contains internal reflection implementation and is a result of a " +
"post-processing of kotlin-reflect.jar by jarjar.\n" +
"Most probably you meant to use classes from org.jetbrains.kotlin.**.\n" +
"Please change references in these files or exclude them in this test:\n%s",
{ source ->
"kotlin.reflect.jvm.internal.impl" in source
}
),
TestData(
"%d source files contain references to package org.objectweb.asm.\n" +
{ source ->
"kotlin.reflect.jvm.internal.impl" in source
}
),
TestData(
"%d source files contain references to package org.objectweb.asm.\n" +
"Package org.jetbrains.org.objectweb.asm should be used instead to avoid troubles with different asm versions in classpath. " +
"Please consider changing the package in these files:\n%s",
{ source ->
" org.objectweb.asm" in source
})
{ source ->
" org.objectweb.asm" in source
})
)
for (sourceFile in FileUtil.findFilesByMask(SOURCES_FILE_PATTERN, File("."))) {
@@ -170,7 +174,7 @@ class CodeConformanceTest : TestCase() {
for (sourceFile in FileUtil.findFilesByMask(SOURCES_FILE_PATTERN, root)) {
val relativePath = FileUtil.toSystemIndependentName(sourceFile.toRelativeString(root))
if (COPYRIGHT_EXCLUDED_FILES_AND_DIRS.any { relativePath.startsWith(it) } ||
knownThirdPartyCode.any { relativePath.startsWith(it) }) continue
knownThirdPartyCode.any { relativePath.startsWith(it)}) continue
sourceFile.useLines { lineSequence ->
for (line in lineSequence) {
@@ -181,23 +185,21 @@ class CodeConformanceTest : TestCase() {
}
}
if (filesWithUnlistedCopyrights.isNotEmpty()) {
fail(
"The following files contain third-party copyrights and no license information. " +
"Please update license/README.md accordingly:\n${filesWithUnlistedCopyrights.joinToString("\n")}"
)
fail("The following files contain third-party copyrights and no license information. " +
"Please update license/README.md accordingly:\n${filesWithUnlistedCopyrights.joinToString("\n")}")
}
}
private fun loadKnownThirdPartyCodeList(): List<String> {
File("license/README.md").useLines { lineSequence ->
return lineSequence
.filter { it.startsWith(" - Path: ") }
.map { it.removePrefix(" - Path: ").trim().ensureFileOrEndsWithSlash() }
.toList()
.filter { it.startsWith(" - Path: ") }
.map { it.removePrefix(" - Path: ").trim().ensureFileOrEndsWithSlash() }
.toList()
}
}
}
private fun String.ensureFileOrEndsWithSlash() =
if (endsWith("/") || "." in substringAfterLast('/')) this else this + "/"
if (endsWith("/") || "." in substringAfterLast('/')) this else this + "/"
@@ -379,6 +379,8 @@ class Kotlin2JsGradlePluginIT : BaseGradleIT() {
assertTrue { "kotlin-stdlib-js</artifactId><version>$kotlinVersion</version><scope>runtime</scope>" in pomText }
assertFileExists(moduleDir + "kotlin-js-plugin-1.0-sources.jar")
assertTestResults("testProject/kotlin-js-plugin-project/tests.xml", "test")
}
}
}
@@ -297,7 +297,7 @@ class MultiplatformGradleIT : BaseGradleIT() {
}
@Test
fun testMppNodeJsTestRun() = with(Project("new-mpp-js-tests", GradleVersionRequired.AtLeast("4.10.2"))) {
fun testMppNodeJsTestRun() = with(Project("new-mpp-js-tests", GradleVersionRequired.AtLeast("5.0"))) {
setupWorkingDir()
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
gradleSettingsScript().modify(::transformBuildScriptWithPluginsDsl)
@@ -307,12 +307,12 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksRegisteredAndNotRealized(
":clientKotlinJsNodeModules",
":clientKotlinJsNodeModulesTestRuntime",
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
":serverKotlinJsNodeModules",
":serverKotlinJsNodeModulesTestRuntime",
":serverTestNodeModules",
":serverTest"
)
}
@@ -321,12 +321,12 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksExecuted(
":clientKotlinJsNodeModules",
":clientKotlinJsNodeModulesTestRuntime",
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
":serverKotlinJsNodeModules",
":serverKotlinJsNodeModulesTestRuntime",
":serverTestNodeModules",
":serverTest"
)
@@ -339,12 +339,12 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksUpToDate(
":clientKotlinJsNodeModules",
":clientKotlinJsNodeModulesTestRuntime",
":kotlinNodeJsTestRuntimeExtract",
":clientTestNodeModules",
":clientTest",
":serverKotlinJsNodeModules",
":serverKotlinJsNodeModulesTestRuntime",
":serverTestNodeModules",
":serverTest"
)
}
@@ -356,15 +356,14 @@ class MultiplatformGradleIT : BaseGradleIT() {
assertSuccessful()
assertTasksUpToDate(
":clientKotlinJsNodeModulesTestRuntime",
":serverKotlinJsNodeModulesTestRuntime"
":kotlinNodeJsTestRuntimeExtract"
)
assertTasksExecuted(
":clientKotlinJsNodeModules",
":clientTestNodeModules",
":clientTest",
":serverKotlinJsNodeModules",
":serverTestNodeModules",
":serverTest"
)
@@ -1,15 +1,23 @@
package com.example
import kotlinx.html.dom.create
import kotlinx.html.js.div
import kotlinx.html.p
import kotlin.browser.document
import kotlinx.html.a
import kotlinx.html.body
import kotlinx.html.div
import kotlinx.html.html
import kotlinx.html.stream.appendHTML
fun hello() = "hello"
fun main() {
document.create.div {
p { hello() }
}
console.log(hello())
println(
StringBuilder().appendHTML().html {
body {
div {
a("https://kotlinlang.org") {
hello()
}
}
}
}
)
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<results>
<testsuite name="MainTest" tests="1" skipped="0" failures="0" errors="0" timestamp="..." hostname="..." time="...">
<properties />
<testcase name="testHello" classname="MainTest" time="..." />
<system-out />
<system-err />
</testsuite>
</results>
@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.TaskProvider
class TaskProviderHolder<T : Task>(project: Project, private val name: String, type: Class<T>, configureAction: (T) -> (Unit)) :
TaskHolder<T> {
private val provider: TaskProvider<T> = project.tasks.register(name, type, configureAction)
class TaskProviderHolder<T : Task>(
private val name: String,
private val provider: TaskProvider<T>
) : TaskHolder<T> {
override fun getTaskOrProvider(): Any = provider
@@ -1,44 +1,52 @@
package org.jetbrains.kotlin.gradle.targets.js
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.plugins.DslObject
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.testing.base.plugins.TestingBasePlugin
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsSetupTask
import org.jetbrains.kotlin.gradle.targets.js.tasks.KotlinJsNodeModulesTask
import org.jetbrains.kotlin.gradle.targets.js.tasks.KotlinNodeJsTestRuntimeToNodeModulesTask
import org.jetbrains.kotlin.gradle.targets.js.tasks.KotlinNodeJsTestTask
import org.jetbrains.kotlin.gradle.targets.js.tasks.*
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File
internal class KotlinJsCompilationTestsConfigurator(
val compilation: KotlinCompilationToRunnableFiles<*>
val compilation: KotlinCompilationToRunnableFiles<*>
) {
private val target get() = compilation.target
private val disambiguationClassifier get() = target.disambiguationClassifier
private val project get() = target.project
private val compileTestKotlin2Js get() = compilation.compileKotlinTask as Kotlin2JsCompile
private val isSinglePlatformProject get() = target is KotlinWithJavaTarget<*>
private val testTaskName: String
get() = if (isSinglePlatformProject) "testJs" else camelCaseTargetName("test")
private fun camelCaseTargetName(prefix: String): String {
return if (isSinglePlatformProject) prefix
else target.name + prefix.capitalize()
private fun disambiguate(name: String, includeCompilation: Boolean = false): MutableList<String> {
val components = mutableListOf<String>()
components.addIfNotNull(disambiguationClassifier)
if (includeCompilation) components.add(compilation.name)
components.add(name)
return components
}
private fun disambiguateCamelCased(name: String, includeCompilation: Boolean): String {
val components = disambiguate(name, includeCompilation)
return components.first() + components.drop(1).joinToString("") { it.capitalize() }
}
@Suppress("SameParameterValue")
private fun underscoredCompilationName(prefix: String): String {
return if (isSinglePlatformProject) prefix
else "${target.name}_${compilation.name}_$prefix"
}
private fun disambiguateUnderscored(name: String, includeCompilation: Boolean) =
disambiguate(name, includeCompilation).joinToString("_")
private val testTaskName: String
get() = disambiguateCamelCased("test", false)
private val nodeModulesDir
get() = project.buildDir.resolve(underscoredCompilationName("node_modules"))
get() = project.buildDir.resolve(disambiguateUnderscored("node_modules", true))
@Suppress("UnstableApiUsage")
private val Project.testResults: File
@@ -56,41 +64,46 @@ internal class KotlinJsCompilationTestsConfigurator(
fun configure() {
val nodeModulesTask = registerTask(
project,
camelCaseTargetName("kotlinJsNodeModules"),
KotlinJsNodeModulesTask::class.java
project,
disambiguateCamelCased("nodeModules", true),
KotlinJsNodeModulesTask::class.java
) {
it.dependsOn(compileTestKotlin2Js)
it.onlyIf {
compileTestKotlin2Js.outputFile.exists()
}
it.nodeModulesDir = nodeModulesDir
it.classpath = compileTask.jsRuntimeClasspath
}
val nodeModulesTestRuntimeTask = registerTask(
project,
camelCaseTargetName("kotlinJsNodeModulesTestRuntime"),
KotlinNodeJsTestRuntimeToNodeModulesTask::class.java
) {
it.nodeModulesDir = nodeModulesDir
}
val projectWithNodeJsPlugin = NodeJsPlugin.ensureAppliedInHierarchy(target.project)
val kotlinJsExtractTestRunnerTask = project.kotlinNodeJsTestRuntimeExtractTask
val testTask = registerTask(project, testTaskName, KotlinNodeJsTestTask::class.java) { testJs ->
testJs.group = "verification"
testJs.dependsOn(
nodeModulesTask.getTaskOrProvider(),
nodeModulesTestRuntimeTask.getTaskOrProvider()
nodeModulesTask.getTaskOrProvider(),
kotlinJsExtractTestRunnerTask.getTaskOrProvider()
)
if (!isSinglePlatformProject) {
testJs.targetName = target.name
testJs.onlyIf {
// run only if there is org.jetbrains.kotlin:kotlin-test-js in classpath
// (kotlin-test-nodejs-runner.js requires kotlin-test.js)
nodeModulesDir.resolve("kotlin-test.js").exists()
compileTestKotlin2Js.outputFile.exists()
}
if (disambiguationClassifier != null) {
testJs.targetName = disambiguationClassifier
}
testJs.nodeJsProcessOptions.workingDir = project.projectDir
testJs.nodeModulesDir = nodeModulesDir
testJs.testRuntimeNodeModule = project.extractedKotlinTestNodeJsRunner
testJs.nodeModulesToLoad = setOf(compileTestKotlin2Js.outputFile.name)
val htmlReport = DslObject(testJs.reports.html)
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.targets.js
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
@@ -19,13 +18,24 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
return Kotlin2JsSourceSetProcessor(compilation.target.project, tasksProvider, compilation, kotlinPluginVersion)
}
override fun configureCompilations(platformTarget: KotlinOnlyTarget<KotlinJsCompilation>) {
super.configureCompilations(platformTarget)
platformTarget.compilations.all {
it.compileKotlinTask.kotlinOptions.moduleKind = "umd"
}
}
override fun configureTest(target: KotlinOnlyTarget<KotlinJsCompilation>) {
target.compilations.all {
it.compileKotlinTask.kotlinOptions.moduleKind = "umd"
if (it.name == KotlinCompilation.TEST_COMPILATION_NAME) {
if (isTestCompilation(it)) {
KotlinJsCompilationTestsConfigurator(it).configure()
}
}
}
companion object {
internal fun isTestCompilation(it: KotlinJsCompilation) =
it.name == KotlinCompilation.TEST_COMPILATION_NAME
}
}
@@ -7,12 +7,8 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.Kotlin2JsSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetConfigurator
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTargetConfigurator
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
open class KotlinJsTargetPreset(
project: Project,
@@ -35,10 +35,15 @@ open class NodeJsSetupTask : DefaultTask() {
val repo = project.repositories.ivy { repo ->
repo.name = "Node Distributions at ${settings.distBaseUrl}"
repo.url = URI(settings.distBaseUrl)
repo.layout("pattern") { layout ->
layout as IvyPatternRepositoryLayout
layout.artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]")
layout.ivy("v[revision]/ivy.xml")
if (isGradleVersionAtLeast(5, 0)) {
repo.patternLayout { layout ->
configureNodeJsIvyPatternLayout(layout)
}
} else {
repo.layout("pattern") { layout ->
configureNodeJsIvyPatternLayout(layout as IvyPatternRepositoryLayout)
}
}
repo.metadataSources { it.artifact() }
@@ -62,6 +67,11 @@ open class NodeJsSetupTask : DefaultTask() {
}
}
private fun configureNodeJsIvyPatternLayout(layout: IvyPatternRepositoryLayout) {
layout.artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]")
layout.ivy("v[revision]/ivy.xml")
}
private fun unpackNodeArchive(archive: File, destination: File) {
project.logger.kotlinInfo("Unpacking $archive to $destination")
@@ -22,27 +22,27 @@ open class KotlinJsNodeModulesTask : DefaultTask() {
@TaskAction
fun copyFromRuntimeClasspath() {
project.copy { copy ->
copy.includeEmptyDirs = false
project.sync { sync ->
sync.includeEmptyDirs = false
classpath.forEach {
if (it.isZip) copy.from(project.zipTree(it))
else copy.from(it)
if (it.isZip) sync.from(project.zipTree(it))
else sync.from(it)
}
copy.include { fileTreeElement ->
sync.include { fileTreeElement ->
isKotlinJsRuntimeFile(fileTreeElement.file)
}
copy.into(nodeModulesDir)
sync.into(nodeModulesDir)
}
}
}
val File.isZip
private val File.isZip
get() = isFile && name.endsWith(".jar")
fun isKotlinJsRuntimeFile(file: File): Boolean {
internal fun isKotlinJsRuntimeFile(file: File): Boolean {
if (!file.isFile) return false
val name = file.name
return (name.endsWith(".js") && !name.endsWith(".meta.js"))
@@ -1,67 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.*
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
const val kotlinNodeJsTestRuntimeBin: String = "kotlin-js-test"
open class KotlinNodeJsTestRuntimeToNodeModulesTask : DefaultTask() {
@Input
public var resourceName: String = "/kotlin-js-test.js"
@OutputDirectory
@SkipWhenEmpty
public lateinit var nodeModulesDir: File
@TaskAction
fun copyRuntime() {
val testsRuntime = javaClass.getResourceAsStream(resourceName) ?: error("Cannot find `$resourceName` in resources")
val bin = nodeModulesDir.resolve(".bin").resolve(kotlinNodeJsTestRuntimeBin)
bin.parentFile.mkdirs()
Files.copy(
testsRuntime,
bin.toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
data class KotlinNodeJsTestRunnerCliArgs(
val moduleNames: List<String>,
val include: Collection<String> = listOf(),
val exclude: Collection<String> = listOf(),
val ignoredTestSuites: IgnoredTestSuitesReporting = IgnoredTestSuitesReporting.reportAllInnerTestsAsIgnored
) {
fun toList(): List<String> = mutableListOf<String>().also { args ->
if (include.isNotEmpty()) {
args.add("--include")
args.add(include.joinToString(","))
}
if (exclude.isNotEmpty()) {
args.add("--exclude")
args.add(exclude.joinToString(","))
}
if (ignoredTestSuites !== IgnoredTestSuitesReporting.reportAllInnerTestsAsIgnored) {
args.add("--ignoredTestSuites")
args.add(ignoredTestSuites.name)
}
args.addAll(moduleNames)
}
@Suppress("EnumEntryName")
enum class IgnoredTestSuitesReporting {
skip, reportAsIgnoredTest, reportAllInnerTestsAsIgnored
}
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.targets.js.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import java.io.File
import java.nio.file.Files
import java.nio.file.StandardCopyOption
const val kotlinTestNodeJsRunnerJs = "kotlin-test-nodejs-runner.js"
internal val Project.extractedKotlinTestNodeJsRunner: File
get() = project.buildDir.resolve("kotlin/$kotlinTestNodeJsRunnerJs")
internal val Project.kotlinNodeJsTestRuntimeExtractTask
get() = project.locateOrRegisterTask<KotlinNodeJsTestRuntimeExtractTask>(
"kotlinNodeJsTestRuntimeExtract"
) { task ->
task.destination = extractedKotlinTestNodeJsRunner
}
open class KotlinNodeJsTestRuntimeExtractTask : DefaultTask() {
@Input
public var resourceName: String = "/$kotlinTestNodeJsRunnerJs"
@OutputFile
@SkipWhenEmpty
public lateinit var destination: File
@TaskAction
fun copyRuntime() {
val testsRuntime = javaClass.getResourceAsStream(resourceName)
?: error("Cannot find `$resourceName` in resources")
check(destination.parentFile.exists() || destination.parentFile.mkdirs()) {
"Cannot create directory ${destination.parentFile}"
}
Files.copy(
testsRuntime,
destination.toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
@@ -45,8 +45,7 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
var nodeModulesToLoad: Set<String> = setOf()
@InputFile
@Optional
var testRuntimeNodeModule: File? = null
lateinit var testRuntimeNodeModule: File
@Suppress("UnstableApiUsage")
private val filterExt: DefaultTestFilter
@@ -99,7 +98,7 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
return TCServiceMessagesTestExecutionSpec(
extendedForkOptions,
listOf(finalTestRuntimeNodeModule.absolutePath) + cliArgs.toList(),
listOf(testRuntimeNodeModule.absolutePath) + cliArgs.toList(),
clientSettings
)
}
@@ -108,16 +107,43 @@ open class KotlinNodeJsTestTask : AbstractTestTask() {
open val execHandleFactory: ExecHandleFactory
get() = injected
private val finalTestRuntimeNodeModule: File
get() = testRuntimeNodeModule
?: nodeModulesDir!!.resolve(".bin").resolve(kotlinNodeJsTestRuntimeBin)
override fun createTestExecuter() = TCServiceMessagesTestExecutor(
execHandleFactory,
buildOperationExecutor
)
}
data class KotlinNodeJsTestRunnerCliArgs(
val moduleNames: List<String>,
val include: Collection<String> = listOf(),
val exclude: Collection<String> = listOf(),
val ignoredTestSuites: IgnoredTestSuitesReporting = IgnoredTestSuitesReporting.reportAllInnerTestsAsIgnored
) {
fun toList(): List<String> = mutableListOf<String>().also { args ->
if (include.isNotEmpty()) {
args.add("--include")
args.add(include.joinToString(","))
}
if (exclude.isNotEmpty()) {
args.add("--exclude")
args.add(exclude.joinToString(","))
}
if (ignoredTestSuites !== IgnoredTestSuitesReporting.reportAllInnerTestsAsIgnored) {
args.add("--ignoredTestSuites")
args.add(ignoredTestSuites.name)
}
args.addAll(moduleNames)
}
@Suppress("EnumEntryName")
enum class IgnoredTestSuitesReporting {
skip, reportAsIgnoredTest, reportAllInnerTestsAsIgnored
}
}
private fun MutableMap<String, Any>.addPath(key: String, path: String) {
val prev = get(key)
if (prev == null) set(key, path)
@@ -18,20 +18,22 @@ package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.UnknownTaskException
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.defaultSourceSetName
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
internal val useLazyTaskConfiguration = org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast(4, 9)
internal val canLocateTask = org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast(5, 0)
/**
* Registers the task with name @param name and type @param type and initialization script @param body
* If gradle with version <4.9 is used the task will be created
* Registers the task with [name] and [type] and initialization script [body]
* If Gradle with version <4.9 is used the task will be created
*/
internal fun <T : Task> registerTask(project: Project, name: String, type: Class<T>, body: (T) -> (Unit)): TaskHolder<T> {
return if (useLazyTaskConfiguration) {
TaskProviderHolder(project, name, type) { with(it, body) }
TaskProviderHolder(name, project.tasks.register(name, type) { with(it, body) })
} else {
val result = LegacyTaskHolder(project.tasks.create(name, type))
with(result.doGetTask(), body)
@@ -39,6 +41,33 @@ internal fun <T : Task> registerTask(project: Project, name: String, type: Class
}
}
/**
* Locates a task by [name] and [type], without triggering its creation or configuration.
*/
internal fun <T : Task> locateTask(project: Project, name: String, type: Class<T>): TaskHolder<T>? =
if (canLocateTask) {
try {
TaskProviderHolder(name, project.tasks.named(name, type))
} catch (e: UnknownTaskException) {
null
}
} else {
project.tasks.findByName(name)?.let {
check(type.isInstance(it))
@Suppress("UNCHECKED_CAST")
LegacyTaskHolder(it as T)
}
}
/**
* Locates a task by [name] and [type], without triggering its creation or configuration or registers new task
* with [name], type [T] and initialization script [body]
*/
internal inline fun <reified T : Task> Project.locateOrRegisterTask(name: String, noinline body: (T) -> (Unit)): TaskHolder<T> {
return locateTask(project, name, T::class.java) ?: registerTask(project, name, T::class.java, body)
}
internal open class KotlinTasksProvider(val targetName: String) {
open fun registerKotlinJVMTask(
project: Project,
@@ -8,4 +8,4 @@ package org.jetbrains.kotlin.gradle.utils
/**
* Utility for functions annotated with @Inject
*/
val injected: Nothing get() = error("Should be injected");
internal val injected: Nothing get() = error("Should be injected");
@@ -26,7 +26,7 @@ tasks {
args = listOf("build")
inputs.dir(projectDir.resolve("src"))
outputs.file(projectDir.resolve("lib/kotlin-js-test.js"))
outputs.file(projectDir.resolve("lib/kotlin-test-nodejs-runner.js"))
}
create<Delete>("cleanYarn") {
@@ -43,7 +43,7 @@ tasks {
}
artifacts {
add("archives", projectDir.resolve("lib/kotlin-js-test.js")) {
add("archives", projectDir.resolve("lib/kotlin-test-nodejs-runner.js")) {
builtBy("yarnBuild")
}
}
@@ -9,7 +9,7 @@ export default [
{
input: './cli.ts',
output: {
file: 'lib/kotlin-js-test.js',
file: 'lib/kotlin-test-nodejs-runner.js',
format: 'cjs',
banner: '#!/usr/bin/env node'
},