457 lines
12 KiB
Markdown
457 lines
12 KiB
Markdown
|
|
# API 文档:003-03 部署操作
|
|||
|
|
|
|||
|
|
## 元数据
|
|||
|
|
|
|||
|
|
- **需求编号**: 003-03
|
|||
|
|
- **需求名称**: 部署操作
|
|||
|
|
- **创建时间**: 2026-02-06
|
|||
|
|
- **创建人**: AI Assistant
|
|||
|
|
- **版本号**: v1.0.0
|
|||
|
|
- **状态**: 已完成
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## API 概述
|
|||
|
|
|
|||
|
|
部署操作 API 提供通用的 ZIP 部署服务,支持字节数组格式的 ZIP 文件部署、同步轮询、状态查询和取消部署功能。该服务与 003-02 的元数据类型定义功能完全解耦,通过通用字节流接口接收 ZIP 数据。
|
|||
|
|
|
|||
|
|
### 核心功能
|
|||
|
|
1. **部署 ZIP 包**: 接收 ZIP 文件进行元数据部署
|
|||
|
|
2. **同步轮询**: 后端轮询直到部署完成(成功或失败)
|
|||
|
|
3. **状态查询**: 通过 deployId 查询部署状态
|
|||
|
|
4. **取消部署**: 取消正在进行的部署操作
|
|||
|
|
|
|||
|
|
### 技术特点
|
|||
|
|
- **通用字节流接口**: Service 层接收 `byte[]` 格式的 ZIP 数据
|
|||
|
|
- **文件上传支持**: 支持最大 50MB 的 ZIP 文件上传
|
|||
|
|
- **同步轮询机制**: 最多轮询 60 次,每 5 秒检查一次状态
|
|||
|
|
- **异步日志记录**: 使用 Spring @Async 异步记录部署历史
|
|||
|
|
- **完整错误码体系**: 定义 6 个标准错误码
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 接口列表
|
|||
|
|
|
|||
|
|
### 1. 部署 ZIP 包
|
|||
|
|
|
|||
|
|
**功能描述**: 接收 ZIP 文件进行元数据部署,返回部署 ID。
|
|||
|
|
|
|||
|
|
**请求方式**: POST
|
|||
|
|
|
|||
|
|
**请求路径**: `/salesforce/metadata/deploy`
|
|||
|
|
|
|||
|
|
**权限要求**: `salesforce:metadata:deploy`
|
|||
|
|
|
|||
|
|
#### 请求参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|--------|------|------|------|
|
|||
|
|
| file | MultipartFile | 是 | ZIP 文件,最大 50MB |
|
|||
|
|
| deployOptionsJson | String | 否 | 部署选项 JSON 字符串 |
|
|||
|
|
|
|||
|
|
#### DeployOptions 字段说明
|
|||
|
|
|
|||
|
|
| 字段名 | 类型 | 默认值 | 说明 |
|
|||
|
|
|--------|------|--------|------|
|
|||
|
|
| allowMissingFiles | boolean | false | 是否允许缺少文件 |
|
|||
|
|
| autoUpdatePackage | boolean | false | 是否自动更新包 |
|
|||
|
|
| checkOnly | boolean | false | 是否只检查不部署 |
|
|||
|
|
| ignoreWarnings | boolean | false | 是否忽略警告 |
|
|||
|
|
| performRetrieve | boolean | false | 是否执行检索 |
|
|||
|
|
| purgeOnDelete | boolean | false | 删除时是否清除 |
|
|||
|
|
| rollbackOnError | boolean | true | 出错时是否回滚 |
|
|||
|
|
| testLevel | String | null | 测试级别(NoTestRun, RunSpecifiedTests, RunLocalTests, RunAllTestsInOrg) |
|
|||
|
|
| runTests | String[] | null | 指定要运行的测试类 |
|
|||
|
|
| singlePackage | boolean | true | 是否为单个包 |
|
|||
|
|
| validateOnly | boolean | false | 是否仅验证 |
|
|||
|
|
|
|||
|
|
#### 响应参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| code | int | 状态码(200 成功,其他失败) |
|
|||
|
|
| msg | String | 提示信息 |
|
|||
|
|
| data | Object | 部署结果 |
|
|||
|
|
|
|||
|
|
#### data 字段说明
|
|||
|
|
|
|||
|
|
| 字段名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| deployId | String | 部署 ID |
|
|||
|
|
|
|||
|
|
#### 成功示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"deployId": "0Afxx0000004M5sCAE"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 失败示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"msg": "部署失败: 文件格式错误,请上传 ZIP 文件"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 错误码
|
|||
|
|
|
|||
|
|
- 500: 部署失败
|
|||
|
|
- 500: 文件格式错误(非 ZIP 文件)
|
|||
|
|
- 500: 文件大小超过 50MB 限制
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 检查部署状态
|
|||
|
|
|
|||
|
|
**功能描述**: 通过 deployId 查询当前部署状态。
|
|||
|
|
|
|||
|
|
**请求方式**: GET
|
|||
|
|
|
|||
|
|
**请求路径**: `/salesforce/metadata/deploy/status/{deployId}`
|
|||
|
|
|
|||
|
|
**权限要求**: `salesforce:metadata:deploy:query`
|
|||
|
|
|
|||
|
|
#### 请求参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|--------|------|------|------|
|
|||
|
|
| deployId | String | 是 | 部署 ID(路径参数) |
|
|||
|
|
|
|||
|
|
#### 响应参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| code | int | 状态码(200 成功,其他失败) |
|
|||
|
|
| msg | String | 提示信息 |
|
|||
|
|
| data | Object | 部署状态结果 |
|
|||
|
|
|
|||
|
|
#### data 字段说明(DeployResultVo)
|
|||
|
|
|
|||
|
|
| 字段名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| success | boolean | 是否成功 |
|
|||
|
|
| id | String | 部署 ID |
|
|||
|
|
| status | String | 部署状态(Queued, InProgress, Succeeded, Failed, Canceled) |
|
|||
|
|
| numberComponentErrors | int | 组件错误数 |
|
|||
|
|
| numberComponentsDeployed | int | 已部署组件数 |
|
|||
|
|
| numberComponentsTotal | int | 总组件数 |
|
|||
|
|
| numberTestErrors | int | 测试错误数 |
|
|||
|
|
| numberTestsCompleted | int | 已完成测试数 |
|
|||
|
|
| numberTestsTotal | int | 总测试数 |
|
|||
|
|
| errorMessage | String | 错误消息 |
|
|||
|
|
| messages | List<DeployMessageVo> | 部署消息列表 |
|
|||
|
|
|
|||
|
|
#### DeployMessageVo 字段说明
|
|||
|
|
|
|||
|
|
| 字段名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| changed | boolean | 是否已更改 |
|
|||
|
|
| columnNumber | int | 列号 |
|
|||
|
|
| componentType | String | 组件类型 |
|
|||
|
|
| fileName | String | 文件名 |
|
|||
|
|
| fullName | String | 完整名称 |
|
|||
|
|
| lineNumber | int | 行号 |
|
|||
|
|
| problem | String | 问题描述 |
|
|||
|
|
| success | boolean | 是否成功 |
|
|||
|
|
|
|||
|
|
#### 成功示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"success": true,
|
|||
|
|
"id": "0Afxx0000004M5sCAE",
|
|||
|
|
"status": "Succeeded",
|
|||
|
|
"numberComponentErrors": 0,
|
|||
|
|
"numberComponentsDeployed": 5,
|
|||
|
|
"numberComponentsTotal": 5,
|
|||
|
|
"numberTestErrors": 0,
|
|||
|
|
"numberTestsCompleted": 10,
|
|||
|
|
"numberTestsTotal": 10,
|
|||
|
|
"errorMessage": null,
|
|||
|
|
"messages": [
|
|||
|
|
{
|
|||
|
|
"changed": true,
|
|||
|
|
"columnNumber": 0,
|
|||
|
|
"componentType": "CustomObject",
|
|||
|
|
"fileName": "objects/Account.object",
|
|||
|
|
"fullName": "Account",
|
|||
|
|
"lineNumber": 0,
|
|||
|
|
"problem": null,
|
|||
|
|
"success": true
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 失败示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"msg": "状态查询失败: 部署 ID 不存在"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 错误码
|
|||
|
|
|
|||
|
|
- 500: 状态查询失败
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 同步轮询部署状态
|
|||
|
|
|
|||
|
|
**功能描述**: 后端轮询直到部署完成(成功或失败),最多轮询 60 次,每 5 秒一次,5 分钟超时。
|
|||
|
|
|
|||
|
|
**请求方式**: GET
|
|||
|
|
|
|||
|
|
**请求路径**: `/salesforce/metadata/deploy/poll/{deployId}`
|
|||
|
|
|
|||
|
|
**权限要求**: `salesforce:metadata:deploy:query`
|
|||
|
|
|
|||
|
|
#### 请求参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|--------|------|------|------|
|
|||
|
|
| deployId | String | 是 | 部署 ID(路径参数) |
|
|||
|
|
|
|||
|
|
#### 响应参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| code | int | 状态码(200 成功,其他失败) |
|
|||
|
|
| msg | String | 提示信息 |
|
|||
|
|
| data | Object | 部署结果(DeployResultVo) |
|
|||
|
|
|
|||
|
|
#### data 字段说明
|
|||
|
|
|
|||
|
|
同"检查部署状态"接口的 data 字段。
|
|||
|
|
|
|||
|
|
#### 成功示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"success": true,
|
|||
|
|
"id": "0Afxx0000004M5sCAE",
|
|||
|
|
"status": "Succeeded",
|
|||
|
|
"numberComponentErrors": 0,
|
|||
|
|
"numberComponentsDeployed": 5,
|
|||
|
|
"numberComponentsTotal": 5,
|
|||
|
|
"numberTestErrors": 0,
|
|||
|
|
"numberTestsCompleted": 10,
|
|||
|
|
"numberTestsTotal": 10,
|
|||
|
|
"errorMessage": null,
|
|||
|
|
"messages": []
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 失败示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"msg": "部署超时(超过5分钟)"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 错误码
|
|||
|
|
|
|||
|
|
- 500: 轮询被中断
|
|||
|
|
- 500: 部署超时(超过5分钟)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. 取消部署
|
|||
|
|
|
|||
|
|
**功能描述**: 取消正在进行的部署操作。
|
|||
|
|
|
|||
|
|
**请求方式**: POST
|
|||
|
|
|
|||
|
|
**请求路径**: `/salesforce/metadata/deploy/cancel/{deployId}`
|
|||
|
|
|
|||
|
|
**权限要求**: `salesforce:metadata:deploy:cancel`
|
|||
|
|
|
|||
|
|
#### 请求参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 必填 | 说明 |
|
|||
|
|
|--------|------|------|------|
|
|||
|
|
| deployId | String | 是 | 部署 ID(路径参数) |
|
|||
|
|
|
|||
|
|
#### 响应参数
|
|||
|
|
|
|||
|
|
| 参数名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| code | int | 状态码(200 成功,其他失败) |
|
|||
|
|
| msg | String | 提示信息 |
|
|||
|
|
| data | Object | 取消结果 |
|
|||
|
|
|
|||
|
|
#### data 字段说明
|
|||
|
|
|
|||
|
|
| 字段名 | 类型 | 说明 |
|
|||
|
|
|--------|------|------|
|
|||
|
|
| success | boolean | 是否成功取消 |
|
|||
|
|
|
|||
|
|
#### 成功示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
"success": true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 失败示例
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 500,
|
|||
|
|
"msg": "取消部署失败: 部署已完成或已取消"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 错误码
|
|||
|
|
|
|||
|
|
- 500: 取消部署失败
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 错误码
|
|||
|
|
|
|||
|
|
### 业务错误码
|
|||
|
|
|
|||
|
|
| 错误码 | 错误信息 | 说明 | 处理建议 |
|
|||
|
|
|--------|----------|------|----------|
|
|||
|
|
| METADATA_DEPLOY_001 | 部署失败 | 部署过程中发生错误 | 检查 ZIP 文件内容和部署选项 |
|
|||
|
|
| METADATA_DEPLOY_002 | 状态查询失败 | 查询部署状态时发生错误 | 检查 deployId 是否正确 |
|
|||
|
|
| METADATA_DEPLOY_003 | 轮询被中断 | 同步轮询过程中被中断 | 检查线程状态,重新发起轮询 |
|
|||
|
|
| METADATA_DEPLOY_004 | 取消部署失败 | 取消部署时发生错误 | 检查部署状态是否可取消 |
|
|||
|
|
| METADATA_DEPLOY_005 | 部署超时(超过5分钟) | 同步轮询超过 5 分钟 | 检查 Salesforce 服务状态,稍后重试 |
|
|||
|
|
| METADATA_DEPLOY_006 | 文件格式错误(非ZIP文件) | 上传的文件不是 ZIP 格式 | 请上传 ZIP 格式的文件 |
|
|||
|
|
|
|||
|
|
### HTTP 状态码
|
|||
|
|
|
|||
|
|
| 状态码 | 说明 | 处理建议 |
|
|||
|
|
|--------|------|----------|
|
|||
|
|
| 200 | 请求成功 | - |
|
|||
|
|
| 401 | 未授权 | 检查用户权限 |
|
|||
|
|
| 403 | 禁止访问 | 检查用户角色权限 |
|
|||
|
|
| 404 | 资源不存在 | 检查请求路径和参数 |
|
|||
|
|
| 500 | 服务器内部错误 | 查看错误日志,联系管理员 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 部署状态说明
|
|||
|
|
|
|||
|
|
| 状态 | 说明 | 是否终态 |
|
|||
|
|
|------|------|----------|
|
|||
|
|
| Queued | 已排队,等待执行 | 否 |
|
|||
|
|
| InProgress | 正在进行中 | 否 |
|
|||
|
|
| Succeeded | 部署成功 | 是 |
|
|||
|
|
| Failed | 部署失败 | 是 |
|
|||
|
|
| Canceled | 已取消 | 是 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 使用示例
|
|||
|
|
|
|||
|
|
### 场景 1:部署 ZIP 包并轮询结果
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 1. 部署 ZIP 包
|
|||
|
|
MultipartFile zipFile = ...; // 获取 ZIP 文件
|
|||
|
|
String deployOptionsJson = "{\"rollbackOnError\":true,\"testLevel\":\"RunLocalTests\"}";
|
|||
|
|
AjaxResult result = deployController.deploy(zipFile, deployOptionsJson);
|
|||
|
|
String deployId = (String) ((Map) result.get("data")).get("deployId");
|
|||
|
|
|
|||
|
|
// 2. 同步轮询直到部署完成
|
|||
|
|
AjaxResult pollResult = deployController.pollStatus(deployId);
|
|||
|
|
DeployResultVo deployResult = (DeployResultVo) pollResult.get("data");
|
|||
|
|
|
|||
|
|
// 3. 处理结果
|
|||
|
|
if (deployResult.isSuccess()) {
|
|||
|
|
System.out.println("部署成功!");
|
|||
|
|
} else {
|
|||
|
|
System.out.println("部署失败:" + deployResult.getErrorMessage());
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 场景 2:查询部署状态
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 查询部署状态
|
|||
|
|
String deployId = "0Afxx0000004M5sCAE";
|
|||
|
|
AjaxResult result = deployController.checkStatus(deployId);
|
|||
|
|
DeployResultVo deployResult = (DeployResultVo) result.get("data");
|
|||
|
|
|
|||
|
|
System.out.println("部署状态:" + deployResult.getStatus());
|
|||
|
|
System.out.println("已部署组件数:" + deployResult.getNumberComponentsDeployed());
|
|||
|
|
System.out.println("总组件数:" + deployResult.getNumberComponentsTotal());
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 场景 3:取消部署
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
// 取消部署
|
|||
|
|
String deployId = "0Afxx0000004M5sCAE";
|
|||
|
|
AjaxResult result = deployController.cancelDeploy(deployId);
|
|||
|
|
boolean success = (Boolean) ((Map) result.get("data")).get("success");
|
|||
|
|
|
|||
|
|
if (success) {
|
|||
|
|
System.out.println("取消部署成功!");
|
|||
|
|
} else {
|
|||
|
|
System.out.println("取消部署失败!");
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. **文件大小限制**: ZIP 文件大小不能超过 50MB,否则会导致内存溢出。
|
|||
|
|
|
|||
|
|
2. **同步轮询超时**: 同步轮询最多持续 5 分钟(60 次,每 5 秒一次),超时后会抛出异常。
|
|||
|
|
|
|||
|
|
3. **部署状态**: 部署状态包括 Queued、InProgress、Succeeded、Failed、Canceled,只有 Succeeded、Failed、Canceled 是终态。
|
|||
|
|
|
|||
|
|
4. **权限控制**: 所有接口都需要相应的权限,确保用户具有足够的权限才能调用。
|
|||
|
|
|
|||
|
|
5. **异步日志**: 部署操作会异步记录到 `datai_metadata_deploy_log` 表,可以通过该表查询部署历史。
|
|||
|
|
|
|||
|
|
6. **错误处理**: 所有错误都会转换为 `SalesforceOperationException`,包含详细的错误码和错误信息。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 相关文档
|
|||
|
|
|
|||
|
|
- [需求文档](../requirements/sub/2026-01-28-003-03-部署操作.md)
|
|||
|
|
- [设计文档](../design/2026-02-03-003-03-部署操作-设计.md)
|
|||
|
|
- [决策记录](../decisions/2026-02-03-003-03-ADR-通用部署接口设计.md)
|
|||
|
|
- [变更日志](../changelog/2026-02-06-003-03-changelog.md)
|
|||
|
|
- [会话记录](../sessions/2026-02-03-003-03-session.md)
|
|||
|
|
- [复盘文档](../retros/2026-02-06-003-03-retro.md)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 版本历史
|
|||
|
|
|
|||
|
|
| 版本号 | 日期 | 变更内容 | 作者 |
|
|||
|
|
|--------|------|----------|------|
|
|||
|
|
| v1.0.0 | 2026-02-06 | 初始版本,实现部署 ZIP 包、同步轮询、状态查询、取消部署功能 | AI Assistant |
|