Gradle, JS: introduce RequiresNpmDependencies

#KT-30530
This commit is contained in:
Sergey Rostov
2019-05-13 10:36:19 +03:00
parent 5ec501dce0
commit a69881850b
12 changed files with 190 additions and 99 deletions
@@ -15,9 +15,7 @@ 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
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
class KotlinBrowserJs( class KotlinBrowserJs(target: KotlinOnlyTarget<KotlinJsCompilation>) : KotlinJsInnerTargetConfigurator(target, "browser") {
target: KotlinOnlyTarget<KotlinJsCompilation>
) : KotlinJsInnerTargetConfigurator(target) {
private val versions = project.nodeJs.versions private val versions = project.nodeJs.versions
override fun configureDefaultTestFramework(it: KotlinJsTest) { override fun configureDefaultTestFramework(it: KotlinJsTest) {
@@ -32,16 +30,6 @@ class KotlinBrowserJs(
val npmProject = project.npmProject val npmProject = project.npmProject
val compileKotlinTask = compilation.compileKotlinTask val compileKotlinTask = compilation.compileKotlinTask
compilation.dependencies {
runtimeOnly(versions.webpack)
runtimeOnly(versions.webpackCli)
runtimeOnly(versions.webpackBundleAnalyzer)
// for source map support
runtimeOnly(versions.sourceMapLoader.npm(project))
runtimeOnly(versions.sourceMapSupport.npm(project))
}
project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("webpack")) { project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("webpack")) {
it.dependsOn(compileKotlinTask) it.dependsOn(compileKotlinTask)
@@ -50,10 +38,6 @@ class KotlinBrowserJs(
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(it) project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(it)
} }
compilation.dependencies {
runtimeOnly(npm("webpack-dev-server", "3.3.1"))
}
project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("run")) { project.createOrRegisterTask<KotlinWebpack>(disambiguateCamelCased("run")) {
it.dependsOn(compileKotlinTask) it.dependsOn(compileKotlinTask)
@@ -16,9 +16,11 @@ import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
import org.jetbrains.kotlin.gradle.testing.internal.registerTestTask import org.jetbrains.kotlin.gradle.testing.internal.registerTestTask
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
abstract class KotlinJsInnerTargetConfigurator(val target: KotlinOnlyTarget<KotlinJsCompilation>) { abstract class KotlinJsInnerTargetConfigurator(
val target: KotlinOnlyTarget<KotlinJsCompilation>,
private val disambiguationClassifier: String
) {
val project get() = target.project val project get() = target.project
private val disambiguationClassifier get() = "browser"
fun configure() { fun configure() {
configureTests() configureTests()
@@ -64,7 +66,6 @@ abstract class KotlinJsInnerTargetConfigurator(val target: KotlinOnlyTarget<Kotl
compileTask.outputFile.exists() compileTask.outputFile.exists()
} }
testJs.runtimeDependencyHandler = compilation
testJs.targetName = disambiguationClassifier testJs.targetName = disambiguationClassifier
testJs.nodeModulesToLoad.add(compileTask.outputFile.name) testJs.nodeModulesToLoad.add(compileTask.outputFile.name)
@@ -85,6 +86,7 @@ abstract class KotlinJsInnerTargetConfigurator(val target: KotlinOnlyTarget<Kotl
} }
protected abstract fun configureDefaultTestFramework(it: KotlinJsTest) protected abstract fun configureDefaultTestFramework(it: KotlinJsTest)
fun configureRun() { fun configureRun() {
target.compilations.all { compilation -> target.compilations.all { compilation ->
if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) { if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.js.npm package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedArtifact import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.component.ProjectComponentIdentifier
@@ -27,30 +28,21 @@ internal class GradleNodeModulesBuilder(val project: Project) : AutoCloseable {
GradleNodeModule(it, dir.resolve(it)) GradleNodeModule(it, dir.resolve(it))
} }
fun visitCompilation(compilation: KotlinCompilation<KotlinCommonOptions>) { fun visitConfiguration(configuration: Configuration) {
val project = compilation.target.project if (configuration.isCanBeResolved) {
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach {
// classpath visitDependency(it)
compilation.relatedConfigurationNames.forEach { configurationName ->
val configuration = project.configurations.getByName(configurationName)
if (configuration.isCanBeResolved) {
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach {
visitDependency(compilation, it)
}
} }
} }
} }
private fun visitDependency( private fun visitDependency(dependency: ResolvedDependency) {
compilation: KotlinCompilation<KotlinCommonOptions>,
dependency: ResolvedDependency
) {
if (!visited.add(dependency)) return if (!visited.add(dependency)) return
visitArtifacts(dependency, dependency.moduleArtifacts) visitArtifacts(dependency, dependency.moduleArtifacts)
dependency.children.forEach { dependency.children.forEach {
visitDependency(compilation, it) visitDependency(it)
} }
} }
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.gradle.targets.js.npm package org.jetbrains.kotlin.gradle.targets.js.npm
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
class NpmPackages { class NpmPackages {
val webpack = NpmPackageVersion("webpack", "4.29.6") val webpack = NpmPackageVersion("webpack", "4.29.6")
@@ -17,6 +19,7 @@ class NpmPackages {
val sourceMapSupport = NpmPackageVersion("source-map-support", "0.5.12") val sourceMapSupport = NpmPackageVersion("source-map-support", "0.5.12")
val mocha = NpmPackageVersion("mocha", "6.1.2") val mocha = NpmPackageVersion("mocha", "6.1.2")
val mochaTeamCityReporter = NpmPackageVersion("mocha-teamcity-reporter", ">=2.0.0")
val karma = NpmPackageVersion("karma", "4.0.1") val karma = NpmPackageVersion("karma", "4.0.1")
val karmaTeamcityReporter = NpmPackageVersion("karma-teamcity-reporter", "1.1.0") val karmaTeamcityReporter = NpmPackageVersion("karma-teamcity-reporter", "1.1.0")
@@ -32,8 +35,19 @@ class NpmPackages {
val karmaWebpack = NpmPackageVersion("karma-webpack", "*") val karmaWebpack = NpmPackageVersion("karma-webpack", "*")
val karmaSourceMapSupport = NpmPackageVersion("karma-source-map-support", "1.4.0") val karmaSourceMapSupport = NpmPackageVersion("karma-source-map-support", "1.4.0")
val kotlinNodeJsTestRunner = KotlinGradleNpmPackage("test-nodejs-runner")
} }
data class NpmPackageVersion(val name: String, var version: String) { interface RequiredKotlinJsDependency {
fun npm(project: Project) = NpmDependency(project, null, name, version) fun createDependency(project: Project): Dependency
}
data class NpmPackageVersion(val name: String, var version: String) : RequiredKotlinJsDependency {
override fun createDependency(project: Project) = NpmDependency(project, null, name, version)
}
data class KotlinGradleNpmPackage(val simpleModuleName: String): RequiredKotlinJsDependency {
override fun createDependency(project: Project): Dependency =
project.dependencies.create("org.jetbrains.kotlin:kotlin-$simpleModuleName")
} }
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.gradle.targets.js.npm
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.file.CopySpec import org.gradle.api.file.CopySpec
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
@@ -46,7 +48,23 @@ internal class NpmResolver private constructor(val rootProject: Project) {
else { else {
val resolver = NpmResolver(rootProject) val resolver = NpmResolver(rootProject)
check(resolver.resolve(rootProject, null)) check(resolver.resolve(rootProject, null))
ResolvedNow(ResolvedProject(resolver.npmPackages)) ResolvedNow(ResolvedProject(resolver.npmPackages, resolver.requiredByTasks))
}
}
fun checkRequiredDependencies(project: Project, target: RequiresNpmDependencies) {
val required = ProjectData[project.rootProject]?.resolved?.requiredByTasks
check(required != null) {
"NPM dependencies should be resolved before $target execution"
}
val targetRequired = required!![target]?.toSet() ?: setOf()
target.requiredNpmDependencies.forEach {
check(it in targetRequired) {
"$it required by $target after npm dependencies was resolved. " +
"This may be caused by changing $target configuration after npm dependencies resolution."
}
} }
} }
} }
@@ -62,9 +80,17 @@ internal class NpmResolver private constructor(val rootProject: Project) {
private val packageManager = nodeJs.packageManager private val packageManager = nodeJs.packageManager
private val hoistGradleNodeModules = npmProject.hoistGradleNodeModules private val hoistGradleNodeModules = npmProject.hoistGradleNodeModules
private val npmPackages = mutableListOf<NpmPackage>() private val npmPackages = mutableListOf<NpmPackage>()
private val requiredByTasks = mutableMapOf<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>()
private val gson = GsonBuilder() private val gson = GsonBuilder()
.setPrettyPrinting() .setPrettyPrinting()
.create() .create()
private val readyTaskGraph: TaskExecutionGraph?
init {
var readyTaskGraph: TaskExecutionGraph? = null
rootProject.gradle.taskGraph.whenReady { readyTaskGraph = it }
this.readyTaskGraph = readyTaskGraph
}
class ProjectData(var resolved: ResolvedProject? = null) { class ProjectData(var resolved: ResolvedProject? = null) {
companion object { companion object {
@@ -74,7 +100,10 @@ internal class NpmResolver private constructor(val rootProject: Project) {
} }
} }
class ResolvedProject(val npmPackages: Collection<NpmPackage>) { class ResolvedProject(
val npmPackages: Collection<NpmPackage>,
val requiredByTasks: Map<RequiresNpmDependencies, Collection<RequiredKotlinJsDependency>>
) {
val dependencies by lazy { val dependencies by lazy {
npmPackages.flatMapTo(mutableSetOf()) { it.npmDependencies } npmPackages.flatMapTo(mutableSetOf()) { it.npmDependencies }
} }
@@ -157,6 +186,8 @@ internal class NpmResolver private constructor(val rootProject: Project) {
val packageJson = PackageJson(project.name, project.version.toString()) val packageJson = PackageJson(project.name, project.version.toString())
val npmDependencies = mutableSetOf<NpmDependency>() val npmDependencies = mutableSetOf<NpmDependency>()
visitTasksRequiredDependencies(project, npmDependencies, gradleComponents)
visitNpmDependencies(project, npmDependencies, gradleComponents, packageJson) visitNpmDependencies(project, npmDependencies, gradleComponents, packageJson)
if (!hoistGradleNodeModules || project == project.rootProject) { if (!hoistGradleNodeModules || project == project.rootProject) {
@@ -178,6 +209,36 @@ internal class NpmResolver private constructor(val rootProject: Project) {
else NpmPackage(project, packageJson, npmDependencies) else NpmPackage(project, packageJson, npmDependencies)
} }
private fun visitTasksRequiredDependencies(
project: Project,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder
) {
var toolsDependenciesConfiguration: Configuration? = project.configurations.create("jsTools")
project.tasks.toList().forEach { task ->
if (task is RequiresNpmDependencies) {
if (readyTaskGraph?.hasTask(task) ?: task.enabled) {
val list = task.requiredNpmDependencies.toList()
requiredByTasks[task] = list
list.forEach { requiredDependency ->
val configuration: Configuration = toolsDependenciesConfiguration
?: project.configurations.create("jsTools").also { new ->
toolsDependenciesConfiguration = new
}
configuration.dependencies.add(requiredDependency.createDependency(project))
}
}
}
}
if (toolsDependenciesConfiguration != null) {
visitConfiguration(toolsDependenciesConfiguration!!, npmDependencies, gradleComponents)
}
}
private fun visitNpmDependencies( private fun visitNpmDependencies(
project: Project, project: Project,
npmDependencies: MutableSet<NpmDependency>, npmDependencies: MutableSet<NpmDependency>,
@@ -213,15 +274,10 @@ internal class NpmResolver private constructor(val rootProject: Project) {
if (target.platformType == KotlinPlatformType.js) { if (target.platformType == KotlinPlatformType.js) {
target.compilations.toList().forEach { compilation -> target.compilations.toList().forEach { compilation ->
compilation.relatedConfigurationNames.forEach { compilation.relatedConfigurationNames.forEach {
project.configurations.getByName(it).allDependencies.forEach { dependency -> val configuration = project.configurations.getByName(it)
when (dependency) { visitConfiguration(configuration, npmDependencies, gradleComponents)
is NpmDependency -> npmDependencies.add(dependency)
}
}
} }
gradleComponents.visitCompilation(compilation)
if (compilation is KotlinJsCompilation) { if (compilation is KotlinJsCompilation) {
visitKotlinJsCompilation(project, compilation) visitKotlinJsCompilation(project, compilation)
@@ -233,6 +289,20 @@ internal class NpmResolver private constructor(val rootProject: Project) {
} }
} }
private fun visitConfiguration(
configuration: Configuration,
npmDependencies: MutableSet<NpmDependency>,
gradleComponents: GradleNodeModulesBuilder
) {
gradleComponents.visitConfiguration(configuration)
configuration.allDependencies.forEach { dependency ->
when (dependency) {
is NpmDependency -> npmDependencies.add(dependency)
}
}
}
private fun visitKotlinJsCompilation( private fun visitKotlinJsCompilation(
project: Project, project: Project,
compilation: KotlinJsCompilation compilation: KotlinJsCompilation
@@ -0,0 +1,10 @@
/*
* 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.npm
interface RequiresNpmDependencies {
val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
}
@@ -12,14 +12,14 @@ import org.gradle.process.internal.DefaultProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout import org.jetbrains.kotlin.gradle.targets.js.npm.*
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma import org.jetbrains.kotlin.gradle.targets.js.testing.karma.KotlinKarma
import org.jetbrains.kotlin.gradle.targets.js.testing.mocha.KotlinMocha import org.jetbrains.kotlin.gradle.targets.js.testing.mocha.KotlinMocha
import org.jetbrains.kotlin.gradle.targets.js.testing.nodejs.KotlinNodeJsTestRunner import org.jetbrains.kotlin.gradle.targets.js.testing.nodejs.KotlinNodeJsTestRunner
import org.jetbrains.kotlin.gradle.tasks.KotlinTest import org.jetbrains.kotlin.gradle.tasks.KotlinTest
open class KotlinJsTest : KotlinTest() { open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies {
@Internal @Internal
@SkipWhenEmpty @SkipWhenEmpty
internal var testFramework: KotlinJsTestFramework? = null internal var testFramework: KotlinJsTestFramework? = null
@@ -27,17 +27,17 @@ open class KotlinJsTest : KotlinTest() {
@Input @Input
var debug: Boolean = false var debug: Boolean = false
@Internal
var runtimeDependencyHandler: HasKotlinDependencies? = null
@Input @Input
var nodeModulesToLoad: MutableList<String> = mutableListOf() var nodeModulesToLoad: MutableList<String> = mutableListOf()
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
get() = testFramework!!.requiredNpmDependencies
fun useNodeJs(body: KotlinNodeJsTestRunner.() -> Unit) = use(KotlinNodeJsTestRunner(), body) fun useNodeJs(body: KotlinNodeJsTestRunner.() -> Unit) = use(KotlinNodeJsTestRunner(), body)
fun useMocha(body: KotlinMocha.() -> Unit) = use(KotlinMocha(), body) fun useMocha(body: KotlinMocha.() -> Unit) = use(KotlinMocha(project), body)
fun useKarma(body: KotlinKarma.() -> Unit) = use(KotlinKarma(), body) fun useKarma(body: KotlinKarma.() -> Unit) = use(KotlinKarma(project), body)
private inline fun <T : KotlinJsTestFramework> use(runner: T, body: T.() -> Unit): T { private inline fun <T : KotlinJsTestFramework> use(runner: T, body: T.() -> Unit): T {
check(testFramework == null) { check(testFramework == null) {
@@ -47,16 +47,12 @@ open class KotlinJsTest : KotlinTest() {
val testFramework = runner.also(body) val testFramework = runner.also(body)
this.testFramework = testFramework this.testFramework = testFramework
val dependenciesHolder = runtimeDependencyHandler
if (dependenciesHolder != null) {
testFramework.configure(dependenciesHolder)
}
return testFramework return testFramework
} }
override fun executeTests() { override fun executeTests() {
NpmResolver.resolve(project) NpmResolver.resolve(project)
NpmResolver.checkRequiredDependencies(project, this)
super.executeTests() super.executeTests()
} }
@@ -65,7 +61,7 @@ open class KotlinJsTest : KotlinTest() {
NpmResolver.resolve(project) NpmResolver.resolve(project)
forkOptions.workingDir = NpmProjectLayout[project].nodeWorkDir forkOptions.workingDir = NpmProject[project].nodeWorkDir
forkOptions.executable = NodeJsPlugin.apply(project).root.environment.nodeExecutable forkOptions.executable = NodeJsPlugin.apply(project).root.environment.nodeExecutable
val nodeJsArgs = mutableListOf<String>() val nodeJsArgs = mutableListOf<String>()
@@ -8,15 +8,12 @@ package org.jetbrains.kotlin.gradle.targets.js.testing
import org.gradle.process.ProcessForkOptions import org.gradle.process.ProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
interface KotlinJsTestFramework { interface KotlinJsTestFramework : RequiresNpmDependencies {
fun createTestExecutionSpec( fun createTestExecutionSpec(
task: KotlinJsTest, task: KotlinJsTest,
forkOptions: ProcessForkOptions, forkOptions: ProcessForkOptions,
nodeJsArgs: MutableList<String> nodeJsArgs: MutableList<String>
): TCServiceMessagesTestExecutionSpec ): TCServiceMessagesTestExecutionSpec
fun configure(dependenciesHolder: HasKotlinDependencies) {
}
} }
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
@@ -24,6 +25,9 @@ class KotlinKarma(val project: Project) : KotlinJsTestFramework {
private val versions = project.nodeJs.versions private val versions = project.nodeJs.versions
override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
get() = requiredDependencies.toList()
init { init {
requiredDependencies.add(versions.karma) requiredDependencies.add(versions.karma)
@@ -49,7 +53,7 @@ class KotlinKarma(val project: Project) : KotlinJsTestFramework {
fun useIe() = useBrowser("Ie", versions.karmaIeLauncher) fun useIe() = useBrowser("Ie", versions.karmaIeLauncher)
fun useBrowser(id: String, dependency: NpmPackageVersion) { private fun useBrowser(id: String, dependency: NpmPackageVersion) {
config.browsers.add(id) config.browsers.add(id)
requiredDependencies.add(dependency) requiredDependencies.add(dependency)
} }
@@ -68,14 +72,6 @@ class KotlinKarma(val project: Project) : KotlinJsTestFramework {
requiredDependencies.add(versions.karmaSourceMapSupport) requiredDependencies.add(versions.karmaSourceMapSupport)
} }
override fun configure(dependenciesHolder: HasKotlinDependencies) {
dependenciesHolder.dependencies {
requiredDependencies.forEach {
npm(it.name, it.version)
}
}
}
override fun createTestExecutionSpec( override fun createTestExecutionSpec(
task: KotlinJsTest, task: KotlinJsTest,
forkOptions: ProcessForkOptions, forkOptions: ProcessForkOptions,
@@ -5,23 +5,28 @@
package org.jetbrains.kotlin.gradle.targets.js.testing.mocha package org.jetbrains.kotlin.gradle.targets.js.testing.mocha
import org.gradle.api.Project
import org.gradle.process.ProcessForkOptions import org.gradle.process.ProcessForkOptions
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinGradleNpmPackage
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
class KotlinMocha : KotlinJsTestFramework { class KotlinMocha(val project: Project) : KotlinJsTestFramework {
override fun configure(dependenciesHolder: HasKotlinDependencies) { private val versions = project.nodeJs.versions
dependenciesHolder.dependencies {
runtimeOnly(kotlin("test-nodejs-runner")) override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
runtimeOnly(npm("mocha", "6.1.2")) get() = listOf(
runtimeOnly(npm("mocha-teamcity-reporter", ">=2.0.0")) KotlinGradleNpmPackage("test-nodejs-runner"),
} versions.mocha,
} versions.mochaTeamCityReporter
)
override fun createTestExecutionSpec( override fun createTestExecutionSpec(
task: KotlinJsTest, task: KotlinJsTest,
@@ -31,7 +36,7 @@ class KotlinMocha : KotlinJsTestFramework {
val clientSettings = TCServiceMessagesClientSettings( val clientSettings = TCServiceMessagesClientSettings(
task.name, task.name,
testNameSuffix = task.targetName, testNameSuffix = task.targetName,
prepandSuiteName = true, prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm, stackTraceParser = ::parseNodeJsStackTraceAsJvm,
ignoreOutOfRootNodes = true ignoreOutOfRootNodes = true
) )
@@ -41,7 +46,7 @@ class KotlinMocha : KotlinJsTestFramework {
task.nodeModulesToLoad.single() task.nodeModulesToLoad.single()
) )
val npmProjectLayout = NpmProjectLayout[task.project] val npmProjectLayout = NpmProject[task.project]
val args = nodeJsArgs + val args = nodeJsArgs +
nodeModules.map { nodeModules.map {
@@ -11,7 +11,10 @@ import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSetti
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout import org.jetbrains.kotlin.gradle.targets.js.npm.KotlinGradleNpmPackage
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTestFramework
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.testing.IgnoredTestSuites import org.jetbrains.kotlin.gradle.testing.IgnoredTestSuites
@@ -20,11 +23,8 @@ class KotlinNodeJsTestRunner : KotlinJsTestFramework {
@Input @Input
var ignoredTestSuites: IgnoredTestSuites = IgnoredTestSuites.showWithContents var ignoredTestSuites: IgnoredTestSuites = IgnoredTestSuites.showWithContents
override fun configure(dependenciesHolder: HasKotlinDependencies) { override val requiredNpmDependencies: Collection<RequiredKotlinJsDependency>
dependenciesHolder.dependencies { get() = listOf(KotlinGradleNpmPackage("test-nodejs-runner"))
runtimeOnly(kotlin("test-nodejs-runner"))
}
}
override fun createTestExecutionSpec( override fun createTestExecutionSpec(
task: KotlinJsTest, task: KotlinJsTest,
@@ -41,16 +41,16 @@ class KotlinNodeJsTestRunner : KotlinJsTestFramework {
val clientSettings = TCServiceMessagesClientSettings( val clientSettings = TCServiceMessagesClientSettings(
task.name, task.name,
testNameSuffix = task.targetName, testNameSuffix = task.targetName,
prepandSuiteName = true, prependSuiteName = true,
stackTraceParser = ::parseNodeJsStackTraceAsJvm stackTraceParser = ::parseNodeJsStackTraceAsJvm
) )
val testRuntimeNodeModules = listOf( val testRuntimeNodeModules = listOf(
"kotlin-test-nodejs-runner.js", "kotlin-test-nodejs-runner/kotlin-test-nodejs-runner.js",
"kotlin-nodejs-source-map-support.js" "kotlin-test-nodejs-runner/kotlin-nodejs-source-map-support.js"
) )
val npmProjectLayout = NpmProjectLayout[task.project] val npmProjectLayout = NpmProject[task.project]
val args = nodeJsArgs + val args = nodeJsArgs +
testRuntimeNodeModules.map { testRuntimeNodeModules.map {
@@ -13,16 +13,19 @@ import org.gradle.deployment.internal.DeploymentHandle
import org.gradle.deployment.internal.DeploymentRegistry import org.gradle.deployment.internal.DeploymentRegistry
import org.gradle.process.internal.ExecHandle import org.gradle.process.internal.ExecHandle
import org.gradle.process.internal.ExecHandleFactory import org.gradle.process.internal.ExecHandleFactory
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmPackageVersion
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
import org.jetbrains.kotlin.gradle.testing.internal.reportsDir import org.jetbrains.kotlin.gradle.testing.internal.reportsDir
import org.jetbrains.kotlin.gradle.utils.injected import org.jetbrains.kotlin.gradle.utils.injected
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
open class KotlinWebpack : DefaultTask() { open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
private val versions by lazy { project.nodeJs.versions }
@get:Inject @get:Inject
open val fileResolver: FileResolver open val fileResolver: FileResolver
get() = injected get() = injected
@@ -66,7 +69,26 @@ open class KotlinWebpack : DefaultTask() {
@Optional @Optional
var devServer: KotlinWebpackConfig.DevServer? = null var devServer: KotlinWebpackConfig.DevServer? = null
internal fun createRunner() = KotlinWebpackRunner( override val requiredNpmDependencies: Collection<NpmPackageVersion>
get() = mutableListOf<NpmPackageVersion>().also {
it.add(versions.webpack)
it.add(versions.webpackCli)
if (report) {
it.add(versions.webpackBundleAnalyzer)
}
if (sourceMaps) {
it.add(versions.sourceMapLoader)
it.add(versions.sourceMapSupport)
}
if (devServer != null) {
it.add(versions.webpackDevServer)
}
}
private fun createRunner() = KotlinWebpackRunner(
project, project,
configFile, configFile,
execHandleFactory, execHandleFactory,
@@ -84,6 +106,9 @@ open class KotlinWebpack : DefaultTask() {
@TaskAction @TaskAction
fun execute() { fun execute() {
NpmResolver.resolve(project)
NpmResolver.checkRequiredDependencies(project, this)
val runner = createRunner() val runner = createRunner()
if (project.gradle.startParameter.isContinuous) { if (project.gradle.startParameter.isContinuous) {