ModReleaser/docs/workflow.md

138 lines
6.4 KiB
Markdown
Raw Normal View History

# 整体框架
## 数据文件
### `secrets.json`
存放 API 密钥,位于项目根目录。
```json
{
"curseforge": "<CurseForge API Token>",
"modrinth": "<Modrinth Personal Access Token>"
}
```
### `configs/{config_name}.json`
存放单个 mod 项目的配置,位于 `configs/` 目录下。文件名即为配置名,用户通过 WebUI 下拉选择。
```jsonc
{
"name": "模组名称",
"modrinth": {
"project_id": "AABBCCDD",
"version_name": "ModName v${version} for Minecraft ${mc_version_range}",
"version": "${version}-mc${mc_version}",
"loaders": ["fabric"],
"environment": "client_and_server",
"dependencies": [
{ "dependency_type": "required", "project_id": "P7dR8mSH" }
]
},
"curseforge": {
"project_id": 123456,
"version_name": "#{filename_format}",
"environment": ["Client", "Server"],
"loaders": ["fabric"],
"relations": {
"projects": []
}
},
"project_dir": "/path/to/project",
"minecraft_properties_dir": "./properties", // 目录内为 ${mc_version}.properties 文件,文件名即对应游戏版本
"project_properties_path": "./gradle.properties", // 项目版本配置文件路径
"mod_version_field": "mod_version", // 版本号在 project_properties_path 文件中的键名
"filename_format": "modname-${version}-mc${mc_version}.jar",
"source_filename_format": "modname-${version}-mc${mc_version}-sources.jar"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `name` | string | 配置文件显示名称(模组名称) |
| `modrinth` | object | Modrinth 配置 |
| `modrinth.project_id` | string | Modrinth 项目 ID8 位 base62 |
| `modrinth.version_name` | string | 版本名称模板,`${mc_version_range}` 为 `"1.19"``"1.20-1.20.2"` |
| `modrinth.version` | string | 版本号模板 |
| `modrinth.loaders` | string[] | 加载器列表 |
| `modrinth.environment` | string | 运行环境,必填。可选值:`client_and_server`、`client_only`、`server_only` 等 |
| `modrinth.dependencies` | object[] | 依赖列表,无依赖填 `[]` |
| `curseforge` | object | CurseForge 配置 |
| `curseforge.project_id` | number | CurseForge 项目 ID |
| `curseforge.version_name` | string | 版本名称模板,如 `"#{filename_format}"` |
| `curseforge.environment` | string[] | 运行环境 |
| `curseforge.loaders` | string[] | 加载器列表 |
| `curseforge.relations` | object | 关联项目,格式 `{ projects: [...] }` |
| `project_dir` | string | 项目目录绝对路径 |
| `minecraft_properties_dir` | string | 相对项目目录的 MC 版本配置目录,默认 `./properties`。目录内为 `${mc_version}.properties` 文件,文件名即为可用游戏版本 |
| `project_properties_path` | string | 相对项目目录的项目版本配置文件路径,默认 `./gradle.properties` |
| `mod_version_field` | string | 版本号在 `project_properties_path` 文件中的键名,默认 `"mod_version"` |
| `filename_format` | string | 构建产物文件名模板,用于反向解析 `${version}``${mc_version}` |
| `source_filename_format` | string | 源码 jar 文件名模板,用于正向生成文件名 |
> **递归解析规则**:所有含占位符的模板字符串,正向 format 或反向解析后,若结果仍包含占位符,则需继续解析,直至结果中不再有占位符为止。
>
> - `#{...}` — 引用占位符,如 `#{filename_format}` 表示此处将引用解析后的值
> - `${...}` — 模板变量,由运行时填入实际值,如 `${version}`、`${mc_version}`
## 运行时流程
### 1. 启动
- 启动 Next.js 开发服务器
- 后端读取 `configs/` 目录,列出所有可用配置文件
- 后端读取 `secrets.json`,加载两个平台的 API 密钥到内存
### 2. 选择配置
- 前端 ConfigSelector 下拉框展示所有配置(按 `name` 显示)
- 用户选择一个配置后,前端请求后端解析项目信息
### 3. 解析项目
后端收到选中配置后:
1. 读取 `{project_dir}/{project_properties_path}`,提取 `mod_version_field` 对应的值 → `version`
2. 扫描 `{project_dir}/{minecraft_properties_dir}/` 目录,获取所有 `${mc_version}.properties` 文件名 → `mc_version[]`
3. 遍历每个 `mc_version`
-`version``mc_version` 填入 `filename_format` 模板,生成构建产物文件名
-`version``mc_version` 填入 `source_filename_format` 模板,生成源码文件名
- 检查 `{project_dir}/build/libs/` 下是否存在对应文件
4. 将所有匹配结果返回前端,由 VersionTable 展示MC 版本 | 构建产物 | 源码)
### 4. 版本确认与发布
#### 第一页:版本选择
1. 用户点击 `[一键发布]`,弹出 PublishModal
2. 前端请求两个平台的已有版本列表:
- Modrinth`GET /project/{id}/version`
- CurseForge通过对应 API 获取
3. 后端比对已有版本与待发布版本(按 `version` 模板生成的值匹配)
4. 前端左右两栏展示(待发布版本与已有版本合并后,按 `mod_version` 降序、`mc_version` 降序排列):
- 顶部绿色行 = 待发布版本,复选框默认勾选
- 下方灰色行 = 已有版本,复选框禁用
- 已存在的待发布版本显示为已有版本颜色,复选框禁用
5. 用户调整勾选后点击"下一步"
#### 第二页:发布设置
- 用户填写 changelogMarkdownCode / Preview 切换)
- 选择 version_type默认 `release`
- 点击"确认发布";可点击"上一步"返回修改
### 5. 执行发布
1. 前端调用 `trpc.release.publish.useMutation()` 发起发布
2. 前端通过 `trpc.release.progress.useSubscription()` 监听进度,实时更新进度条
3. 进度条格式:`{平台图标} 平台名: [======== ] 0 / N`,仅显示有勾选任务的平台
4. 单个平台内按 MC 版本顺序逐个提交,**不可并行**;两个平台之间可以并行执行
5. 每个版本的发布流程:
- 解析模板:用 `version``mc_version` 填入各平台 `version_name`、`version` 模板(含递归解析)
- Modrinth构造 multipart/form-data 请求,含 `data` JSON + 构建产物文件 + 源码文件
- CurseForge构造 multipart/form-data 请求,含 `metadata` JSON + 文件
- 通过 tRPC subscription 推送进度更新
6. **任一请求失败则取消当前平台的后续所有任务**,不影响另一个平台
7. 全部完成或失败后,弹出结果 Modal 显示最终状态(成功数 / 失败数)