User: kyle wood Date: 27 Mar 26 07:30 Revision: 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb Summary: Execute tests in parallel and bump deps TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=10447&personal=false Index: build.gradle.kts =================================================================== --- build.gradle.kts (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ build.gradle.kts (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -19,11 +19,14 @@ */ import io.sentry.android.gradle.extensions.SentryPluginExtension +import java.util.concurrent.atomic.AtomicInteger +import kotlin.concurrent.atomics.AtomicInt import org.gradle.kotlin.dsl.configure import org.jetbrains.changelog.Changelog import org.jetbrains.gradle.ext.settings import org.jetbrains.gradle.ext.taskTriggers import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.intellij.platform.gradle.tasks.CleanSandboxTask import org.jetbrains.intellij.platform.gradle.tasks.PrepareSandboxTask plugins { @@ -102,8 +105,12 @@ exclude(group = "org.slf4j") } + implementation(libs.jspecify) + intellijPlatform { - intellijIdeaCommunity(libs.versions.intellij.ide, useInstaller = false) + intellijIdeaCommunity(libs.versions.intellij.ide) { + useInstaller = false + } // Bundled plugin dependencies bundledPlugin("com.intellij.java") @@ -121,7 +128,6 @@ bundledPlugin("org.toml.lang") bundledPlugin("org.jetbrains.plugins.yaml") - testFramework(TestFrameworkType.JUnit5) testFramework(TestFrameworkType.Platform) testFramework(TestFrameworkType.Plugin.Java) @@ -198,8 +204,39 @@ } } +// Run unit tests in paralllel. Unfortunately, to accomplish this, we also need separate sandboxes for each test fork. +// All of this is still worth doing since the IntelliJ test fixtures themselves are rather slow. +val testForks = 6 +val sandboxTestTasks = mutableListOf>() +repeat(testForks) { + sandboxTestTasks += tasks.register("prepareTestSandboxFork$it") { + sandboxSuffix.set("-fork-$it") + doFirst { + sandboxDirectory.get().asFile.listFiles() + ?.filter { f -> f.name.endsWith("-fork-$it") } + ?.forEach { f -> f.deleteRecursively() } + } + } +} +tasks.prepareTestSandbox { + doFirst { + sandboxDirectory.get().asFile.listFiles() + ?.filter { f -> f.name.endsWith("-test") } + ?.forEach { f -> f.deleteRecursively() } + } +} + +val cleanTestSandboxForks by tasks.registering(Delete::class) { + doFirst { + tasks.prepareTestSandbox.flatMap { it.sandboxDirectory } + .get().asFile.listFiles() + ?.filter { it.name.matches(Regex(".*-(?:fork-\\d+|test)")) } + ?.let { delete(it) } + } +} tasks.test { - dependsOn(tasks.jar, testLibs) + dependsOn(tasks.jar, testLibs, sandboxTestTasks) + finalizedBy(cleanTestSandboxForks) testLibs.resolvedConfiguration.resolvedArtifacts.forEach { systemProperty("testLibs.${it.name}", it.file.absolutePath) @@ -211,6 +248,12 @@ "-Dsun.io.useCanonCaches=false", "-Dsun.io.useCanonPrefixCache=false", ) + + val sandboxDir = tasks.prepareTestSandbox.flatMap { it.sandboxDirectory }.get().asFile + + maxParallelForks = testForks + systemProperty("sandboxDir", sandboxDir.absolutePath) + systemProperty("forks", testForks.toString()) } idea { Index: buildSrc/src/main/kotlin/mcdev-core.gradle.kts =================================================================== --- buildSrc/src/main/kotlin/mcdev-core.gradle.kts (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ buildSrc/src/main/kotlin/mcdev-core.gradle.kts (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -194,12 +194,6 @@ jvmArgs("--add-exports=java.base/jdk.internal.vm=ALL-UNNAMED") } -tasks.register("cleanSandbox", Delete::class) { - group = "intellij" - description = "Deletes the sandbox directory." - delete(layout.projectDirectory.dir(".sandbox")) -} - tasks.test { useJUnitPlatform() } Index: buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts =================================================================== --- buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ buildSrc/src/main/kotlin/mcdev-publishing.gradle.kts (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -26,6 +26,7 @@ import kotlin.io.path.absolute import org.jetbrains.intellij.platform.gradle.utils.IdeServicesPluginRepositoryService import org.jetbrains.intellij.pluginRepository.PluginRepositoryFactory +import org.jetbrains.intellij.pluginRepository.model.ProductFamily plugins { id("org.jetbrains.intellij.platform") @@ -63,8 +64,9 @@ false -> PluginRepositoryFactory.create(host.get(), token.get()) } @Suppress("DEPRECATION") - val uploadBean = repositoryClient.uploader.upload( + val uploadBean = repositoryClient.uploader.uploadUpdateByXmlIdAndFamily( id = pluginId, + family = ProductFamily.INTELLIJ, file = path.toFile(), channel = channel.takeIf { it != "default" }, notes = null, Index: gradle/libs.versions.toml =================================================================== --- gradle/libs.versions.toml (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ gradle/libs.versions.toml (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -1,17 +1,15 @@ [versions] -kotlin = "2.2.20" +kotlin = "2.3.20" coroutines = "1.10.2" -junit = "5.10.2" -junit-platform = "1.10.2" -asm = "9.6" +junit = "6.0.3" +asm = "9.9.1" fuel = "2.3.1" licenser = "0.7.5" -changelog = "2.2.0" -intellij-plugin = "2.6.0" -intellij-plugin-repository-rest-client = "2.0.46" +changelog = "2.5.0" +intellij-plugin = "2.13.1" +intellij-plugin-repository-rest-client = "2.0.50" intellij-ide = "2025.2" -idea-ext = "1.1.10" -psiPlugin = "251.175" +idea-ext = "1.4.1" [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } @@ -19,7 +17,7 @@ idea-ext = { id = "org.jetbrains.gradle.plugin.idea-ext", version.ref = "idea-ext" } licenser = { id = "net.neoforged.licenser", version.ref = "licenser" } changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } -sentry = "io.sentry.jvm.gradle:5.12.2" +sentry = "io.sentry.jvm.gradle:6.3.0" [libraries] intellij-plugin-repository-rest-client = { module = "org.jetbrains.intellij:plugin-repository-rest-client", version.ref = "intellij-plugin-repository-rest-client" } @@ -34,7 +32,7 @@ coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" } -mappingIo = "net.fabricmc:mapping-io:0.2.1" +mappingIo = "net.fabricmc:mapping-io:0.8.0" mixinExtras-expressions = "io.github.llamalad7:mixinextras-expressions:0.0.6" jgraphx = "com.github.vlsi.mxgraph:jgraphx:4.2.2" @@ -45,35 +43,36 @@ # Gradle Tooling gradleToolingExtension = { module = "com.jetbrains.intellij.gradle:gradle-tooling-extension", version = "252.23892.409" } -annotations = "org.jetbrains:annotations:24.0.0" -groovy = "org.codehaus.groovy:groovy:3.0.19" +annotations = "org.jetbrains:annotations:26.1.0" +groovy = "org.codehaus.groovy:groovy:3.0.25" asm = { module = "org.ow2.asm:asm", version.ref = "asm" } asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } asm-analysis = { module = "org.ow2.asm:asm-analysis", version.ref = "asm" } asm-util = { module = "org.ow2.asm:asm-util", version.ref = "asm" } -gson = "com.google.code.gson:gson:2.10.1" +gson = "com.google.code.gson:gson:2.13.2" +jspecify = "org.jspecify:jspecify:1.0.0" fuel = { module = "com.github.kittinunf.fuel:fuel", version.ref = "fuel" } fuel-coroutines = { module = "com.github.kittinunf.fuel:fuel-coroutines", version.ref = "fuel" } -sentry = "io.sentry:sentry:8.22.0" +sentry = "io.sentry:sentry:8.37.1" # Testing test-mixin = "org.spongepowered:mixin:0.8.5" -test-spigotapi = "org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT" -test-bungeecord = "net.md-5:bungeecord-api:1.21-R0.3" +test-spigotapi = "org.spigotmc:spigot-api:1.21.11-R0.2-SNAPSHOT" +test-bungeecord = "net.md-5:bungeecord-api:1.21-R0.4" test-spongeapi = "org.spongepowered:spongeapi:7.4.0" -test-fabricloader = "net.fabricmc:fabric-loader:0.15.11" +test-fabricloader = "net.fabricmc:fabric-loader:0.18.5" test-nbt = "com.demonwav.mcdev:all-types-nbt:1.0" junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } junit-vintage = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit" } -junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit-platform" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit" } -mixinExtras-common = "io.github.llamalad7:mixinextras-common:0.5.0-beta.1" +mixinExtras-common = "io.github.llamalad7:mixinextras-common:0.5.3" [bundles] coroutines = ["coroutines-swing"] Index: src/main/kotlin/platform/fabric/FabricModule.kt =================================================================== --- src/main/kotlin/platform/fabric/FabricModule.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/fabric/FabricModule.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -136,7 +136,7 @@ override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?) = false - override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String?) = false + override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, endOpIdx: Int, srcName: String?) = false override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String) { if (namespace == namedIndex && name == "net/minecraft/client/MinecraftClient") { Index: src/main/kotlin/platform/mcp/fabricloom/TinyUnscrambler.kt =================================================================== --- src/main/kotlin/platform/mcp/fabricloom/TinyUnscrambler.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/mcp/fabricloom/TinyUnscrambler.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -137,21 +137,25 @@ return true } - override fun visitField(srcName: String, srcDesc: String): Boolean { + override fun visitField(srcName: String?, srcDesc: String?): Boolean { + if (srcName != null) { - src = srcName + src = srcName + } return true } - override fun visitMethod(srcName: String, srcDesc: String): Boolean { + override fun visitMethod(srcName: String?, srcDesc: String?): Boolean { + if (srcName != null) { - src = srcName + src = srcName + } return true } - override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String): Boolean { + override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?): Boolean { return false } - override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String): Boolean { + override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, endOpIdx: Int, srcName: String?): Boolean { return false } Index: src/main/kotlin/platform/mcp/srg/TinySrgParser.kt =================================================================== --- src/main/kotlin/platform/mcp/srg/TinySrgParser.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/mcp/srg/TinySrgParser.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -136,17 +136,17 @@ return true } - override fun visitMethod(srcName: String, srcDesc: String): Boolean { + override fun visitMethod(srcName: String?, srcDesc: String?): Boolean { inter = srcName desc = srcDesc return true } - override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String): Boolean { + override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?): Boolean { return false } - override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String): Boolean { + override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, endOpIdx: Int, srcName: String?): Boolean { return false } Index: src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt =================================================================== --- src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/mcp/vanillagradle/VanillaGradleDecompileSourceProvider.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -68,7 +68,7 @@ val taskCallback = object : TaskCallback { override fun onSuccess() { val importSpec = ImportSpecBuilder(project, GradleConstants.SYSTEM_ID) - .callback( + .withCallback( object : ExternalProjectRefreshCallback { override fun onSuccess(externalProject: DataNode?) = callback.setDone() Index: src/main/kotlin/platform/mixin/inspection/MixinClassTypeInspection.kt =================================================================== --- src/main/kotlin/platform/mixin/inspection/MixinClassTypeInspection.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/mixin/inspection/MixinClassTypeInspection.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -27,6 +27,7 @@ import com.intellij.codeInspection.LocalQuickFix import com.intellij.codeInspection.LocalQuickFixOnPsiElement import com.intellij.codeInspection.ProblemsHolder +import com.intellij.java.syntax.parser.JavaKeywords import com.intellij.openapi.project.Project import com.intellij.psi.JavaElementVisitor import com.intellij.psi.JavaPsiFacade @@ -61,9 +62,9 @@ val fixes = mutableListOf() if (classKeywordElement != null) { if (needsToBeClass && !needsToBeInterface) { - fixes += ChangeClassTypeFix(classKeywordElement, PsiKeyword.CLASS) + fixes += ChangeClassTypeFix(classKeywordElement, JavaKeywords.CLASS) } else if (needsToBeInterface && !needsToBeClass) { - fixes += ChangeClassTypeFix(classKeywordElement, PsiKeyword.INTERFACE) + fixes += ChangeClassTypeFix(classKeywordElement, JavaKeywords.INTERFACE) } } Index: src/main/kotlin/platform/mixin/util/AsmUtil.kt =================================================================== --- src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/platform/mixin/util/AsmUtil.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -42,6 +42,7 @@ import com.intellij.byteCodeViewer.ByteCodeViewerManager import com.intellij.codeEditor.JavaEditorFileSwapper import com.intellij.ide.highlighter.JavaFileType +import com.intellij.java.syntax.parser.JavaKeywords import com.intellij.openapi.module.Module import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.project.Project @@ -1050,7 +1051,7 @@ if (body != null) { val children = body.children val superCtorIndex = children.indexOfFirst { - it is PsiMethodCallExpression && it.methodExpression.text == PsiKeyword.SUPER + it is PsiMethodCallExpression && it.methodExpression.text == JavaKeywords.SUPER } result += children.take(superCtorIndex + 1) sourceMethod.containingClass?.children?.forEach { element -> Index: src/main/kotlin/toml/platform/forge/inspections/ModsTomlValidationInspection.kt =================================================================== --- src/main/kotlin/toml/platform/forge/inspections/ModsTomlValidationInspection.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/toml/platform/forge/inspections/ModsTomlValidationInspection.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -53,7 +53,7 @@ override fun getStaticDescription(): String = "Checks mods.toml files for errors" - override fun processFile(file: PsiFile, manager: InspectionManager): MutableList { + override fun processFile(file: PsiFile, manager: InspectionManager): List { if (file.virtualFile.name in ForgeTomlConstants.FILE_NAMES) { return super.processFile(file, manager) } Index: src/main/kotlin/update/PluginUpdater.kt =================================================================== --- src/main/kotlin/update/PluginUpdater.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/main/kotlin/update/PluginUpdater.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -59,7 +59,7 @@ val finalUpdate = updateStatus ApplicationManager.getApplication().invokeLater({ callback(finalUpdate) }, ModalityState.any()) - } catch (e: Exception) { + } catch (_: Exception) { PluginUpdateStatus.CheckFailed("Minecraft Development plugin update check failed") } } @@ -107,8 +107,9 @@ private fun checkUpdatesInCustomRepo(host: String): PluginUpdateStatus { val plugins = try { - RepositoryHelper.loadPlugins(host, null, null) - } catch (e: IOException) { + RepositoryHelper.loadPluginModels(host, null, null) + .map { it.getDescriptor() } + } catch (_: IOException) { return PluginUpdateStatus.CheckFailed("Checking custom plugin repository $host failed") } Index: src/test/kotlin/framework/EdtInterceptor.kt =================================================================== --- src/test/kotlin/framework/EdtInterceptor.kt (revision 57591ddb2d07d52dea774b269a12fdecb979171f) +++ src/test/kotlin/framework/EdtInterceptor.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -3,7 +3,7 @@ * * https://mcdev.io/ * - * Copyright (C) 2025 minecraft-dev + * Copyright (C) 2026 minecraft-dev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -30,31 +30,31 @@ class EdtInterceptor : InvocationInterceptor { override fun interceptBeforeEachMethod( - invocation: InvocationInterceptor.Invocation, + invocation: InvocationInterceptor.Invocation, invocationContext: ReflectiveInvocationContext, - extensionContext: ExtensionContext, + extensionContext: ExtensionContext ) { exec(invocation, invocationContext) } override fun interceptAfterEachMethod( - invocation: InvocationInterceptor.Invocation, + invocation: InvocationInterceptor.Invocation, invocationContext: ReflectiveInvocationContext, - extensionContext: ExtensionContext, + extensionContext: ExtensionContext ) { exec(invocation, invocationContext) } override fun interceptTestMethod( - invocation: InvocationInterceptor.Invocation, + invocation: InvocationInterceptor.Invocation, invocationContext: ReflectiveInvocationContext, - extensionContext: ExtensionContext, + extensionContext: ExtensionContext ) { exec(invocation, invocationContext) } private fun exec( - invocation: InvocationInterceptor.Invocation, + invocation: InvocationInterceptor.Invocation, invocationContext: ReflectiveInvocationContext, ) { if (invocationContext.executable.getAnnotation(NoEdt::class.java) != null) { Index: src/test/kotlin/framework/EnvSetup.kt =================================================================== --- src/test/kotlin/framework/EnvSetup.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) +++ src/test/kotlin/framework/EnvSetup.kt (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -0,0 +1,48 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2026 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.framework + +import com.intellij.openapi.application.PathManager +import kotlin.io.path.Path +import kotlin.io.path.absolutePathString +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.ExtensionContext + +class EnvSetup : BeforeAllCallback { + override fun beforeAll(context: ExtensionContext) { + // Assign each worker to a different fork directory. The worker ids are not indexed from 0, they are random + // numbers. They are sequential, though, so we can just use modulo to turn whatever arbitrary ids we get into + // valid indexes. + val worker = + (System.getProperty("org.gradle.test.worker") ?: "1").toInt() % System.getProperty("forks").toInt() + val container = Path(System.getProperty("sandboxDir")) + + val configDir = container.resolve("config-fork-$worker") + val systemDir = container.resolve("system-fork-$worker") + val pluginsDir = container.resolve("plugins-fork-$worker") + val logsDir = container.resolve("log-fork-$worker") + + System.setProperty(PathManager.PROPERTY_CONFIG_PATH, configDir.absolutePathString()) + System.setProperty(PathManager.PROPERTY_SYSTEM_PATH, systemDir.absolutePathString()) + System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, pluginsDir.absolutePathString()) + System.setProperty(PathManager.PROPERTY_LOG_PATH, logsDir.absolutePathString()) + } +} Index: src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension =================================================================== --- src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) +++ src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension (revision 9a4e5d33475a0466e4b26648df8eb34eb65d2fdb) @@ -0,0 +1,1 @@ +com.demonwav.mcdev.framework.EnvSetup