Files

11 KiB
Raw Permalink Blame History

Gitea Adapter — 写模式(Write Patterns

Gitea adapter 参考实现(Increment 3,自 dogfood 源 _shared/gitea-write-patterns.md 拆分上提)。本目录承载后端绑定的 API 形态(REST 端点 + swagger 契约,curl 形态);页名规范与寻址语义 是后端中立契约,见 core/rules/artifact-addressing.md(本文不重复)。 实例基址由实例配置提供(下文 <gitea-base-url>),见 core/adapters/TERMINOLOGY.md。认证一律 -H "Authorization: token <token>" 端点契约以 <gitea-base-url>/swagger.v1.json 为唯一正典(按需 jq 提取, 见 core/skills/gitea-rest/)。

Owner/repo 固定为 Octopus/octopus。所有 wiki 页名遵循 Core 契约 {slug}/{type}-{seq:02d}-{title}(例外页全枚举见 artifact-addressing.md)。

Wiki URL 构造 — html_url 规则

黄金规则:绝不手工拼接 wiki URL。 POST .../wiki/newGET .../wiki/page/{mangled-name}GET .../wiki/pages 响应中的 html_url 字段是唯一权威链接,发布时捕获并原样复用。页名 → html_url 的变换不可推导(/%2F、含斜杠页名带 .- 尾缀、CJK 百分号编码),必须读 API。

两种标识符勿混淆

标识符 是什么 用途
逻辑页名(title 原始页标识;字面 /、无主机、无编码 写侧:POST .../wiki/newtitlePATCH 省略 title 保名
mangled pageNamesub_url 后端改写的存储名(含 %2F 编码与 .- 尾缀) 读侧/改侧路径参数:先 GET .../wiki/pagessub_url原样用于 wiki/page/{pageName},绝不手工拼
html_url 后端生成的完整可点击 URL markdown 链接、target_url、PR 正文

去向

  • 工件索引位置列 — 一个单元格同时存两者: [`{page_name}`]({html_url})。链接文本供读侧回读该页,href 供人 点击(见 Pattern 10)。
  • commit-status target_url — 终报页的 html_url(见 Pattern 8)。
  • 页内交叉链接 — 用 html_url

无 API 响应可用时(静态源串)用 <gitea-base-url>,且仅此一处来源。

Pattern 1: create-wiki-page

curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/new" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{
    "title": "{slug}/{type}-{seq:02d}-{title}",
    "content_base64": "<base64(内容)>",
    "message": "{可选 commit message}"
  }'

base64 陷阱(强制注明)wiki 写接口只认 content_base64;传 content 会被静默忽略(无报错、返回 2xx,页面存成 0 字节)。正文必须 先 base64 编码,且发布后回读确认非空。

发布→验证(强制):发布后立刻回读确认存在且内容一致:

# 1. 列页拿 mangled sub_url(绝不手工拼 mangled name
curl -fsS -H "Authorization: token <token>" \
  "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/pages"
# 2. 用返回的 sub_url 原样读页
curl -fsS -H "Authorization: token <token>" \
  "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{sub_url}"

404 / 内容为空或不一致 → 修复后重发。页名冲突(409)→ 该页已存在, 改用 Pattern 2 update,绝不另发新页。响应的 html_url 立即捕获复用。

Pattern 2: update-wiki-page

curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{sub_url}" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{
    "content_base64": "<base64(新内容)>",
    "message": "{commit message}"
  }'

路径参数用 mangled sub_url(先 GET .../wiki/pages 获取,原样使用)。 省略 title 保持页名不变——只发 content_base64+message。 同样只认 content_base64content 会静默存 0 字节页)。更新后再回读 验证;409 冲突 → 拉最新内容手工合并后重试。

Pattern 3: create-issue

curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{"title":"{标题}","body":"{正文}","labels":[{label_id}]}'

工单交叉链接(强制)

父子工单组必须双向链接:父工单 task list 引用 #<number>;子工单正文 带 ## 父级 / Parent 节引用父 #<number>

衍生工单创建

  • 技术债(verify Phase 5.5):TD-NNN 经分配台账取号后升票,## Parent 指回登记册源工单。
  • 基线失败(Phase 5.55):label baseline-failure + BF-NNN(族伞签, 按失败签名去重)。
  • 不稳定测试(Phase 5.56):label flaky-test + FT-NNN(同上)。

Pattern 4: update-issue

curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{"body":"{正文}","state":"{open|closed}"}'

原位更新正文(checklist 勾选、live 状态表维护);关闭工单即触发 归档动作(见 artifact-addressing.md §4.3 + Pattern 10)。

Pattern 5: add-issue-comment

curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}/comments" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{"body":"{评论正文}"}'

首次评论后捕获返回的 comment_id——后续对同一逻辑评论的更新必须走 Pattern 6 原位 edit,绝不再 create。用于:评审综合(Synthesis)、 状态备注、TD 登记、claim 认领。

Pattern 6: edit-issue-comment

curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/comments/{comment_id}" \
  -H "Authorization: token <token>" -H "Content-Type: application/json" \
  -d '{"body":"{新正文}"}'

单评论聚合不变量(工件索引、当前状态表等)的执行手段。

Pattern 7: move-issue-to-column

