Merge pull request 'gitlink-growth 开源贡献者成长系统 Skill 贡献' (#54) from yingjie/gitlink-cli:feat/growth-system into master
This commit is contained in:
commit
7a7f554881
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
name: gitlink-growth
|
||||
version: 1.0.0
|
||||
description: "开源贡献者成长体系:追踪 PR/Issue 活动 → 生成贡献排行 → 自动颁发徽章。当用户提到贡献者排行、贡献成长、颁发徽章、开发者活跃度排名等意图时触发。"
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["gitlink-cli", "sqlite3"]
|
||||
cliHelp: "gitlink-cli health +fetch --help"
|
||||
---
|
||||
|
||||
# gitlink-growth(开源贡献者成长体系)
|
||||
|
||||
**CRITICAL — 前置阅读:**
|
||||
1. [`../gitlink-shared/SKILL.md`](../gitlink-shared/SKILL.md) — 认证、权限处理
|
||||
2. [`../gitlink-health/references/queries.md`](../gitlink-health/references/queries.md) — 共享数据库表结构
|
||||
3. [`../gitlink-health/SKILL.md`](../gitlink-health/SKILL.md) — 数据采集命令参考
|
||||
|
||||
## 与 gitlink-health 的关系
|
||||
|
||||
gitlink-growth **复用** gitlink-health 的 `health +fetch` 命令和同一 SQLite 数据库,但分析视角完全不同:
|
||||
|
||||
| 维度 | gitlink-health | gitlink-growth |
|
||||
|------|---------------|----------------|
|
||||
| **视角** | 项目整体健康度 | 个人贡献者成长 |
|
||||
| **输出** | 项目的 Issue/PR/贡献者指标 | 贡献者排行 + 徽章 |
|
||||
| **关心** | 合并率、解决时长、活跃度 | 谁贡献最多、什么类型、持续度 |
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
skills/gitlink-growth/
|
||||
├── SKILL.md # 本文件
|
||||
├── references/
|
||||
│ └── queries.md # 排名 & 徽章 SQL 查询
|
||||
└── asset/
|
||||
└── growth_report_template.md # 报告模板
|
||||
```
|
||||
|
||||
> **数据库**直接读取 gitlink-health 的 SQLite 文件,不维护独立数据目录。
|
||||
|
||||
## 工作流程
|
||||
|
||||
### 1. 询问分析偏好
|
||||
|
||||
向用户确认以下参数,如果用户未明确指定全部参数,必须逐一询问:
|
||||
|
||||
| 参数 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `--owner` | 仓库所有者 | 自动从 git remote 推断 |
|
||||
| `--repo` | 仓库名称 | 自动从 git remote 推断 |
|
||||
| **时间周期** | 分析的时间范围 | **全量**(从仓库存在至今) |
|
||||
|
||||
时间周期选项:
|
||||
- **本周** — 本周一 00:00:00 至现在
|
||||
- **本月** — 本月 1 日 00:00:00 至现在
|
||||
- **本年** — 今年 1 月 1 日 00:00:00 至现在
|
||||
- **自定义范围** — 用户指定起止日期(如 `2026-01-01 ~ 2026-06-30`)
|
||||
- **全量**(默认)— 不设时间过滤,查询全部数据
|
||||
|
||||
> **记住偏好**:将用户选择的时间周期存入记忆,后续分析直接使用。
|
||||
|
||||
### 2. 采集数据
|
||||
|
||||
```bash
|
||||
gitlink-cli health +fetch --owner <owner> --repo <repo>
|
||||
```
|
||||
|
||||
`health +fetch` 会将 PR、Issue、用户、标签数据全部拉取到本地 SQLite 数据库中。数据库默认路径为 `~/.agents/skills/gitlink-health/data/gitlink_health.db`。
|
||||
|
||||
> **注意:** 如果数据库已有该仓库的数据且用户只追加了少量新活动,再次 `+fetch` 会增量更新不会丢失历史。
|
||||
|
||||
### 3. 查询排名并生成报告
|
||||
|
||||
1. 打开 [`references/queries.md`](references/queries.md) 获取 SQL 查询参考
|
||||
2. 确定 `repo_id`
|
||||
3. 根据用户选择的时间周期替换 `<start_date>` 和 `<end_date>`
|
||||
4. 按查询清单逐项执行
|
||||
5. 将结果填入 [`asset/growth_report_template.md`](asset/growth_report_template.md)
|
||||
6. 根据 [`references/queries.md#9-徽章生成`](references/queries.md#9-徽章生成) 中的流程分析数据并设计颁发徽章
|
||||
|
||||
### 4. 输出报告
|
||||
|
||||
将填充完毕的报告写入 markdown 文件并告知用户文件路径。
|
||||
|
||||
### 5. 提交报告并上传
|
||||
|
||||
询问用户当前报告是否合格,若通过,则通过`git add`添加报告文件,通过`git commit`提交修改,通过`git push`将报告推送至平台。
|
||||
|
||||
## 数据库路径
|
||||
|
||||
数据存储在 gitlink-health 的 SQLite 数据库中。默认路径:
|
||||
|
||||
- **Linux / macOS:** `~/.agents/skills/gitlink-health/data/gitlink_health.db`
|
||||
- 如果 `health +fetch` 使用了 `--db` 指定了其他路径,则使用该路径
|
||||
|
||||
## 徽章规则
|
||||
|
||||
Agent 应根据仓库实际数据自行设计徽章,而非套用预定义列表。详见 [`references/queries.md#9-徽章生成`](references/queries.md#9-徽章生成)。
|
||||
|
||||
**原则:**
|
||||
- 执行查询 1-8 和勘探查询获取完整数据画像,从数据中识别模式
|
||||
- 徽章名称从数据特征派生(如标签名、行为类型),不套用固定模板
|
||||
- 阈值参考数据分布(取前 N 名、高于均值、或连续 N 周活跃等)
|
||||
- 达到阈值的贡献者都获得徽章,不设人数上限;贡献者平票时多人并列
|
||||
- 每个徽章至少 1 人获得;无人达标则不发
|
||||
|
||||
> **关于"处理者"(processor):** 表中的 `processor_id` 即**指派人**(assignee)。GitLink API 不提供 `merged_by`(合入者)信息,所以用 `processor_id` 来代表负责处理该 PR/Issue 的人。
|
||||
|
||||
## 边界情况处理
|
||||
|
||||
| 情况 | 处理方式 |
|
||||
|------|---------|
|
||||
| 数据库不存在 | 提示用户先执行 `health +fetch`,不要试图创建空报告 |
|
||||
| 时段内无数据 | 排行榜显示「本期无贡献数据」,不颁发任何徽章 |
|
||||
| 贡献者平票 | 同一名次允许多人并列,徽章颁发给所有平票者 |
|
||||
| 无标签数据 | 跳过"细分领域排行"章节,不输出空表 |
|
||||
| 仓库无 Issue/PR | 跳过对应的排行章节 |
|
||||
| `processor_id` 均为 NULL | 跳过"处理排行"章节,并说明「暂无已指派的记录」 |
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# 开源贡献者成长报告
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| **仓库** | {owner}/{repo} |
|
||||
| **分析期间** | {start_date} ~ {end_date} |
|
||||
| **生成时间** | {generated_at} |
|
||||
|
||||
---
|
||||
|
||||
## 🏅 徽章展示
|
||||
|
||||
本期共有 **{badge_count}** 位贡献者获得徽章:
|
||||
|
||||
| 徽章 | 获得者 | 说明 |
|
||||
|------|--------|------|
|
||||
| {badge_list} | | |
|
||||
|
||||
> *徽章条件由数据分布决定;达标者均颁发。平票时多人并列。*
|
||||
|
||||
---
|
||||
|
||||
## 📊 贡献排行榜
|
||||
|
||||
### 综合贡献排名(PR + Issue)
|
||||
|
||||
| 排名 | 贡献者 | PR 数 | Issue 数 | 合计 |
|
||||
|------|--------|-------|----------|------|
|
||||
| {rank} | {user_name} | {pr_count} | {issue_count} | {total} |
|
||||
|
||||
### PR 创建数排名
|
||||
|
||||
| 排名 | 贡献者 | PR 数 | 已合并 | 合并率 |
|
||||
|------|--------|-------|--------|--------|
|
||||
| {rank} | {user_name} | {pr_count} | {merged_count} | {merge_rate_pct}% |
|
||||
|
||||
### Issue 创建数排名
|
||||
|
||||
| 排名 | 贡献者 | Issue 数 | 已解决 |
|
||||
|------|--------|----------|--------|
|
||||
| {rank} | {user_name} | {issue_count} | {closed_count} |
|
||||
|
||||
### PR 处理数排名
|
||||
|
||||
| 排名 | 贡献者 | 处理 PR 数 |
|
||||
|------|--------|-----------|
|
||||
| {rank} | {user_name} | {processed_count} |
|
||||
|
||||
*{pr_processed_note}*
|
||||
|
||||
### Issue 处理数排名
|
||||
|
||||
| 排名 | 贡献者 | 处理 Issue 数 |
|
||||
|------|--------|--------------|
|
||||
| {rank} | {user_name} | {processed_count} |
|
||||
|
||||
*{issue_processed_note}*
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 细分领域排行
|
||||
|
||||
### PR 按标签排名
|
||||
|
||||
| 标签 | 贡献者 | PR 数 |
|
||||
|------|--------|-------|
|
||||
| {tag} | {user_name} | {count} |
|
||||
|
||||
{pr_tag_note}
|
||||
|
||||
### Issue 按标签排名
|
||||
|
||||
| 标签 | 贡献者 | Issue 数 |
|
||||
|------|--------|----------|
|
||||
| {tag} | {user_name} | {count} |
|
||||
|
||||
{issue_tag_note}
|
||||
|
||||
---
|
||||
|
||||
## 报告说明
|
||||
|
||||
- 数据来源:GitLink API,通过 `gitlink-cli health +fetch` 采集
|
||||
- 分析期间:{start_date} ~ {end_date}
|
||||
- 徽章根据仓库实际数据动态设计颁发
|
||||
- {note_empty}
|
||||
|
|
@ -0,0 +1,444 @@
|
|||
# 贡献排行 & 徽章 SQL 查询参考
|
||||
|
||||
所有查询使用 SQLite。将 `<repo_id>`、`<start_date>`、`<end_date>` 替换为实际值。
|
||||
|
||||
> **已知数据质量问题:** `health +fetch` 在采集标签时可能将跨仓库的同名标签复用为同一个 `tag_id`,导致 `pull_tags`/`issue_tags` 引用了不属于目标仓库的标签。为此,所有 JOIN `tags` 的查询都加了 `t.repo_id = <repo_id>` 防护。如果发现标签数据异常,请先执行查询 8 确认目标仓库的实际标签列表。
|
||||
|
||||
> **注意:** 时间范围条件需用 `date()` 包裹列名,避免字典序比较导致当日数据被排除。下文所有查询已按此规则编写。
|
||||
|
||||
## 表结构
|
||||
|
||||
gitlink-growth 与 gitlink-health 共用同一 SQLite 数据库,表结构由 `health +fetch` 创建。核心表如下:
|
||||
|
||||
### users
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_name TEXT NOT NULL UNIQUE
|
||||
);
|
||||
```
|
||||
|
||||
### repos
|
||||
|
||||
```sql
|
||||
CREATE TABLE repos (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
repo_name TEXT NOT NULL,
|
||||
owner_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (owner_id) REFERENCES users(id),
|
||||
UNIQUE(repo_name, owner_id)
|
||||
);
|
||||
```
|
||||
|
||||
### pulls
|
||||
|
||||
```sql
|
||||
CREATE TABLE pulls (
|
||||
id INTEGER PRIMARY KEY,
|
||||
repo_id INTEGER NOT NULL,
|
||||
number INTEGER NOT NULL,
|
||||
creater_id INTEGER,
|
||||
processor_id INTEGER,
|
||||
status TEXT CHECK(status IN ('merged', 'closed', 'open')),
|
||||
create_time TIMESTAMP,
|
||||
close_time TIMESTAMP,
|
||||
FOREIGN KEY (repo_id) REFERENCES repos(id),
|
||||
FOREIGN KEY (creater_id) REFERENCES users(id),
|
||||
FOREIGN KEY (processor_id) REFERENCES users(id)
|
||||
);
|
||||
```
|
||||
|
||||
`status` 取值:`open`(开放)、`merged`(已合并)、`closed`(已关闭未合并)。`close_time` 始终为 NULL(API 不提供)。
|
||||
`processor_id` 表示 PR 的**指派人**(assignee)——因为 GitLink API 不提供 `merged_by`(合并者)信息,所以用 `processor_id` 代表"处理者"角色,即被指派来 review/merge 该 PR 的人。
|
||||
|
||||
### issues
|
||||
|
||||
```sql
|
||||
CREATE TABLE issues (
|
||||
id INTEGER PRIMARY KEY,
|
||||
repo_id INTEGER NOT NULL,
|
||||
number INTEGER,
|
||||
creater_id INTEGER,
|
||||
processor_id INTEGER,
|
||||
create_time TIMESTAMP,
|
||||
close_time TIMESTAMP,
|
||||
status TEXT CHECK(status IN ('close', 'open')),
|
||||
FOREIGN KEY (repo_id) REFERENCES repos(id),
|
||||
FOREIGN KEY (creater_id) REFERENCES users(id),
|
||||
FOREIGN KEY (processor_id) REFERENCES users(id)
|
||||
);
|
||||
```
|
||||
|
||||
`status` 取值:`open`(开放)、`close`(已关闭)。
|
||||
`processor_id` 表示 Issue 的**指派人**(assignee)——与 PR 同理,因 API 无 `merged_by`,`processor_id` 代表负责处理该 Issue 的人。
|
||||
|
||||
### tags
|
||||
|
||||
```sql
|
||||
CREATE TABLE tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
repo_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
FOREIGN KEY (repo_id) REFERENCES repos(id),
|
||||
UNIQUE(repo_id, name)
|
||||
);
|
||||
```
|
||||
|
||||
### pull_tags / issue_tags
|
||||
|
||||
```sql
|
||||
CREATE TABLE pull_tags (
|
||||
pull_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (pull_id) REFERENCES pulls(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (pull_id, tag_id)
|
||||
);
|
||||
|
||||
CREATE TABLE issue_tags (
|
||||
issue_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (issue_id, tag_id)
|
||||
);
|
||||
```
|
||||
|
||||
> 完整字段映射说明见 [`../gitlink-health/references/queries.md`](../gitlink-health/references/queries.md#表结构)。
|
||||
|
||||
## 数据库路径
|
||||
|
||||
默认:`~/.agents/skills/gitlink-health/data/gitlink_health.db`
|
||||
|
||||
```bash
|
||||
DB=~/.agents/skills/gitlink-health/data/gitlink_health.db
|
||||
```
|
||||
|
||||
## 时间范围计算
|
||||
|
||||
| 周期 | SQL 计算 |
|
||||
|------|---------|
|
||||
| 本周 | `date('now', 'weekday 0', '-6 days')` ~ `date('now')` |
|
||||
| 本月 | `date('now', 'start of month')` ~ `date('now')` |
|
||||
| 本年 | `date('now', 'start of year')` ~ `date('now')` |
|
||||
| 自定义 | `'<user-start>'` ~ `'<user-end>'` |
|
||||
| 全量 | `'1970-01-01'` ~ `date('now')` |
|
||||
|
||||
## 0. 确定目标仓库
|
||||
|
||||
```bash
|
||||
# 列出所有仓库
|
||||
sqlite3 "$DB" "SELECT r.id, u.user_name AS owner, r.repo_name FROM repos r JOIN users u ON r.owner_id = u.id;"
|
||||
|
||||
# 精确查找 repo_id
|
||||
sqlite3 "$DB" "SELECT r.id FROM repos r JOIN users u ON r.owner_id = u.id WHERE u.user_name = '<owner>' AND r.repo_name = '<repo>';"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 综合贡献排名(PR + Issue)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COALESCE(pr.cnt, 0) AS pr_count,
|
||||
COALESCE(iss.cnt, 0) AS issue_count,
|
||||
COALESCE(pr.cnt, 0) + COALESCE(iss.cnt, 0) AS total
|
||||
FROM users u
|
||||
LEFT JOIN (
|
||||
SELECT creater_id, COUNT(*) AS cnt
|
||||
FROM pulls
|
||||
WHERE repo_id = <repo_id>
|
||||
AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY creater_id
|
||||
) pr ON u.id = pr.creater_id
|
||||
LEFT JOIN (
|
||||
SELECT creater_id, COUNT(*) AS cnt
|
||||
FROM issues
|
||||
WHERE repo_id = <repo_id>
|
||||
AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY creater_id
|
||||
) iss ON u.id = iss.creater_id
|
||||
WHERE pr.creater_id IS NOT NULL OR iss.creater_id IS NOT NULL
|
||||
ORDER BY total DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. PR 创建数排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(*) AS pr_created,
|
||||
SUM(CASE WHEN p.status = 'merged' THEN 1 ELSE 0 END) AS merged_count,
|
||||
ROUND(CAST(SUM(CASE WHEN p.status = 'merged' THEN 1 ELSE 0 END) AS REAL) / NULLIF(COUNT(*), 0) * 100, 1) AS merge_rate_pct
|
||||
FROM pulls p
|
||||
JOIN users u ON p.creater_id = u.id
|
||||
WHERE p.repo_id = <repo_id>
|
||||
AND date(p.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY p.creater_id
|
||||
ORDER BY pr_created DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Issue 创建数排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(*) AS issue_created,
|
||||
SUM(CASE WHEN i.status = 'close' THEN 1 ELSE 0 END) AS closed_count
|
||||
FROM issues i
|
||||
JOIN users u ON i.creater_id = u.id
|
||||
WHERE i.repo_id = <repo_id>
|
||||
AND date(i.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY i.creater_id
|
||||
ORDER BY issue_created DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PR 处理数排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(*) AS processed_count
|
||||
FROM pulls p
|
||||
JOIN users u ON p.processor_id = u.id
|
||||
WHERE p.repo_id = <repo_id>
|
||||
AND date(p.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY p.processor_id
|
||||
ORDER BY processed_count DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Issue 处理数排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(*) AS processed_count
|
||||
FROM issues i
|
||||
JOIN users u ON i.processor_id = u.id
|
||||
WHERE i.repo_id = <repo_id>
|
||||
AND date(i.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY i.processor_id
|
||||
ORDER BY processed_count DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 按标签统计 PR 排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
t.name AS tag,
|
||||
u.user_name,
|
||||
COUNT(*) AS pr_count
|
||||
FROM pulls p
|
||||
JOIN users u ON p.creater_id = u.id
|
||||
JOIN pull_tags pt ON p.id = pt.pull_id
|
||||
JOIN tags t ON pt.tag_id = t.id
|
||||
WHERE p.repo_id = <repo_id>
|
||||
AND t.repo_id = <repo_id>
|
||||
AND date(p.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY t.name, p.creater_id
|
||||
ORDER BY t.name, pr_count DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 按标签统计 Issue 排名
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
t.name AS tag,
|
||||
u.user_name,
|
||||
COUNT(*) AS issue_count
|
||||
FROM issues i
|
||||
JOIN users u ON i.creater_id = u.id
|
||||
JOIN issue_tags it ON i.id = it.issue_id
|
||||
JOIN tags t ON it.tag_id = t.id
|
||||
WHERE i.repo_id = <repo_id>
|
||||
AND t.repo_id = <repo_id>
|
||||
AND date(i.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY t.name, i.creater_id
|
||||
ORDER BY t.name, issue_count DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 标签列表(确认仓库有哪些标签)
|
||||
|
||||
```sql
|
||||
SELECT t.name, COUNT(pt.pull_id) + COUNT(it.issue_id) AS usage_count
|
||||
FROM tags t
|
||||
LEFT JOIN pull_tags pt ON t.id = pt.tag_id
|
||||
LEFT JOIN issue_tags it ON t.id = it.tag_id
|
||||
WHERE t.repo_id = <repo_id>
|
||||
GROUP BY t.id
|
||||
ORDER BY usage_count DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 徽章生成
|
||||
|
||||
Agent 应根据仓库实际数据自行设计徽章,而非套用预定义列表。
|
||||
|
||||
### 流程
|
||||
|
||||
1. 执行查询 1-8 获取排名和标签数据
|
||||
2. 从数据中识别值得表彰的模式(活跃度、质量、持续性、领域专精等)
|
||||
3. 为每种模式设计徽章:命名、设定条件、确定获奖者
|
||||
|
||||
### 勘探查询
|
||||
|
||||
以下附加查询用于提取维度数据,帮助发现模式。
|
||||
|
||||
#### 用户综合画像
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(DISTINCT p.id) AS pr_created,
|
||||
SUM(CASE WHEN p.status = 'merged' THEN 1 ELSE 0 END) AS pr_merged,
|
||||
COUNT(DISTINCT i.id) AS issue_created,
|
||||
COUNT(DISTINCT proc_pr.id) AS pr_processed,
|
||||
COUNT(DISTINCT proc_is.id) AS issue_processed
|
||||
FROM users u
|
||||
LEFT JOIN pulls p ON u.id = p.creater_id AND p.repo_id = <repo_id>
|
||||
AND date(p.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
LEFT JOIN issues i ON u.id = i.creater_id AND i.repo_id = <repo_id>
|
||||
AND date(i.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
LEFT JOIN pulls proc_pr ON u.id = proc_pr.processor_id AND proc_pr.repo_id = <repo_id>
|
||||
AND date(proc_pr.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
LEFT JOIN issues proc_is ON u.id = proc_is.processor_id AND proc_is.repo_id = <repo_id>
|
||||
AND date(proc_is.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY u.id
|
||||
HAVING pr_created > 0 OR issue_created > 0 OR pr_processed > 0 OR issue_processed > 0
|
||||
ORDER BY (pr_created + pr_merged + issue_created + pr_processed + issue_processed) DESC;
|
||||
```
|
||||
|
||||
#### 新人发现
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
MIN(MIN(p.create_time), MIN(i.create_time)) AS first_activity,
|
||||
COALESCE(pr.cnt, 0) + COALESCE(iss.cnt, 0) AS period_activity
|
||||
FROM users u
|
||||
LEFT JOIN pulls p ON u.id = p.creater_id AND p.repo_id = <repo_id>
|
||||
LEFT JOIN issues i ON u.id = i.creater_id AND i.repo_id = <repo_id>
|
||||
LEFT JOIN (
|
||||
SELECT creater_id, COUNT(*) AS cnt FROM pulls
|
||||
WHERE repo_id = <repo_id> AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY creater_id
|
||||
) pr ON u.id = pr.creater_id
|
||||
LEFT JOIN (
|
||||
SELECT creater_id, COUNT(*) AS cnt FROM issues
|
||||
WHERE repo_id = <repo_id> AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
GROUP BY creater_id
|
||||
) iss ON u.id = iss.creater_id
|
||||
WHERE first_activity IS NOT NULL
|
||||
GROUP BY u.id
|
||||
HAVING date(first_activity) BETWEEN '<start_date>' AND '<end_date>'
|
||||
ORDER BY period_activity DESC;
|
||||
```
|
||||
|
||||
#### 活跃持续性(按周)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
u.user_name,
|
||||
COUNT(DISTINCT week) AS active_weeks,
|
||||
MIN(week) AS first_week,
|
||||
MAX(week) AS last_week
|
||||
FROM (
|
||||
SELECT creater_id, strftime('%Y-%W', create_time) AS week FROM pulls
|
||||
WHERE repo_id = <repo_id> AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
UNION
|
||||
SELECT creater_id, strftime('%Y-%W', create_time) FROM issues
|
||||
WHERE repo_id = <repo_id> AND date(create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
) activity
|
||||
JOIN users u ON activity.creater_id = u.id
|
||||
GROUP BY u.id
|
||||
HAVING active_weeks >= 2
|
||||
ORDER BY active_weeks DESC;
|
||||
```
|
||||
|
||||
#### 标签贡献模板
|
||||
|
||||
先执行查询 8 获取标签列表,再逐个代入:
|
||||
|
||||
```sql
|
||||
-- 将 <tag_name> 替换为查询 8 返回的实际标签名
|
||||
SELECT u.user_name, COUNT(*) AS tag_contribution
|
||||
FROM users u
|
||||
LEFT JOIN (
|
||||
SELECT creater_id FROM pulls p
|
||||
JOIN pull_tags pt ON p.id = pt.pull_id
|
||||
JOIN tags t ON pt.tag_id = t.id
|
||||
WHERE p.repo_id = <repo_id> AND t.repo_id = <repo_id>
|
||||
AND t.name = '<tag_name>'
|
||||
AND date(p.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
) tag_pr ON u.id = tag_pr.creater_id
|
||||
LEFT JOIN (
|
||||
SELECT creater_id FROM issues i
|
||||
JOIN issue_tags it ON i.id = it.issue_id
|
||||
JOIN tags t ON it.tag_id = t.id
|
||||
WHERE i.repo_id = <repo_id> AND t.repo_id = <repo_id>
|
||||
AND t.name = '<tag_name>'
|
||||
AND date(i.create_time) BETWEEN '<start_date>' AND '<end_date>'
|
||||
) tag_iss ON u.id = tag_iss.creater_id
|
||||
WHERE tag_pr.creater_id IS NOT NULL OR tag_iss.creater_id IS NOT NULL
|
||||
GROUP BY u.id
|
||||
ORDER BY tag_contribution DESC;
|
||||
```
|
||||
|
||||
### 设计原则
|
||||
|
||||
- 徽章名称从数据特征派生(如标签名、行为类型),不套用固定模板
|
||||
- 阈值参考数据分布(取前 N 名、高于均值、或连续 N 周活跃等)
|
||||
- 每个徽章至少 1 人获得;无人达标则不发
|
||||
- 在报告中说明每个徽章的数据依据
|
||||
|
||||
---
|
||||
|
||||
## 报告组装清单
|
||||
|
||||
**按以下顺序逐项执行查询、填入模板。每完成一项打勾,最终输出前核对所有 ✅ 是否齐全。**
|
||||
|
||||
### 排行榜数据
|
||||
|
||||
- [ ] **综合贡献排名** → 执行查询 1,取全部结果
|
||||
- [ ] **PR 创建数排名** → 执行查询 2,取前 10 名
|
||||
- [ ] **Issue 创建数排名** → 执行查询 3,取前 10 名
|
||||
- [ ] **PR 处理数排名** → 执行查询 4,取前 10 名(结果为空则跳过此项)
|
||||
- [ ] **Issue 处理数排名** → 执行查询 5,取前 10 名(结果为空则跳过此项)
|
||||
|
||||
### 细分领域排行(仅当有标签数据时)
|
||||
|
||||
- [ ] **标签列表** → 执行查询 8,确认仓库有哪些标签
|
||||
- [ ] **按标签 PR 排名** → 执行查询 6,有标签数据时执行
|
||||
- [ ] **按标签 Issue 排名** → 执行查询 7,有标签数据时执行
|
||||
- [ ] **按标签汇总填充** → 填入模板的「细分领域排行」章节
|
||||
|
||||
### 徽章数据
|
||||
|
||||
- [ ] 执行查询 1-8 和勘探查询获取完整数据画像
|
||||
- [ ] 分析数据,识别值得表彰的模式
|
||||
- [ ] 为每种模式设计徽章(名称、条件、获奖者),附数据依据
|
||||
- [ ] 若全维度均无突出数据,输出"本期无人获得徽章"
|
||||
|
||||
### 最终输出核对
|
||||
|
||||
- [ ] 报告包含「徽章展示」「贡献排行榜」「细分领域排行」三个主要章节
|
||||
- [ ] 徽章表格不为空(即使无徽章,也显示"本期无人获得徽章")
|
||||
- [ ] 排行榜表格有列名
|
||||
- [ ] 报告头部包含 owner/repo、分析期间、生成时间
|
||||
Loading…
Reference in New Issue