Importing test tasks and targets is implemented
This commit is contained in:
@@ -15,6 +15,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.ExternalSystemTestTask
|
||||
import org.jetbrains.kotlin.gradle.*
|
||||
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
@@ -48,6 +49,7 @@ class KotlinSourceSetInfo @PropertyMapping("kotlinModule") constructor(val kotli
|
||||
var isTestModule: Boolean = false
|
||||
var sourceSetIdsByName: MutableMap<String, String> = LinkedHashMap()
|
||||
var dependsOn: List<String> = emptyList()
|
||||
var externalSystemTestTasks: Collection<ExternalSystemTestTask> = emptyList()
|
||||
}
|
||||
|
||||
class KotlinAndroidSourceSetData @PropertyMapping("sourceSetInfos") constructor(val sourceSetInfos: List<KotlinSourceSetInfo>
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.ExternalSystemTestTask
|
||||
import org.jetbrains.kotlin.gradle.*
|
||||
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
@@ -44,6 +45,7 @@ class KotlinSourceSetInfo(val kotlinModule: KotlinModule) : Serializable {
|
||||
var isTestModule: Boolean = false
|
||||
var sourceSetIdsByName: MutableMap<String, String> = LinkedHashMap()
|
||||
var dependsOn: List<String> = emptyList()
|
||||
var externalSystemTestTasks: Collection<ExternalSystemTestTask> = emptyList()
|
||||
}
|
||||
|
||||
class KotlinAndroidSourceSetData(
|
||||
|
||||
+57
-4
@@ -30,10 +30,12 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.ManualLanguageFeatureSetting
|
||||
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
|
||||
import org.jetbrains.kotlin.config.ExternalSystemTestTask
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.gradle.*
|
||||
import org.jetbrains.kotlin.idea.configuration.GradlePropertiesFileFacade.Companion.KOTLIN_NOT_IMPORTED_COMMON_SOURCE_SETS_SETTING
|
||||
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.plugins.gradle.model.*
|
||||
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
@@ -259,6 +261,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
|
||||
val sourceSetMap = projectDataNode.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS)!!
|
||||
|
||||
val sourceSetToTestTasks = calculateTestTasks(mppModel, gradleModule, resolverCtx)
|
||||
|
||||
val sourceSetToCompilationData = LinkedHashMap<KotlinSourceSet, MutableSet<GradleSourceSetData>>()
|
||||
for (target in mppModel.targets) {
|
||||
if (target.platform == KotlinPlatform.ANDROID) continue
|
||||
@@ -305,7 +309,13 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
it.sdkName = jdkName
|
||||
}
|
||||
|
||||
val kotlinSourceSet = createSourceSetInfo(compilation, gradleModule, resolverCtx) ?: continue
|
||||
val kotlinSourceSet = createSourceSetInfo(
|
||||
compilation,
|
||||
gradleModule,
|
||||
resolverCtx
|
||||
) ?: continue
|
||||
kotlinSourceSet.externalSystemTestTasks =
|
||||
compilation.sourceSets.firstNotNullResult { sourceSetToTestTasks[it] } ?: emptyList()
|
||||
|
||||
if (compilation.platform == KotlinPlatform.JVM || compilation.platform == KotlinPlatform.ANDROID) {
|
||||
compilationData.targetCompatibility = (kotlinSourceSet.compilerArguments as? K2JVMCompilerArguments)?.jvmTarget
|
||||
@@ -364,6 +374,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
}
|
||||
|
||||
val kotlinSourceSet = createSourceSetInfo(sourceSet, gradleModule, resolverCtx) ?: continue
|
||||
kotlinSourceSet.externalSystemTestTasks = sourceSetToTestTasks[sourceSet] ?: emptyList()
|
||||
|
||||
val sourceSetDataNode =
|
||||
(existingSourceSetDataNode ?: mainModuleNode.createChild(GradleSourceSetData.KEY, sourceSetData)).also {
|
||||
@@ -383,6 +394,34 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
|
||||
mainModuleNode.coroutines = mppModel.extraFeatures.coroutinesState
|
||||
mainModuleNode.isHmpp = mppModel.extraFeatures.isHMPPEnabled
|
||||
//TODO improve passing version of used multiplatform
|
||||
}
|
||||
|
||||
private fun calculateTestTasks(
|
||||
mppModel: KotlinMPPGradleModel,
|
||||
gradleModule: IdeaModule,
|
||||
resolverCtx: ProjectResolverContext
|
||||
): Map<KotlinSourceSet, Collection<ExternalSystemTestTask>> {
|
||||
val sourceSetToTestTasks: MutableMap<KotlinSourceSet, MutableCollection<ExternalSystemTestTask>> = HashMap()
|
||||
val dependsOnReverseGraph: MutableMap<String, MutableSet<KotlinSourceSet>> = HashMap()
|
||||
mppModel.targets.forEach { target ->
|
||||
target.compilations.forEach { compilation ->
|
||||
val testTasks = target.testTasks.filter { testTask -> testTask.compilationName == compilation.name }
|
||||
.map { ExternalSystemTestTask(it.taskName, getKotlinModuleId(gradleModule, compilation, resolverCtx), target.name) }
|
||||
compilation.sourceSets.forEach { sourceSet ->
|
||||
sourceSetToTestTasks.getOrPut(sourceSet) { LinkedHashSet() } += testTasks
|
||||
sourceSet.dependsOnSourceSets.forEach { dependentModule ->
|
||||
dependsOnReverseGraph.getOrPut(dependentModule) { LinkedHashSet() } += sourceSet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mppModel.sourceSets.forEach { (sourceSetName, sourceSet) ->
|
||||
dependsOnReverseGraph[sourceSetName]?.forEach { dependingSourceSet ->
|
||||
sourceSetToTestTasks.getOrPut(sourceSet) { LinkedHashSet() } += sourceSetToTestTasks[dependingSourceSet] ?: emptyList()
|
||||
}
|
||||
}
|
||||
return sourceSetToTestTasks
|
||||
}
|
||||
|
||||
fun populateContentRoots(
|
||||
@@ -567,7 +606,12 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
return ideModule.findChildModuleById(usedModuleId)
|
||||
}
|
||||
|
||||
private fun createContentRootData(sourceDirs: Set<File>, sourceType: ExternalSystemSourceType, packagePrefix: String?, parentNode: DataNode<*>) {
|
||||
private fun createContentRootData(
|
||||
sourceDirs: Set<File>,
|
||||
sourceType: ExternalSystemSourceType,
|
||||
packagePrefix: String?,
|
||||
parentNode: DataNode<*>
|
||||
) {
|
||||
for (sourceDir in sourceDirs) {
|
||||
val contentRootData = ContentRootData(GradleConstants.SYSTEM_ID, sourceDir.absolutePath)
|
||||
contentRootData.storePath(sourceType, sourceDir.absolutePath, packagePrefix)
|
||||
@@ -652,7 +696,11 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
return PathUtilRt.suggestFileName(moduleName.toString(), true, false)
|
||||
}
|
||||
|
||||
private fun createExternalSourceSet(compilation: KotlinCompilation, compilationData: GradleSourceSetData, mppModel: KotlinMPPGradleModel): ExternalSourceSet {
|
||||
private fun createExternalSourceSet(
|
||||
compilation: KotlinCompilation,
|
||||
compilationData: GradleSourceSetData,
|
||||
mppModel: KotlinMPPGradleModel
|
||||
): ExternalSourceSet {
|
||||
return DefaultExternalSourceSet().also { sourceSet ->
|
||||
val effectiveClassesDir = compilation.output.effectiveClassesDir
|
||||
val resourcesDir = compilation.output.resourcesDir
|
||||
@@ -688,7 +736,11 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
}
|
||||
|
||||
|
||||
private fun createExternalSourceSet(ktSourceSet: KotlinSourceSet, ktSourceSetData: GradleSourceSetData, mppModel: KotlinMPPGradleModel): ExternalSourceSet {
|
||||
private fun createExternalSourceSet(
|
||||
ktSourceSet: KotlinSourceSet,
|
||||
ktSourceSetData: GradleSourceSetData,
|
||||
mppModel: KotlinMPPGradleModel
|
||||
): ExternalSourceSet {
|
||||
return DefaultExternalSourceSet().also { sourceSet ->
|
||||
sourceSet.name = ktSourceSet.name
|
||||
sourceSet.targetCompatibility = ktSourceSetData.targetCompatibility
|
||||
@@ -745,6 +797,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
|
||||
}
|
||||
|
||||
// TODO: Unite with other createSourceSetInfo
|
||||
// This method is used in Android side of import and it's signature could not be changed
|
||||
fun createSourceSetInfo(
|
||||
compilation: KotlinCompilation,
|
||||
gradleModule: IdeaModule,
|
||||
|
||||
+1
@@ -150,6 +150,7 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
|
||||
kind = kotlinSourceSet.kotlinModule.kind
|
||||
|
||||
isTestModule = kotlinSourceSet.isTestModule
|
||||
externalSystemTestTasks = ArrayList(kotlinSourceSet.externalSystemTestTasks)
|
||||
|
||||
externalProjectId = kotlinSourceSet.gradleModuleId
|
||||
|
||||
|
||||
+1
@@ -348,6 +348,7 @@ class HierarchicalMultiplatformProjectImportingTest : MultiplePluginVersionGradl
|
||||
exhaustiveModuleList,
|
||||
exhaustiveSourceSourceRootList,
|
||||
exhaustiveDependencyList,
|
||||
false,
|
||||
body
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class KaptImportingTest : MultiplePluginVersionGradleImportingTestCase() {
|
||||
configureByFiles()
|
||||
importProject(true)
|
||||
|
||||
checkProjectStructure(myProject, projectPath, true, true, true) {
|
||||
checkProjectStructure(myProject, projectPath, true, true, true, false) {
|
||||
module("project")
|
||||
module("project_main") {
|
||||
sourceFolder("build/generated/source/kapt/main", JavaSourceRootType.SOURCE)
|
||||
@@ -65,7 +65,7 @@ class KaptImportingTest : MultiplePluginVersionGradleImportingTestCase() {
|
||||
configureByFiles()
|
||||
importProject(false)
|
||||
|
||||
checkProjectStructure(myProject, projectPath, true, true, true) {
|
||||
checkProjectStructure(myProject, projectPath, true, true, true, false) {
|
||||
module("project") {
|
||||
sourceFolder("build/generated/source/kapt/main", JavaSourceRootType.SOURCE)
|
||||
sourceFolder("build/generated/source/kaptKotlin/main", JavaSourceRootType.SOURCE)
|
||||
|
||||
+2
-1
@@ -33,7 +33,8 @@ class NewMultiplatformKaptProjectImportingTest : MultiplePluginVersionGradleImpo
|
||||
projectPath,
|
||||
exhaustiveModuleList = true,
|
||||
exhaustiveSourceSourceRootList = false,
|
||||
exhaustiveDependencyList = false
|
||||
exhaustiveDependencyList = false,
|
||||
exhaustiveTestsList = false
|
||||
) {
|
||||
module("project")
|
||||
|
||||
|
||||
+29
@@ -395,6 +395,33 @@ class NewMultiplatformProjectImportingTest : MultiplePluginVersionGradleImportin
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODObub(auskov): enable this test after publishing new api in gradle plugin
|
||||
//@Test
|
||||
fun testImportTestsAndTargets() {
|
||||
configureByFiles()
|
||||
importProject()
|
||||
|
||||
checkProjectStructure(exhaustiveSourceSourceRootList = false, exhaustiveDependencyList = false, exhaustiveTestsList = true) {
|
||||
module("project")
|
||||
module("project_commonMain")
|
||||
module("project_commonTest") {
|
||||
externalSystemTestTask("jsBrowserTest", "project:jsTest", "js")
|
||||
externalSystemTestTask("jsNodeTest", "project:jsTest", "js")
|
||||
externalSystemTestTask("test", "project:jvmTest", "jvm")
|
||||
}
|
||||
module("project_jsMain")
|
||||
module("project_jsTest") {
|
||||
externalSystemTestTask("jsBrowserTest", "project:jsTest", "js")
|
||||
externalSystemTestTask("jsNodeTest", "project:jsTest", "js")
|
||||
}
|
||||
module("project_jvmMain")
|
||||
module("project_jvmTest") {
|
||||
externalSystemTestTask("test", "project:jvmTest", "jvm")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDependencyOnRoot() {
|
||||
configureByFiles()
|
||||
@@ -773,6 +800,7 @@ class NewMultiplatformProjectImportingTest : MultiplePluginVersionGradleImportin
|
||||
exhaustiveModuleList: Boolean = true,
|
||||
exhaustiveSourceSourceRootList: Boolean = true,
|
||||
exhaustiveDependencyList: Boolean = true,
|
||||
exhaustiveTestsList: Boolean = false,
|
||||
body: ProjectInfo.() -> Unit = {}
|
||||
) {
|
||||
checkProjectStructure(
|
||||
@@ -781,6 +809,7 @@ class NewMultiplatformProjectImportingTest : MultiplePluginVersionGradleImportin
|
||||
exhaustiveModuleList,
|
||||
exhaustiveSourceSourceRootList,
|
||||
exhaustiveDependencyList,
|
||||
exhaustiveTestsList,
|
||||
body)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ class PackagePrefixImportingTest : MultiplePluginVersionGradleImportingTestCase(
|
||||
projectPath,
|
||||
exhaustiveModuleList = true,
|
||||
exhaustiveSourceSourceRootList = true,
|
||||
exhaustiveDependencyList = false
|
||||
exhaustiveDependencyList = false,
|
||||
exhaustiveTestsList = false
|
||||
) {
|
||||
module("project") {
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ import com.intellij.openapi.roots.impl.ModuleOrderEntryImpl
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import org.jetbrains.kotlin.config.ExternalSystemTestTask
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.facet.externalSystemTestTasks
|
||||
import org.jetbrains.kotlin.idea.project.isHMPPEnabled
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.platform.SimplePlatform
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.presentableDescription
|
||||
|
||||
@@ -42,7 +43,8 @@ class ProjectInfo(
|
||||
internal val projectPath: String,
|
||||
internal val exhaustiveModuleList: Boolean,
|
||||
internal val exhaustiveSourceSourceRootList: Boolean,
|
||||
internal val exhaustiveDependencyList: Boolean
|
||||
internal val exhaustiveDependencyList: Boolean,
|
||||
internal val exhaustiveTestsList: Boolean
|
||||
) {
|
||||
internal val messageCollector = MessageCollector()
|
||||
private val moduleManager = ModuleManager.getInstance(project)
|
||||
@@ -88,6 +90,8 @@ class ModuleInfo(
|
||||
private val rootModel = module.rootManager
|
||||
private val expectedDependencyNames = HashSet<String>()
|
||||
private val expectedSourceRoots = HashSet<String>()
|
||||
private val expectedExternalSystemTestTasks = ArrayList<ExternalSystemTestTask>()
|
||||
|
||||
private val sourceFolderByPath by lazy {
|
||||
rootModel.contentEntries.asSequence()
|
||||
.flatMap { it.sourceFolders.asSequence() }
|
||||
@@ -156,6 +160,10 @@ class ModuleInfo(
|
||||
}
|
||||
}
|
||||
|
||||
fun externalSystemTestTask(taskName: String, projectId: String, targetName: String) {
|
||||
expectedExternalSystemTestTasks.add(ExternalSystemTestTask(taskName, projectId, targetName))
|
||||
}
|
||||
|
||||
fun libraryDependency(libraryName: String, scope: DependencyScope) {
|
||||
val libraryEntries = rootModel.orderEntries.filterIsInstance<LibraryOrderEntry>().filter { it.libraryName == libraryName }
|
||||
if (libraryEntries.size > 1) {
|
||||
@@ -271,6 +279,12 @@ class ModuleInfo(
|
||||
}
|
||||
}
|
||||
|
||||
if ((!module.externalSystemTestTasks().containsAll(expectedExternalSystemTestTasks)) || (projectInfo.exhaustiveTestsList && (module.externalSystemTestTasks() != expectedExternalSystemTestTasks))) {
|
||||
projectInfo.messageCollector.report(
|
||||
"Module '${module.name}': Expected tests list $expectedExternalSystemTestTasks doesn't match the actual one: ${module.externalSystemTestTasks()}"
|
||||
)
|
||||
}
|
||||
|
||||
if (projectInfo.exhaustiveSourceSourceRootList) {
|
||||
val actualSourceRoots = sourceFolderByPath.keys.sorted()
|
||||
val expectedSourceRoots = expectedSourceRoots.sorted()
|
||||
@@ -319,6 +333,7 @@ fun checkProjectStructure(
|
||||
exhaustiveModuleList: Boolean,
|
||||
exhaustiveSourceSourceRootList: Boolean,
|
||||
exhaustiveDependencyList: Boolean,
|
||||
exhaustiveTestsList: Boolean,
|
||||
body: ProjectInfo.() -> Unit = {}
|
||||
) {
|
||||
ProjectInfo(
|
||||
@@ -326,6 +341,7 @@ fun checkProjectStructure(
|
||||
projectPath,
|
||||
exhaustiveModuleList,
|
||||
exhaustiveSourceSourceRootList,
|
||||
exhaustiveDependencyList
|
||||
exhaustiveDependencyList,
|
||||
exhaustiveTestsList
|
||||
).run(body)
|
||||
}
|
||||
@@ -153,6 +153,18 @@ enum class KotlinMultiplatformVersion(val version: Int) {
|
||||
get() = version >= 3
|
||||
}
|
||||
|
||||
data class ExternalSystemTestTask(val testName: String, val externalSystemProjectId: String, val targetName: String?) {
|
||||
|
||||
fun toStringRepresentation() = "$testName|$externalSystemProjectId|$targetName"
|
||||
|
||||
companion object {
|
||||
fun fromStringRepresentation(line: String) =
|
||||
line.split("|").let { if (it.size == 3) ExternalSystemTestTask(it[0], it[1], it[2]) else null }
|
||||
}
|
||||
|
||||
override fun toString() = "$testName@$externalSystemProjectId [$targetName]"
|
||||
}
|
||||
|
||||
class KotlinFacetSettings {
|
||||
companion object {
|
||||
// Increment this when making serialization-incompatible changes to configuration data
|
||||
@@ -219,6 +231,7 @@ class KotlinFacetSettings {
|
||||
return field
|
||||
}
|
||||
|
||||
var externalSystemTestTasks: List<ExternalSystemTestTask> = emptyList()
|
||||
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
@Deprecated(
|
||||
|
||||
@@ -136,8 +136,11 @@ private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
|
||||
element.getAttributeValue("useProjectSettings")?.let { useProjectSettings = it.toBoolean() }
|
||||
val targetPlatform = element.getFacetPlatformByConfigurationElement()
|
||||
this.targetPlatform = targetPlatform
|
||||
readModulesList(element, "implements", "implement")?.let { implementedModuleNames = it }
|
||||
readModulesList(element, "dependsOnModuleNames", "dependsOn")?.let { dependsOnModuleNames = it }
|
||||
readElementsList(element, "implements", "implement")?.let { implementedModuleNames = it }
|
||||
readElementsList(element, "dependsOnModuleNames", "dependsOn")?.let { dependsOnModuleNames = it }
|
||||
readElementsList(element, "externalSystemTestTasks", "externalSystemTestTask")?.let {
|
||||
externalSystemTestTasks = it.mapNotNull { ExternalSystemTestTask.fromStringRepresentation(it) }
|
||||
}
|
||||
|
||||
element.getChild("sourceSets")?.let {
|
||||
val items = it.getChildren("sourceSet")
|
||||
@@ -178,7 +181,7 @@ private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
|
||||
}
|
||||
}
|
||||
|
||||
private fun readModulesList(element: Element, rootElementName: String, elementName: String): List<String>? {
|
||||
private fun readElementsList(element: Element, rootElementName: String, elementName: String): List<String>? {
|
||||
element.getChild(rootElementName)?.let {
|
||||
val items = it.getChildren(elementName)
|
||||
return if (items.isNotEmpty()) {
|
||||
@@ -310,8 +313,8 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
|
||||
if (!useProjectSettings) {
|
||||
element.setAttribute("useProjectSettings", useProjectSettings.toString())
|
||||
}
|
||||
saveModulesList(element, implementedModuleNames, "implements", "implement")
|
||||
saveModulesList(element, dependsOnModuleNames, "dependsOnModuleNames", "dependsOn")
|
||||
saveElementsList(element, implementedModuleNames, "implements", "implement")
|
||||
saveElementsList(element, dependsOnModuleNames, "dependsOnModuleNames", "dependsOn")
|
||||
|
||||
if (sourceSetNames.isNotEmpty()) {
|
||||
element.addContent(
|
||||
@@ -330,6 +333,14 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
|
||||
if (isHmppEnabled) {
|
||||
element.setAttribute("isHmppProject", isHmppEnabled.toString())
|
||||
}
|
||||
if (externalSystemTestTasks.isNotEmpty()) {
|
||||
saveElementsList(
|
||||
element,
|
||||
externalSystemTestTasks.map { it.toStringRepresentation() },
|
||||
"externalSystemTestTasks",
|
||||
"externalSystemTestTask"
|
||||
)
|
||||
}
|
||||
if (pureKotlinSourceFolders.isNotEmpty()) {
|
||||
element.setAttribute("pureKotlinSourceFolders", pureKotlinSourceFolders.joinToString(";"))
|
||||
}
|
||||
@@ -354,15 +365,15 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveModulesList(element: Element, moduleList: List<String>, rootElementName: String, elementName: String) {
|
||||
if (moduleList.isNotEmpty()) {
|
||||
private fun saveElementsList(element: Element, elementsList: List<String>, rootElementName: String, elementName: String) {
|
||||
if (elementsList.isNotEmpty()) {
|
||||
element.addContent(
|
||||
Element(rootElementName).apply {
|
||||
val singleModule = moduleList.singleOrNull()
|
||||
val singleModule = elementsList.singleOrNull()
|
||||
if (singleModule != null) {
|
||||
addContent(singleModule)
|
||||
} else {
|
||||
moduleList.map { addContent(Element(elementName).apply { addContent(it) }) }
|
||||
elementsList.map { addContent(Element(elementName).apply { addContent(it) }) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -151,6 +151,7 @@ interface KotlinTarget : Serializable {
|
||||
|
||||
interface KotlinTestTask : Serializable {
|
||||
val taskName: String
|
||||
val compilationName: String
|
||||
}
|
||||
|
||||
interface ExtraFeatures : Serializable {
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel.Companion.NO_KOTLIN_NATIVE_HOME
|
||||
import org.jetbrains.plugins.gradle.model.*
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
@@ -26,6 +27,9 @@ import java.io.File
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
// This flag enables import of source sets which do not belong to any compilation
|
||||
private val DEFAULT_IMPORT_ORPHAN_SOURCE_SETS = true
|
||||
|
||||
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||
return ErrorMessageBuilder
|
||||
.create(project, e, "Gradle import errors")
|
||||
@@ -53,7 +57,7 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
reportUnresolvedDependencies(targets)
|
||||
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
|
||||
return KotlinMPPGradleModelImpl(
|
||||
sourceSetMap,
|
||||
filterOrphanSourceSets(sourceSetMap, targets, project),
|
||||
targets,
|
||||
ExtraFeaturesImpl(coroutinesState, isHMPPEnabled(project)),
|
||||
kotlinNativeHome,
|
||||
@@ -61,8 +65,21 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
)
|
||||
}
|
||||
|
||||
private fun filterOrphanSourceSets(
|
||||
sourceSets: Map<String, KotlinSourceSetImpl>,
|
||||
targets: Collection<KotlinTarget>,
|
||||
project: Project
|
||||
): Map<String, KotlinSourceSetImpl> {
|
||||
if (project.properties["import_orphan_source_sets"]?.toString()?.toBoolean() ?: DEFAULT_IMPORT_ORPHAN_SOURCE_SETS) return sourceSets
|
||||
val compiledSourceSets: Collection<String> = targets.flatMap { it.compilations }.flatMap { it.sourceSets }.flatMap { it.dependsOnSourceSets.union(listOf(it.name)) }.distinct()
|
||||
sourceSets.filter { !compiledSourceSets.contains(it.key) }.forEach {
|
||||
logger.warn("[sync warning] Source set \"${it.key}\" is not compiled with any compilation. This source set is not imported in the IDE.")
|
||||
}
|
||||
return sourceSets.filter { compiledSourceSets.contains(it.key) }
|
||||
}
|
||||
|
||||
private fun isHMPPEnabled(project: Project): Boolean {
|
||||
//TODO(auskov): replace with Project.isKotlinGranularMetadataEnabled after merging with gradle pranch
|
||||
//TODO(auskov): replace with Project.isKotlinGranularMetadataEnabled after merging with gradle branch
|
||||
return (project.findProperty("kotlin.mpp.enableGranularSourceSetsMetadata") as? String)?.toBoolean() ?: false
|
||||
}
|
||||
|
||||
@@ -314,7 +331,24 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
}
|
||||
|
||||
private fun buildTestTasks(project: Project, gradleTarget: Named): Collection<KotlinTestTask> {
|
||||
// TODO: use the test runs API to extract the test tasks once it is available
|
||||
val getTestRunsMethod = gradleTarget.javaClass.getMethodOrNull("getTestRuns")
|
||||
if (getTestRunsMethod != null) {
|
||||
val testRuns = getTestRunsMethod?.invoke(gradleTarget) as? Iterable<Any>
|
||||
if (testRuns != null) {
|
||||
val testReports = testRuns.mapNotNull { (it.javaClass.getMethodOrNull("getExecutionTask")?.invoke(it) as? TaskProvider<Task>)?.get() }
|
||||
val testTasks = testReports.flatMap {
|
||||
((it.javaClass.getMethodOrNull("getTestTasks")?.invoke(it) as? Collection<Provider<Task>>)?.map { it.get() })
|
||||
?: listOf(it)
|
||||
}
|
||||
return testTasks.mapNotNull {
|
||||
val name = it.name
|
||||
val compilation = it.javaClass.getMethodOrNull("getCompilation")?.invoke(it)
|
||||
val compilationName = compilation?.javaClass?.getMethodOrNull("getCompilationName")?.invoke(compilation)?.toString() ?: KotlinCompilation.TEST_COMPILATION_NAME
|
||||
KotlinTestTaskImpl(name, compilationName)
|
||||
}.toList()
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// Otherwise, find the Kotlin test task with names matching the target name. This is a workaround that makes assumptions about
|
||||
// the tasks naming logic and is therefore an unstable and temporary solution until test runs API is implemented:
|
||||
@@ -335,14 +369,23 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
// The 'targetName' of a test task matches the target disambiguation classifier, potentially with suffix, e.g. jsBrowser
|
||||
val getTargetName = kotlinTestTaskClass.getDeclaredMethodOrNull("getTargetName") ?: return emptyList()
|
||||
|
||||
return project.tasks.filter { kotlinTestTaskClass.isInstance(it) }.mapNotNull { task ->
|
||||
val testTaskDisambiguationClassifier = getTargetName(task) as String?
|
||||
val jvmTestTaskClass = try {
|
||||
gradleTarget.javaClass.classLoader.loadClass("org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest") as Class<out Task>
|
||||
} catch (_: ClassNotFoundException) {
|
||||
return emptyList()
|
||||
}
|
||||
val getJvmTargetName = jvmTestTaskClass.getDeclaredMethodOrNull("getTargetName") ?: return emptyList()
|
||||
|
||||
|
||||
return project.tasks.filter { kotlinTestTaskClass.isInstance(it) || jvmTestTaskClass.isInstance(it)}.mapNotNull { task ->
|
||||
val testTaskDisambiguationClassifier =
|
||||
(if (kotlinTestTaskClass.isInstance(task)) getTargetName(task) else getJvmTargetName(task)) as String?
|
||||
task.name.takeIf {
|
||||
targetDisambiguationClassifier.isNullOrEmpty() ||
|
||||
testTaskDisambiguationClassifier != null &&
|
||||
testTaskDisambiguationClassifier.startsWith(targetDisambiguationClassifier.orEmpty())
|
||||
}
|
||||
}.map(::KotlinTestTaskImpl)
|
||||
}.map { KotlinTestTaskImpl(it, KotlinCompilation.TEST_COMPILATION_NAME) }
|
||||
}
|
||||
|
||||
private fun buildTargetJar(gradleTarget: Named, project: Project): KotlinTargetJar? {
|
||||
@@ -544,21 +587,14 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
for (compilation in target.compilations) {
|
||||
for (sourceSet in compilation.sourceSets) {
|
||||
sourceSetToCompilations.getOrPut(sourceSet) { LinkedHashSet() } += compilation
|
||||
sourceSet.dependsOnSourceSets.mapNotNull { sourceSets[it] }.forEach {
|
||||
sourceSetToCompilations.getOrPut(it) { LinkedHashSet() } += compilation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (sourceSet in sourceSets.values) {
|
||||
val name = sourceSet.name
|
||||
if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) {
|
||||
sourceSet.isTestModule = false
|
||||
continue
|
||||
}
|
||||
if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) {
|
||||
sourceSet.isTestModule = true
|
||||
continue
|
||||
}
|
||||
|
||||
val compilations = sourceSetToCompilations[sourceSet]
|
||||
if (compilations != null) {
|
||||
val platforms = compilations.map { it.platform }
|
||||
@@ -572,8 +608,16 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
|
||||
sourceSet.isTestModule = compilations.all { it.isTestModule }
|
||||
} else {
|
||||
// TODO: change me after design about it
|
||||
sourceSet.isTestModule = "Test" in sourceSet.name
|
||||
//TODO(auskov): remove this branch as far as import of orphan source sets is dropped
|
||||
val name = sourceSet.name
|
||||
if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) {
|
||||
sourceSet.isTestModule = false
|
||||
continue
|
||||
}
|
||||
if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) {
|
||||
sourceSet.isTestModule = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ data class KotlinTargetImpl(
|
||||
}
|
||||
}.toList(),
|
||||
target.testTasks.map { initialTestTask ->
|
||||
(cloningCache[initialTestTask] as? KotlinTestTask) ?: KotlinTestTaskImpl(initialTestTask.taskName).also {
|
||||
(cloningCache[initialTestTask] as? KotlinTestTask) ?: KotlinTestTaskImpl(initialTestTask.taskName, initialTestTask.compilationName).also {
|
||||
cloningCache[initialTestTask] = it
|
||||
}
|
||||
},
|
||||
@@ -160,7 +160,8 @@ data class KotlinTargetImpl(
|
||||
}
|
||||
|
||||
data class KotlinTestTaskImpl(
|
||||
override val taskName: String
|
||||
override val taskName: String,
|
||||
override val compilationName: String
|
||||
) : KotlinTestTask
|
||||
|
||||
data class ExtraFeaturesImpl(
|
||||
|
||||
@@ -188,6 +188,8 @@ fun KotlinFacet.configureFacet(
|
||||
module.externalCompilerVersion = compilerVersion
|
||||
}
|
||||
|
||||
fun Module.externalSystemTestTasks() = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this).externalSystemTestTasks
|
||||
|
||||
@Suppress("DEPRECATION_ERROR", "DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated(
|
||||
message = "IdePlatform is deprecated and will be removed soon, please, migrate to org.jetbrains.kotlin.platform.TargetPlatform",
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.multiplatform' version '1.3.50'
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
mavenCentral()
|
||||
|
||||
}
|
||||
|
||||
|
||||
group 'com.example'
|
||||
version '0.0.1'
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
}
|
||||
|
||||
js {
|
||||
browser {
|
||||
}
|
||||
nodejs {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib-common')
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
}
|
||||
}
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib-jdk8')
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test')
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib-js')
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
kotlin.code.style=official
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
|
||||
mavenLocal()
|
||||
|
||||
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||
|
||||
mavenCentral()
|
||||
|
||||
maven { url 'https://plugins.gradle.org/m2/' }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
rootProject.name = 'project'
|
||||
|
||||
|
||||
enableFeaturePreview('GRADLE_METADATA')
|
||||
Reference in New Issue
Block a user