Skip to content

Commit c40c587

Browse files
authored
docs: add plugin dependencies docs (#467)
### What this PR does? 新增插件依赖开发文档 ```release-note None ```
1 parent 86b9b26 commit c40c587

File tree

6 files changed

+670
-4
lines changed

6 files changed

+670
-4
lines changed
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
---
2+
title: 依赖其他插件
3+
description: 介绍如何在 Halo 插件中声明和管理插件依赖关系,及提供插件依赖的项目结构示例。
4+
---
5+
6+
在插件开发过程中,依赖管理是确保插件间协作和功能扩展的关键。
7+
通过正确的依赖声明,插件能够依赖其他插件提供的功能,避免重复实现或资源浪费。
8+
Halo 插件框架允许开发者通过 `plugin.yaml` 文件中的 `pluginDependencies` 字段来声明插件的依赖关系,从而确保插件在运行时能够正确加载所需的其他插件。
9+
10+
本节将介绍如何在 `plugin.yaml` 文件中声明插件依赖,包括强制依赖、可选依赖及其版本管理规则。我们还将讨论依赖关系如何影响插件的加载顺序及运行时行为。
11+
12+
## 插件依赖管理
13+
14+
Halo 插件系统支持在 `plugin.yaml` 文件中通过 `pluginDependencies` 字段声明插件依赖关系。这些依赖关系可以是强制性的,也可以是可选的。
15+
依赖声明的规则非常灵活,能够满足不同的插件需求。
16+
17+
以下是如何在 `plugin.yaml` 文件中声明依赖的具体方式。
18+
19+
### 依赖声明方式
20+
21+
依赖关系通过 `pluginDependencies` 字段声明,采用 YAML 列表格式。每个依赖项包含插件名称和可选的版本号。
22+
23+
> 以下示例中将省略 `plugin.yaml` 文件中的其他字段,仅展示 `pluginDependencies` 字段。
24+
>
25+
> 下列提到的**插件名称**指的是 `plugin.yaml` 文件中的 `metadata.name` 字段。
26+
27+
以下是几种常见的依赖声明方式:
28+
29+
- **固定版本依赖**:如果插件依赖于另一个插件的特定版本,可以指定精确版本号。例如,`pluginA` 依赖于 `pluginB` 的版本 1.0.0:
30+
31+
```yaml
32+
# 省略其他字段
33+
spec:
34+
pluginDependencies:
35+
36+
```
37+
38+
- **版本范围依赖**:如果插件对版本有一定的要求,可以指定版本范围。通过 `>=`(大于等于)和 `<`(小于)等符号,可以表示插件版本的区间。例如,`pluginA` 依赖于版本在 1.0.0 到 2.0.0 之间(不包括 2.0.0):
39+
40+
```yaml
41+
spec:
42+
pluginDependencies:
43+
- pluginB@>=1.0.0 & <2.0.0
44+
```
45+
46+
- **可选依赖**:某些情况下,插件的依赖是可选的,即使依赖未被满足,插件仍然可以加载。通过在插件名称后加上 `?` 来声明可选依赖。例如,`pluginA` 可选依赖于 `pluginB` 的 1.0 版本:
47+
48+
```yaml
49+
spec:
50+
pluginDependencies:
51+
52+
```
53+
54+
- **多个依赖声明**:一个插件可能依赖多个插件,所有依赖可以在同一列表中列出,使用逗号分隔。例如,`pluginA` 依赖于 `pluginB` 的 1.0.0 到 2.0.0 版本区间,以及 `pluginC` 的 0.0.1 到 0.1.0 版本区间:
55+
56+
```yaml
57+
spec:
58+
pluginDependencies:
59+
- pluginB@>=1.0.0 & <=2.0.0
60+
- pluginC@>=0.0.1 & <=0.1.0
61+
```
62+
63+
### 依赖加载逻辑
64+
65+
在 Halo 插件系统中,插件的依赖关系会影响其加载顺序和运行时行为。具体来说,插件的加载只有在其所有强制依赖都得到满足时才会进行。
66+
67+
以下是依赖关系加载的关键点:
68+
69+
- **强制依赖**:插件的强制依赖必须在插件加载前完成。只有当所有指定的强制依赖被满足(即对应的插件及其指定版本存在并加载完成)时,插件才会被加载。否则,插件无法被启动。
70+
71+
- **可选依赖**:插件可以依赖某些插件,但这些依赖项是可选的。即便可选依赖没有被满足,插件仍会被加载并运行。在某些情况下,如果缺少某个可选插件的依赖,插件的某些功能可能会受到限制或无法启用,但插件本身不会失败。
72+
73+
- **版本匹配**:当插件依赖于其他插件的特定版本时,Halo 插件框架会根据声明的版本范围匹配所需的插件。如果版本范围要求匹配的插件版本不可用,插件将无法加载。如果插件指定了多个版本范围,框架会选择最适合的版本。如果多个版本都能满足要求,开发者需要确保没有版本冲突,以避免不一致的行为。
74+
75+
通过合理的依赖声明,插件的加载和运行将更加顺畅,能够确保所有必需的功能模块按预期协同工作。
76+
77+
### 依赖声明注意事项
78+
79+
- **版本管理**:在声明版本时,推荐使用明确的版本号或版本范围,避免使用过于宽松的版本要求(如 `pluginB@*`),以确保插件在不同环境中一致性地运行。
80+
- **依赖冲突**:多个插件可能依赖于不同版本的同一插件,这可能导致版本冲突。为避免这种情况,开发者应该尽量保持插件版本的兼容性,必要时在 `plugin.yaml` 文件中使用具体的版本号范围进行严格控制。
81+
- **插件间的依赖层级**:插件可能依赖于其他插件,而这些插件又可能依赖于其他插件。建议开发者清晰地管理依赖链,避免过于复杂的依赖层级。合理规划插件之间的依赖关系有助于减少维护难度和潜在的运行时问题。
82+
83+
通过以上方式,开发者可以灵活地声明和管理插件的依赖关系,确保插件的高效运行和模块化扩展。
84+
85+
## 提供依赖的插件项目结构
86+
87+
为了确保插件的可维护性、模块化和可扩展性,设计合理的项目结构是非常重要的。使用 Gradle 作为项目管理工具时,可以通过规范的目录结构来清晰地管理插件的依赖和代码。特别是当插件需要提供类型共享或者支持多个插件互相依赖时,合理的项目结构能够大大提高开发效率和代码复用性。
88+
89+
本节将介绍如何使用 Gradle 构建插件项目,并提供一些最佳实践,以确保插件项目结构清晰、模块化,**并便于其他插件进行引用**。
90+
91+
### 推荐项目结构 {#project-structure}
92+
93+
在 Gradle 项目中,推荐使用标准的项目结构,以便于插件代码的管理和依赖的声明。以下是一个典型的 Halo 插件项目结构示例:
94+
95+
```plaintext
96+
my-halo-plugin/
97+
├── build.gradle # 项目的构建配置
98+
├── settings.gradle # Gradle 设置文件
99+
├── src/
100+
│ ├── main/
101+
│ │ ├── java/ # Java 源代码目录
102+
│ │ └── resources/ # 插件资源文件目录
103+
│ │ └── plugin.yaml # 插件元数据配置文件
104+
│ └── test/ # 测试代码目录
105+
└── README.md # 项目说明文件,提供项目的介绍、安装和使用文档
106+
```
107+
108+
参考 [插件项目结构](../basics/structure.md) 了解更多关于 Halo 插件项目结构的信息。
109+
110+
### 类型定义文件的组织
111+
112+
当插件需要为其他插件提供类型时,项目结构需要进一步优化。特别是在使用 Gradle 构建时,可以将共享的类型和接口定义放置到专门的模块中,使其成为一个独立的依赖模块,供其他插件使用。
113+
114+
一个常见的做法是创建一个独立的 `api` 模块,专门存放所有的类型定义(例如接口、抽象类等)。这样,其他插件就可以通过引用这个 `api` 模块来共享这些类型,而不需要直接依赖实现模块。
115+
116+
以下是一个优化后的项目结构示例,包含 `api` 和 `plugin` 模块:
117+
118+
```plaintext
119+
my-halo-plugin/
120+
├── build.gradle # 根项目构建配置文件
121+
├── settings.gradle # 设置文件,声明子模块
122+
├── api/ # 存放 API 类型的模块
123+
│ ├── build.gradle # API 模块的构建配置
124+
│ ├── src/
125+
│ │ ├── main/
126+
│ │ │ └── java/ # API 类型定义文件
127+
│ │ └── resources/ # API 模块的资源文件(如果有的话)
128+
│ └── README.md # API 模块说明文档
129+
├── plugin/ # 插件实现模块
130+
│ ├── build.gradle # 插件实现模块的构建配置
131+
│ ├── src/
132+
│ │ ├── main/
133+
│ │ │ ├── java/ # 插件实现代码
134+
│ │ │ └── resources/ # 插件资源文件,包括 plugin.yaml
135+
│ │ └── test/ # 插件的测试代码
136+
│ └── README.md # 插件模块说明文档
137+
└── README.md # 项目说明文件
138+
```
139+
140+
#### API 模块构建配置
141+
142+
`api` 模块仅包含接口和类型定义,没有具体的实现逻辑。你可以通过 Gradle 将这个模块发布到 Maven 仓库,让其他插件能够依赖它。
143+
144+
`api/build.gradle` 配置如下:
145+
146+
```gradle
147+
plugins {
148+
id 'java-library'
149+
id 'maven-publish'
150+
}
151+
152+
group = 'com.example'
153+
version = '1.0.0'
154+
155+
repositories {
156+
mavenCentral() // 使用 Maven Central 仓库
157+
}
158+
159+
dependencies {
160+
// API 模块可能需要的一些依赖
161+
// 例如:如果需要一些常用的库
162+
}
163+
164+
publishing {
165+
publications {
166+
mavenJava(MavenPublication) {
167+
from components.java // 发布 Java 项目组件
168+
artifactId = 'my-halo-api' // API 模块的 artifactId
169+
version = project.hasProperty('version') ? project.property('version') : 'unspecified'
170+
171+
// pom 额外信息,这是可选的
172+
pom {
173+
// POM 中的插件信息,一般为插件的 displayName
174+
name = 'My Halo Plugin'
175+
// POM 中的插件描述
176+
description = 'A sample plugin for Halo'
177+
// 插件的官网 URL
178+
url = 'https://example.com/my-halo-plugin'
179+
180+
licenses {
181+
license {
182+
// 插件的开源许可协议
183+
name = 'Apache License 2.0'
184+
// 许可协议的 URL
185+
url = 'https://opensource.org/licenses/Apache-2.0'
186+
}
187+
}
188+
189+
developers {
190+
developer {
191+
id = 'guqing' // 开发者的 ID
192+
name = 'guqing' // 开发者姓名
193+
email = '[email protected]' // 开发者邮箱
194+
}
195+
}
196+
197+
scm {
198+
// Git 仓库连接
199+
connection = 'scm:git:[email protected]:halo-sigs/my-halo-plugin.git'
200+
// Git 仓库连接,用于开发者
201+
developerConnection = 'scm:git:[email protected]:halo-sigs/my-halo-plugin.git'
202+
// Git 仓库 URL
203+
url = 'https://github.com/halo-sigs/my-halo-plugin'
204+
}
205+
}
206+
}
207+
}
208+
repositories {
209+
maven {
210+
// 以 -SNAPSHOT 结尾的版本发布到快照仓库,否则发布到正式仓库
211+
url = version.endsWith('-SNAPSHOT') ? 'https://s01.oss.sonatype.org/content/repositories/snapshots/' :
212+
'https://s01.oss.sonatype.org/content/repositories/releases/'
213+
credentials {
214+
// 从 gradle.properties 中读取 或者从环境变量中读取
215+
username = project.findProperty("ossr.user") ?: System.getenv("OSSR_USERNAME")
216+
password = project.findProperty("ossr.password") ?: System.getenv("OSSR_PASSWORD")
217+
}
218+
}
219+
}
220+
}
221+
```
222+
223+
API 模块的代码应该是接口或抽象类,用于插件之间共享。例如:
224+
225+
```java
226+
// src/main/java/com/example/api/MyApi.java
227+
package com.example.api;
228+
229+
public interface MyApi {
230+
void doSomething();
231+
}
232+
```
233+
234+
当你完成上述配置后,可以通过 Gradle 发布 API 模块到 Maven 仓库。以下是发布的步骤:
235+
236+
1. Maven 现已支持通过 GiHub 账号注册并发布包,你可以在 [Maven Central](https://central.sonatype.org/register/central-portal) 注册账号并获取凭证。
237+
2. 得到你可以通过在 `~/.gradle/gradle.properties` 文件中添加以下内容来配置 Maven 仓库的凭证:
238+
239+
```properties
240+
ossr.user=your-username
241+
ossr.password=your-password
242+
```
243+
244+
3. 发布 API 模块到 Maven 仓库:
245+
246+
```bash
247+
./gradlew :api:publish
248+
```
249+
250+
除了手动发布到 Maven 仓库,你也可以使用 GitHub Actions 等 CI/CD 工具自动发布 API 模块,以避免出错。
251+
252+
以下是一个 GitHub Actions 的示例配置:
253+
254+
```yaml
255+
# .github/workflows/publish-api.yml
256+
name: Publish plugin API module to Maven
257+
258+
on:
259+
release:
260+
types: [published]
261+
262+
jobs:
263+
build:
264+
runs-on: ubuntu-latest
265+
266+
steps:
267+
- name: Checkout code
268+
uses: actions/checkout@v4
269+
with:
270+
fetch-depth: 0
271+
272+
- name: Set up JDK 17
273+
uses: actions/setup-java@v4
274+
with:
275+
java-version: '17'
276+
distribution: 'temurin'
277+
278+
- name: Cache Gradle packages
279+
uses: actions/cache@v4
280+
with:
281+
path: |
282+
~/.gradle/caches
283+
~/.gradle/wrapper
284+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
285+
restore-keys: |
286+
${{ runner.os }}-gradle-
287+
288+
- name: Extract version from GitHub tag
289+
id: extract_version
290+
run: |
291+
tag_name=${{ github.event.release.tag_name }}
292+
VERSION=${tag_name#v}
293+
echo "Extracted Version: $VERSION"
294+
echo "VERSION=$VERSION" >> $GITHUB_ENV
295+
296+
- name: Build with Gradle
297+
run: ./gradlew clean build -Pversion=${{ env.VERSION }}
298+
299+
- name: Publish to Maven
300+
env:
301+
OSSR_USERNAME: ${{ secrets.MAVEN_USERNAME }}
302+
OSSR_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
303+
run: ./gradlew :api:publish -Pversion=${{ env.VERSION }}
304+
```
305+
306+
它会在创建新的 Release 时自动发布 API 模块到 Maven 仓库。
307+
308+
你需要在仓库的 `Settings` -> `Secrets and variables` -> `Actions` -> `New Repository secret` 中添加 `MAVEN_USERNAME` 和 `MAVEN_PASSWORD` 两个密钥,分别对应 Maven 仓库的用户名和密码。
309+
310+
#### plugin 模块构建配置
311+
312+
`plugin` 模块是插件的具体实现,它依赖于 `api` 模块,并包含插件的具体功能和业务逻辑。
313+
314+
它的结构与 [推荐项目结构](#project-structure) 中的 `plugin` 模块基于一致,但需要在 `build.gradle` 中声明对 `api` 模块的依赖:
315+
316+
需要注意的是 `run.halo.plugin.devtools` Gradle 插件应该始终在 `plugin` 模块中引入,不能放在项目根目录的 `build.gradle` 或 `api` 模块的 `build.gradle` 中,以确保插件在开发模式下能够正确运行。
317+
318+
## 版本管理
319+
320+
API 模块和插件模块的版本应该保持一致,以确保插件在不同环境中的一致性。
321+
322+
版本的发布应该遵循 [插件语义化版本规范](../publish.md#version-control),以确保插件的版本号能够清晰地表达插件的变化和向后兼容性。

docs/developer-guide/plugin/publish.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ description: 了解如何与我们的社区分享你的插件
77

88
## 创建 Release
99

10-
当你完成了你的插件并进行充分测试后,就可以在 GitHub 上创建新的 Release,其中版本规范可以参考[版本控制](#版本控制)
10+
当你完成了你的插件并进行充分测试后,就可以在 GitHub 上创建新的 Release,其中版本规范可以参考[版本控制](#version-control)
1111

1212
## 自动构建
1313

@@ -145,7 +145,7 @@ Halo 不提供对第三方应用程序的支持。作为插件的开发者,你
145145
当提交插件到 [awesome-halo](https://github.com/halo-sigs/awesome-halo) 时,
146146
你需要添加服务支持联系人(Support contact)。这可以是用户可以联系的电子邮件地址,也可以是网站或帮助中心的链接。
147147
148-
## 版本控制
148+
## 版本控制 {#version-control}
149149
150150
为了保持 Halo 生态系统的健康、可靠和安全,每次你对自己拥有的插件进行重大更新时,我们建议在遵循 [semantic versioning spec](http://semver.org/) 的基础上,
151151
发布新版本。遵循语义版本控制规范有助于其他依赖你代码的开发人员了解给定版本的更改程度,并在必要时调整自己的代码。

sidebars.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,17 @@ module.exports = {
289289
},
290290
]
291291
},
292+
{
293+
type: "category",
294+
label: "与其他插件交互",
295+
link: {
296+
type: "doc",
297+
id: "developer-guide/plugin/interaction/dependency",
298+
},
299+
items: [
300+
"developer-guide/plugin/interaction/dependency",
301+
]
302+
},
292303
{
293304
type: "category",
294305
label: "安全和权限管理",

0 commit comments

Comments
 (0)