Jenkins 插件開發之旅:兩天內從 idea 到發佈(下篇)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文分上下兩篇,上篇介紹了從產生 idea 到插件開發完成的過程; 下篇將介紹將插件託管到 Jenkins 插件更新中心的一系列過程。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"託管插件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"託管插件包括一系列流程步驟。 筆者完成了它所有步驟(包括非必須的步驟),其中主要有兩個具有標誌性的任務: "}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插件代碼被託管在 jenkinsci GitHub 組織的一個倉庫,然後作者擁有它的管理權限。筆者插件的代碼倉庫爲:"},{"type":"link","attrs":{"href":"https://github.com/jenkinsci/maven-snapshot-check-plugin","title":null},"content":[{"type":"text","text":"jenkinsci/maven-snapshot-check-plugin"}]},{"type":"text","text":" 。 "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以將插件發佈到 Jenkins 項目的 Maven 倉庫,它是 Jenkins 項目所使用的更新站點的數據來源。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"準備工作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在請求插件託管之前,需要完成以下幾個步驟。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"查找類似的插件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 社區歡迎任何人的貢獻,但爲了讓 Jenkins 用戶受益, 它要求查找解決相同或類似問題的插件,看看是否可以與現有的維護人員聯手。 可以在 "},{"type":"link","attrs":{"href":"https://plugins.jenkins.io/","title":null},"content":[{"type":"text","text":"https://plugins.jenkins.io"}]},{"type":"text","text":" 查看所有的插件, 以確認是否已有類似的插件實現了你計劃實現的功能。 筆者在之前已進行過查找,並沒有找到可以實現筆者計劃實現的功能的類似插件。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"命名規約"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 制定了一些與插件相關的命名規約。 插件開發者要確保遵循這些命名規約。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"artifactId"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插件的 artifactId 被用於文件基本名稱,是 Jenkins 插件和更新站點的唯一標識。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它需要遵循一些發佈規約:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用小寫 ID ,並根據需要使用連字符分隔術語。 "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除非名稱有任何意義,否則不要在 ID 中包含 jenkins 或 plugin 。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"插件名稱"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插件的名稱在 Jenkins UI 和其它地方(如:插件站點)展示給用戶。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果可以,建議使用簡短的描述性名稱,如 "},{"type":"text","marks":[{"type":"italic"}],"text":"Subversion"},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"筆者所寫的插件的名稱爲:"},{"type":"text","marks":[{"type":"italic"}],"text":"Maven SNAPSHOT Check"},{"type":"text","text":" 。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"groupId"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"推薦使用 "},{"type":"codeinline","content":[{"type":"text","text":"io.jenkins.plugins"}]},{"type":"text","text":" 或 "},{"type":"codeinline","content":[{"type":"text","text":"org.jenkins-ci.plugins"}]},{"type":"text","text":" 作爲 groupId 。 但是不禁止其他組織 ID ,除非它們是惡意的(例如引用與你沒有關係的組織)。 筆者所寫的插件使用的 groupId 爲: "},{"type":"codeinline","content":[{"type":"text","text":"org.jenkins-ci.plugins"}]},{"type":"text","text":" 。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Java 源代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 項目一般遵循 "},{"type":"link","attrs":{"href":"https://jenkins.io/doc/developer/publishing/style-guides/www.oracle.com/technetwork/java/codeconvtoc-136057.html","title":null},"content":[{"type":"text","text":"Oracle Java 代碼規約"}]},{"type":"text","text":", 但是並沒有很好的強制甚至在覈心組件中。 個別的插件維護者有時會選擇使用不同的風格指南作爲插件。 筆者日常使用 IDEA 進行開發,之前安裝了「阿里 Java 規約插件」, 因而使用它作爲編碼規約。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"提交消息"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Git 提交消息應該從引用與之相關的 JIRA 問題開始(如果適用), 然後在第一行進行簡短的總結,並在隨後的行中提供更多詳細信息。例如:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"[JENKINS-00000] Frobnicate the widget"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果給定的提交修復了指定的問題, 那麼使用以下前綴中的任何一個將會自動化解決相關的 JIRA 問題。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"[FIX JENKINS-00000] Frobnicate the widget\n[FIXED JENKINS-00000] Frobnicate the widget\n[FIXES JENKINS-00000] Frobnicate the widget"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於還沒過將插件託管,筆者並沒有遵循該規約, 等插件發佈後,筆者將考慮遵循該規約。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"License"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 項目分發的所有插件都需要是免費的開源軟件。 這適用於插件源代碼及其所有依賴項。 要確保在 "},{"type":"codeinline","content":[{"type":"text","text":"pom.xml"}]},{"type":"text","text":" 文件和倉庫中的 "},{"type":"codeinline","content":[{"type":"text","text":"LICENSE"}]},{"type":"text","text":" 文件指定協議。 官方建議使用 MIT license ,它用於 Jenkins 核心和大多數插件和庫, 但是任何 OSI 批准的開源 license 都可以。 筆者這裏使用了 MIT license 。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"要求註冊的賬號"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過 Jenkins 項目更新站點分發的插件需要託管在 "},{"type":"link","attrs":{"href":"https://github.com/jenkinsci","title":null},"content":[{"type":"text","text":"jenkinsci GitHub 組織"}]},{"type":"text","text":"中, 因此需要在 GitHub 上有一個賬號,並且需要有一個公共倉庫來存放插件源代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了完整地發佈你的插件,需要註冊一個 "},{"type":"link","attrs":{"href":"https://accounts.jenkins.io/","title":null},"content":[{"type":"text","text":"Jenkins 社區帳號"}]},{"type":"text","text":", 它可以讓你訪問 "},{"type":"link","attrs":{"href":"https://issues.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"JIRA"}]},{"type":"text","text":","},{"type":"link","attrs":{"href":"https://wiki.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"wiki"}]},{"type":"text","text":" 和 "},{"type":"link","attrs":{"href":"https://repo.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"Maven 倉庫"}]},{"type":"text","text":" 。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發起託管請求"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:Jenkins 官方自動化流程使用更容易實現的 fork + 刪除的方式(見下文),而不是轉移倉庫所有者。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"登錄到 "},{"type":"link","attrs":{"href":"https://issues.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"JIRA"}]},{"type":"text","text":" 然後在 "},{"type":"link","attrs":{"href":"https://issues.jenkins-ci.org/browse/HOSTING","title":null},"content":[{"type":"text","text":"HOSTING"}]},{"type":"text","text":" 項目創建一個問題。 請確保按照描述填寫所有字段。 Jenkins 項目成員將在幾天內審查你的請求。 如果審查人員要求你更改,那麼請按照要求進行更改。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"筆者提交的申請爲:"},{"type":"link","attrs":{"href":"https://issues.jenkins-ci.org/browse/HOSTING-750","title":null},"content":[{"type":"text","text":"HOSTING-750"}]},{"type":"text","text":", 比較幸運的是當天凌晨(北京時間)筆者的請求就被審查, 正巧那時筆者未眠,於是隨後按要求進行了更改並在不久後該申請被審批通過。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一旦滿足了所有的需求,你的倉庫將被 fork 到 jenkinsci 組織中, 並且你將被邀請加入該組織,並且將爲你在 JENKINS 項目中創建 JIRA 組件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此時,將要求你刪除 Jenkins 從中 fork 的倉庫。 之後你可以通過再次從 "},{"type":"codeinline","content":[{"type":"text","text":"jenkinsci"}]},{"type":"text","text":" 那裏 fork 來重新創建它。 這將確保 "},{"type":"codeinline","content":[{"type":"text","text":"jenkinsci"}]},{"type":"text","text":" 倉庫是 Github 上網絡圖的根。 這意味着: "}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不會混淆哪個倉庫是權威倉庫。 "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"即使在 GitHub 上沒有大量的關注者,"},{"type":"link","attrs":{"href":"https://help.github.com/articles/searching-in-forks/","title":null},"content":[{"type":"text","text":"源代碼搜索"}]},{"type":"text","text":"也會成功。 "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他人更可能在 "},{"type":"codeinline","content":[{"type":"text","text":"jenkinsci"}]},{"type":"text","text":" 倉庫中提交 pull request(這是協作的理想選擇)。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"創建 wiki 頁面"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管這對發佈插件來說這不是嚴格要求的,但最好爲插件創建一個 wiki 頁面來存儲文檔。關於如何執行此操作的詳細信息,請參閱"},{"type":"link","attrs":{"href":"https://jenkins.io/doc/developer/publishing/wiki-page","title":null},"content":[{"type":"text","text":"插件 wiki 頁面指南"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"筆者所寫的插件的 wiki 頁面爲:"},{"type":"link","attrs":{"href":"https://wiki.jenkins.io/display/JENKINS/Maven+SNAPSHOT+Check+Plugin","title":null},"content":[{"type":"text","text":"Maven SNAPSHOT Check Plugin"}]},{"type":"text","text":" 。 其間除了官方文檔,筆者還參考了其它插件 wiki 頁面的排版。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"開啓 CI 構建"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 項目託管了一個 Jenkins 實例來執行插件的持續集成構建。 官方推薦通過在插件的 Github 倉庫根目錄創建一個 Jenkinsfile, 爲在 Jenkinsci Github 組織中的插件設置 CI 構建。 典型的插件構建( Maven 或 Gradle )只需在 Jenkinsfile 中包含以下語句即可運行:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"buildPlugin()"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"申請上傳權限"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在源代碼被 fork 到 "},{"type":"codeinline","content":[{"type":"text","text":"jenkinsci"}]},{"type":"text","text":" 組織後,需要提交一個上傳權限請求。 按照 "},{"type":"link","attrs":{"href":"https://github.com/jenkins-infra/repository-permissions-updater/","title":null},"content":[{"type":"text","text":"jenkins-infra/repository-permissions-updater/"}]},{"type":"text","text":" 倉庫的 README 文件中所說的來做就可以。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 項目在 "},{"type":"link","attrs":{"href":"https://repo.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"Artifactory"}]},{"type":"text","text":" 上託管 Maven 製品,例如核心和插件發佈。 它的權限系統與 Github 是獨立的, 限制了那些用戶(由 Jenkins LDAP 帳戶標識,與 wiki 和 JIRA 一樣)可以上傳。 這個倉庫包含 YAML 格式的 Artifactory 上傳權限定義, 以及將它們同步到 Artifactory 的工具。 "}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先決條件:在申請權限之前,需要先用 Jenkins 社區帳號登錄一次 "},{"type":"link","attrs":{"href":"https://repo.jenkins-ci.org/","title":null},"content":[{"type":"text","text":"Artifactory"}]},{"type":"text","text":" 。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要請求對製品(通常是插件)的上傳權限,需要提交一個 PR , 該 PR 需要創建與申請上傳權限相關的 YAML 文件。 筆者所提交的 PR 爲:"},{"type":"link","attrs":{"href":"https://github.com/jenkins-infra/repository-permissions-updater/pull/1107","title":null},"content":[{"type":"text","text":"Plugin: Permission for maven-snapshot-check-plugin"}]},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過查看它可以看出該 PR 增加了一個文件:permissions/plugin-maven-snapshot-check.yml ,其內容如下:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"name: \"maven-snapshot-check\"\ngithub: \"jenkinsci/maven-snapshot-check-plugin\"\npaths:\n- \"org/jenkins-ci/plugins/maven-snapshot-check\"\ndevelopers:\n- \"donhui\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在創建 PR 後,會有幫助說明以及 checklist 讓提交人對該 PR 進行檢查確認。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"等這個 PR 被審批後,插件開發者就會擁有該插件的發佈權限。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"發佈插件"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"前提"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要先確認擁有發佈該插件的權限。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Maven 要使用的 Artifactory 憑據"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"需要告訴 Maven 訪問 Artifactory 的憑據。 登錄 Artifactory ,從用戶 profile 中獲取"},{"type":"codeinline","content":[{"type":"text","text":"加密的密碼"}]},{"type":"text","text":"。 在 "},{"type":"codeinline","content":[{"type":"text","text":"~/.m2/settings.xml"}]},{"type":"text","text":" 文件配置 server 認證信息,如下所示:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"\n\n \n \n maven.jenkins-ci.org \n your_user_name_here\n your_encrypted_password_here\n \n \n\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"配置 GitHub 以接受你的 SSH key"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當執行 release 時,Maven Release Plugin 會自動往倉庫推送代碼, 所以需要"},{"type":"link","attrs":{"href":"https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/","title":null},"content":[{"type":"text","text":"配置 GitHub 以接受你的 SSH key"}]},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更多信息可以參考:"},{"type":"link","attrs":{"href":"https://help.github.com/articles/connecting-to-github-with-ssh/","title":null},"content":[{"type":"text","text":"GitHub help on SSH"}]},{"type":"text","text":" 。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"執行發佈"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當 GitHub 和 Maven 憑據配置好後, 執行一次發佈應該很簡單,只需要運行下面的命令:"}]},{"type":"codeblock","attrs":{"lang":"shell"},"content":[{"type":"text","text":"mvn release:prepare release:perform"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可能在執行發佈時會遇到 “401 Unauthorized” 或 “403 Forbidden” 之類問題, 這一般是 settings.xml 配置問題或是沒有上傳權限。 一些公共的問題處理方案可以查看:"},{"type":"link","attrs":{"href":"https://wiki.jenkins.io/display/JENKINS/Hosting+Plugins#HostingPlugins-Workingaroundcommonissues","title":null},"content":[{"type":"text","text":"HostingPlugins-Workingaroundcommonissues"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插件發佈後,8 小時內,將可以在插件更新中心看到它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"筆者所寫的 maven-snapshot-check 插件, 在插件列表頁的地址爲:"},{"type":"link","attrs":{"href":"https://plugins.jenkins.io/maven-snapshot-check","title":null},"content":[{"type":"text","text":"https://plugins.jenkins.io/maven-snapshot-check"}]},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jenkins 實例的插件管理頁面的「可選插件」選項截圖如下:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ce/cef045d4069da89a3f9487bccd5b5186.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"爲插件分類"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Jenkins "},{"type":"link","attrs":{"href":"https://plugins.jenkins.io/","title":null},"content":[{"type":"text","text":"插件列表頁面"}]},{"type":"text","text":",可以對插件進行分類顯示。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要爲插件添加一個分類,需要向 "},{"type":"link","attrs":{"href":"https://github.com/jenkins-infra/update-center2","title":null},"content":[{"type":"text","text":"jenkins-infra/update-center2"}]},{"type":"text","text":" 倉庫提交一個 PR 。 筆者所提交的 PR 爲:"},{"type":"link","attrs":{"href":"https://github.com/jenkins-infra/update-center2/pull/271","title":null},"content":[{"type":"text","text":"add maven-snapshot-check category"}]},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過查看它可以看出該 PR 在 "},{"type":"codeinline","content":[{"type":"text","text":"src/main/resources/label-definitions.properties"}]},{"type":"text","text":" 文件增加了一行,如下所示:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"maven-snapshot-check=builder"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"兩天的 Jenkins 插件開發之旅, 讓筆者瞭解了插件開發的基本知識,並在託管插件的過程中學到一些知識。 然後在週末花了幾個小時總結回顧,並將它寫成文檔。 同時也希望此文能給 Jenkins 插件開發者入門帶來一點幫助!"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"參考"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://jenkins.io/doc/developer/publishing/requesting-hosting/","title":null},"content":[{"type":"text","text":"Guide to Plugin Hosting"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://jenkins.io/doc/developer/publishing/releasing/","title":null},"content":[{"type":"text","text":"Performing a Plugin Release"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章