idea 插件開發自動發布到 nexus 私服中(腳本實例)

如下腳本內容為 idea 插件開發項目中的 build.gradle.kts 文件示例,其中自定了 updatePluginsXmlToNexusuploadPluginToNexus 兩個任務,一個用來自動修改 nexus 中的配置文件,一個用來自動將當前插件打包后的 zip 文件上傳到 nexus 私服中。

腳本僅供參考:

import okhttp3.Credentials
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.asRequestBody
import org.dom4j.io.OutputFormat
import org.dom4j.io.SAXReader
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.w3c.dom.Element
import java.io.StringReader
import java.io.StringWriter
import java.nio.file.Files
import java.nio.file.Paths
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import javax.xml.xpath.XPathConstants
import javax.xml.xpath.XPathFactoryplugins {id("java") // 使用Java插件id("org.jetbrains.kotlin.jvm") version "2.1.20-RC" // 使用Kotlin JVM插件,指定版本id("org.jetbrains.intellij.platform") version "2.4.0" // 使用IntelliJ插件,用于開發JetBrains插件,指定版本id("com.github.node-gradle.node") version "7.1.0" // Node.js插件,集成Node.js和npm到Gradle構建中
}
buildscript {repositories {mavenCentral()}dependencies {// 添加 OkHttp 依賴classpath("com.squareup.okhttp3:okhttp:4.12.0")classpath("org.dom4j:dom4j:2.1.4")}
}
repositories {// mavenCentral() // 定義Maven中央倉庫作為依賴庫來源mavenLocal()intellijPlatform {defaultRepositories()}maven(url = "https://plugins.gradle.org/m2/")maven(url = "https://oss.sonatype.org/content/repositories/releases/")
}dependencies {compileOnly("org.projectlombok:lombok:1.18.36") // 提供Lombok支持,僅在編譯時使用annotationProcessor("org.projectlombok:lombok:1.18.36") // Lombok注解處理器intellijPlatform {// 獲取在gradle.properties中配置的參數platformVersionval version = providers.gradleProperty("platformVersion") // 2023.2.6// IntellijIdeaCommunity=IC, IntellijIdeaUltimate=IUcreate(org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaCommunity, version)// 使用bundledPlugin設置捆綁的插件//bundledPlugin("com.intellij.java")// 使用plugin設置當前插件依賴的其他插件//plugin("org.intellij.scala", "2024.1.4")pluginVerifier()testFramework(org.jetbrains.intellij.platform.gradle.TestFrameworkType.Platform)}
}group = "com.shanhy.plugin"
version = "1.0.0-20250520"// 文檔 https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform
intellijPlatform {pluginConfiguration {id = "demo-idea-apiflow-designer"name = "demo ApiFlow Designer" // 名稱// 直接使用項目級別的 version 屬性version = project.version.toString()description ="該插件時一個為 IntelliJ IDEA 打造的 demo Http 接口設計器插件。它提供了一個 `.apiflow` 文件編輯器,具有可視化設計快速開發 Http 接口的能力。"// 讀取 CHANGELOG.md 文件的內容changeNotes = Files.readString(Paths.get(project.projectDir.path, "CHANGELOG.md"))// 適用的idea版本ideaVersion {sinceBuild = "232" // 插件支持的最低IDE構建號untilBuild = "251.*" // 插件支持的最高IDE構建號}// 產品描述productDescriptor {// ...}// 開發者信息vendor {name = "shanhy"email = "shanhy@shanhy.com"url = "http://www.shanhy.com"}}// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform-signingsigning {// 配置在gradle.properties中certificateChain = providers.gradleProperty("certificateChain") // 簽名證書鏈privateKey = providers.gradleProperty("privateKey") // 簽名私鑰password = providers.gradleProperty("privateKeyPassword") // 簽名私鑰的密碼}// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform-publishingpublishing {token = providers.gradleProperty("publishToken") // 發布插件時使用的令牌}// https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform-pluginVerificationpluginVerification {// ...}
}node {version.set("20.11.1") // Node.js版本設置download.set(true) // 自動下載Node.js
}tasks {// 設置JVM兼容性版本withType<JavaCompile> {sourceCompatibility = JvmTarget.JVM_17.target // Java源代碼兼容版本targetCompatibility = JvmTarget.JVM_17.target // 編譯目標版本}withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {compilerOptions {jvmTarget.set(JvmTarget.JVM_17) // Kotlin編譯目標版本}}val buildNpm = register<com.github.gradle.node.npm.task.NpmTask>("buildNpm") {args.set(listOf("run", "build")) // NPM任務參數,運行npm buildworkingDir.set(file("${project.projectDir}/editor-web")) // 設置工作目錄}buildPlugin {// 構建插件前先執行NPM構建任務// 如果你的前端頁面沒有做修改,在反復進行插件開發打包測試,可以注釋掉這個構建依賴,不然每次都重復構建沒有修改的前端浪費時間dependsOn(buildNpm)}// 定義 Nexus 相關配置val nexusBaseUrl = providers.gradleProperty("nexusBaseUrl").getOrElse("https://nexus.shanhy.com")val nexusUsername = providers.gradleProperty("nexusUsername").getOrElse("")val nexusPassword = providers.gradleProperty("nexusPassword").getOrElse("")// 更新 plugins.xml 的任務val updatePluginsXmlToNexus = register("updatePluginsXmlToNexus") {group = "deployment"description = "更新 Nexus 上的 pluginsXml 文件版本信息"// 使用 Provider 延遲獲取所有值val pluginId = providers.provider { intellijPlatform.pluginConfiguration.id.get() }val pluginVersion = providers.provider { project.version.toString() }val sinceBuild = providers.provider { intellijPlatform.pluginConfiguration.ideaVersion.sinceBuild.get() }val changelogFile = providers.provider { layout.projectDirectory.file("CHANGELOG.md").asFile }val projectName = providers.provider { project.name }outputs.upToDateWhen { false } // 總是執行更新doLast {// 在任務執行時獲取所有需要的值val pluginIdValue = pluginId.get()val pluginVersionValue = pluginVersion.get()val sinceBuildValue = sinceBuild.get()val changelogFileValue = changelogFile.get()val projectNameValue = projectName.get()// 讀取 CHANGELOG.md 內容val changelogContent = changelogFileValue.readText()val client = OkHttpClient.Builder().followRedirects(true).followSslRedirects(true).build()// 創建認證信息val credentials = Credentials.basic(nexusUsername, nexusPassword)// 下載現有的 plugins.xmlval tempFile = File.createTempFile("plugins", ".xml")try {client.newCall(Request.Builder().url("$nexusBaseUrl/repository/raw-public/idea-plugin/plugins.xml").build()).execute().use { response ->if (!response.isSuccessful) {val errorBody = response.body?.string() ?: "無錯誤詳情"throw GradleException("下載文件失敗: ${response.code} ${response.message}\n錯誤詳情: $errorBody")}val contentType = response.header("Content-Type", "")if (contentType != null) {if (!contentType.contains("xml") && !contentType.contains("text/plain")) {println("警告: 響應Content-Type不是XML: $contentType")}}response.body?.byteStream()?.use { input ->tempFile.outputStream().use { output ->input.copyTo(output)}} ?: throw GradleException("下載文件失敗: 響應體為空")}// 檢查下載的文件if (!tempFile.exists() || tempFile.length() == 0L) {throw GradleException("下載文件失敗,文件不存在或為空")}// 讀取文件內容進行檢查val content = tempFile.readText()// 驗證下載的文件是否為有效的 XMLtry {DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(tempFile)} catch (e: Exception) {throw GradleException("下載的文件不是有效的 XML: ${e.message}\n文件內容: ${content}...")}// 讀取并解析 XMLval document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(tempFile)val xpath = XPathFactory.newInstance().newXPath()// 查找對應的插件節點val pluginNode = xpath.evaluate("//plugin[@id='$pluginIdValue']", document, XPathConstants.NODE)as? Element?: throw GradleException("插件 '$pluginIdValue' 在 plugins.xml 中不存在,請先在 plugins.xml 中手動添加插件配置")// 更新 plugin 節點的屬性pluginNode.setAttribute("url", "$nexusBaseUrl/repository/raw-hosted/idea-plugin/files/$projectNameValue-$pluginVersionValue.zip")pluginNode.setAttribute("version", pluginVersionValue)// 更新 idea-version 節點val ideaVersionNode = xpath.evaluate(".//idea-version", pluginNode, XPathConstants.NODE) as? ElementideaVersionNode?.setAttribute("since-build", sinceBuildValue)// 更新或創建 change-notes 節點val changeNotesNode = xpath.evaluate(".//change-notes", pluginNode, XPathConstants.NODE) as? Elementif (changeNotesNode != null) {while (changeNotesNode.hasChildNodes()) {changeNotesNode.removeChild(changeNotesNode.firstChild)}val cdataNode = document.createCDATASection(changelogContent)changeNotesNode.appendChild(cdataNode)}// 保存更新后的文件val transformer = TransformerFactory.newInstance().newTransformer()transformer.setOutputProperty(OutputKeys.INDENT, "yes")transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8")transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")// 使用 StringWriter 先獲取轉換后的內容val writer = StringWriter()transformer.transform(DOMSource(document),StreamResult(writer))// 使用 dom4j 重新格式化 XML,去除xml中的多余空行和美化xml格式val xmlContent = writer.toString()val reader = SAXReader()val dom4jDocument = reader.read(StringReader(xmlContent))// 創建格式化配置val format = OutputFormat.createPrettyPrint().apply {encoding = "UTF-8"              // 設置輸出編碼isNewlines = true              // 每個節點換行isTrimText = true              // 是否去除元素中的文本前后空白isPadText = true               // 補齊空白以對齊標簽isExpandEmptyElements = true   // <tag/> 變成 <tag></tag>isSuppressDeclaration = false  // 是否省略頭部 <?xml ...?> 聲明isOmitEncoding = false         // 是否省略 encoding 屬性}// 將格式化后的 XML 寫入字符串val stringWriter = StringWriter()val xmlWriter = org.dom4j.io.XMLWriter(stringWriter, format)xmlWriter.write(dom4jDocument)xmlWriter.close()// 將清理后的內容寫入臨時文件tempFile.writeText(stringWriter.toString())// 上傳新文件println("正在上傳新文件...")val requestBody = MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("raw.directory", "/idea-plugin").addFormDataPart("raw.asset1.filename", "plugins.xml").addFormDataPart("raw.asset1","plugins.xml","application/xml".toMediaTypeOrNull()?.let { mediaType ->tempFile.asRequestBody(mediaType)} ?: throw GradleException("無法創建請求體")).build()val uploadRequest = Request.Builder().url("$nexusBaseUrl/service/rest/v1/components?repository=raw-hosted").post(requestBody).header("Authorization", credentials).build()client.newCall(uploadRequest).execute().use { response ->if (!response.isSuccessful) {throw GradleException("上傳文件失敗: ${response.code} ${response.message}")}}} finally {tempFile.delete()}}}// 上傳 zip 文件到 Nexus 的任務val uploadPluginToNexus = register("uploadPluginToNexus") {group = "deployment"description = "上傳插件 zip 文件到 Nexus"// 聲明任務的輸入和輸出,以支持配置緩存val zipFileName = "${project.name}-${project.version}.zip"val zipFile = layout.buildDirectory.file("distributions/$zipFileName").get().asFileinputs.file(zipFile)outputs.upToDateWhen { false } // 總是執行上傳dependsOn(buildPlugin)doLast {if (!zipFile.exists()) {throw GradleException("插件 zip 文件未找到: ${zipFile.absolutePath}")}val client = okhttp3.OkHttpClient.Builder().followRedirects(true).followSslRedirects(true).build()// 創建認證信息val credentials = okhttp3.Credentials.basic(nexusUsername, nexusPassword)// 構建上傳請求val requestBody = okhttp3.MultipartBody.Builder().setType(okhttp3.MultipartBody.FORM).addFormDataPart("raw.directory", "/idea-plugin/files").addFormDataPart("raw.asset1.filename", zipFileName).addFormDataPart("raw.asset1",zipFileName,"application/zip".toMediaTypeOrNull()?.let { mediaType ->zipFile.asRequestBody(mediaType)} ?: throw GradleException("無法創建請求體")).build()val uploadRequest = Request.Builder().url("$nexusBaseUrl/service/rest/v1/components?repository=raw-hosted").post(requestBody).header("Authorization", credentials).build()client.newCall(uploadRequest).execute().use { response ->if (!response.isSuccessful) {val errorBody = response.body?.string() ?: "無錯誤詳情"throw GradleException("上傳文件失敗: ${response.code} ${response.message}\n錯誤詳情: $errorBody")}println("插件文件上傳成功: $zipFileName")}}}// 組合任務:部署到 Nexusregister("deployToNexus") {group = "deployment"description = "部署插件到 Nexus 倉庫"dependsOn(uploadPluginToNexus, updatePluginsXmlToNexus)}
}sourceSets {main {resources {// 指定內容區的前端靜態資源目錄,這個決定了最終被作為資源打包到插件中srcDir("${project.projectDir}/editor-web/dist")}}
}

(END)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82251.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82251.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82251.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot-11-基于注解和XML方式的SpringBoot應用場景對比

文章目錄 1 基于注解的方式1.1 @Mapper1.2 @select1.3 @insert1.4 @update1.5 @delete2 基于XML的方式2.1 namespace2.2 resultMap2.3 select2.4 insert2.5 update2.6 delete3 service和controller3.1 service3.2 controller4 注解和xml的選擇如果SQL簡單且項目規模較小,推薦使…

C++復習核心精華

一、內存管理與智能指針 內存管理是C區別于其他高級語言的關鍵特性&#xff0c;掌握好它就掌握了C的靈魂。 1. 原始指針與內存泄漏 先來看看傳統C的內存管理方式&#xff1a; void oldWay() {int* p new int(42); // 分配內存// 如果這里發生異常或提前return&#xff0c…

期貨反向跟單軟件—提高盤手杠桿的方式及剖析

在期貨反向跟單領域&#xff0c;期貨跟單軟件對盤手杠桿的調節&#xff0c;是整個策略運作的核心環節之一。其背后蘊含著科學的金融邏輯。? 期貨跟單軟件提高盤手杠桿主要通過兩種方式。第一種是降低期貨保證金。在盤手資金總量固定的情況下&#xff0c;保證金降低&#xff0…

【計算機網絡】基于UDP進行socket編程——實現服務端與客戶端業務

&#x1f525;個人主頁&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收錄專欄&#x1f308;&#xff1a;Linux &#x1f339;往期回顧&#x1f339;&#xff1a; 【Linux筆記】——網絡基礎 &#x1f516;流水不爭&#xff0c;爭的是滔滔不息 一、UDPsocket編程UDPsocket編…

ae卡通打架煙霧特效

1、創建一個合成&#xff08;合成1&#xff09;&#xff0c;右鍵創建形狀圖層&#xff0c;使用橢圓工具&#xff0c;長按shift鍵拖動鼠標左鍵畫出圓形&#xff0c;同時按ctrlalthome三個鍵使圓形中心錨點對齊圓心&#xff0c;關閉描邊&#xff0c;圓形圖層填充白色。 2、選擇形…

UE5 Va Res發送請求、處理請求、json使用

文章目錄 介紹發送一個Get請求發送Post請求設置請求頭請求體帶添json發送請求完整的發送藍圖 處理收到的數據常用的json處理節點 介紹 UE5 自帶的Http插件&#xff0c;插件內自帶json解析功能 發送一個Get請求 只能寫在事件圖表里 發送Post請求 只能寫在事件圖表里 設置…

SQL 結構化模型設計與現代技術融合深度解讀

摘要 本文系統展示了基于 JSON Schema 的 SQL 結構化模型設計&#xff0c;包括通用定義、四大基本操作&#xff08;SELECT、INSERT、UPDATE、DELETE&#xff09;的模型規范&#xff0c;以及面向現代場景的設計擴展。重點結合數據權限控制、樂觀鎖并發控制、表單自動化、自定義…

el-dialog 組件 多層嵌套 被遮罩問題

<el-dialog title"提示" :visible.sync"dialogBindUserVisible" width"30%" append-to-body :before-close"handleClose"> <span>這是一段信息</span> <span slot"footer" class"dialog-footer&q…

【KWDB 2025 創作者計劃】_KWDB時序數據庫特性及跨模查詢

一、概述 數據庫的類型多種多樣&#xff0c;關系型數據庫、時序型數據庫、非關系型數據庫、內存數據庫、分布式數據庫、圖數據庫等等&#xff0c;每種類型都有其特定的使用場景和優勢&#xff0c;KaiwuDB 是一款面向 AIoT 場景的分布式、多模融合、支持原生 AI 的數據庫…

學習心得(12-13)HTML 是什么 abort函數and自定義異常

一. abort函數 將后端的數據給到前端 二. 自定義異常 要結合abort函數使用 1.編寫的時候都在abort的函數這個文件里面 錯誤信息在前端頁面的展示&#xff1a; 如果想要在出現異常的時候返回一個頁面&#xff1a; 1. 新建一個HTML文件 例如命名為404 2.將圖庫里的圖片拖入…

理解全景圖像拼接

1 3D到2D透視投影 三維空間上點 p 投影到二維空間 q 有兩種方式&#xff1a;1&#xff09;正交投影&#xff0c;2&#xff09;透視投影。 正交投影直接舍去 z 軸信息&#xff0c;該模型僅在遠心鏡頭上是合理的&#xff0c;或者對于物體深度遠小于其到攝像機距離時的近似模型。…

Linux基本指令篇 —— whoami指令

whoami 是 Linux 和 Unix 系統中一個簡單但實用的命令&#xff0c;全稱 Who Am I&#xff08;我是誰&#xff09;。它的功能是顯示當前登錄用戶的用戶名。以下是關于 whoami 的詳細解析&#xff1a; 目錄 1. 基本用法 2. 命令特點 3. 實際應用場景 場景 1&#xff1a;腳本中…

華為OD機試真題——仿LISP運算(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳實現

2025 B卷 200分 題型 本專欄內全部題目均提供Java、python、JavaScript、C、C++、GO六種語言的最佳實現方式; 并且每種語言均涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、3個測試用例以及綜合分析; 本文收錄于專欄:《2025華為OD真題目錄+全流程解析+備考攻略+經驗分…

創建dummy

訪客_dc1fc4 class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int left0;int right0;int n nums.size(); int sum0;int ans100001; for(right0;right<n;right) { sumnums[right]; //每次更新右端點之后&#xff0c;立即向右移動…

面向惡劣條件的道路交通目標檢測----大創自用(當然你也可以在里面學到很多東西)

全部內容梳理 目標檢測的兩個任務&#xff1a; 預測標簽 邊界框 語義分割 實力分割 一個是類別 一個是實例級別 分類任務把每個圖像當作一張圖片看待 所有解決方法是先生成候選區域 再進行分類 置信度&#xff1a; 包括對類別和邊界框預測的自信程度 輸出分類和IOU分數的…

需求管理工具使用不當,如何優化?

要優化需求管理工具的使用&#xff0c;需從選擇合適工具、規范使用流程、加強用戶培訓、統一數據結構、定期審查與優化使用配置五個方面著手。其中&#xff0c;選擇合適工具是前提。錯誤的工具選擇往往會導致項目溝通效率低、需求追蹤失效甚至造成交付物偏離客戶預期。因此&…

openwrt虛擬機安裝調試

分類 lienol lean immortalwrt 一、獲取固件 &#xff08;1&#xff09;下載地址 1.官網構建下載 OpenWrt Firmware Selector 官網 OpenWrt Firmware Selector 2.第三方構建網站 ImmortalWrt Firmware Selector ImmortalWrt Firmware Selector 3.第三方構建下載 ht…

Apache OFBiz 17.12.01 的遠程命令執行漏洞 -Java 反序列化 + XML-RPC 請求機制

目錄 漏洞原理 &#x1f3af; 一、漏洞背景&#xff08;CVE-2020-9496&#xff09; ?? 二、攻擊原理簡述 &#x1f9f1; 三、完整攻擊流程步驟詳解 &#x1f50e; 1. 信息收集 &#x1f6e0;? 2. 工具準備 &#x1f9ea; 3. 構造初始 payload&#xff1a;下載惡意腳本…

最好用的wordpress外貿主題

產品展示獨立站wordpress主題 橙色的首頁大banner外貿英文wordpress主題&#xff0c;適合用于產品展示型的外貿網站。 https://www.jianzhanpress.com/?p8556 Machine機器wordpress模板 寬屏簡潔實用的wordpress外貿建站模板&#xff0c;適合工業機器生產、加工、制造的外貿…

Q1:Go協程、Channel通道 被close后,讀會帶來什么問題?

在 Go 語言中&#xff0c;Channel&#xff08;通道&#xff09;關閉后讀取的行為是一個常見但需要謹慎處理的問題。以下是詳細的分析和注意事項&#xff1a; 1. 關閉 Channel 后讀取的行為 (1) 讀取已關閉的 Channel 剩余數據仍可讀取&#xff1a; 關閉 Channel 后&#xff0…