Files
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

172 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: '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).'
name: 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,可认证) |
## 快速开始
```bash
# 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 ...`)。
### 组织与人员
```bash
python3 gitea_ops.py config # 当前配置
python3 gitea_ops.py org repos # 组织仓库列表(名称/公私/描述)
python3 gitea_ops.py org members # 组织成员(人员),含邮箱
```
### 工单(issue
```bash
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
```bash
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` 变组织级(组织级标签所有仓库共享)。
```bash
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
```
### 仓库信息
```bash
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`
```bash
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 click**`fetch/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 加🐛缺陷。
## 典型工作流(新需求从提出到上板)
```bash
# 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 四仓库治理现状(里程碑/看板列/标签全量清单),动治理前先读。