Skip to content

Commit ea8a70b

Browse files
authored
fix(store): 校验并追踪 API 3 requires 能力声明 (#10)
* fix(store): validate and track API 3 capability requirements * fix(ci): sync marketplace schema from the active Lithe repository
1 parent 01e6707 commit ea8a70b

7 files changed

Lines changed: 388 additions & 59 deletions

File tree

‎.github/workflows/validate.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656

5757
- name: Check the schema copy matches Lithe
5858
run: |
59-
url="https://raw.githubusercontent.com/Lithe-IDEA/Lithe-IDEA/preview/shared/contracts/plugins/v1/plugin-index.schema.json"
59+
url="https://raw.githubusercontent.com/1lck/Lithe-IDEA/preview/shared/contracts/plugins/v1/plugin-index.schema.json"
6060
status=$(curl -sS -o "$RUNNER_TEMP/upstream-schema.json" -w '%{http_code}' "$url")
6161
if [ "$status" = "404" ]; then
6262
echo "::notice::Lithe preview does not publish plugin-index.schema.json yet; skipping drift check."

‎docs/publishing.md‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
**不能**使用 `dev.lithe` 或 `dev.lithe.*`。
2727
- `vendor.signatureRequirement` 必须是 `"none"`(社区包不带 Lithe 签名)。
2828
- `version` 是 `MAJOR.MINOR.PATCH`,每次发布都必须递增,已发布的版本号不能复用。
29+
- `pluginAPIVersion: 3` 必须有非空 `requires`,逐项声明包实际使用的能力及其契约版本。
30+
例如只使用声明式构建系统的包为 `"requires": { "buildSystems": 1 }`;不要无故增加
31+
`buildProviders` 等能力。API 1/2 继续使用原有格式,不能带 `requires`。
32+
- `requires` 的键是小写字母开头、后接英文字母或数字、最长 64 个字符的能力 ID,
33+
值是正整数。索引允许未知能力 ID,由宿主能力表决定可安装性;这不表示当前宿主支持它。
2934
- 包内路径只用 `/`,不能有 `..`、绝对路径或符号链接。
3035
- 可以附带可执行文件(例如打包好的语言服务器),但它们必须在 `plugin.json` 中声明;
3136
用户安装前会看到完整的程序列表并确认。版本更新新增了程序时,用户需要重新确认。
@@ -42,6 +47,10 @@ zig-support-2.0.0-darwin-arm64.zip
4247
└── …
4348
```
4449

50+
同一插件版本的所有平台包必须使用相同的 `version`、`pluginAPIVersion` 和 `requires`。
51+
能力表按键和值比较,键的书写顺序可以不同。API 3 索引版本项必须逐项复制包清单的
52+
`requires`;不同平台需要不同能力时,应使用不同的插件版本,不能共用一个版本项。
53+
4554
Release 资产名必须以平台结尾,自动追踪才能识别:
4655

4756
| 资产名结尾 | 对应平台 |
@@ -99,6 +108,16 @@ shasum -a 256 zig-support-2.0.0-darwin-arm64.zip
99108

100109
字段说明见 [schema/plugin-index.schema.json](../schema/plugin-index.schema.json)。`homepage`、
101110
`localizedDescriptions`、`tags`、`icon` 可选;`icon` 只能是同一仓库的 raw 文件。
111+
API 3 的版本项还必须在 `pluginAPIVersion` 旁加入与包内相同的能力表,例如:
112+
113+
```json
114+
"pluginAPIVersion": 3,
115+
"requires": { "buildSystems": 1 }
116+
```
117+
118+
提高 API 等级或能力版本时发布新的插件版本,并保留最后一个旧要求的版本项,
119+
让旧宿主仍能选择可安装版本。当前 Core 对未来 API 等级(4 及以上)的索引项允许
120+
省略 `requires`,提供时仍校验能力表;这只是索引格式的前向兼容,不承诺宿主可安装。
102121

103122
2. 统一格式并本地校验(CI 要求索引使用统一格式:两格缩进,纯值列表写在一行):
104123

@@ -107,8 +126,14 @@ shasum -a 256 zig-support-2.0.0-darwin-arm64.zip
107126
node scripts/validate-index.mjs --verify-archives
108127
```
109128

110-
3. 提交 PR,按模板填写。CI 会下载每个新增的包,核对 SHA-256、包内 `plugin.json` 的
111-
`id`、`version`、`pluginAPIVersion` 和 `signatureRequirement`。维护者审查后合并。
129+
3. 提交 PR,按模板填写。CI 会下载每个新增或校验预期发生变化的包,核对 SHA-256、
130+
包内 `plugin.json` 的 `id`、`version`、`pluginAPIVersion`、`requires` 和
131+
`signatureRequirement`。即使 URL 和 SHA-256 不变,修改 ID、版本、API 等级或能力表
132+
也会重新校验;完整校验不使用基线跳过。维护者审查后合并。
133+
134+
索引与归档检查只覆盖上述发布字段、社区信任声明和现有路径检查,不替代完整的 Core
135+
清单校验或插件运行验收。安装端仍由 Core 验证能力是否与清单实际内容相符,并由宿主
136+
检查能力支持情况。没有运行这些验证时,PR 应明确标记为待验证。
112137

113138
也可以先开一个 [插件收录申请 issue](../../issues/new?template=plugin-submission.yml),由维护者帮你提 PR。
114139

@@ -118,15 +143,21 @@ shasum -a 256 zig-support-2.0.0-darwin-arm64.zip
118143

119144
1. 在你的仓库递增 `plugin.json` 的 `version`,打包,发布新的正式 Release(资产命名同上)。
120145
2. `Track plugin releases` 工作流每 6 小时扫描一次已收录插件最近 20 个 Release,
121-
把新版本写进索引(版本号、`pluginAPIVersion` 取自包内 `plugin.json`,发布日期取 Release
122-
发布时间,SHA-256 由 CI 计算),然后开一个 `chore(index): 追踪插件新版本` PR。
146+
把新版本写进索引(版本号、`pluginAPIVersion`、`requires` 取自包内 `plugin.json`,
147+
能力表按键排序写入;发布日期取 Release 发布时间,SHA-256 由 CI 计算),
148+
然后开一个 `chore(index): 追踪插件新版本` PR。
123149
3. 维护者审查合并后,Lithe 用户刷新插件市场就能看到更新。
124150

125151
想更快上线,可以在 issue 里请维护者手动触发工作流,或者自己提 PR 在 `versions` 里加一项
126152
(保持新版本在前)。
127153

128-
自动追踪会跳过并在日志中说明原因的情况:没有符合命名的 zip、包内 `plugin.json` 不匹配、
129-
多个资产声明了不同的版本号、版本号已被别的资产占用。
154+
自动追踪只收录正式 Release,继续跳过 draft 和 pre-release;预发布版本需要手工提交
155+
索引条目并接受相同的校验,不能靠调整追踪策略自动收录。Maven、Gradle 的 `0.1.0`
156+
预发布收录属于这种手工流程,条目是否存在不代表发布或运行验证已经完成。
157+
158+
自动追踪会在日志中说明归档无法收录的原因:没有符合命名的 zip、包内 `plugin.json`
159+
不匹配或缺失/畸形的能力表、多个资产声明了不同的版本号、API 等级或能力表、
160+
版本号已被别的资产占用。单个发布存在分歧时拒绝整个版本,不只保留其中一个平台包。
130161

131162
## 5. 修改信息、转移或下架
132163

‎schema/plugin-index.schema.json‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,27 @@
3939
"type": "object",
4040
"additionalProperties": false,
4141
"required": ["version", "pluginAPIVersion", "releaseDate", "downloads"],
42+
"if": { "properties": { "pluginAPIVersion": { "const": 3 } } },
43+
"then": { "required": ["requires"] },
4244
"properties": {
4345
"version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
4446
"pluginAPIVersion": { "type": "integer", "minimum": 1 },
47+
"requires": {
48+
"description": "API level 3: the package manifest's requires, including buildProviders: 1 when any buildSystems[].provider is present (own or shared language server), so hosts can tell before downloading whether they run every capability it needs. Capability IDs this contract does not define are allowed; such a version is never available.",
49+
"type": "object",
50+
"minProperties": 1,
51+
"propertyNames": { "pattern": "^[a-z][A-Za-z0-9]{0,63}$" },
52+
"additionalProperties": { "type": "integer", "minimum": 1 }
53+
},
4554
"releaseDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
4655
"downloads": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/download" } }
47-
}
56+
},
57+
"allOf": [
58+
{
59+
"if": { "properties": { "pluginAPIVersion": { "maximum": 2 } } },
60+
"then": { "not": { "required": ["requires"] } }
61+
}
62+
]
4863
},
4964
"download": {
5065
"type": "object",

‎scripts/fixtures/invalid-index-entries.json‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
{ "name": "homepage with embedded credentials", "edits": [{ "op": "set", "path": "/homepage", "value": "https://user:secret@example.com" }], "expectedCode": "plugin.index.invalid" },
2323
{ "name": "tag with whitespace", "edits": [{ "op": "set", "path": "/tags", "value": ["two words"] }], "expectedCode": "plugin.index.invalid" },
2424
{ "name": "localized description with a malformed language tag", "edits": [{ "op": "set", "path": "/localizedDescriptions", "value": { "Chinese": "Zig 语言服务器集成。" } }], "expectedCode": "plugin.index.invalid" },
25-
{ "name": "empty localized description", "edits": [{ "op": "set", "path": "/localizedDescriptions", "value": { "zh-Hans": " " } }], "expectedCode": "plugin.index.invalid" }
25+
{ "name": "empty localized description", "edits": [{ "op": "set", "path": "/localizedDescriptions", "value": { "zh-Hans": " " } }], "expectedCode": "plugin.index.invalid" },
26+
{ "name": "requires below plugin API 3", "edits": [{ "op": "set", "path": "/versions/0/requires", "value": { "languages": 1 } }], "expectedCode": "plugin.index.invalid" },
27+
{ "name": "plugin API 3 version without requires", "edits": [{ "op": "set", "path": "/versions/0/pluginAPIVersion", "value": 3 }], "expectedCode": "plugin.index.invalid" },
28+
{ "name": "capability version is not a positive integer", "edits": [{ "op": "set", "path": "/versions/0/pluginAPIVersion", "value": 3 }, { "op": "set", "path": "/versions/0/requires", "value": { "languages": 0 } }], "expectedCode": "plugin.index.invalid" }
2629
]
2730
}

0 commit comments

Comments
 (0)