import com.jetbrains.plugin.structure.base.utils.isFile import org.jetbrains.changelog.markdownToHTML import org.jetbrains.intellij.platform.gradle.Constants import kotlin.io.path.absolute import kotlin.io.path.isDirectory plugins { id("java") alias(libs.plugins.kotlinJvm) alias(libs.plugins.changelog) id("org.jetbrains.intellij.platform") version "2.10.4" // See https://github.com/JetBrains/intellij-platform-gradle-plugin/releases id("me.filippov.gradle.jvm.wrapper") version "0.14.0" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } val DotnetSolution: String by project val BuildConfiguration: String by project val ProductVersion: String by project val DotnetPluginId: String by project val RiderPluginId: String by project val PublishToken: String by project allprojects { repositories { maven { setUrl("https://cache-redirector.jetbrains.com/maven-central") } } } repositories { intellijPlatform { defaultRepositories() jetbrainsRuntime() } } tasks.wrapper { gradleVersion = "8.8" distributionType = Wrapper.DistributionType.ALL distributionUrl = "https://cache-redirector.jetbrains.com/services.gradle.org/distributions/gradle-${gradleVersion}-all.zip" } version = extra["PluginVersion"] as String tasks.processResources { from("dependencies.json") { into("META-INF") } } tasks.processTestResources { duplicatesStrategy = DuplicatesStrategy.INCLUDE } sourceSets { main { java.srcDir("src/rider/main/java") kotlin.srcDir("src/rider/main/kotlin") resources.srcDir("src/rider/main/resources") } test { kotlin.srcDir("src/test/kotlin") resources.srcDir("src/test/resources") } } tasks.compileKotlin { kotlinOptions { jvmTarget = "21" } } tasks.compileTestKotlin { kotlinOptions { jvmTarget = "21" } } tasks.test { useTestNG() } val dotNetSrcDir = File(projectDir, "src/dotnet") val riderSdkPath by lazy { val path = intellijPlatform.platformPath.resolve("lib/DotNetSdkForRdPlugins").absolute() if (!path.isDirectory()) error("$path does not exist or not a directory") println("Rider SDK path: $path") return@lazy path } val generateDotNetSdkProperties by tasks.registering { val dotNetSdkGeneratedPropsFile = file("build/DotNetSdkPath.Generated.props") doLast { dotNetSdkGeneratedPropsFile.writeTextIfChanged(""" $riderSdkPath """) } } val generateNuGetConfig by tasks.registering { val nuGetConfigFile = dotNetSrcDir.resolve("nuget.config") doLast { nuGetConfigFile.writeTextIfChanged(""" """) } } val compileDotNet by tasks.registering { dependsOn(generateDotNetSdkProperties, generateNuGetConfig) doLast { exec { executable(layout.projectDirectory.file("dotnet.cmd")) args("build", "${DotnetSolution}", "--configuration", BuildConfiguration) workingDir(rootDir) } } } val testDotNet by tasks.registering { dependsOn(generateDotNetSdkProperties, generateNuGetConfig) doLast { exec { executable(layout.projectDirectory.file("dotnet.cmd")) args("test", "${DotnetSolution}", "--logger", "GitHubActions", "--logger", "trx") workingDir(rootDir) } } } tasks.buildPlugin { dependsOn(compileDotNet) doLast { copy { from("${buildDir}/distributions/${rootProject.name}-${version}.zip") into("${rootDir}/output") } // TODO: See also org.jetbrains.changelog: https://github.com/JetBrains/gradle-changelog-plugin val changelogText = file("${rootDir}/CHANGELOG.md").readText() val changelogMatches = Regex("(?s)(-.+?)(?=##|$)").findAll(changelogText) val changeNotes = changelogMatches.map { it.groups[1]!!.value.replace("(?s)- ".toRegex(), "\u2022 ").replace("`", "").replace(",", "%2C").replace(";", "%3B") }.take(1).joinToString() exec { executable(layout.projectDirectory.file("dotnet.cmd")) args("pack", "${DotnetSolution}", "--configuration", BuildConfiguration, "--output", "${rootDir}/output", "/p:PackageReleaseNotes=${changeNotes}", "/p:PackageVersion=${version}") workingDir(rootDir) } } } dependencies { intellijPlatform { rider(ProductVersion, useInstaller = false) jetbrainsRuntime() testFramework(org.jetbrains.intellij.platform.gradle.TestFrameworkType.Bundled) // TODO: add plugins // bundledPlugin("uml") // bundledPlugin("com.jetbrains.ChooseRuntime:1.0.9") } testImplementation("org.testng:testng:7.10.2") } intellijPlatform { pluginVerification { ides { recommended() } } pluginConfiguration { version = providers.gradleProperty("PluginVersion") ideaVersion { sinceBuild = providers.gradleProperty("pluginSinceBuild") } } } changelog { groups.empty() repositoryUrl.set(providers.gradleProperty("PluginRepositoryUrl")) } tasks.runIde { // Match Rider's default heap size of 1.5Gb (default for runIde is 512Mb) maxHeapSize = "1500m" } tasks.patchPluginXml { // TODO: See also org.jetbrains.changelog: https://github.com/JetBrains/gradle-changelog-plugin val changelogText = file("${rootDir}/CHANGELOG.md").readText() val changelogMatches = Regex("(?s)(-.+?)(?=##|\$)").findAll(changelogText) changeNotes.set(changelogMatches.map { it.groups[1]!!.value.replace("(?s)\r?\n".toRegex(), "
\n") }.take(1).joinToString()) // Extract multiple sections from README.md using markers val readmeText = file("${rootDir}/README.md").readText() val sectionRegex = Regex("(?s)\\s*(.+?)\\s*") val sections = sectionRegex.findAll(readmeText).map { match -> val sectionName = match.groups[1]?.value ?: "main" val content = match.groups[2]?.value ?: "" sectionName to markdownToHTML(content) }.toList() if (sections.isNotEmpty()) { val readmeDescription = sections.joinToString("\n") { it.second } val pluginXmlFile = file("${rootDir}/src/rider/main/resources/META-INF/plugin.xml") val pluginXmlText = pluginXmlFile.readText() val descriptionRegex = Regex("(?s)") val existingDescription = descriptionRegex.find(pluginXmlText)?.groups?.get(1)?.value?.trim() ?: "" val combinedDescription = if (existingDescription.isNotEmpty()) { "$readmeDescription\n$existingDescription" } else { readmeDescription } pluginDescription.set(combinedDescription) } } tasks.prepareSandbox { dependsOn(compileDotNet) val outputFolder = "${rootDir}/src/dotnet/${DotnetPluginId}/bin/${DotnetPluginId}.Rider/${BuildConfiguration}" val dllFiles = listOf( "$outputFolder/${DotnetPluginId}.dll", "$outputFolder/${DotnetPluginId}.pdb", "$outputFolder/Microsoft.Extensions.Caching.Abstractions.dll", "$outputFolder/Microsoft.Extensions.Caching.Memory.dll", ) dllFiles.forEach({ f -> val file = file(f) from(file, { into("${rootProject.name}/dotnet") }) }) doLast { dllFiles.forEach({ f -> val file = file(f) if (!file.exists()) throw RuntimeException("File ${file} does not exist") }) } } tasks.publishPlugin { dependsOn(testDotNet) dependsOn(tasks.buildPlugin) token.set(providers.environmentVariable("PUBLISH_TOKEN")) doLast { exec { executable(layout.projectDirectory.file("dotnet.cmd")) val nugetToken = System.getenv("PUBLISH_TOKEN") ?: "" args("nuget", "push", "output/${DotnetPluginId}.${version}.nupkg", "--api-key", nugetToken, "--source", "https://plugins.jetbrains.com") workingDir(rootDir) } } } fun File.writeTextIfChanged(content: String) { val bytes = content.toByteArray() if (!exists() || !readBytes().contentEquals(bytes)) { println("Writing $path") parentFile.mkdirs() writeBytes(bytes) } } val riderModel: Configuration by configurations.creating { isCanBeConsumed = true isCanBeResolved = false } artifacts { add(riderModel.name, provider { intellijPlatform.platformPath.resolve("lib/rd/rider-model.jar").also { check(it.isFile) { "rider-model.jar is not found at $riderModel" } } }) { builtBy(Constants.Tasks.INITIALIZE_INTELLIJ_PLATFORM_PLUGIN) } }