Generate structured weekly work reports from Git commit history and file-change statistics. Use when the user asks for a weekly report, work summary, progress review, or sprint recap based on repository activity, or when they need a Markdown report of what changed in a project over a time range.
集成
gitlab-work-stats
试用生成 GitLab 用户工作统计报告(仅限只读分析)。分析指定用户在指定时间段内的合并请求、代码提交、代码审查活动。不修改服务器数据,不提供加密功能。
它能做什么
生成 GitLab 用户工作统计报告(仅限只读分析)。分析指定用户在指定时间段内的合并请求、代码提交、代码审查活动。不修改服务器数据,不提供加密功能。
技能文档
gitlab-work-stats — GitLab 用户工作统计分析器
⚠️ 重要说明:本工具用于生成 GitLab 用户工作统计报告(只读分析)。
- 不会修改 GitLab 服务器上的任何数据
- 不提供加密功能,生成的报告需用户自行保护
- 需要用户提供明确的分析目标和时间范围
⚠️ 安全警告:
- 本操作会分析用户的工作活动数据,可能涉及敏感信息
- 确保已获得目标用户的授权或这是您自己的工作数据
- 生成的报告包含工作统计信息,请妥善保管
- 所有数据库操作均为只读(SELECT),不会修改任何数据
激活条件
高优先级(明确意图):
- "生成 GitLab 工作统计报告"
- "分析 GitLab 用户的提交活动"
- "统计 GitLab 上的代码审查数据"
低优先级(需要确认):
- "看看某人在 GitLab 做了什么"
- "分析 XX 的 GitLab 活动"
不触发的情况:
- 只是提到 GitLab 但没有要求分析工作统计
- 询问 GitLab 的使用方法或功能介绍
- 需要 GitLab API 或其他非统计分析的操作
激活前必须确认:
- 目标用户的 GitLab username
- 明确的时间范围
- 用户已知晓数据隐私和安全要求
核心原则
只读操作 — 所有数据库查询和 git 命令必须是只读的(SELECT / git log),绝不修改服务器上的任何文件或数据。每次执行前向用户声明这一点。
参数提取 — 激活后必须从用户输入中提取三个关键参数:
- 目标用户名(GitLab username,如
{target_username}) - 时间范围(起止日���,如
2026-07-01~2026-07-31) - (可选)项目过滤(限定某个项目,默认分析全部项目)
如果缺少用户名或时间范围,主动询问用户。
Step 0: 读取服务器配置
从 references/server-config.json 读取 GitLab 服务器连接信息。
⚠️ 凭据安全警告:
- 配置文件中的凭据(如 host、token)由用户自行提供
- 不要将配置文件提交到公共代码仓库
- 建议使用环境变量或配置管理工具存储敏感信息
- 确保文件权限设置为仅当前用户可读
如果配置文件不存在或需要连接不同的服务器,询问用户提供:
- GitLab 服务器地址(host)
- GitLab API Token(推荐)或 SSH 访问凭据
- GitLab Web URL(可选)
Step 1: SSH 连接与数据库定位
1.1 连接方式
使用 Python paramiko 库通过 SSH 连接服务器。
前置条件:
- Python 3.8+
- paramiko 库(需要用户自行安装:
pip install paramiko)
连接模板:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(HOST, port=22, username=USER, password=PASSWORD, timeout=15)
⚠️ 安全说明:
- 使用受管 Python 环境运行 paramiko
- SSH 凭据从 server-config.json 读取,不要硬编码在脚本中
- 建议使用受限的 SSH 账户,遵循最小权限原则
1.2 数据库连接
GitLab Omnibus 默认使用内置 PostgreSQL,通过 Unix Socket 连接(不监听 TCP 端口),使用 peer 认证(无需密码)。
连接方式(通过 socket + peer 认证,以当前 SSH 用户身份直接执行,不使用 sudo 提权):
/opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -d gitlabhq_production -c "SQL语句"
⚠️ 权限说明:
- 需要 SSH 用户本身具有执行 psql 的权限(属组包含 gitlab-psql 或配置了 peer 认证白名单)
- 不使用
sudo -u gitlab-psql,避免 sudo 提权带来的安全风险 - 建议使用受限的专用 SSH 账户,遵循最小权限原则
- 所有 SQL 查询必须为只读(SELECT),禁止执行 INSERT/UPDATE/DELETE
- 如果当前用户无法直接连接,应由管理员配置 peer 认证规则,而非使用 sudo
注意:如果 GitLab 版本不同或使用了外部数据库,需要根据
database.yml的host、port、username、password字段调整连接方式。详见 references/database-guide.md。
Step 2: 确认用户身份
查询 users 表确认用户存在,获取 user_id:
SELECT id, username, name, state, created_at, last_sign_in_at
FROM users WHERE username = '{username}';
⚠️ 隐私保护:
- 仅收集工作统计相关的最小必要信息
- 不收集 email、IP 地址等敏感个人信息
- 如果用户要求分析自己的数据,可以包含 email 用于报告标识
如果找不到用户,尝试模糊匹配:
SELECT id, username, name FROM users WHERE username ILIKE '%{keyword}%';
Step 3: 数据采集(全部只读 SELECT)
以下所有查询中 {user_id}、{start_date}、{end_date} 为参数占位符。
3.1 合并请求 (Merge Requests)
查询用户作为作者的 MR:
SELECT mr.id, mr.iid, mr.title, mr.state_id, mr.created_at, mr.updated_at,
p.name as project_name, p.id as project_id
FROM merge_requests mr
JOIN projects p ON mr.target_project_id = p.id
WHERE mr.author_id = {user_id}
AND mr.created_at >= '{start_date}'
AND mr.created_at < '{end_date}'
ORDER BY mr.created_at DESC;
state_id 含义:1=opened, 2=closed, 3=merged, 4=locked
3.2 代码推送 (Push Events) 与 Commit 标题
Push 事件存储在 events 表(action=5),commit 详情在 push_event_payloads 表。
SELECT e.created_at, pepe.commit_title, pepe.ref, pepe.commit_count,
p.name as project_name
FROM events e
JOIN push_event_payloads pepe ON pepe.event_id = e.id
JOIN projects p ON e.project_id = p.id
WHERE e.author_id = {user_id}
AND e.action = 5
AND e.created_at >= '{start_date}'
AND e.created_at < '{end_date}'
ORDER BY e.created_at DESC;
汇总统计(不需要逐条列出,按分支/任务分组统计):
SELECT
regexp_replace(pepe.ref, 'feature-([0-9]+).*', 'task-\1') as task_branch,
count(*) as push_count,
sum(pepe.commit_count) as total_commits,
count(DISTINCT pepe.commit_title) as distinct_titles
FROM events e
JOIN push_event_payloads pepe ON pepe.event_id = e.id
WHERE e.author_id = {user_id} AND e.action = 5
AND e.created_at >= '{start_date}' AND e.created_at < '{end_date}'
GROUP BY pepe.ref
ORDER BY push_count DESC;
3.3 代码审查 (Code Reviews)
3.3.1 获取该用户所有 MR 上的评论
notes 表的正文列名为 note(不是 body):
-- 别人对该用户 MR 的评论(含审批、审查意见)
SELECT n.created_at, u.username as author,
LEFT(n.note, 300) as note_preview,
mr.iid, mr.title, p.name as project_name,
n.system
FROM notes n
JOIN users u ON n.author_id = u.id
JOIN merge_requests mr ON n.noteable_id = mr.id AND n.noteable_type = 'MergeRequest'
JOIN projects p ON mr.target_project_id = p.id
WHERE mr.author_id = {user_id}
AND n.created_at >= '{start_date}'
AND n.created_at < '{end_date}'
ORDER BY n.created_at DESC;
3.3.2 AI 代码审查内容
如果服务器配置了 AI 代码审查(bot 用户名从 server-config.json 的 ai_reviewer_bot_username 读取,默认匹配规则见下),查询审查详情:
SELECT n.created_at, mr.iid, mr.title,
LEFT(n.note, 500) as review_content
FROM notes n
JOIN merge_requests mr ON n.noteable_id = mr.id AND n.noteable_type = 'MergeRequest'
JOIN users u ON n.author_id = u.id
WHERE mr.author_id = {user_id}
AND u.username IN ('{ai_bot_username}', 'ai-code-reviewer', 'code-reviewer')
AND n.created_at >= '{start_date}'
AND n.created_at < '{end_date}'
ORDER BY n.created_at DESC;
3.3.3 审批记录
SELECT n.created_at, u.username as approver,
mr.iid, mr.title, n.note
FROM notes n
JOIN users u ON n.author_id = u.id
JOIN merge_requests mr ON n.noteable_id = mr.id AND n.noteable_type = 'MergeRequest'
WHERE mr.author_id = {user_id}
AND n.note LIKE 'approved this merge request'
AND n.created_at >= '{start_date}'
AND n.created_at < '{end_date}'
ORDER BY n.created_at DESC;
3.3.4 用户作为评审人的 MR
SELECT mr.id, mr.iid, mr.title, mr.state_id, mr.created_at, mr.updated_at,
u.username as author, p.name as project_name
FROM merge_requests mr
JOIN merge_request_assignees mra ON mra.merge_request_id = mr.id
JOIN users u ON mr.author_id = u.id
JOIN projects p ON mr.target_project_id = p.id
WHERE mra.user_id = {user_id}
AND mr.updated_at >= '{start_date}'
AND mr.updated_at < '{end_date}'
ORDER BY mr.updated_at DESC;
3.4 用户自己发表的评论
SELECT n.created_at, n.noteable_type,
LEFT(n.note, 200) as note_preview,
p.name as project_name
FROM notes n
LEFT JOIN projects p ON n.project_id = p.id
WHERE n.author_id = {user_id}
AND n.created_at >= '{start_date}'
AND n.created_at < '{end_date}'
AND n.system = false
ORDER BY n.created_at DESC;
Step 4: 多行 SQL 执行
通过 SSH 执行多行 SQL 时,使用参数化查询避免引号转义问题:
import shlex
def pg_query(ssh, sql):
# 使用参数化命令,避免 sudo 链式执行
cmd = '/opt/gitlab/embedded/bin/psql ' \
'-h /var/opt/gitlab/postgresql ' \
'-d gitlabhq_production ' \
f'-c {shlex.quote(sql)} 2>&1'
# 以当前 SSH 用户身份执行(需要该用户具有 psql 执行权限)
stdin, stdout, stderr = ssh.exec_command(cmd, timeout=60)
return stdout.read().decode('utf-8', errors='replace')
⚠️ 安全说明:
- 不使用
sudo -u gitlab-psql,需要 SSH 用户本身具有 psql 执行权限 - 使用
shlex.quote()防止 SQL 注入 - 所有查询必须为 SELECT 语句
Step 5: (可选)从 Git 仓库提取 Commit 详情
数据库中的 push_event_payloads 只记录 commit 标题,如需完整的 commit message、变更文件列表等,需直接查询 git 仓库。
5.1 获取仓库物理路径
GitLab 使用 hashed storage,需通过 project_repositories 表获取磁盘路径:
SELECT pr.project_id, p.name, pr.disk_path
FROM project_repositories pr
JOIN projects p ON pr.project_id = p.id
WHERE p.id IN (
SELECT DISTINCT target_project_id
FROM merge_requests
WHERE author_id = {user_id}
AND created_at >= '{start_date}'
AND created_at < '{end_date}'
UNION
SELECT DISTINCT project_id
FROM events
WHERE author_id = {user_id}
AND action = 5
AND created_at >= '{start_date}'
AND created_at < '{end_date}'
);
⚠️ 安全说明:
- 只查询目标用户在指定时间段内有活动的仓库
- 不枚举所有仓库的磁盘路径
- 仅用于获取 commit 详情,不访问仓库源代码
5.2 查询 git log
REPO="/var/opt/gitlab/git-data/repositories/{disk_path}.git"
/opt/gitlab/embedded/bin/git -C "$REPO" \
log --all --author='{username}' \
--since='{start_date}' --until='{end_date}' \
--format='%h|%ai|%s'
⚠️ 安全说明:
- 仅使用
git log命令,不访问仓库源代码内容 - 需要 SSH 用户具有读取该仓库的权限
- 不使用
sudo提权,直接使用当前用户权限执行
注意:hashed storage 的磁盘路径格式为
@hashed/{前2位}/{次2位}/{完整hash},完整路径为/var/opt/gitlab/git-data/repositories/@hashed/XX/YY/XXXX.git。数据库记录的disk_path不含.git后缀。
Step 6: 生成报告
报告格式为 Markdown,保存到工作目录下,文件名格式:{username}_{年月}_活动报告.md。
报告结构
# {username} {时间范围}活动报告
> 用户: {username} ({name}) | ID: {user_id} | 项目: {projects}
---
## 一、合并请求 (MR) 清单 — 共 N 个
| # | MR IID | 标题 | 创建时间 | 状态 | 评审人 | 审批时间 |
|---|--------|------|----------|------|--------|----------|
| 1 | !xxx | ... | ... | ... | ... | ... |
## 二、代码推送统计
### 按任务/分支分组统计(不逐条列举)
| 任务/分支 | 推送次数 | Commit总数 | 主要内容 |
|-----------|----------|------------|----------|
| task-xxxx | N | N | 简述 |
## 三、代码审查
### AI 代码审查结果
(列出关键审查意见和发现的风险)
### 人工审批记录
(列出审批人和审批时间)
## 四、工作内容总结
### 按任务归类的工作主题
| 任务号 | 主题 | MR数 | 核心工作内容 |
|--------|------|------|--------------|
### 提交内容语义分析
根据所有 commit 标题和 MR 标题,对用户的工作内容进行主题归类和语义分析:
- 主要技术方向(如:退款逻辑、导出功能、告警系统...)
- 工作类型分布(新功能 vs Bug修复 vs 优化重构)
- 涉及的模块/技术栈
- 关键技术决策和实现思路
报告要点
- Push Events 做统计汇总,不逐条列举——按分支/任务分组,统计推送次数和 commit 数,简述主要内容
- 最后必须有一段「提交内容语义分析总结」——基于所有 commit title 和 MR title,分析用户做了什么、技术方向是什么、工作类型分布
- 报告完成后调用
present_files展示给用户
重要注意事项
数据安全
- 所有操作只读:只用 SELECT 查询和 git log 命令,绝不执行 INSERT/UPDATE/DELETE 或任何写操作
- 每次开始前明确告知用户"所有操作不会修改服务器上的任何文件或数据"
GitLab 版本差异
- 不同 GitLab 版本的表结构可能有差异(如
merge_requests表的statevsstate_id列) - 遇到列不存在错误时,先查
information_schema.columns确认列名 notes表的正文列名固定为note(不是body)
编码问题
- psql 输出可能包含中文,使用
decode('utf-8', errors='replace')处理 - base64 编码方式处理多行 SQL,避免 shell 引号转义问题
性能
events和notes表可能很大,查询时务必带author_id和时间范围条件- 避免全表扫描
配置文件
服务器连接配置存放在 references/server-config.json,包含 IP、端口、用户名、密码等。
数据库结构参考
详细的 GitLab PostgreSQL 数据库表结构和查询方法见 references/database-guide.md。
版本
| 版本 | 日期 | 作者 | 变更 |
|---|---|---|---|
| 1.0.0 | 2026-07-23 | — | 初始版本,支持用户工作统计分析报告生成 |
| 1.1.0 | 2026-07-24 | — | 安全修复:移除 sudo 链式执行、users 表隐私字段标注、git 命令移除提权 |
相关技能
面向个人开发者的Git仓库协作模式分析工具,只读、零依赖、隐私优先,输出仓库级聚合报告。Use when 需要数据分析、报表生成、统计洞察、数据可视化时使用。不适用于实时流数据处理。适用于独立开发者、企业团队和自动化工作流场景。支持中文交互,无需复杂配置即开即用。输出结果可直接使用,减少二次加工成本。
GitLab projects, MRs, and CI/CD operations
禅道(Zentao)用户工作内容分析工具。通过数据库只读查询分析指定用户在指定时间段内的需求、任务、Bug、工时日志,生成 Markdown 格式的工作报告。仅支持 SQL SELECT 查询,不修改任何数据。
Generate evidence-based project weekly reports from a local code repository. Use when the user asks for a project weekly report, weekly update, status summar...
GitLab (gitlab.com). Use this skill for ANY GitLab request — reading, creating, updating, and deleting data. Whenever a task involves GitLab, use this skill instead of calling the API directly.