fb63d134e5
- gitea_ops.py: API CLI(组织/成员/工单/标签/里程碑/仓库),纯标准库 - board_ops.py: 看板网页 CLI(Playwright),处理 Gitea 1.26 看板无 API 限制 - SKILL.md: QwenPaw skill 文档(命令手册 + 血泪教训 + 失败模式) - README.md: 项目说明
11 KiB
11 KiB
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 API(swagger 里 300 个端点完全没有 project 相关),工单/标签/里程碑有 API 但看板必须走浏览器 DOM。这是版本事实,不是配置问题。
环境与凭据
| 条目 | 内容 |
|---|---|
| Gitea Web | 内网 http://192.168.1.3:10082(API 前缀 /api/v1)· 外网 code.infoepoch.cn |
| 组织 | PineSound(可 --org 覆盖) |
| API Token | /app/working.secret/gitea_token(chmod 600,管理员权限,不提交 git、不出现在文档) |
| 网页登录 | Gitea 1.26 登录页无 CSRF,直接表单提交;凭据用 GITEA_USER / GITEA_PASS 环境变量传入(不写明文进脚本/文档) |
| SSH push | ssh -i ~/.ssh/id_ed25519_gitea -p 2222 git@192.168.1.3(Gitea 用户 Luci,可认证) |
快速开始
# gitea_ops.py:token 自动从 /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.py(API 操作)
全局参数:--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}/labels:PATCH /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)
关键经验(血泪教训,勿改)
- 工单进看板必须 DOM click:
fetch/requests模拟POST /issues/projects、/issues/milestone返回{"ok":true}但实际不生效(Gitea 无 CSRF meta、cookie httpOnly、API 不暴露 project 字段)。必须打开工单详情页 → 点侧栏「项目」下拉 → 点项目项。 - 拖拽用两步法:跨多列一次性拖拽不稳定,先拖到中间列再拖到目标列(脚本已自动)。
- JS 派发的事件无效(
isTrusted=false),必须 Playwright/浏览器真实鼠标点击与拖拽。 - 卡片默认
draggable=false,进看板页后先刷新一次再拖(脚本已处理)。 - 列选择器用
.project-column[data-id="X"];#board_X .ui.cards是后代选择器永远匹配不到(#board_X本身就是.ui.cards)。 - 登录页按钮没有
type=submit,用button.ui.primary.button定位。 wait_for_load_state("networkidle")会超时(Gitea 有长轮询),一律用"load"+ 固定等待。- 移到「✅ 完成」列 = 顺手关闭工单(治理惯例,根治"干完忘关");
done-close实现批量。 - 标签体系(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 四仓库治理现状(里程碑/看板列/标签全量清单),动治理前先读。