Files
GiteaProjectOps/SKILL.md
T
Luci fb63d134e5 feat: Gitea 项目治理工具箱(工单/标签/里程碑/人员/看板)
- gitea_ops.py: API CLI(组织/成员/工单/标签/里程碑/仓库),纯标准库
- board_ops.py: 看板网页 CLI(Playwright),处理 Gitea 1.26 看板无 API 限制
- SKILL.md: QwenPaw skill 文档(命令手册 + 血泪教训 + 失败模式)
- README.md: 项目说明
2026-08-01 17:19:07 +00:00

11 KiB
Raw Blame History

description, name
description name
Use this skill when the user needs to manage Gitea projects/orgs: listing or creating issues (获取/创建工单), milestones (查看/创建/管理里程碑), labels, getting org members/people (获取人员), repo info/topics, or creating and managing kanban boards (创建和管理看板). Triggers on PineSound repo governance, Gitea API scripts, board/project operations, or "查工单/建工单/看板/里程碑". Provides ready-to-run scripts gitea_ops.py (API) and board_ops.py (Playwright for boards, which have no REST API in Gitea 1.26). gitea-project-manage

Gitea 项目管理操作(gitea-project-manage

概述

对 Gitea 组织/仓库做项目治理操作的完整工具箱:工单(issue)、标签(label)、里程碑(milestone)、人员(组织成员)、组织/仓库信息、看板(project board

一次写好的两个脚本,避免每次重复手写 curl/网页操作:

脚本 定位 依赖
scripts/gitea_ops.py API 操作:工单/标签/里程碑/成员/组织/仓库(看板除外 Python 3.10+ 标准库,零第三方依赖
scripts/board_ops.py 看板网页操作:新建/改名/删除看板、列管理、工单进看板、卡片拖拽、完成列关单 playwright + chromium

⚠️ 为什么拆两个脚本Gitea 1.26 的看板(Projects没有 REST APIswagger 里 300 个端点完全没有 project 相关),工单/标签/里程碑有 API 但看板必须走浏览器 DOM。这是版本事实,不是配置问题。

环境与凭据

条目 内容
Gitea Web 内网 http://192.168.1.3:10082API 前缀 /api/v1)· 外网 code.infoepoch.cn
组织 PineSound(可 --org 覆盖)
API Token /app/working.secret/gitea_tokenchmod 600,管理员权限,不提交 git、不出现在文档
网页登录 Gitea 1.26 登录页无 CSRF,直接表单提交;凭据用 GITEA_USER / GITEA_PASS 环境变量传入(不写明文进脚本/文档
SSH push ssh -i ~/.ssh/id_ed25519_gitea -p 2222 git@192.168.1.3Gitea 用户 Luci,可认证)

快速开始

# gitea_ops.pytoken 自动从 /app/working.secret/gitea_token 读取,直接跑
python3 scripts/gitea_ops.py org members
python3 scripts/gitea_ops.py issue list PineSoundServer --state open

# board_ops.py:首次需 playwright 环境
pip install playwright && playwright install chromium
GITEA_USER=Pine GITEA_PASS='<密码>' python3 scripts/board_ops.py boards PineSoundServer
# 登录态 cookie 缓存到 /tmp/gitea_board_state.json,之后同目录复用;密码只从环境变量读

gitea_ops.pyAPI 操作)

全局参数:--org <组织>(默认 PineSound)、--json(原始 JSON必须放在子命令前,如 gitea_ops.py --json issue get ...)。

组织与人员

python3 gitea_ops.py config                          # 当前配置
python3 gitea_ops.py org repos                       # 组织仓库列表(名称/公私/描述)
python3 gitea_ops.py org members                     # 组织成员(人员),含邮箱

工单(issue

python3 gitea_ops.py issue list <repo> [--state open|closed|all] [--milestone 标题] [--label 标签名] [--assignee 用户名] [--limit N]
python3 gitea_ops.py issue get <repo> <number>
python3 gitea_ops.py issue create <repo> --title "标题" [--body] [--labels "标签1,标签2"] [--milestone "Beta-V1.1"] [--assignee "YangYi,Luci"] [--deadline 2026-08-31]
python3 gitea_ops.py issue edit <repo> <number> [--title] [--body] [--labels "标签1" | ""] [--assignee "用户" | ""] [--milestone 标题|none] [--state open|closed] [--deadline YYYY-MM-DD|none]
python3 gitea_ops.py issue close <repo> <number> [--comment "原因"]   # 同理 reopen
python3 gitea_ops.py issue comment <repo> <number> --body "评论内容"
python3 gitea_ops.py issue delete <repo> <number> --yes                # 危险,不可恢复

关键事实(实测):

  • --labels / --milestone / --assignee 都支持名称(自动解析 id),不必查 id。
  • 换标签必须走 PUT /issues/{index}/labelsPATCH /issues/{index} 里的 labels 字段不生效(实测 201 但标签不变),gitea_ops.py 内部已处理。
  • 工单列表自动过滤 PR(issue 对象带 "pull_request": null 键,直接判断会把 PR 也算进来)。
  • 关闭后工单仍在里程碑统计内,--comment 会顺带加关闭说明(团队习惯:为什么关)。

里程碑(milestone

python3 gitea_ops.py milestone list <repo> [--state all|open|closed]
python3 gitea_ops.py milestone create <repo> --title "Beta-V1.1" [--description] [--deadline 2026-08-31]
python3 gitea_ops.py milestone edit <repo> <id> [--title] [--description] [--deadline] [--state]
python3 gitea_ops.py milestone delete <repo> <id> --yes

标签(label

默认仓库级;加 --org-level 变组织级(组织级标签所有仓库共享)。

python3 gitea_ops.py label list <repo>                # 仓库级
python3 gitea_ops.py label list --org-level          # 组织级
python3 gitea_ops.py label create <repo> --name "🐛 缺陷(Bug" --color "#d73a4a" [--description]
python3 gitea_ops.py label edit <repo> <id> [--name] [--color] [--description]
python3 gitea_ops.py label delete <repo> <id> --yes

仓库信息

python3 gitea_ops.py repo info <repo>                 # 描述/topics/头像/默认分支
python3 gitea_ops.py repo topics <repo> --topics backend,api,go
python3 gitea_ops.py repo avatar <repo> /path/logo.png

board_ops.py(看板网页操作)

Gitea 1.26 看板无 API,用 Playwright 驱动真实浏览器。依赖pip install playwright && playwright install chromium(浏览器在 /usr/bin/chromium)。

登录GITEA_USER / GITEA_PASS 环境变量(或 --user/--pass)。登录态存 /tmp/gitea_board_state.json + profile 目录 /tmp/gitea_board_profile,同目录复跑不再要密码(换机器/清 /tmp 后重新登录)。调试可见模式:BOARD_HEADED=1

python3 board_ops.py boards <repo>                     # 列出所有看板 + 每列(id/名/卡片数)
python3 board_ops.py create <repo> --name "开发看板"    # 新建(基础看板模板,4 列)
python3 board_ops.py rename <repo> --board 3 --name "新名字"
python3 board_ops.py delete <repo> --board 3 --yes
python3 board_ops.py add-column <repo> --board 3 --name "🚧 测试列"
python3 board_ops.py rename-column <repo> --board 3 --column 10 --name "新列名"   # column 支持 id 或当前名
python3 board_ops.py add-issue <repo> --issue 8 --board 3      # 工单进看板(进"默认列"= 星标列)
python3 board_ops.py move <repo> --issue 8 --board 3 --to "🛠 开发中"   # 卡片拖拽(自动两步法)
python3 board_ops.py done-close <repo> --board 3 --done "✅ 完成"       # 完成列所有工单批量关闭(内部调 gitea_ops.py

关键经验(血泪教训,勿改)

  1. 工单进看板必须 DOM clickfetch/requests 模拟 POST /issues/projects/issues/milestone 返回 {"ok":true}实际不生效Gitea 无 CSRF meta、cookie httpOnly、API 不暴露 project 字段)。必须打开工单详情页 → 点侧栏「项目」下拉 → 点项目项。
  2. 拖拽用两步法:跨多列一次性拖拽不稳定,先拖到中间列再拖到目标列(脚本已自动)。
  3. JS 派发的事件无效isTrusted=false),必须 Playwright/浏览器真实鼠标点击与拖拽。
  4. 卡片默认 draggable=false,进看板页后先刷新一次再拖(脚本已处理)。
  5. 列选择器用 .project-column[data-id="X"]#board_X .ui.cards 是后代选择器永远匹配不到(#board_X 本身就是 .ui.cards)。
  6. 登录页按钮没有 type=submit,用 button.ui.primary.button 定位。
  7. wait_for_load_state("networkidle") 会超时Gitea 有长轮询),一律用 "load" + 固定等待。
  8. 移到「 完成」列 = 顺手关闭工单(治理惯例,根治"干完忘关");done-close 实现批量。
  9. 标签体系(PineSound 标准):中文名 + 括号英文,如 🐛 缺陷(Bug;打标签规则:新功能类🟠高、维护优化类🟡中、bug 加🐛缺陷。

典型工作流(新需求从提出到上板)

# 1. 建工单(带标签/里程碑/指派)
python3 gitea_ops.py issue create PineSoundServer --title "音频向量化接口" \
  --labels "✨ 新功能(Feature,🟠 高(High,🧠 AI算法(AI Algorithm" \
  --milestone "Beta-V1.1" --assignee YangYi
# 2. 进看板(默认列=待办)
python3 board_ops.py add-issue PineSoundServer --issue <N> --board 3
# 3. 开发中
python3 board_ops.py move PineSoundServer --issue <N> --board 3 --to "🛠 开发中"
# 4. dev 测试 / 合并 main
python3 board_ops.py move PineSoundServer --issue <N> --board 3 --to "🧪 dev 测试"
python3 board_ops.py move PineSoundServer --issue <N> --board 3 --to "🚀 已合并 main"
# 5. 完成 → 拖到 ✅ 完成 + 关单(两步可以合并:done-close)
python3 board_ops.py move PineSoundServer --issue <N> --board 3 --to "✅ 完成"
python3 gitea_ops.py issue close PineSoundServer <N> --comment "合入 main,关闭"

失败模式与恢复

现象 原因 处理
issue edit --labels 后标签没变 PATCH 的 labels 字段不生效 已修复为 PUT /labels;确认在最新脚本
board_ops.py 登录报 Timeout 按钮选择器/networkidle 更新到最新脚本;手动用浏览器验证登录页结构
拖拽后卡片没动 卡片 draggable=false 或一次跨太多列 脚本已刷新+两步法;仍失败可开 BOARD_HEADED=1 人工看
add-issue 找不到项目下拉 工单详情页结构变化(Gitea 升级) 打开工单页找 .ui.dropdown.full-width 里 strong 文本 ==「项目」
404 on org repos BASE 少了 /api/v1 GITEA_BASE 必须带 /api/v1
看板列 id 与名称 列 id 不稳定(不同看板不同) 一律用 boards 子命令先查 id,或用列名(脚本按名匹配)

维护说明

  • 脚本自带 python3 -m py_compile 可快速验证语法。
  • 若 Gitea 升级导致 DOM 变化,用 Playwright/浏览器 DevTools 重新抓取选择器(参考:列 .project-column[data-id]、列名 .project-column-title-text、列菜单 .project-column-header .ui.dropdown.tw-p-1、创建列表单 #project-column-title-input + .project-column-button-save、看板删除 button[data-url*="/projects/{id}/delete"]、确认按钮 .ui.primary.ok.button)。
  • 经验文档 docs/gitea-project-governance.md 记录了 PineSound 四仓库治理现状(里程碑/看板列/标签全量清单),动治理前先读。