看板列迁移(Todo → In Progress → Review → Done)。projects/columns 发现用 REST;「把工单移到列」的操作端点语义复杂,经 swagger 查询后 调用,不臆造路径:

# 列出 repo 级 projectsprojects 仅 repo 级,无 org/user 级端点)
curl -fsS -H "Authorization: token <token>" \
  "<gitea-base-url>/api/v1/repos/Octopus/octopus/projects"
# 列某 project 的 columns
curl -fsS -H "Authorization: token <token>" \
  "<gitea-base-url>/api/v1/repos/Octopus/octopus/projects/{project_id}/columns"
# 移动工单到列:先经 swagger.v1.json 查询 projects 相关端点后调用
curl -s <gitea-base-url>/swagger.v1.json -o /tmp/gitea-sw.json
jq -r '.paths | keys[]' /tmp/gitea-sw.json | grep projects

Pattern 7.5: move-issue-to-pipeline-stage

管线阶段板列(Pipeline Stages board column)承载阶段迁移——阶段转移 落到板列,不落 ## 当前状态 行(该表只承载 PR / 评审 / CI 行与 非阶段阻塞项)。列序列按管线阶段定义;移动与 Pattern 7 同款 projects/columns 经 REST + swagger 发现,同上)。

Pattern 8: post-commit-status

commit status 直发 REST(评审综合的 Tier-2 落点):

curl -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/statuses/{sha}" \
  -H "Authorization: token <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "context": "pipeline/review-{stage}",
    "state": "{success|failure|pending|error}",
    "target_url": "{html_url}",
    "description": "{≤140 chars 摘要}"
  }'

context 公式:pipeline/review-{stage}code / review-dag / audit-process)。token 从实例配置读取(此处 <token> 占位)。 merge 前读回验证:GET /commits/{PR_SHA}/status

Pattern 9: create-iteration-board

# 建 projectboard):先经 swagger 查询 create 端点契约
curl -s <gitea-base-url>/swagger.v1.json -o /tmp/gitea-sw.json
jq '.paths["/repos/{owner}/{repo}/projects"].post' /tmp/gitea-sw.json
# 随后 POST 建板(title="{slug} — Iteration {N}", description="…"
# 再对每列(Todo / In Progress / Review / Done):
jq '.paths["/repos/{owner}/{repo}/projects/{project_id}/columns"].post' /tmp/gitea-sw.json
# 随后 POST 建列

projects 仅 repo 级。DAG 聚合 agent 在单门 PASS 后建板;工单正文模板带 ## Node Reference(指向 {epic-slug}/dag)、## Acceptance Criteria## Parent

Pattern 10: artifact-index(工单 ↔ 工件索引)

技能发布工件后,在源工单维护 ## 工件索引 评论——单一原位编辑的 索引(反向链接 + compaction 恢复主路径;语义不变量见 core/rules/artifact-addressing.md §4):

# 1. 找源工单(PR body / commit 的 Closes #N,或 DAG 父映射);无则跳过
# 2. 评论已存在?
curl -fsS -H "Authorization: token <token>" \
  "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}/comments"
#    → 扫 body 以 "## 工件索引" 开头的评论(遗留前缀 "## Pipeline 工件追踪表"
#      原位升级,不重复发)
# 3a. 不存在 → POST .../issues/{index}/comments 初始化
# 3b. 存在   → PATCH .../issues/comments/{comment_id} 原位编辑(复用 comment_id

索引表模板(每工件一行;技能只增改自己的行,绝不删他技的行):

## 工件索引

slug: `{slug}` — source issue #{N}

| 工件 | 类型 | 版本 | 位置 | 重读 |
|------|------|------|------|------|
| DAG | 任务图 | v1 (frozen) | [`{epic-slug}/dag`]({html_url}) | CORE |

位置列填充规则:单元格 = markdown 链接 [`{page_name}`]({html_url}) 链接文本(逻辑页名,字面 /)供读侧先 GET .../wiki/pagessub_url 后回读该页;href(html_url)供人点击,必须取自 API 响应,严禁拼接。

重读优先级CORE = compaction 后必读(重读集 = 全部 CORE 行); ON-DEMAND = 按需;ARCHIVE = 已归档不读。

归档动作(archive-at-close:工单关闭时由关闭方 agent 原位 edit 本评论——表格上方加归档横幅(> **状态**: ✅ 已归档 — issue #{N} 关闭于 {date}+ 全部行 重读 置 ARCHIVE;不删行、不改位置列、不发第二条 评论。主路径 verify Phase 5.6;跳过 verify 的路由由关闭 agent 补执行。

各技能行映射

技能 工件 ID 位置
analyze-dag DAG {epic-slug}/dag
review-artifact REVIEW-{stage} {slug}/reviews/{stage}/final/report
review-code REVIEW-code {slug}/reviews/code/final/report
review-codeDAG task REVIEW-code-task-{node-id} {epic-slug}/reviews/code/final/report-task-{node-id}
verify VERIFY-{N} {slug}/05-verify-iteration-{N}
verifymilestone VERIFY-M-{M-id} {epic-slug}/05-verify-milestone-{M-id}(重读 ON-DEMAND
verifyDAG task VERIFY-TASK-{node-id} {epic-slug}/05-verify-task-{node-id}(重读 ON-DEMAND