禅道项目需求管理(HTTP API 版)
通过禅道页面内置 HTTP 接口和 REST API 管理项目需求,支持创建/编辑/删除/查询,确保需求正确关联到项目。同时支持需求文档编写与禅道需求的双向同步。
核心工作流:需求文档 ↔ 禅道需求
需求文档(.md) ──创建──> 禅道需求(story)
↑ │
└────回写禅道ID──────────┘
↑ │
└──更新文档──>──询问是否同步──>──编辑禅道需求
1. 需求文档编写
当用户要求编写或更新需求文档时:
- 遵循工作区规则:仅当用户确认功能OK并主动说明时,才更新需求文档
- 阅读需求文档:先读取
config.json中requirements_doc指定的文档路径 - 按文档格式编写:保持现有文档的章节结构和格式
- 禅道ID标注:每个功能标题格式为
### F001 - 功能名称(#禅道ID)- 已创建禅道需求的:标注ID,如
### F001 - 多人分工(#155) - 未创建的:不标注,如
### F005 - 登录认证
- 已创建禅道需求的:标注ID,如
2. 文档更新后询问同步
需求文档更新完成后,主动询问用户是否需要同步到禅道:
"需求文档已更新。是否需要同步到禅道?"
3. 同步逻辑
根据需求文档中的禅道ID标注,自动判断操作类型:
| 禅道ID标注 | 同步操作 |
|------------|---------|
| 有ID(如 #155) | 编辑禅道需求,将文档描述转为HTML格式更新 |
| 无ID | 创建禅道需求,创建成功后回写ID到文档标题 |
4. 禅道ID回写
创建需求成功后,自动更新需求文档中对应功能标题:
- 创建前:
### F005 - 开始编写校验 - 创建后:
### F005 - 开始编写校验(#172)
5. 描述转换规则
将需求文档的 Markdown 内容转为禅道 HTML 格式,按以下结构组织描述内容:
| 章节 | 必填 | 说明 |
|------|------|------|
| 用户故事 | 是 | 格式:作为<b>角色</b>,我希望<b>功能</b>,以便<b>价值</b>。来源:文档中 > 引用 块 |
| 前置条件 | 否 | 使用前置需满足的条件,用无序列表 |
| 功能要点 | 是 | 核心操作步骤或业务规则,用有序列表;子步骤用嵌套无序列表 |
| 字段说明 | 否 | 涉及的数据字段,用表格(字段、类型、必填、默认值、说明) |
| 注意事项 | 否 | 需特别关注的规则、边界情况或约束 |
| 其他规则 | 否 | 权限控制、联动逻辑等补充规则 |
Markdown → HTML 映射:
| Markdown | HTML |
|----------|------|
| ### 标题 | <h3>标题</h3> |
| > 引用 | 用户故事格式 |
| 1. 步骤 | <ol><li>步骤</li></ol> |
| - 要点 | <ul><li>要点</li></ul> |
| **加粗** | <b>加粗</b> |
| 表格 | <table>...</table> |
转换时遵循写作规范:不写英文字段名、不写UI样式细节。
配置
在 config.json 中配置:
{
"zentao_url": "http://your-zentao-server/zentao",
"zentao_user": "your_username",
"zentao_password": "your_password",
"default_project": 0,
"default_product": 0,
"requirements_doc": "requirements.md"
}
| 字段 | 说明 | |------|------| | zentao_url | 禅道服务地址 | | zentao_user | 登录账号 | | zentao_password | 登录密码 | | default_project | 项目ID(从项目需求页面URL获取) | | default_product | 产品ID(从创建需求URL参数获取) | | requirements_doc | 需求文档路径(相对于工作区根目录),用于双向同步 |
功能列表
1. 创建需求
# 单条创建
python create_story_api.py create --title "需求标题" --desc "描述" --pri 3
# 批量创建
python create_story_api.py create --input stories.json
创建接口:POST /story-create-{product}-all-{module}-0-{project}-0-0-0--story.html
URL 中的 {project} 参数确保需求关联到项目。
| 参数 | 必填 | 说明 | |------|------|------| | --title | 是 | 需求标题 | | --desc | 否 | 需求描述(用户故事格式) | | --pri | 否 | 优先级 1-4,默认 3 | | --module | 否 | 模块ID,默认 0 | | --status | 否 | draft=草稿(默认), active=激活 | | --input | 否 | JSON文件路径(批量模式) | | --project | 否 | 项目ID | | --product | 否 | 产品ID | | --json | 否 | 输出JSON格式 |
2. 编辑需求
# 修改标题和优先级
python create_story_api.py edit --id 163 --title "新标题" --pri 1
# 修改描述
python create_story_api.py edit --id 163 --desc "新的需求描述"
# 从文件读取描述(推荐用于HTML长文本)
python create_story_api.py edit --id 163 --desc-file description.html
# 修改状态为激活
python create_story_api.py edit --id 163 --status active
编辑接口:POST /story-edit-{storyID}-default-story.html?zin=1
编辑前会自动查询当前需求数据,仅提交修改的字段,未修改字段保留原值。
| 参数 | 必填 | 说明 | |------|------|------| | --id | 是 | 需求ID | | --title | 否 | 新标题 | | --desc | 否 | 新描述 | | --desc-file | 否 | 从文件读取描述(推荐用于HTML长文本) | | --pri | 否 | 新优先级 1-4 | | --module | 否 | 新模块ID | | --status | 否 | 新状态: draft/active/closed/changed | | --category | 否 | 新分类: feature/performance/security/experience/improve | | --assignedTo | 否 | 指派给 | | --json | 否 | 输出JSON格式 |
3. 删除需求
python create_story_api.py delete --id 166
删除接口:DELETE /api.php/v1/stories/{storyID}(REST API)
请求头需携带 Token 认证。
| 参数 | 必填 | 说明 | |------|------|------| | --id | 是 | 需求ID | | --json | 否 | 输出JSON格式 |
4. 查询需求
python create_story_api.py get --id 163
查询接口:GET /api.php/v1/stories/{storyID}
| 参数 | 必填 | 说明 | |------|------|------| | --id | 是 | 需求ID | | --json | 否 | 输出JSON格式(完整数据) |
5. 同步需求文档到禅道
# 扫描需求文档,同步所有功能到禅道(有ID的编辑,无ID的创建)
python create_story_api.py sync
# 只同步指定功能编号
python create_story_api.py sync --features F001 F002 F003
# 只做试运行(不实际操作禅道,仅显示计划)
python create_story_api.py sync --dry-run
同步逻辑:读取需求文档,解析每个功能标题中的禅道ID标注:
- 有
(#ID)→ 编辑该禅道需求 - 无标注 → 创建禅道需求,创建成功后回写ID到文档
| 参数 | 必填 | 说明 | |------|------|------| | --features | 否 | 指定要同步的功能编号列表(如 F001 F002),不指定则同步全部 | | --dry-run | 否 | 试运行模式,仅显示计划不实际操作 | | --json | 否 | 输出JSON格式 | | --doc | 否 | 需求文档路径(覆盖config中的requirements_doc)|
描述字段格式
写作规范
- 不写英文字段名(如
readinessStatus、uploadedFiles),这些属于技术实现,由前端/后端把控 - 不写UI样式细节(如色值
#e74c3c、字号11px、像素宽度48px),这些由UI设计师把控 - 可以写字段中文名和属性(如类型、是否必填、默认值、说明),用表格展示
- 用HTML格式让描述更直观,禅道富文本编辑器支持 HTML
HTML 格式模板
<h3>用户故事</h3>
<p>作为<b>编制人员</b>,我希望<b>功能描述</b>,以便<b>业务价值</b>。</p>
<h3>前置条件</h3>
<ul>
<li>条件1</li>
<li>条件2</li>
</ul>
<h3>功能要点</h3>
<ol>
<li>步骤1</li>
<li>步骤2</li>
<li>步骤3</li>
</ol>
<h3>字段说明</h3>
<table border="1" cellpadding="4" cellspacing="0" style="border-collapse:collapse;width:100%;">
<tr><th>字段</th><th>类型</th><th>必填</th><th>默认值</th><th>说明</th></tr>
<tr><td>字段中文名</td><td>类型</td><td>是/否</td><td>默认值</td><td>说明</td></tr>
</table>
<h3>注意事项</h3>
<ul>
<li>注意1</li>
<li>注意2</li>
</ul>
支持的 HTML 标签
| 标签 | 用途 | 示例 |
|------|------|------|
| <h3> | 小标题 | <h3>功能要点</h3> |
| <p> | 段落 | <p>普通文字</p> |
| <b> | 加粗 | <b>重点内容</b> |
| <ol> | 有序列表 | <ol><li>步骤1</li></ol> |
| <ul> | 无序列表 | <ul><li>要点1</li></ul> |
| <table> | 表格 | 见上方模板 |
| <span style="color:red"> | 文字颜色 | 仅用于强调重要信息 |
格式选择逻辑
- 描述包含 HTML 块级标签(
<h3>,<ul>,<ol>,<table>等)→ 直接使用原始 HTML - 描述为纯文本 → 按换行分段,每段自动包裹
<p><span>...</span></p>
认证原理
- 通过
/api.php/v1/tokens获取 token - 该 token 同时作为
zentaosidcookie(用于页面内置接口) - 也作为
Token请求头(用于 REST API)
接口详情
创建接口
POST /story-create-{product}-{branch}-{module}-{parent}-{project}-{execution}-{plan}-{storyType}--story.html
Content-Type: multipart/form-data
Cookie: zentaosid={token}
X-Requested-With: XMLHttpRequest
表单字段:
| 字段 | 值 | 说明 |
|------|-----|------|
| product | 产品ID | 产品标识 |
| module | 0 | 模块ID |
| title | 需求标题 | 必填 |
| pri | 3 | 优先级 1-4 |
| spec | HTML格式描述 | <p><span>文本</span></p> |
| status | draft | draft=草稿 |
| category | feature | 分类 |
| needNotReview | 1 | 免评审 |
| fileList | [] | 附件列表 |
| type | story | 类型 |
| grade | 1 | 级别 |
| files[] | 空文件 | 必须存在(multipart要求) |
| uid | 随机13位hex | 文件上传标识 |
关键:必须包含 files[] 空文件字段,否则请求失败。
编辑接口
POST /story-edit-{storyID}-default-story.html?zin=1
Content-Type: multipart/form-data
Cookie: zentaosid={token}
X-Requested-With: XMLHttpRequest
表单字段与创建类似,额外字段:
| 字段 | 说明 | |------|------| | stage | 阶段(保留原值,如 projected) | | comment | 修改备注 | | estimate | 预计工时 |
删除接口
DELETE /api.php/v1/stories/{storyID}
Token: {token}
响应:{"message": "success"}
查询接口
GET /api.php/v1/stories/{storyID}
Token: {token}
示例对话
用户: 在禅道创建一个需求"章节分工功能"
AI:
- 登录获取 token
- 创建需求:title="章节分工功能", pri=3, status=draft
- 查询获取需求ID
- 返回:已创建需求 #168(草稿),链接:http://xxx/zentao/projectstory-view-168-45.html
用户: 把需求 #168 的优先级改为 1
AI:
- 登录获取 token
- 查询需求 #168 当前数据
- 编辑:pri=1
- 返回:编辑需求 #168 成功
用户: 删除需求 #167
AI:
- 登录获取 token
- 删除需求 #167
- 返回:删除需求 #167 成功
文件结构
zentao-story-api/
├── SKILL.md # 本文件
├── config.json # 配置文件(需填写真实信息)
└── scripts/
└── create_story_api.py # 管理脚本(创建/编辑/删除/查询)
注意事项
- 认证方式:token 同时用于 cookie(内置接口)和请求头(REST API)
- 请求格式:创建和编辑必须用
multipart/form-data(因为有 files[] 字段) - 空文件字段:
files[]必须存在但为空 - 项目关联:创建时 URL 中的
{project}参数确保需求关联到项目 - 草稿状态:新建需求默认 status=draft
- 描述格式:描述必须用 HTML 格式(
<p><span>文本</span></p>) - 编辑合并:编辑时自动查询当前数据,未修改字段保留原值
- Token有效期:约2小时,批量操作无需重复获取
- 双向同步:需求文档中通过
(#ID)标注禅道需求ID,创建新需求后自动回写ID到文档 - 需求文档规则:仅当用户确认功能OK并主动说明时,才更新需求文档
- 同步询问:更新需求文档后主动询问用户是否需要同步到禅道
- 创建接口选择:创建需求使用内置页面接口而非官方 RESTful API,原因是项目类型为【项目型】而非【产品型】时,创建项目需求池无需填写关联产品字段,但 RESTful API 中关联产品为必填,因此创建功能采用内置页面接口
- --desc-file 参数:当描述内容较长或包含HTML时,建议使用 --desc-file 从文件读取,避免命令行解析问题
AI 行为指南
当用户要求编写/更新需求文档时
- 先读取需求文档,了解当前内容和已有禅道ID标注
- 按文档现有格式和规范编写需求内容
- 更新文档后,主动询问:"需求文档已更新,是否需要同步到禅道?"
- 如用户确认同步,执行 sync 流程
当用户要求创建禅道需求时
- 检查需求文档中该功能是否已有禅道ID
- 如有ID → 提醒用户该需求已存在于禅道,询问是否编辑
- 如无ID → 创建需求,成功后自动回写ID到需求文档标题
当用户要求同步需求时
- 读取需求文档,解析所有功能及禅道ID标注
- 列出同步计划(哪些要创建、哪些要编辑)
- 确认后逐条执行,创建成功的自动回写ID
依赖要求
- Python 3.7+
- requests 库(
pip install requests)
扫码联系在线客服