Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 169 additions & 20 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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("org.jetbrains.intellij.platform") version "2.11.0" // See https://github.com/JetBrains/intellij-platform-gradle-plugin/releases
id("me.filippov.gradle.jvm.wrapper") version "0.14.0"
}

Expand Down Expand Up @@ -49,6 +49,36 @@ tasks.wrapper {

version = extra["PluginVersion"] as String


// ============ Plugin File Definitions ==============

val pluginStagingDir = layout.buildDirectory.dir("plugin-staging").get().asFile
val pluginContentDir = file("${pluginStagingDir}/${rootProject.name}")
val signingManifestFile = file("${pluginStagingDir}/files-to-sign.txt")

val dotNetSrcDir = File(projectDir, "src/dotnet")
val dotNetOutputDir = "${dotNetSrcDir}/${DotnetPluginId}/bin/${DotnetPluginId}.Rider/${BuildConfiguration}"

// All .NET files to include in the plugin
val dotNetOutputFiles = listOf(
"${DotnetPluginId}.dll",
"${DotnetPluginId}.pdb",
"Microsoft.Extensions.Caching.Abstractions.dll",
"Microsoft.Extensions.Caching.Memory.dll",
)

// .NET files that need signing (only our own code, not third-party dependencies)
val dotNetFilesToSign = listOf(
"${DotnetPluginId}.dll",
)

// JAR files that need signing (only our own code, not third-party dependencies)
val jarFilesToSign = listOf(
"${rootProject.name}-${version}.jar",
"${rootProject.name}-${version}-searchableOptions.jar",
)


tasks.processResources {
from("dependencies.json") { into("META-INF") }
}
Expand Down Expand Up @@ -85,7 +115,6 @@ tasks.test {
useTestNG()
}

val dotNetSrcDir = File(projectDir, "src/dotnet")

val riderSdkPath by lazy {
val path = intellijPlatform.platformPath.resolve("lib/DotNetSdkForRdPlugins").absolute()
Expand Down Expand Up @@ -143,11 +172,118 @@ val testDotNet by tasks.registering {
}
}

tasks.buildPlugin {
dependsOn(compileDotNet)
// ========= Two-Phase Build for Signing Support ================

// Preparation for signing. Build all dll's and jar's and puts them into ${pluginStagingDir}
val preparePluginForSigning by tasks.registering {
description = "Prepares plugin files for signing and generates signing manifest"
group = "build"

// Mirror BuildPluginTask dependencies:
// - prepareSandbox provides the main plugin directory
// - jarSearchableOptions provides the searchable options JAR
dependsOn(tasks.prepareSandbox)
dependsOn(tasks.jarSearchableOptions)

// Clean staging directory FIRST to prevent poisoning
doFirst {
delete(pluginStagingDir)
mkdir(pluginStagingDir)
}

doLast {
// Step 1: Copy from prepareSandbox.pluginDirectory (same as BuildPluginTask)
val sandboxPluginDir = tasks.prepareSandbox.get().pluginDirectory.get().asFile
copy {
from(sandboxPluginDir)
into(pluginContentDir)
}

// Step 2: Copy searchable options JAR to lib/ (same as BuildPluginTask)
copy {
from(tasks.jarSearchableOptions.get().archiveFile)
into(file("${pluginContentDir}/lib"))
}

// Step 3: Generate signing manifest
val filesToSign = mutableListOf<String>()

// Add JAR files that need signing (only our own code)
jarFilesToSign.forEach { jarName ->
filesToSign.add("${rootProject.name}/lib/${jarName}")
}

// Add .NET files that need signing
dotNetFilesToSign.forEach { fileName ->
filesToSign.add("${rootProject.name}/dotnet/${fileName}")
}

// Write manifest
signingManifestFile.writeText(filesToSign.joinToString("\n"))

// Summary
println("Plugin prepared for signing: ${pluginStagingDir}")
println("Signing manifest: ${signingManifestFile}")
println("Files to sign: ${filesToSign.size}")
filesToSign.forEach { println(" - $it") }
}
}

// Validates that ${pluginStagingDir} has all required files to assemble the plugin
val validatePluginStaging by tasks.registering {
description = "Validates that plugin staging directory exists and contains required files"
group = "build"

doLast {
if (!pluginContentDir.exists()) {
throw RuntimeException(
"Plugin staging directory not found: ${pluginContentDir}\n" +
"Run './gradlew preparePluginForSigning' first."
)
}

// Validate expected .NET output files exist
dotNetOutputFiles.forEach { fileName ->
val file = file("${pluginContentDir}/dotnet/${fileName}")
if (!file.exists()) throw RuntimeException("Expected .NET file not found: ${file}")
}

// Validate expected JAR files exist
jarFilesToSign.forEach { jarName ->
val file = file("${pluginContentDir}/lib/${jarName}")
if (!file.exists()) throw RuntimeException("Expected JAR file not found: ${file}")
}
}
}

// Assembles the final zip-archive by taking the files from ${pluginStagingDir}
val assemblePlugin by tasks.registering(Zip::class) {
description = "Assembles the final plugin ZIP from staged files"
group = "build"

dependsOn(validatePluginStaging)

from(pluginStagingDir) {
// Include plugin content directory
include("${rootProject.name}/**")
// Exclude signing manifest from final ZIP
exclude("files-to-sign.txt")
}

// Use same naming convention as original BuildPluginTask:
// archiveBaseName comes from plugin.xml (via IntelliJ plugin extension)
archiveBaseName.convention(intellijPlatform.projectName)
destinationDirectory.set(layout.buildDirectory.dir("distributions"))

// Register artifact to INTELLIJ_PLATFORM_DISTRIBUTION configuration (same as original BuildPluginTask)
// This ensures publishPlugin and other dependent tasks can find the archive
val intellijPlatformDistributionConfiguration = configurations[Constants.Configurations.INTELLIJ_PLATFORM_DISTRIBUTION]
artifacts.add(intellijPlatformDistributionConfiguration.name, this)

doLast {
// Copy to output directory
copy {
from("${buildDir}/distributions/${rootProject.name}-${version}.zip")
from(archiveFile)
into("${rootDir}/output")
}

Expand All @@ -163,6 +299,24 @@ tasks.buildPlugin {
args("pack", "${DotnetSolution}", "--configuration", BuildConfiguration, "--output", "${rootDir}/output", "/p:PackageReleaseNotes=${changeNotes}", "/p:PackageVersion=${version}")
workingDir(rootDir)
}

println("Plugin assembled: output/${rootProject.name}-${version}.zip")
}
}

tasks.buildPlugin {
// Disable the IntelliJ plugin's default buildPlugin behavior for ZIP creation
// and make it use our two-phase approach instead
actions.clear()

// Make it depend on our assembly task
dependsOn(preparePluginForSigning)
dependsOn(assemblePlugin)

// Phase 2 (assemblePlugin + all its dependencies) must run after Phase 1
assemblePlugin.get().mustRunAfter(preparePluginForSigning)
assemblePlugin.get().taskDependencies.getDependencies(assemblePlugin.get()).forEach { task ->
task.mustRunAfter(preparePluginForSigning)
}
}

Expand Down Expand Up @@ -244,24 +398,19 @@ tasks.patchPluginXml {
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") })
})
// Use shared .NET output files list
dotNetOutputFiles.forEach { fileName ->
from("${dotNetOutputDir}/${fileName}") {
into("${rootProject.name}/dotnet")
}
}

doLast {
dllFiles.forEach({ f ->
val file = file(f)
// Validation: ensure all .NET output files exist
dotNetOutputFiles.forEach { fileName ->
val file = file("${dotNetOutputDir}/${fileName}")
if (!file.exists()) throw RuntimeException("File ${file} does not exist")
})
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pluginManagement {
// Provide repositories to resolve plugins
repositories {
maven { url "https://cache-redirector.jetbrains.com/plugins.gradle.org" }
maven { url "https://cache-redirector.jetbrains.com/dl.bintray.com/kotlin/kotlin-eap" }
maven { url "https://cache-redirector.jetbrains.com/myget.org.rd-snapshots.maven" }
maven { url = "https://cache-redirector.jetbrains.com/plugins.gradle.org" }
maven { url = "https://cache-redirector.jetbrains.com/dl.bintray.com/kotlin/kotlin-eap" }
maven { url = "https://cache-redirector.jetbrains.com/myget.org.rd-snapshots.maven" }
}
resolutionStrategy {
eachPlugin {
Expand Down