From 0ff84eaa63c7d4267349ad9ec10a12f24f52b8be Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Mon, 23 Dec 2019 18:08:50 +0300 Subject: [PATCH] [Gradle, JS] Copy JS subtargets dsl for IR --- .../targets/js/KotlinJsPlatformTestRun.kt | 35 ++- .../targets/js/dsl/KotlinJsTargetDsl.kt | 56 +++- .../gradle/targets/js/ir/KotlinBrowserJsIr.kt | 292 ++++++++++++++++++ .../targets/js/ir/KotlinJsIrSubTarget.kt | 137 ++++++++ .../gradle/targets/js/ir/KotlinJsIrTarget.kt | 22 +- .../gradle/targets/js/ir/KotlinNodeJsIr.kt | 43 +++ 6 files changed, 564 insertions(+), 21 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt index 6b22ea5e957..a2fec413564 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.plugin.CompilationExecutionSource import org.jetbrains.kotlin.gradle.plugin.CompilationExecutionSourceSupport import org.jetbrains.kotlin.gradle.plugin.KotlinTargetTestRun import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrSubTarget import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinJsSubTarget import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest @@ -41,6 +42,26 @@ open class KotlinJsPlatformTestRun(testRunName: String, subtarget: KotlinJsSubTa } } +open class KotlinJsIrPlatformTestRun(testRunName: String, subtarget: KotlinJsIrSubTarget) : + KotlinTaskTestRun(testRunName, subtarget.target), + CompilationExecutionSourceSupport { + + private var _executionSource: JsCompilationExecutionSource by Delegates.notNull() + + final override var executionSource: JsCompilationExecutionSource + get() = _executionSource + set(value) { + executionTask.configure { it.compilation = value.compilation } + _executionSource = value + } + + override fun setExecutionSourceFrom(compilation: KotlinJsCompilation) { + requireCompilationOfTarget(compilation, target) + + executionSource = JsCompilationExecutionSource(compilation) + } +} + class JsAggregatingExecutionSource(private val aggregatingTestRun: KotlinJsReportAggregatingTestRun) : KotlinAggregateExecutionSource { @@ -93,7 +114,7 @@ open class KotlinJsReportAggregatingTestRun( open class KotlinJsIrReportAggregatingTestRun( testRunName: String, override val target: KotlinJsIrTarget -) : KotlinReportAggregatingTestRun(testRunName), +) : KotlinReportAggregatingTestRun(testRunName), KotlinTargetTestRun, CompilationExecutionSourceSupport { @@ -104,9 +125,9 @@ open class KotlinJsIrReportAggregatingTestRun( override val executionSource: JsIrAggregatingExecutionSource get() = JsIrAggregatingExecutionSource(this) - private fun KotlinJsSubTarget.getChildTestExecution() = testRuns.maybeCreate(testRunName) + private fun KotlinJsIrSubTarget.getChildTestExecution() = testRuns.maybeCreate(testRunName) - override fun getConfiguredExecutions(): Iterable = mutableListOf().apply { + override fun getConfiguredExecutions(): Iterable = mutableListOf().apply { if (target.isNodejsConfigured) { add(target.nodejs.getChildTestExecution()) } @@ -115,12 +136,12 @@ open class KotlinJsIrReportAggregatingTestRun( } } - override fun configureAllExecutions(configure: KotlinJsPlatformTestRun.() -> Unit) { - val doConfigureInChildren: KotlinJsSubTarget.() -> Unit = { + override fun configureAllExecutions(configure: KotlinJsIrPlatformTestRun.() -> Unit) { + val doConfigureInChildren: KotlinJsIrSubTarget.() -> Unit = { configure(getChildTestExecution()) } - target.whenBrowserConfigured { doConfigureInChildren(this as KotlinJsSubTarget) } - target.whenNodejsConfigured { doConfigureInChildren(this as KotlinJsSubTarget) } + target.whenBrowserConfigured { doConfigureInChildren(this as KotlinJsIrSubTarget) } + target.whenNodejsConfigured { doConfigureInChildren(this as KotlinJsIrSubTarget) } } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dsl/KotlinJsTargetDsl.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dsl/KotlinJsTargetDsl.kt index 172883e4e88..4500b984ff7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dsl/KotlinJsTargetDsl.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/dsl/KotlinJsTargetDsl.kt @@ -9,6 +9,7 @@ import groovy.lang.Closure import org.gradle.api.NamedDomainObjectContainer import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce +import org.jetbrains.kotlin.gradle.targets.js.KotlinJsIrPlatformTestRun import org.jetbrains.kotlin.gradle.targets.js.KotlinJsIrReportAggregatingTestRun import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlatformTestRun import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun @@ -18,7 +19,7 @@ import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack interface KotlinJsIrTargetDsl { fun browser() = browser { } - fun browser(body: KotlinJsBrowserDsl.() -> Unit) + fun browser(body: KotlinJsIrBrowserDsl.() -> Unit) fun browser(fn: Closure<*>) { browser { ConfigureUtil.configure(fn, this) @@ -26,7 +27,7 @@ interface KotlinJsIrTargetDsl { } fun nodejs() = nodejs { } - fun nodejs(body: KotlinJsNodeDsl.() -> Unit) + fun nodejs(body: KotlinJsIrNodeDsl.() -> Unit) fun nodejs(fn: Closure<*>) { nodejs { ConfigureUtil.configure(fn, this) @@ -67,6 +68,17 @@ interface KotlinJsSubTargetDsl { val testRuns: NamedDomainObjectContainer } +interface KotlinJsIrSubTargetDsl { + fun testTask(body: KotlinJsTest.() -> Unit) + fun testTask(fn: Closure<*>) { + testTask { + ConfigureUtil.configure(fn, this) + } + } + + val testRuns: NamedDomainObjectContainer +} + interface KotlinJsBrowserDsl : KotlinJsSubTargetDsl { fun runTask(body: KotlinWebpack.() -> Unit) fun runTask(fn: Closure<*>) { @@ -103,6 +115,46 @@ interface KotlinJsBrowserDsl : KotlinJsSubTargetDsl { } } +interface KotlinJsIrBrowserDsl : KotlinJsIrSubTargetDsl { + fun runTask(body: KotlinWebpack.() -> Unit) + fun runTask(fn: Closure<*>) { + runTask { + ConfigureUtil.configure(fn, this) + } + } + + @ExperimentalDistributionDsl + fun distribution(body: Distribution.() -> Unit) + + @ExperimentalDistributionDsl + fun distribution(fn: Closure<*>) { + distribution { + ConfigureUtil.configure(fn, this) + } + } + + fun webpackTask(body: KotlinWebpack.() -> Unit) + fun webpackTask(fn: Closure<*>) { + webpackTask { + ConfigureUtil.configure(fn, this) + } + } + + @ExperimentalDceDsl + fun dceTask(body: KotlinJsDce.() -> Unit) + + @ExperimentalDceDsl + fun dceTask(fn: Closure<*>) { + dceTask { + ConfigureUtil.configure(fn, this) + } + } +} + interface KotlinJsNodeDsl : KotlinJsSubTargetDsl { fun runTask(body: NodeJsExec.() -> Unit) +} + +interface KotlinJsIrNodeDsl : KotlinJsIrSubTargetDsl { + fun runTask(body: NodeJsExec.() -> Unit) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt new file mode 100644 index 00000000000..57b068dc348 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt @@ -0,0 +1,292 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.ir + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Task +import org.gradle.api.plugins.BasePluginConvention +import org.gradle.api.tasks.Copy +import org.gradle.api.tasks.TaskProvider +import org.gradle.language.base.plugins.LifecycleBasePlugin +import org.jetbrains.kotlin.gradle.dsl.KotlinJsDce +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.dsl.* +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.subtargets.BrowserDistribution +import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Devtool +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode +import org.jetbrains.kotlin.gradle.tasks.registerTask +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import java.io.File +import javax.inject.Inject +import org.jetbrains.kotlin.gradle.tasks.KotlinJsDce as KotlinJsDceTask + +open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : + KotlinJsIrSubTarget(target, "browser"), + KotlinJsIrBrowserDsl { + + private val commonWebpackConfigurations: MutableList Unit> = mutableListOf() + private val commonRunConfigurations: MutableList Unit> = mutableListOf() + private val dceConfigurations: MutableList Unit> = mutableListOf() + private val distribution: Distribution = BrowserDistribution() + + private lateinit var buildVariants: NamedDomainObjectContainer + + override val testTaskDescription: String + get() = "Run all ${target.name} tests inside browser using karma and webpack" + + override fun configureDefaultTestFramework(it: KotlinJsTest) { + it.useKarma { + useChromeHeadless() + } + } + + override fun runTask(body: KotlinWebpack.() -> Unit) { + commonRunConfigurations.add(body) + } + + @ExperimentalDistributionDsl + override fun distribution(body: Distribution.() -> Unit) { + distribution.body() + } + + override fun webpackTask(body: KotlinWebpack.() -> Unit) { + commonWebpackConfigurations.add(body) + } + + @ExperimentalDceDsl + override fun dceTask(body: KotlinJsDce.() -> Unit) { + dceConfigurations.add(body) + } + + override fun configureMain(compilation: KotlinJsCompilation) { + val dceTaskProvider = configureDce(compilation) + + configureRun(compilation, dceTaskProvider) + configureBuild(compilation, dceTaskProvider) + } + + private fun configureRun( + compilation: KotlinJsCompilation, + dceTaskProvider: TaskProvider + ) { + + val project = compilation.target.project + val nodeJs = NodeJsRootPlugin.apply(project.rootProject) + + val compileKotlinTask = compilation.compileKotlinTask + + buildVariants.all { buildVariant -> + val kind = buildVariant.kind + val runTask = project.registerTask( + disambiguateCamelCased( + buildVariant.name, + RUN_TASK_NAME + ) + ) { + it.dependsOn( + nodeJs.npmInstallTask, + target.project.tasks.getByName(compilation.processResourcesTaskName) + ) + + it.configureOptimization(kind) + + it.bin = "webpack-dev-server/bin/webpack-dev-server.js" + it.compilation = compilation + it.description = "start ${kind.name.toLowerCase()} webpack dev server" + + it.devServer = KotlinWebpackConfig.DevServer( + open = true, + contentBase = listOf(compilation.output.resourcesDir.canonicalPath) + ) + + it.outputs.upToDateWhen { false } + + when (kind) { + BuildVariantKind.PRODUCTION -> { + // Breaking of Task Configuration Avoidance is not so critical + // because this task is dependent on DCE task + it.entry = dceTaskProvider.get() + .destinationDir + .resolve(compileKotlinTask.outputFile.name) + it.resolveFromModulesFirst = true + it.dependsOn(dceTaskProvider) + } + BuildVariantKind.DEVELOPMENT -> { + it.dependsOn(compileKotlinTask) + } + } + + commonRunConfigurations.forEach { configure -> + it.configure() + } + } + + if (kind == BuildVariantKind.DEVELOPMENT) { + target.runTask.dependsOn(runTask) + project.registerTask(disambiguateCamelCased(RUN_TASK_NAME)) { + it.dependsOn(runTask) + } + } + } + } + + private fun configureBuild( + compilation: KotlinJsCompilation, + dceTaskProvider: TaskProvider + ) { + val project = compilation.target.project + val nodeJs = NodeJsRootPlugin.apply(project.rootProject) + + val compileKotlinTask = compilation.compileKotlinTask + + val basePluginConvention = project.convention.plugins["base"] as BasePluginConvention? + + val baseDist = project.buildDir.resolve(basePluginConvention!!.distsDirName) + distribution.directory = distribution.directory ?: baseDist + + val distributionTask = project.registerTask( + disambiguateCamelCased( + DISTRIBUTION_TASK_NAME + ) + ) { + it.from(compilation.output.resourcesDir) + it.into(distribution.directory ?: baseDist) + } + + val assembleTask = project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME) + assembleTask.dependsOn(distributionTask) + + buildVariants.all { buildVariant -> + val kind = buildVariant.kind + val webpackTask = project.registerTask( + disambiguateCamelCased( + buildVariant.name, + WEBPACK_TASK_NAME + + ) + ) { + it.dependsOn( + nodeJs.npmInstallTask, + target.project.tasks.getByName(compilation.processResourcesTaskName), + distributionTask + ) + + it.configureOptimization(kind) + + it.compilation = compilation + it.description = "build webpack ${kind.name.toLowerCase()} bundle" + it.destinationDirectory = distribution.directory + + when (kind) { + BuildVariantKind.PRODUCTION -> { + // Breaking of Task Configuration Avoidance is not so critical + // because this task is dependent on DCE task + it.entry = dceTaskProvider.get() + .destinationDir + .resolve(compileKotlinTask.outputFile.name) + it.resolveFromModulesFirst = true + it.dependsOn(dceTaskProvider) + } + BuildVariantKind.DEVELOPMENT -> { + it.dependsOn(compileKotlinTask) + } + } + + commonWebpackConfigurations.forEach { configure -> + it.configure() + } + } + + if (kind == BuildVariantKind.PRODUCTION) { + assembleTask.dependsOn(webpackTask) + project.registerTask(disambiguateCamelCased(WEBPACK_TASK_NAME)) { + it.dependsOn(webpackTask) + } + } + } + } + + private fun configureDce(compilation: KotlinJsCompilation): TaskProvider { + val project = compilation.target.project + + val dceTaskName = lowerCamelCaseName( + DCE_TASK_PREFIX, + compilation.target.disambiguationClassifier, + compilation.name.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, + DCE_TASK_SUFFIX + ) + + val kotlinTask = compilation.compileKotlinTask + + return project.registerTask(dceTaskName) { + dceConfigurations.forEach { configure -> + it.configure() + } + + it.dependsOn(kotlinTask) + + it.kotlinFilesOnly = true + + it.classpath = project.configurations.getByName(compilation.runtimeDependencyConfigurationName) + it.destinationDir = it.dceOptions.outputDirectory?.let { File(it) } + ?: compilation.npmProject.dir.resolve(DCE_DIR) + + it.source(kotlinTask.outputFile) + } + } + + private fun KotlinWebpack.configureOptimization(kind: BuildVariantKind) { + mode = getByKind( + kind = kind, + releaseValue = Mode.PRODUCTION, + debugValue = Mode.DEVELOPMENT + ) + + devtool = getByKind( + kind = kind, + releaseValue = Devtool.SOURCE_MAP, + debugValue = Devtool.EVAL_SOURCE_MAP + ) + } + + private fun getByKind( + kind: BuildVariantKind, + releaseValue: T, + debugValue: T + ): T = when (kind) { + BuildVariantKind.PRODUCTION -> releaseValue + BuildVariantKind.DEVELOPMENT -> debugValue + } + + override fun configureBuildVariants() { + buildVariants = project.container(BuildVariant::class.java) + buildVariants.create(PRODUCTION) { + it.kind = BuildVariantKind.PRODUCTION + } + buildVariants.create(DEVELOPMENT) { + it.kind = BuildVariantKind.DEVELOPMENT + } + } + + companion object { + const val DCE_TASK_PREFIX = "processDce" + const val DCE_TASK_SUFFIX = "kotlinJs" + + const val DCE_DIR = "kotlin-dce" + + const val PRODUCTION = "production" + const val DEVELOPMENT = "development" + + private const val WEBPACK_TASK_NAME = "webpack" + private const val DISTRIBUTION_TASK_NAME = "distribution" + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt new file mode 100644 index 00000000000..2cb45940098 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.ir + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.plugins.ExtensionAware +import org.gradle.language.base.plugins.LifecycleBasePlugin +import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.plugin.whenEvaluated +import org.jetbrains.kotlin.gradle.targets.js.KotlinJsIrPlatformTestRun +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsIrSubTargetDsl +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolverPlugin +import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject +import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest +import org.jetbrains.kotlin.gradle.tasks.registerTask +import org.jetbrains.kotlin.gradle.testing.internal.configureConventions +import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry +import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName + +abstract class KotlinJsIrSubTarget( + val target: KotlinJsIrTarget, + private val disambiguationClassifier: String +) : KotlinJsIrSubTargetDsl { + val project get() = target.project + private val nodeJs = NodeJsRootPlugin.apply(project.rootProject) + + abstract val testTaskDescription: String + + final override lateinit var testRuns: NamedDomainObjectContainer + private set + + fun configure() { + NpmResolverPlugin.apply(project) + + configureBuildVariants() + configureTests() + configureMain() + + target.compilations.all { + val npmProject = it.npmProject + it.compileKotlinTask.kotlinOptions.outputFile = npmProject.dir.resolve(npmProject.main).canonicalPath + } + } + + override fun testTask(body: KotlinJsTest.() -> Unit) { + testRuns.getByName(KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME).executionTask.configure(body) + } + + protected fun disambiguateCamelCased(vararg names: String): String = + lowerCamelCaseName(target.disambiguationClassifier, disambiguationClassifier, *names) + + abstract fun configureBuildVariants() + + private fun configureTests() { + testRuns = project.container(KotlinJsIrPlatformTestRun::class.java) { name -> KotlinJsIrPlatformTestRun(name, this) }.also { + (this as ExtensionAware).extensions.add(this::testRuns.name, it) + } + + testRuns.all { configureTestRunDefaults(it) } + testRuns.create(KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME) + } + + protected open fun configureTestRunDefaults(testRun: KotlinJsIrPlatformTestRun) { + target.compilations.matching { it.name == KotlinCompilation.TEST_COMPILATION_NAME }.all { compilation -> + configureTestsRun(testRun, compilation) + } + } + + private fun configureTestsRun(testRun: KotlinJsIrPlatformTestRun, compilation: KotlinJsCompilation) { + fun KotlinJsIrPlatformTestRun.subtargetTestTaskName(): String = disambiguateCamelCased( + lowerCamelCaseName( + name.takeIf { it != KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME }, + AbstractKotlinTargetConfigurator.testTaskNameSuffix + ) + ) + + val testJs = project.registerTask(testRun.subtargetTestTaskName()) { testJs -> + val compileTask = compilation.compileKotlinTask + + testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP + testJs.description = testTaskDescription + + testJs.dependsOn(nodeJs.npmInstallTask, compileTask, nodeJs.nodeJsSetupTask) + + testJs.onlyIf { + compileTask.outputFile.exists() + } + + testJs.compilation = compilation + testJs.targetName = listOfNotNull(target.disambiguationClassifier, disambiguationClassifier) + .takeIf { it.isNotEmpty() } + ?.joinToString() + + testJs.configureConventions() + } + + testRun.executionTask = testJs + + target.testRuns.matching { it.name == testRun.name }.all { parentTestRun -> + target.project.kotlinTestRegistry.registerTestTask( + testJs, + parentTestRun.executionTask + ) + } + + project.whenEvaluated { + testJs.configure { + if (it.testFramework == null) { + configureDefaultTestFramework(it) + } + } + } + } + + protected abstract fun configureDefaultTestFramework(it: KotlinJsTest) + + private fun configureMain() { + target.compilations.all { compilation -> + if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) { + configureMain(compilation) + } + } + } + + protected abstract fun configureMain(compilation: KotlinJsCompilation) + + companion object { + const val RUN_TASK_NAME = "run" + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt index e0e95c022fe..505f2756eb9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt @@ -15,11 +15,9 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget import org.jetbrains.kotlin.gradle.targets.js.JsIrAggregatingExecutionSource import org.jetbrains.kotlin.gradle.targets.js.KotlinJsIrReportAggregatingTestRun -import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBrowserDsl +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsIrBrowserDsl +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsIrNodeDsl import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsIrTargetDsl -import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsNodeDsl -import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinBrowserJs -import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinNodeJs import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport import org.jetbrains.kotlin.gradle.testing.testTaskName @@ -44,42 +42,42 @@ open class KotlinJsIrTarget @Inject constructor(project: Project, platformType: } private val browserLazyDelegate = lazy { - project.objects.newInstance(KotlinBrowserJs::class.java, this).also { + project.objects.newInstance(KotlinBrowserJsIr::class.java, this).also { it.configure() browserConfiguredHandlers.forEach { handler -> handler(it) } browserConfiguredHandlers.clear() } } - private val browserConfiguredHandlers = mutableListOf Unit>() + private val browserConfiguredHandlers = mutableListOf Unit>() val browser by browserLazyDelegate internal val isBrowserConfigured: Boolean = browserLazyDelegate.isInitialized() - override fun browser(body: KotlinJsBrowserDsl.() -> Unit) { + override fun browser(body: KotlinJsIrBrowserDsl.() -> Unit) { body(browser) } private val nodejsLazyDelegate = lazy { - project.objects.newInstance(KotlinNodeJs::class.java, this).also { + project.objects.newInstance(KotlinNodeJsIr::class.java, this).also { it.configure() nodejsConfiguredHandlers.forEach { handler -> handler(it) } nodejsConfiguredHandlers.clear() } } - private val nodejsConfiguredHandlers = mutableListOf Unit>() + private val nodejsConfiguredHandlers = mutableListOf Unit>() val nodejs by nodejsLazyDelegate internal val isNodejsConfigured: Boolean = nodejsLazyDelegate.isInitialized() - override fun nodejs(body: KotlinJsNodeDsl.() -> Unit) { + override fun nodejs(body: KotlinJsIrNodeDsl.() -> Unit) { body(nodejs) } - fun whenBrowserConfigured(body: KotlinJsBrowserDsl.() -> Unit) { + fun whenBrowserConfigured(body: KotlinJsIrBrowserDsl.() -> Unit) { if (browserLazyDelegate.isInitialized()) { browser(body) } else { @@ -87,7 +85,7 @@ open class KotlinJsIrTarget @Inject constructor(project: Project, platformType: } } - fun whenNodejsConfigured(body: KotlinJsNodeDsl.() -> Unit) { + fun whenNodejsConfigured(body: KotlinJsIrNodeDsl.() -> Unit) { if (nodejsLazyDelegate.isInitialized()) { nodejs(body) } else { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt new file mode 100644 index 00000000000..ba68160ccec --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.ir + +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsIrNodeDsl +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExec +import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest +import javax.inject.Inject + +open class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) : + KotlinJsIrSubTarget(target, "node"), + KotlinJsIrNodeDsl { + override val testTaskDescription: String + get() = "Run all ${target.name} tests inside nodejs using the builtin test framework" + + private val runTaskName = disambiguateCamelCased("run") + + override fun runTask(body: NodeJsExec.() -> Unit) { + (project.tasks.getByName(runTaskName) as NodeJsExec).body() + } + + override fun configureDefaultTestFramework(it: KotlinJsTest) { + it.useMocha { } + } + + override fun configureMain(compilation: KotlinJsCompilation) { + configureRun(compilation) + } + + private fun configureRun( + compilation: KotlinJsCompilation + ) { + val runTaskHolder = NodeJsExec.create(compilation, disambiguateCamelCased(RUN_TASK_NAME)) + target.runTask.dependsOn(runTaskHolder) + } + + override fun configureBuildVariants() { + } +} \ No newline at end of file