chore: migrate to new gradle intellij plugin

This commit is contained in:
Carl-Robert Linnupuu 2025-06-05 18:43:26 +01:00
parent 66f9f634c9
commit d117d45459
16 changed files with 202 additions and 239 deletions

1
.gitignore vendored
View file

@ -15,6 +15,7 @@ local.properties
### IntelliJ IDEA ###
.idea/*
.intellijPlatform/*
*.iws
*.iml
*.ipr

View file

@ -1,7 +1,8 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.tasks.RunIdeTask
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.intellij.platform.gradle.tasks.RunIdeTask
import java.io.FileInputStream
import java.util.*
@ -13,208 +14,212 @@ fun loadProperties(filename: String): Properties = Properties().apply {
}
val localProperties: Properties? = if (localPropertiesFile.exists()) {
loadProperties("local.properties")
loadProperties("local.properties")
} else {
null
null
}
val customIdePath: String? = localProperties?.getProperty("customIdePath")
fun properties(key: String): Provider<String> {
if ("win-arm64" == env) {
val property = loadProperties("gradle-win-arm64.properties").getProperty(key)
if ("win-arm64" == env) {
val property = loadProperties("gradle-win-arm64.properties").getProperty(key)
?: return providers.gradleProperty(key)
return providers.provider { property }
}
return providers.gradleProperty(key)
return providers.provider { property }
}
return providers.gradleProperty(key)
}
fun environment(key: String) = providers.environmentVariable(key)
plugins {
id("codegpt.java-conventions")
alias(libs.plugins.changelog)
alias(libs.plugins.protobuf)
id("codegpt.java-conventions")
id("org.jetbrains.intellij.platform")
alias(libs.plugins.changelog)
alias(libs.plugins.protobuf)
}
group = properties("pluginGroup").get()
version = properties("pluginVersion").get() + "-" + properties("pluginSinceBuild").get()
checkstyle {
toolVersion = libs.versions.checkstyle.get()
}
repositories {
mavenCentral()
gradlePluginPortal()
}
mavenCentral()
gradlePluginPortal()
intellij {
pluginName.set(properties("pluginName"))
version.set(properties("platformVersion"))
type.set(properties("platformType"))
plugins.set(listOf("java", "PythonCore:241.14494.240", "Git4Idea", "org.jetbrains.kotlin"))
intellijPlatform {
defaultRepositories()
}
}
changelog {
groups.empty()
repositoryUrl.set(properties("pluginRepositoryUrl"))
groups.empty()
repositoryUrl.set(properties("pluginRepositoryUrl"))
}
dependencies {
implementation(project(":codegpt-telemetry"))
implementation(project(":codegpt-treesitter"))
intellijPlatform {
intellijIdeaCommunity(properties("platformVersion"))
implementation(platform(libs.jackson.bom))
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation(libs.flexmark.all) {
// vulnerable transitive dependency
exclude(group = "org.jsoup", module = "jsoup")
}
implementation(kotlin("stdlib"))
implementation(kotlin("reflect"))
implementation(libs.jsoup)
implementation(libs.commons.text)
implementation(libs.jtokkit)
implementation(libs.grpc.protobuf)
implementation(libs.grpc.stub)
implementation(libs.grpc.netty.shaded)
testImplementation(kotlin("test"))
bundledPlugin("com.intellij.java")
bundledPlugin("org.jetbrains.kotlin")
bundledPlugin("Git4Idea")
plugin("PythonCore:241.14494.240")
testFramework(TestFrameworkType.Platform)
testFramework(TestFrameworkType.JUnit5)
}
implementation(project(":codegpt-telemetry"))
implementation(project(":codegpt-treesitter"))
implementation(platform(libs.jackson.bom))
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation(libs.flexmark.all) {
// vulnerable transitive dependency
exclude(group = "org.jsoup", module = "jsoup")
}
implementation(kotlin("stdlib"))
implementation(kotlin("reflect"))
implementation(libs.jsoup)
implementation(libs.commons.text)
implementation(libs.jtokkit)
implementation(libs.grpc.protobuf)
implementation(libs.grpc.stub)
implementation(libs.grpc.netty.shaded)
testImplementation("junit:junit:4.13.2")
testImplementation(kotlin("test"))
}
tasks.register<Exec>("updateSubmodules") {
workingDir(rootDir)
commandLine("git", "submodule", "update", "--init", "--recursive")
workingDir(rootDir)
commandLine("git", "submodule", "update", "--init", "--recursive")
}
intellijPlatform {
pluginConfiguration {
name = properties("pluginName")
version = properties("pluginVersion").get() + "-" + properties("pluginSinceBuild").get()
description =
providers.fileContents(layout.projectDirectory.file("DESCRIPTION.md")).asText.map {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"
with(it.lines()) {
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in DESCRIPTION.md:\n$start ... $end")
}
subList(indexOf(start) + 1, indexOf(end)).joinToString("\n")
.let(::markdownToHTML)
}
}
val changelog = project.changelog // local variable for configuration cache compatibility
// Get the latest available change notes from the changelog file
changeNotes = properties("pluginVersion").map { pluginVersion ->
with(changelog) {
renderItem(
(getOrNull(pluginVersion) ?: getUnreleased())
.withHeader(false)
.withEmptySections(false),
Changelog.OutputType.HTML,
)
}
}
ideaVersion {
sinceBuild = properties("pluginSinceBuild")
untilBuild = properties("pluginUntilBuild")
}
}
pluginVerification {
ides {
recommended()
}
}
signing {
certificateChain = System.getenv("CERTIFICATE_CHAIN")
privateKey = System.getenv("PRIVATE_KEY")
password = System.getenv("PRIVATE_KEY_PASSWORD")
}
publishing {
token = System.getenv("PUBLISH_TOKEN")
channels = listOf("stable")
}
}
/**
* Task to run a custom IntelliJ IDEA sandbox.
*
* This task launches a custom IntelliJ IDEA installation using the path specified in the
* 'customIdePath' property from local.properties.
*
* IMPORTANT:
* - On macOS, the path must include the 'Contents' directory (e.g., /Applications/IntelliJ IDEA.app/Contents).
* - For Windows or Linux, specify the appropriate path to the IntelliJ IDEA installation.
*
* Usage:
* ./gradlew runCustomIde
*/
- * Task to run a custom IntelliJ IDEA sandbox.
- *
- * This task launches a custom IntelliJ IDEA installation using the path specified in the
- * 'customIdePath' property from local.properties.
- *
- * IMPORTANT:
- * - On macOS, the path must include the 'Contents' directory (e.g., /Applications/IntelliJ IDEA.app/Contents).
- * - For Windows or Linux, specify the appropriate path to the IntelliJ IDEA installation.
- *
- * Usage:
- * ./gradlew runCustomIde
- */
if (customIdePath != null) {
tasks.register<RunIdeTask>("runCustomIde") {
group = "intellij"
description = "Start custom idea sandbox"
ideDir.set(file(customIdePath))
sandboxDirectory = file(customIdePath)
environment("ENVIRONMENT", "LOCAL")
autoReloadPlugins.set(false)
}
}
tasks {
wrapper {
gradleVersion = properties("gradleVersion").get()
}
wrapper {
gradleVersion = properties("gradleVersion").get()
}
verifyPlugin {
enabled = true
}
runPluginVerifier {
enabled = true
}
patchPluginXml {
enabled = true
version.set(properties("pluginVersion").get() + "-" + properties("pluginSinceBuild").get())
sinceBuild.set(properties("pluginSinceBuild"))
untilBuild.set(properties("pluginUntilBuild"))
pluginDescription.set(providers.fileContents(layout.projectDirectory.file("DESCRIPTION.md")).asText.map {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"
with(it.lines()) {
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in DESCRIPTION.md:\n$start ... $end")
prepareSandbox {
dependsOn("updateSubmodules")
from("src/main/cpp/llama.cpp") {
into("ProxyAI/llama.cpp")
}
subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML)
}
})
val changelog = project.changelog // local variable for configuration cache compatibility
// Get the latest available change notes from the changelog file
changeNotes.set(properties("pluginVersion").map { pluginVersion ->
with(changelog) {
renderItem(
(getOrNull(pluginVersion) ?: getUnreleased())
.withHeader(false)
.withEmptySections(false),
Changelog.OutputType.HTML,
)
}
})
}
prepareSandbox {
enabled = true
dependsOn("updateSubmodules")
from("src/main/cpp/llama.cpp") {
into("ProxyAI/llama.cpp")
}
}
signPlugin {
enabled = true
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}
buildPlugin {
enabled = true
}
publishPlugin {
enabled = true
dependsOn("patchChangelog")
token.set(System.getenv("PUBLISH_TOKEN"))
channels.set(listOf("stable"))
}
runIde {
enabled = true
environment("ENVIRONMENT", "LOCAL")
autoReloadPlugins.set(false) // is triggered when building llama server
}
test {
exclude("**/testsupport/*")
useJUnitPlatform()
testLogging {
events("started", "passed", "skipped", "failed")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
runIde {
environment("ENVIRONMENT", "LOCAL")
}
publishPlugin {
dependsOn("patchChangelog")
}
test {
exclude("**/testsupport/*")
testLogging {
events("started", "passed", "skipped", "failed")
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = true
}
}
}
}
protobuf {
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
plugins {
create("grpc") {
artifact = libs.protobuf.java.get().toString()
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
plugins {
create("grpc") {
artifact = libs.protobuf.java.get().toString()
}
}
generateProtoTasks {
all()
.forEach {
it.plugins {
create("grpc")
}
}
}
}
generateProtoTasks {
all()
.forEach {
it.plugins {
create("grpc")
}
}
}
}

View file

@ -1,3 +1,4 @@
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -6,10 +7,9 @@ fun lib(reference: String) = libs.findLibrary(reference).get()
fun properties(key: String) = project.findProperty(key).toString()
plugins {
checkstyle
id("java")
id("idea")
id("org.jetbrains.intellij")
id("org.jetbrains.intellij.platform.module")
id("org.jetbrains.kotlin.jvm")
}
@ -17,18 +17,23 @@ version = properties("pluginVersion")
repositories {
mavenCentral()
}
intellij {
type.set(properties("platformType"))
version.set(properties("platformVersion"))
}
checkstyle {
toolVersion = "10.15.0"
intellijPlatform {
defaultRepositories()
}
}
dependencies {
if (project.name != rootProject.name) {
intellijPlatform {
val type = providers.gradleProperty("platformType")
val version = providers.gradleProperty("platformVersion")
create(type, version)
testFramework(TestFrameworkType.Platform)
}
}
implementation(lib("llm.client"))
constraints {
implementation(lib("okio")) {
@ -36,6 +41,7 @@ dependencies {
}
}
testImplementation("junit:junit:4.13.2")
testImplementation(platform(lib("junit.bom")))
testImplementation(lib("assertj.core"))
testImplementation("org.junit.jupiter:junit-jupiter-params")
@ -54,28 +60,4 @@ tasks {
compilerOptions.jvmTarget.set(JvmTarget.fromTarget(it))
}
}
runIde {
enabled = false
}
verifyPlugin {
enabled = false
}
runPluginVerifier {
enabled = false
}
patchPluginXml {
enabled = false
}
publishPlugin {
enabled = false
}
signPlugin {
enabled = false
}
}

View file

@ -32,7 +32,6 @@ public class TelemetryConfigurable implements SearchableConfigurable {
private TelemetryComponent component;
private final TelemetryConfiguration configuration = TelemetryConfiguration.getInstance();
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return "ProxyAI Telemetry";

View file

@ -8,7 +8,7 @@ pluginVersion = 3.4.1
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 241.1
pluginUntilBuild = 251.1
pluginUntilBuild = 252.*
# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension
platformType = IC

View file

@ -5,14 +5,14 @@ changelog = "2.2.1"
checkstyle = "10.15.0"
commons-text = "1.13.0"
flexmark = "0.64.8"
gradle-intellij-plugin-version = "1.17.4"
gradle-intellij-plugin-version = "2.6.0"
gson = "2.12.1"
jackson = "2.18.3"
jsoup = "1.19.1"
jtokkit = "1.1.0"
junit = "5.12.1"
kotlin = "2.1.20"
llm-client = "0.8.41"
llm-client = "0.8.43"
okio = "3.10.2"
tree-sitter = "0.24.5"
grpc = "1.71.0"
@ -24,7 +24,7 @@ analytics = { module = "com.rudderstack.sdk.java.analytics:analytics", version.r
assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
commons-text = { module = "org.apache.commons:commons-text", version.ref = "commons-text" }
flexmark-all = { module = "com.vladsch.flexmark:flexmark-all", version.ref = "flexmark" }
gradle-intellij-plugin = { module = "org.jetbrains.intellij.plugins:gradle-intellij-plugin", version.ref = "gradle-intellij-plugin-version" }
gradle-intellij-plugin = { module = "org.jetbrains.intellij.platform:intellij-platform-gradle-plugin", version.ref = "gradle-intellij-plugin-version" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
jackson-bom = { module = "com.fasterxml.jackson:jackson-bom", version.ref = "jackson" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }

View file

@ -10,7 +10,6 @@ public class GeneralSettingsConfigurable implements Configurable {
private GeneralSettingsComponent component;
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return CodeGPTBundle.get("settings.displayName");

View file

@ -10,7 +10,6 @@ public class AdvancedSettingsConfigurable implements Configurable {
private AdvancedSettingsComponent component;
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return CodeGPTBundle.get("advancedSettingsConfigurable.displayName");

View file

@ -15,7 +15,6 @@ public class ConfigurationConfigurable implements Configurable {
private ConfigurationComponent component;
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return CodeGPTBundle.get("configurationConfigurable.displayName");

View file

@ -16,7 +16,7 @@ public class CodeGPTStatusBarWidgetFactory extends StatusBarEditorBasedWidgetFac
}
@Override
public @Nls @NotNull String getDisplayName() {
public @NotNull String getDisplayName() {
return CodeGPTBundle.get("project.label");
}

View file

@ -1,28 +1,19 @@
package ee.carlrobert.codegpt.codecompletions
import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import java.util.concurrent.ConcurrentHashMap
@Service(Service.Level.PROJECT)
class CodeCompletionCacheService() {
private val cacheCounter = ConcurrentHashMap<String, Int>()
private val cache: LoadingCache<String, String?> = CacheBuilder.newBuilder()
private val cache: Cache<String, String> = CacheBuilder.newBuilder()
.maximumSize(10)
.recordStats()
.build(object : CacheLoader<String, String?>() {
override fun load(key: String): String? = null
})
fun getAll(): Map<String, String?> {
return ConcurrentHashMap(cache.asMap())
}
.build()
fun get(key: String): String? {
val value = cache.getIfPresent(key)
@ -83,11 +74,4 @@ class CodeCompletionCacheService() {
val key = getKey(prefix, suffix)
set(key, completion)
}
companion object {
@JvmStatic
fun <T> getInstance(project: Project): CodeCompletionCacheService {
return project.service<CodeCompletionCacheService>()
}
}
}

View file

@ -1,4 +1,3 @@
/*
package ee.carlrobert.codegpt.codecompletions.psi
import com.intellij.openapi.project.Project
@ -16,22 +15,23 @@ import ee.carlrobert.codegpt.codecompletions.InfillContext
class PythonContextFinder : LanguageContextFinder {
*/
/**
/**
* Finds enclosing [PyFunction] or [PyClass] of [psiElement] and
* determines source code elements of all used [PyReferenceExpression]s for the context.
*//*
*/
override fun findContext(psiElement: PsiElement): InfillContext {
val enclosingElement = findEnclosingElement(psiElement)
val referenceExpressions = findRelevantElements(enclosingElement, enclosingElement)
val declarations =
referenceExpressions.map { findDeclarations(it, psiElement.containingFile.project) }.flatten().distinct()
referenceExpressions.map { findDeclarations(it, psiElement.containingFile.project) }
.flatten().distinct()
.filter {
// Filter out elements whose source code is inside the enclosingElement
// e.g. for something like this: [i for i in range(10)] findRelevantElements()
// would return a "PyReferenceExpression: i" which is irrelevant
!it.containingFile.equals(enclosingElement.containingFile) || !enclosingElement.textRange.contains(it.textRange)
!it.containingFile.equals(enclosingElement.containingFile) || !enclosingElement.textRange.contains(
it.textRange
)
}
val sourceElements = declarations.mapNotNull { findSourceElement(it) }
return InfillContext(
@ -53,12 +53,10 @@ class PythonContextFinder : LanguageContextFinder {
psiElement.map { findRelevantElements(it, rootElement) }.flatten().distinctBy { it.name }
.toSet()
*/
/**
/**
* Finds [PyReferenceExpression]s inside of [psiElement].
* If [psiElement] is a [PyFunction] inside of a [PyClass] it also adds all [PyReferenceExpression] of any class/instance fields.
*//*
*/
fun findRelevantElements(
psiElement: PsiElement,
rootElement: PsiElement
@ -122,7 +120,9 @@ class PythonContextFinder : LanguageContextFinder {
)
)
)?.let {
if (PyBuiltinCache.getInstance(pyReference).isBuiltin(it) || it.filePath().contains("/stdlib/")) {
if (PyBuiltinCache.getInstance(pyReference).isBuiltin(it) || it.filePath()
.contains("/stdlib/")
) {
null
} else {
setOf(it)
@ -141,4 +141,3 @@ class PythonContextFinder : LanguageContextFinder {
}
}
*/

View file

@ -43,7 +43,7 @@ object ComponentFactory {
val actionManager = ActionManager.getInstance()
val originalGroup = actionManager.getAction(groupId)
if (originalGroup is ActionGroup) {
addAll(originalGroup.getChildren(null, actionManager).toList())
addAll(originalGroup.getChildren(null).toList())
}
}
}

View file

@ -1,7 +1,6 @@
package ee.carlrobert.codegpt.ui
import com.intellij.ui.components.JBTextField
import org.jetbrains.annotations.Nls
import java.awt.event.FocusAdapter
import java.awt.event.FocusEvent
@ -11,8 +10,8 @@ import java.awt.event.FocusEvent
class URLTextField : JBTextField {
constructor() : super()
constructor(columns: Int) : super(columns)
constructor(text: @Nls String?) : super(text)
constructor(text: @Nls String?, columns: Int) : super(text, columns)
constructor(text: String?) : super(text)
constructor(text: String?, columns: Int) : super(text, columns)
init {
addFocusListener(object : FocusAdapter() {

View file

@ -6,8 +6,8 @@
<depends>com.intellij.modules.lang</depends>
<depends optional="true" config-file="plugin-kotlin.xml">org.jetbrains.kotlin</depends>
<depends optional="true" config-file="plugin-java.xml">com.intellij.modules.java</depends>
<depends optional="true" config-file="plugin-python.xml">com.intellij.modules.python</depends>
<!-- TODO-->
<!-- <depends optional="true" config-file="plugin-python.xml">com.intellij.modules.python</depends>-->
<!-- <depends optional="true" config-file="plugin-js.xml">JavaScript</depends>-->
<!-- <depends optional="true" config-file="plugin-go.xml">org.jetbrains.plugins.go</depends>-->
<!-- <depends optional="true" config-file="plugin-ruby.xml">com.intellij.modules.ruby</depends>-->
@ -25,8 +25,6 @@
</projectListeners>
<extensions defaultExtensionNs="com.intellij">
<supportsKotlinPluginMode supportsK2="true" />
<postStartupActivity implementation="ee.carlrobert.codegpt.CodeGPTProjectActivity"/>
<postStartupActivity implementation="ee.carlrobert.codegpt.CodeGPTUpdateActivity"/>
<editorFactoryListener implementation="ee.carlrobert.codegpt.CodeGPTEditorFactoryListener"/>

View file

@ -1,4 +1,3 @@
/*
package ee.carlrobert.codegpt.codecompletions.psi
import com.intellij.openapi.editor.VisualPosition
@ -66,4 +65,4 @@ class PythonContextFinderTest : BasePlatformTestCase() {
)
}
}*/
}