本章详细讲解下插件工程的配置,官方在github上提供了一个idea插件开发的模板工程,可在https://github.com/JetBrains/intellij-platform-plugin-template下载,此工程模板与idea中创建的工程最大不同之处就是配置了github的ci-action流程以及junit-test,其它方面没有区别,本文会详细讲解下在进行编码进行要掌握的必要的插件配置相关的知识。
涉及到一些Gradle的知识可参考笔者写的另一篇关于Gradle工程构建的文章。典型的Idea-plugin工程完整的目录大体如下所示:
├── build.gradle # gradle构建脚本文件,相当于maven的pom.xml文件,****重要****
├── gradle.properties # 可定义一些属性值在build.gradle中使用,****重要****
├── gradle # Gradle包装器,有了包装器就不需要在系统中安装gradle了
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties # 包装器配置文件,****重要****
├── gradlew # 适用于mac和linux系统的shell脚本,不需要改动
├── gradlew.bat # 适用于windows系统的批处理脚本,不需要改动
├── settings.gradle # 多模块管理时的模块依赖配置文件,对于单个项目此文件可选
└── src
└── main
├── java #插件源码
└── resources #存放语言文件以及插件需要的图片等文件
│ └── messages
│ │ └── Bundle_zh_CN.properties #国际化Bundle,需要在plugin.xml文件中配置
| │
| └─── META-INF
| └─── plugin.xml # 插件配置文件,****重要****
└────────└─── pluginIcon.svg #插件在IDEA/Plugins中的展示图标
其中有5个配置文件非常重要:
【注意事项】:构建脚本和工程管理配置文件是可编程的,高版本的idea工程中文件以.gradle.kts结尾的,区别是.kts需要用kotlin语言,.gradle需要用groovy语言来扩展这两个脚本。
此文件主要是用于多模块配置用的,比如父子工程结构,在父模块中可以配置一些公共的依赖以及依赖的版本等信息,方便实现整个工程统一的管理。
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "firstplugin"
如果是多个模块可按如下配置配置,工程名称为b2bdemo,包含两个子模块api和server:
rootProject.name = 'b2bdemo'
include 'api'
include 'server'
此配置文件主要是配置Gradle构建工具的版本等信息。常用的就是如下5个属性,其中distributionUrl默认为-bin,建议配置成-all,原因是包含源代码,这样在构建过程出现问题可以分析源代码。
#Gradle 解包后存储的父目录,默认在userName/.gradle下面;
distributionBase=GRADLE_USER_HOME
#distributionBase指定目录的子目录, distributionBase+distributionPath就是 Gradle 解包后的存放的具体目录
distributionPath=wrapper/dists
#Gradle 指定版本的压缩包下载地址,如果你使用IDEA的话,它会推荐下载all版,包含源代码,这样IDEA就可以分析源代码,提供更加精确的gradle脚本支持,可用于全组统一,而不需要在本地安装各自的版本
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
#Gradle 压缩包下载后存储父目录
zipStoreBase=GRADLE_USER_HOME
#zipStoreBase指定目录的子目录。zipStoreBase+zipStorePath就是 Gradle 压缩包的存放位置
zipStorePath=wrapper/dists
有两个功能:1、可以自定义多个key-value值,供构建脚本引用;2、定义构建的默认行为;多数配置都很清晰,看注释即可。在开发初始也可以把此文件置空,后续需要时再进行配置。
#性能配置
kotlin.incremental.useClasspathSnapshot = false
kotlin.stdlib.default.dependency = false
org.gradle.configuration-cache = true
org.gradle.caching = true
systemProp.org.gradle.unsafe.kotlin.assignment = true
#供build.gradle.kts构建脚本使用的属性
pluginSinceBuild = 221
pluginUntilBuild = 231.*
platformType = IC
platformVersion = 2022.1.4
其它几个常用的配置如下:
这是Gradle的核心文件,可用groovy和kotlin语言编写。一般专门做运维时会编写一些程序代码,在idea插件开发时采用纯配置即可。本例中提供了两种配置带脚本语言和不带脚本语言的。
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
fun properties(key: String) = providers.gradleProperty(key)
fun environment(key: String) = providers.environmentVariable(key)
plugins {
id("java") // Java support
alias(libs.plugins.kotlin) // Kotlin support
alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin
alias(libs.plugins.changelog) // Gradle Changelog Plugin
alias(libs.plugins.qodana) // Gradle Qodana Plugin
alias(libs.plugins.kover) // Gradle Kover Plugin
}
group = properties("pluginGroup").get()
version = properties("pluginVersion").get()
// Configure project's dependencies
repositories {
mavenCentral()
}
// Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog
dependencies {
// implementation(libs.annotations)
}
// Set the JVM language level used to build the project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
kotlin {
jvmToolchain(11)
}
// Configure Gradle IntelliJ Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
pluginName = properties("pluginName")
version = properties("platformVersion")
type = properties("platformType")
// Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file.
plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) }
}
// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin
changelog {
groups.empty()
repositoryUrl = properties("pluginRepositoryUrl")
}
// Configure Gradle Qodana Plugin - read more: https://github.com/JetBrains/gradle-qodana-plugin
qodana {
cachePath = provider { file(".qodana").canonicalPath }
reportPath = provider { file("build/reports/inspections").canonicalPath }
saveReport = true
showReport = environment("QODANA_SHOW_REPORT").map { it.toBoolean() }.getOrElse(false)
}
// Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration
kover.xmlReport {
onCheck = true
}
tasks {
wrapper {
gradleVersion = properties("gradleVersion").get()
}
patchPluginXml {
version = properties("pluginVersion")
sinceBuild = properties("pluginSinceBuild")
untilBuild = properties("pluginUntilBuild")
// Extract the section from README.md and provide for the plugin's manifest
pluginDescription = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map {
val start = ""
val end = ""
with (it.lines()) {
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.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,
)
}
}
}
// Configure UI tests plugin
// Read more: https://github.com/JetBrains/intellij-ui-test-robot
runIdeForUiTests {
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "")
systemProperty("jb.consents.confirmation.enabled", "false")
}
signPlugin {
certificateChain = environment("CERTIFICATE_CHAIN")
privateKey = environment("PRIVATE_KEY")
password = environment("PRIVATE_KEY_PASSWORD")
}
publishPlugin {
dependsOn("patchChangelog")
token = environment("PUBLISH_TOKEN")
// The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
channels = properties("pluginVersion").map { listOf(it.split('-').getOrElse(1) { "default" }.split('.').first()) }
}
}
plugins {
id("java")
id("org.jetbrains.intellij") version "1.13.3"
}
group = "com.example"
version = "1.0-SNAPSHOT"
repositories {
mavenLocal()
maven("https://maven.aliyun.com/nexus/content/repositories/central/")
mavenCentral()
}
// Configure Gradle IntelliJ Plugin
// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
intellij {
version.set("2022.2.5")
type.set("IC") // Target IDE Platform, IU旗舰版, IC社区版
plugins.set(listOf(/* Plugin Dependencies */))
}
dependencies {
}
tasks {
// Set the JVM compatibility versions
withType {
sourceCompatibility = "17"
targetCompatibility = "17"
}
patchPluginXml {
version.set("${project.version}")
sinceBuild.set("222")
untilBuild.set("232.*")
}
signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}
publishPlugin {
token.set(System.getenv("PUBLISH_TOKEN"))
}
// 将依赖打进jar包中
jar.configure {
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.INCLUDE
from(configurations.runtimeClasspath.get().filter { it.name.endsWith("jar")}.map { zipTree(it) })
}
}
plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.8.21"
}
java {
sourceCompatibility = JavaVersion.VERSION_17
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "17"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "17"
}
}
Gradle IntelliJ 插件是 Jetllij官方开发的一个插件,可帮助配置您的环境方便开发idea插件包含基于 IntelliJ 的 IDE 构建、测试、验证和发布插件。
需要配置plugins标签中,pulgins中声明的内容是为了开发插件而依赖的其它框架,比如我们要开发微服务一般要引入springboot框架一个道理。
详细配置可参考https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
plugins {
id("java")
id("org.jetbrains.intellij") version "1.13.3"
}
【注意事项】:如果插件适用的idea版本是2022.3+,需要在Settings | Build, Execution, Deployment | Build Tools | Gradle,设置JDK不低于Java 17。
配置要发布的插件适配的jetllij家族产品的种类和版本。其中 version和type是必填项。如果此插件不依赖其它插件,则plugins.set()设置为空即可。
intellij {
version.set("2022.1.1")
type.set("IU")
plugins.set(listOf("com.jetbrains.php:221.5787.21"))
}
/*plugins.set(listOf("com.jetbrains.php:221.5787.21"))这段代码等价于
om.jetbrains.php */
intellij {
plugins.set(listOf(file("/path/to/plugin/lib/")))
}
详细可参考Plugin Compatibility with IntelliJ Platform Products | IntelliJ Platform Plugin SDK
或开发自己的idea产品一文。
详细的配置在https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#tasks 中查看说明,task中的一些配置可替换plugin.xml和grablew.properties中的一些默认行为配置。下面列出几个重的经常用到的一些子配置,示例如下:
tasks {
withType {
sourceCompatibility = "17"
targetCompatibility = "17"
}
patchPluginXml {
sinceBuild.set("222")
untilBuild.set("232.*")
}
}
alpha、eap、beta三个
。改变插件测试运行时的一些设置,并不影响插件发布后的设置,一般用于开发时使用。比如下列几个配置:
tasks {
runIde {
jvmArgs("-DmyProperty=value") #启动 IDE 时添加一些 JVM 参数
systemProperty("name", "value") #修改runIde任务的系统属性
autoReloadPlugins.set(false) #设置启动自动加载
buildSearchableOptions { #禁用构建可搜索选项
enabled = false
}
}
}
如果插件涉及到ui界面,则可以在 IntelliJ IDEA 中启用内部模式时打开相应的调试工具,idea默认是关闭的,可以在【菜单】选择修改属性,然后修改idea.properties文件,添加以下语句然后重启,就可以在【工具】-【内部操作】菜单中看到了。
idea.is.internal=true
使用时,将光标置于 UI 元素的中心单击鼠标左键可显示 Swing 组件的属性,也可以打开工具】-【内部操作】-【UI】-【Laf 默认值】窗口进行UI组件的设置。
与插件相关的唯一配置文件,也就是说插件行为样式等所有功能都是在这个文件中配置的,配置项也比较多,详细配置可参考plugin.xml官方文档。必要的描述示例如下:
MyPrluginName
YourCompany
io.org.example.plugin
Integrates Volume Snapshot Service W10
Initial release of the plugin.
1.1.1
com.intellij.java
com.MySecondPlugin
messages.Bundle
...
......
可选,仅适用于付费或免费增值插件;在免费软件中不要设置此值。它有三个必要属性code、release-date、release-version。其中code需要按照官方要求来设置,详细可参考code规范
必填项,配置插件适用范围,一般可以用build.grale的patchPluginXml属性来代替。
可选,如果当前插件依赖另一个插件的话,需要用此值,比如扩展点依赖等。值为另一个插件的id值。config-file相当于一个子的配置文件,可把依赖的插件的配置专让放在另一个文件中,这样可以分别管理。
com.example.dependencypluginid
com.example.dependencypluginid
com.intellij.modules.java
intellij {
plugins.set(listOf(file("/path/to/plugin/lib/")))
}
ide插件定义的任何一个点击事件称为Action,需要继承AnAction类。所以定义action后需要在配置文件中进行配置,这样idea才能识别此动作。它有以下5个属性。
它有6个子元素:
add-to-group
override-text
布局元素,它包含action、group、add-to-group子元素,上述这3个元素可以相互嵌套循环,最终可设计成一个复杂的菜单。特有的子元素主要有:
reference
将现有操作元素添加到组中。可以在
separator
定义组中action之间的分隔符。该元素可以在
用于扩展另一个插件声明使用,它可以包含子元素
#使用完全限定扩展名称的扩展声明:
插件详细的扩展点配置,现在已公布的扩展点有1000多个,需要查看官方文档。有以下几个重要属性;
with
为扩展点指定所需的父类型。单个
上述代码的含义是自定的MyExtensionBean.java的扩展点类中有一个属性,这个属性要用@Attribute注解声明为PsiElement类型。注意属性名称的对应。
public class MyExtensionBean{
@Attribute("psiElementClass")
private PsiElement psiElementClass;
}
如果发布插件到平台上需要必要的签名和认证,这些信息会涉及到安全性问题。所以最好不要打包到插件的发布包中或是源码中,有三种配置方式:
在【run/debug】时配置,设置为jvm参数的模式。
#系统环境变量
signPlugin {
certificateChain = environment("CERTIFICATE_CHAIN")
privateKey = environment("PRIVATE_KEY")
password = environment("PRIVATE_KEY_PASSWORD")
}
publishPlugin {
token.set(System.getenv("ORG_GRADLE_PROJECT_intellijPublishToken"))
}
或
signPlugin {
certificateChain.set(providers.environmentVariable("CERTIFICATE_CHAIN"))
privateKey.set(providers.environmentVariable("PRIVATE_KEY"))
password.set(providers.environmentVariable("PRIVATE_KEY_PASSWORD"))
}
#本地文件方式
signPlugin {
certificateChainFile.set(file("certificate/chain.crt"))
privateKeyFile.set(file("certificate/private.pem"))
password.set("8awS22%#3(4wVDDBMlTREX")
}
publishPlugin {
token.set("perm:a961riC....l17oW8t+Qw==")
}
Plugin Configuration File | IntelliJ Platform Plugin SDK
#idea-plugin基本配置
国际化资源
声明与提供的模块不兼容
为扩展点标记或属性中提供的类名指定所需的父类型