Install
openclaw skills install @endcy/gitlab-work-stats生成 GitLab 用户工作统计报告(仅限只读分析)。分析指定用户在指定时间段内的合并请求、代码提交、代码审查活动。不修改服务器数据,不提供加密功能。
openclaw skills install @endcy/gitlab-work-stats⚠️ 重要说明:本工具用于生成 GitLab 用户工作统计报告(只读分析)。
- 不会修改 GitLab 服务器上的任何数据
- 不提供加密功能,生成的报告需用户自行保护
- 需要用户提供明确的分析目标和时间范围
⚠️ 安全警告:
高优先级(明确意图):
低优先级(需要确认):
不触发的情况:
激活前必须确认:
只读操作 — 所有数据库查询和 git 命令必须是只读的(SELECT / git log),绝不修改服务器上的任何文件或数据。每次执行前向用户声明这一点。
参数提取 — 激活后必须从用户输入中提取三个关键参数:
{target_username})2026-07-01 ~ 2026-07-31)如果缺少用户名或时间范围,主动询问用户。
从 references/server-config.json 读取 GitLab 服务器连接信息。
⚠️ 凭据安全警告:
如果配置文件不存在或需要连接不同的服务器,询问用户提供:
使用 Python paramiko 库通过 SSH 连接服务器。
前置条件:
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)
⚠️ 安全说明:
GitLab Omnibus 默认使用内置 PostgreSQL,通过 Unix Socket 连接(不监听 TCP 端口),使用 peer 认证(无需密码)。
连接命令(通过 socket + peer 认证,以 gitlab-psql 用户身份):
sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql \
-h /var/opt/gitlab/postgresql -d gitlabhq_production -c "SQL语句"
⚠️ 权限说明:
sudo -u gitlab-psql 命令)注意:如果 GitLab 版本不同或使用了外部数据库,需要根据
database.yml的host、port、username、password字段调整连接方式。详见 references/database-guide.md。
查询 users 表确认用户存在,获取 user_id:
SELECT id, username, name, state, created_at, last_sign_in_at
FROM users WHERE username = '{username}';
⚠️ 隐私保护:
如果找不到用户,尝试模糊匹配:
SELECT id, username, name FROM users WHERE username ILIKE '%{keyword}%';
以下所有查询中 {user_id}、{start_date}、{end_date} 为参数占位符。
查询用户作为作者的 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
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;
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;
如果服务器配置了 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;
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;
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;
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;
通过 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 注入数据库中的 push_event_payloads 只记录 commit 标题,如需完整的 commit message、变更文件列表等,需直接查询 git 仓库。
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}'
);
⚠️ 安全说明:
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 命令,不访问仓库源代码内容sudo 提权,直接使用当前用户权限执行注意:hashed storage 的磁盘路径格式为
@hashed/{前2位}/{次2位}/{完整hash},完整路径为/var/opt/gitlab/git-data/repositories/@hashed/XX/YY/XXXX.git。数据库记录的disk_path不含.git后缀。
报告格式为 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 优化重构)
- 涉及的模块/技术栈
- 关键技术决策和实现思路
present_files 展示给用户merge_requests 表的 state vs state_id 列)information_schema.columns 确认列名notes 表的正文列名固定为 note(不是 body)decode('utf-8', errors='replace') 处理events 和 notes 表可能很大,查询时务必带 author_id 和时间范围条件服务器连接配置存放在 references/server-config.json,包含 IP、端口、用户名、密码等。
详细的 GitLab PostgreSQL 数据库表结构和查询方法见 references/database-guide.md。
| 版本 | 日期 | 作者 | 变更 |
|---|---|---|---|
| 1.0.0 | 2026-07-23 | — | 初始版本,支持用户工作统计分析报告生成 |