From d86d78c187d35267c5947318733840807cc08231 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:09:46 +0000 Subject: [PATCH 1/2] Initial plan From b3a518b9ec32489482346556c310ad13a67421e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:41:04 +0000 Subject: [PATCH 2/2] docs(project): add master branch 4-week commit analysis report Add commit analysis report for ralf003/zeroclaw master branch based on GitHub API data (1,400 unique commits, 15 pages). Includes: - Methodology: rolling 7-day windows, bot/merge exclusion rules, author identity resolution (login-first) - Strict 4-week window table (2026-03-12..2026-04-08): 0 commits, documented with explanation that last commit was 2026-03-08 - Actual 4-week activity window table (2026-02-09..2026-03-08): full per-week totals, author counts, Top 10 authors - Analysis summary: activity trend, top contributor profiles, dominant maintainer (chumyin), burst-pattern contributors - Appendix: helper script commit_weekly_stats.py with usage example Also adds scripts/commit_weekly_stats.py for reproducible local stats. Agent-Logs-Url: https://github.com/ralf003/zeroclaw/sessions/65e67763-2712-481f-afda-03721ae7cadc Co-authored-by: ralf003 <206904126+ralf003@users.noreply.github.com> --- docs/commit-analysis-2026-04-08.md | 312 +++++++++++++++++++++++++++++ scripts/commit_weekly_stats.py | 144 +++++++++++++ 2 files changed, 456 insertions(+) create mode 100644 docs/commit-analysis-2026-04-08.md create mode 100644 scripts/commit_weekly_stats.py diff --git a/docs/commit-analysis-2026-04-08.md b/docs/commit-analysis-2026-04-08.md new file mode 100644 index 00000000000..844b674c006 --- /dev/null +++ b/docs/commit-analysis-2026-04-08.md @@ -0,0 +1,312 @@ +# ZeroClaw master 分支近 4 周 Commit 提交分析报告 + +> **报告基准日期**:2026-04-08 +> **数据来源**:GitHub REST API (`GET /repos/ralf003/zeroclaw/commits`),共收集 `master` 分支全部历史提交(约 1,400 条,分 15 页拉取)。 + +--- + +## 1. 统计方法说明 + +### 1.1 周区间划分 + +以**报告基准日期(2026-04-08)**为终点,向前滚动 28 天(4 × 7 天),形成 4 个统计周: + +| 周次 | 区间(UTC,含首尾) | +|------|----------------------| +| 第 4 周(最近) | 2026-04-02..2026-04-08 | +| 第 3 周 | 2026-03-26..2026-04-01 | +| 第 2 周 | 2026-03-19..2026-03-25 | +| 第 1 周(最早) | 2026-03-12..2026-03-18 | + +> ⚠️ **数据说明**:经 API 完整拉取,该仓库 `master` 分支最后一次提交时间为 **2026-03-08 03:33 UTC**(PR #2954,`fix: resolve unused import warnings`)。上述严格基准窗口(2026-03-12..2026-04-08)内**实际存在 0 条提交**,即仓库在报告日期前约 31 天已停止接收新提交。 +> +> 因此,本报告**同时提供基于实际活跃周期的分析表格**——以最后提交日期(2026-03-08)为终点向前滚动 28 天(2026-02-09..2026-03-08),以保证分析结果具有实质意义。两套数据均已注明,便于读者对照。 + +### 1.2 数据收集方式 + +- **工具**:GitHub REST API `GET /repos/ralf003/zeroclaw/commits?sha=master&per_page=100`,分页遍历,去重(按 SHA)后合并,共采集 **1,400 条唯一提交**。 +- **时间字段**:使用 `commit.author.date`(提交者本地创作时间)而非 `commit.committer.date`,更准确反映代码贡献时间点。 +- **时区统一**:所有时间转换为 UTC 再进行区间归档。 + +### 1.3 排除规则 + +| 类型 | 识别标准 | 处理方式 | +|------|----------|----------| +| **Merge commit** | 消息以 `"Merge pull request"` 或 `"Merge branch"` 开头 | 计入总数,但在 Top 10 作者统计中可单独标注 | +| **Bot 提交** | 作者名或 GitHub login 包含 `[bot]`、`dependabot`、`github-actions` | 计入总数时单独列出,Top 10 中剔除 | + +### 1.4 作者身份判定 + +优先使用 **GitHub 登录名(`author.login`)**作为作者标识(唯一且稳定);若 API 返回的 `author` 字段为 `null`(外部贡献者未关联账户),则回退为 `commit.author.name`。 + +> **注意**:`chumyin`(GitHub login)与 `Chummy`(部分早期提交中的 `author.name`)为同一账号,已统一归并到 `chumyin`。 + +--- + +## 2. 提交统计表格 + +### 2A. 基于报告基准日期的严格窗口(2026-03-12..2026-04-08) + +| 周次 | 区间 | 总提交数 | 有提交的作者数 | Top 10 作者(作者名:提交数) | +|------|------|:--------:|:------------:|-------------------------------| +| 第 4 周 | 2026-04-02..2026-04-08 | 0 | 0 | — | +| 第 3 周 | 2026-03-26..2026-04-01 | 0 | 0 | — | +| 第 2 周 | 2026-03-19..2026-03-25 | 0 | 0 | — | +| 第 1 周 | 2026-03-12..2026-03-18 | 0 | 0 | — | +| **合计** | 2026-03-12..2026-04-08 | **0** | **0** | — | + +> 该窗口内无任何提交。仓库最近一次 commit 发生于 2026-03-08(窗口开始前 4 天)。 + +--- + +### 2B. 基于实际活跃周期的滚动窗口(2026-02-09..2026-03-08) + +> 以仓库最后一次提交日期(2026-03-08)为终点,向前滚动 28 天。下表展示真实提交数据。 + +#### 汇总概览 + +| 周次 | 区间 | 总提交数 | Bot 提交数 | 人工提交数 | 有提交的作者数 | +|------|------|:--------:|:----------:|:----------:|:-------------:| +| 第 1 周 | 2026-02-09..2026-02-15 | 192 | 0 | 192 | 17 | +| 第 2 周 | 2026-02-16..2026-02-22 | 1,127 | 31 | 1,096 | 109 | +| 第 3 周 | 2026-02-23..2026-03-01 | 56 | 0 | 56 | 16 | +| 第 4 周 | 2026-03-02..2026-03-08 | 25 | 0 | 25 | 4 | +| **合计** | 2026-02-09..2026-03-08 | **1,400** | **31** | **1,369** | **~136** | + +#### 第 1 周:2026-02-09..2026-02-15 + +| 排名 | 作者(GitHub 登录名) | 当周提交数 | +|------|----------------------|:---------:| +| 1 | theonlyhennygod | 119 | +| 2 | fettpl | 36 | +| 3 | ecschoye | 9 | +| 4 | Chummy (→ chumyin) | 6 | +| 5 | vrescobar | 5 | +| 6 | Codex | 3 | +| 7 | willsarg | 2 | +| 8 | kumanday | 2 | +| 9 | jbradf0rd | 2 | +| 10 | Abhishek | 1 | + +> 该周从 2026-02-13 才有首次提交(初始版本发布 `feat: initial release — ZeroClaw v0.1.0`)。 + +#### 第 2 周:2026-02-16..2026-02-22 + +| 排名 | 作者(GitHub 登录名) | 当周提交数 | +|------|----------------------|:---------:| +| 1 | chumyin | 430 | +| 2 | willsarg | 119 | +| 3 | agorevski | 112 | +| 4 | theonlyhennygod | 56 | +| 5 | fettpl | 39 | +| 6 | ecschoye | 29 | +| 7 | zverozabr | 21 | +| 8 | vernonstinebaker | 19 | +| 9 | reidliu41 | 18 | +| 10 | v0l | 14 | + +> 该周为活跃度峰值,共 1,127 次提交(含 31 次 bot 提交),109 位作者参与贡献。 + +#### 第 3 周:2026-02-23..2026-03-01 + +| 排名 | 作者(GitHub 登录名) | 当周提交数 | +|------|----------------------|:---------:| +| 1 | chumyin | 35 | +| 2 | theonlyhennygod | 4 | +| 3 | Preventnetworkhacking | 2 | +| 4 | Mike Johnson-Maxted | 2 | +| 5 | reidliu41 | 2 | +| 6 | Allen Huang | 1 | +| 7 | NorbertBodziony | 1 | +| 8 | adam-singer | 1 | +| 9 | bzivic | 1 | +| 10 | madamak | 1 | + +#### 第 4 周:2026-03-02..2026-03-08 + +| 排名 | 作者(GitHub 登录名) | 当周提交数 | +|------|----------------------|:---------:| +| 1 | JordanTheJet | 21 | +| 2 | SimianAstronaut7 | 2 | +| 3 | theonlyhennygod | 1 | +| 4 | antonvice | 1 | + +--- + +## 3. 简要分析总结 + +### 3.1 活跃度趋势 + +``` +提交数 +1127 |██████████████████████████████████████████ + | + 192 |████████ + | + 56 |███ + 25 |█ + |—————————————————————————————————————————→ 周次 + W1(02/09) W2(02/16) W3(02/23) W4(03/02) +``` + +活跃度呈**极端倒 V 形**:仓库于 2026-02-13 初始发布,W2(2026-02-16..2026-02-22)仅用一周即爆发至 **1,127 次提交、109 位作者**,随后急剧回落——W3 降至 56 次(降幅 95%),W4 仅余 25 次。2026-03-08 后仓库不再有新提交(截至报告日 2026-04-08)。 + +### 3.2 Top 作者贡献特征 + +| 作者 | 总提交数(近 4 活跃周) | 主要活跃周 | 备注 | +|------|:-----------------------:|------------|------| +| **chumyin** | 471 | W2(430)、W3(35) | 核心维护者,峰值单周 430 次 | +| **theonlyhennygod** | 180 | W1(119)、W2(56) | 项目创始人(初始版本作者) | +| **willsarg** | 121 | W2(119)主导 | 集中贡献于峰值周 | +| **agorevski** | 112 | W2(112)主导 | 集中贡献于峰值周 | +| **fettpl** | 75 | W1(36)、W2(39) | 横跨前两周的早期贡献者 | +| **JordanTheJet** | 21 | W4(21)主导 | 后期主力,最后一批活跃贡献者 | + +### 3.3 主力作者分析 + +- **明显主力作者存在**:`chumyin` 在 28 天内贡献了 **471 次提交(占比约 33.6%)**,是无可争议的核心维护者,高度集中在 W2 峰值周(430 次,占该周总数的 38.2%)。 +- **冲刺型贡献者**:`willsarg`(119 次)、`agorevski`(112 次)在 W2 集中大量贡献后几乎退出,表现出典型的"冲刺合并"模式——可能是集中 PR review/merge 批量落库。 +- **长期活跃作者**:`theonlyhennygod` 横跨 W1~W3 持续贡献(共 180 次),`fettpl` 横跨 W1~W2(共 75 次)。 +- **后期收缩明显**:W3、W4 的参与作者数从峰值 109 位骤降至 16、4 位,表明该仓库在快速开发冲刺后进入低活跃维护期或已结束主动开发。 + +### 3.4 补充说明 + +- **Merge commit 占比**:W2 包含约 101 次人工 merge commit,实际代码变更提交数约为 995 次。 +- **Bot 提交**:W2 出现 31 次 `dependabot[bot]` 自动提交(依赖升级),其余三周无 bot 提交。 +- **报告窗口差异说明**:基于当前日期的严格窗口(2026-03-12..2026-04-08)无数据,本报告以最后提交日(2026-03-08)为基准补充实际活跃数据分析,两套结果均已在 §2 中呈现。 + +--- + +## 4. 附录:辅助分析脚本 + +以下 Python 脚本可本地复现上述统计,仅需 GitHub Token 即可运行。 + +### 用法示例 + +```bash +# 安装依赖 +pip install requests + +# 设置 GitHub Token(可选,提升速率上限) +export GITHUB_TOKEN="your_token_here" + +# 运行统计 +python3 scripts/commit_weekly_stats.py \ + --owner ralf003 \ + --repo zeroclaw \ + --branch master \ + --base-date 2026-04-08 \ + --weeks 4 +``` + +### 脚本核心逻辑(`scripts/commit_weekly_stats.py`) + +```python +#!/usr/bin/env python3 +""" +ZeroClaw 周提交统计脚本 +用法: python3 commit_weekly_stats.py --owner OWNER --repo REPO [--base-date YYYY-MM-DD] [--weeks N] +""" + +import argparse +import os +import sys +from collections import defaultdict +from datetime import datetime, timedelta, timezone + +import requests + + +def fetch_commits(owner: str, repo: str, branch: str, token: str | None = None) -> list[dict]: + """分页拉取全部提交,按 author.date 降序返回。""" + headers = {"Accept": "application/vnd.github.v3+json"} + if token: + headers["Authorization"] = f"Bearer {token}" + + all_commits: list[dict] = [] + page = 1 + while True: + url = f"https://api.github.com/repos/{owner}/{repo}/commits" + resp = requests.get(url, headers=headers, params={"sha": branch, "per_page": 100, "page": page}, timeout=30) + resp.raise_for_status() + data = resp.json() + if not data: + break + all_commits.extend(data) + page += 1 + return all_commits + + +def parse_date(commit: dict) -> datetime: + return datetime.fromisoformat(commit["commit"]["author"]["date"].replace("Z", "+00:00")) + + +def get_author(commit: dict) -> str: + author_obj = commit.get("author") + if author_obj and author_obj.get("login") and "[bot]" not in author_obj["login"]: + return author_obj["login"] + return commit["commit"]["author"]["name"] + + +def is_bot(commit: dict) -> bool: + name = commit["commit"]["author"]["name"].lower() + login = (commit.get("author") or {}).get("login", "").lower() + return any(kw in name or kw in login for kw in ("[bot]", "dependabot", "github-actions")) + + +def build_weeks(base_date: datetime, n_weeks: int) -> list[tuple[datetime, datetime]]: + """返回 [(week_start, week_end), ...] 从最旧到最新排列。""" + weeks = [] + end = base_date.replace(hour=23, minute=59, second=59, microsecond=0) + for _ in range(n_weeks): + start = end - timedelta(days=6) + start = start.replace(hour=0, minute=0, second=0, microsecond=0) + weeks.append((start, end)) + end = start - timedelta(seconds=1) + return list(reversed(weeks)) + + +def analyze(commits: list[dict], weeks: list[tuple[datetime, datetime]]) -> None: + print(f"\n{'周次':<6} {'区间':<25} {'总提交':>6} {'Bot':>5} {'作者数':>6} Top 10 作者") + print("-" * 100) + for i, (wstart, wend) in enumerate(weeks, 1): + wc = [c for c in commits if wstart <= parse_date(c) <= wend] + n_bot = sum(1 for c in wc if is_bot(c)) + author_counts: dict[str, int] = defaultdict(int) + for c in wc: + if not is_bot(c): + author_counts[get_author(c)] += 1 + top10 = sorted(author_counts.items(), key=lambda x: -x[1])[:10] + top_str = ", ".join(f"{a}:{n}" for a, n in top10) + label = f"{wstart.strftime('%Y-%m-%d')}..{wend.strftime('%Y-%m-%d')}" + print(f"W{i:<5} {label:<25} {len(wc):>6} {n_bot:>5} {len(author_counts):>6} {top_str}") + + +def main() -> None: + parser = argparse.ArgumentParser(description="ZeroClaw 周提交统计") + parser.add_argument("--owner", required=True) + parser.add_argument("--repo", required=True) + parser.add_argument("--branch", default="master") + parser.add_argument("--base-date", default=datetime.now(tz=timezone.utc).strftime("%Y-%m-%d")) + parser.add_argument("--weeks", type=int, default=4) + args = parser.parse_args() + + token = os.environ.get("GITHUB_TOKEN") + base = datetime.strptime(args.base_date, "%Y-%m-%d").replace(tzinfo=timezone.utc) + weeks = build_weeks(base, args.weeks) + + print(f"正在拉取 {args.owner}/{args.repo}@{args.branch} 的提交历史…") + commits = fetch_commits(args.owner, args.repo, args.branch, token) + print(f"共拉取 {len(commits)} 条提交。") + analyze(commits, weeks) + + +if __name__ == "__main__": + main() +``` + +> 脚本完整版本位于仓库 `scripts/commit_weekly_stats.py`(如该文件尚未创建,可将上述代码复制保存后直接运行)。 + +--- + +*本报告由 GitHub API 数据自动生成,生成时间:2026-04-08T08:10:13Z。* diff --git a/scripts/commit_weekly_stats.py b/scripts/commit_weekly_stats.py new file mode 100644 index 00000000000..fa168b4c069 --- /dev/null +++ b/scripts/commit_weekly_stats.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +"""ZeroClaw 周提交统计脚本 + +使用方式: + python3 scripts/commit_weekly_stats.py \\ + --owner ralf003 \\ + --repo zeroclaw \\ + --branch master \\ + --base-date 2026-04-08 \\ + --weeks 4 + +环境变量: + GITHUB_TOKEN (可选) GitHub Personal Access Token,可提升 API 速率上限 +""" + +import argparse +import os +from collections import defaultdict +from datetime import datetime, timedelta, timezone + +import requests + + +def fetch_commits(owner: str, repo: str, branch: str, token: str | None = None) -> list[dict]: + """分页拉取指定分支的全部提交(按 author.date 降序返回)。""" + headers = {"Accept": "application/vnd.github.v3+json"} + if token: + headers["Authorization"] = f"Bearer {token}" + + all_commits: list[dict] = [] + page = 1 + while True: + url = f"https://api.github.com/repos/{owner}/{repo}/commits" + resp = requests.get( + url, + headers=headers, + params={"sha": branch, "per_page": 100, "page": page}, + timeout=30, + ) + resp.raise_for_status() + data = resp.json() + if not data: + break + all_commits.extend(data) + page += 1 + return all_commits + + +def parse_date(commit: dict) -> datetime: + """解析 commit.author.date 为带时区的 datetime(UTC)。""" + return datetime.fromisoformat(commit["commit"]["author"]["date"].replace("Z", "+00:00")) + + +def get_author(commit: dict) -> str: + """优先返回 GitHub login;若不可用则回退到 commit author name。""" + author_obj = commit.get("author") + if author_obj and author_obj.get("login") and "[bot]" not in author_obj["login"]: + return author_obj["login"] + return commit["commit"]["author"]["name"] + + +def is_bot(commit: dict) -> bool: + """判断是否为 bot 提交(dependabot、github-actions 等)。""" + name = commit["commit"]["author"]["name"].lower() + login = (commit.get("author") or {}).get("login", "").lower() + return any(kw in name or kw in login for kw in ("[bot]", "dependabot", "github-actions")) + + +def is_merge(commit: dict) -> bool: + """判断是否为 merge commit。""" + msg = commit["commit"]["message"] + return msg.startswith("Merge pull request") or msg.startswith("Merge branch") + + +def build_weeks(base_date: datetime, n_weeks: int) -> list[tuple[datetime, datetime]]: + """构建滚动周区间,返回 [(week_start, week_end), ...] 从最旧到最新排列。""" + weeks: list[tuple[datetime, datetime]] = [] + end = base_date.replace(hour=23, minute=59, second=59, microsecond=0) + for _ in range(n_weeks): + start = (end - timedelta(days=6)).replace(hour=0, minute=0, second=0, microsecond=0) + weeks.append((start, end)) + end = start - timedelta(seconds=1) + return list(reversed(weeks)) + + +def analyze(commits: list[dict], weeks: list[tuple[datetime, datetime]], top_n: int = 10) -> None: + """输出 Markdown 格式的周统计表格。""" + print( + "\n| 周次 | 区间 | 总提交数 | Bot 提交 | 人工提交 | 作者数 | " + f"Top {top_n} 作者(作者:提交数) |" + ) + print("|------|------|:--------:|:--------:|:--------:|:------:|---|") + + for i, (wstart, wend) in enumerate(weeks, 1): + wc = [c for c in commits if wstart <= parse_date(c) <= wend] + n_bot = sum(1 for c in wc if is_bot(c)) + author_counts: dict[str, int] = defaultdict(int) + for c in wc: + if not is_bot(c): + author_counts[get_author(c)] += 1 + top = sorted(author_counts.items(), key=lambda x: -x[1])[:top_n] + top_str = ", ".join(f"`{a}`:{n}" for a, n in top) if top else "—" + label = f"{wstart.strftime('%Y-%m-%d')}..{wend.strftime('%Y-%m-%d')}" + human = len(wc) - n_bot + print( + f"| W{i} | {label} | {len(wc)} | {n_bot} | {human} | " + f"{len(author_counts)} | {top_str} |" + ) + + +def main() -> None: + parser = argparse.ArgumentParser(description="ZeroClaw 周提交统计") + parser.add_argument("--owner", required=True, help="仓库所有者(用户名/组织名)") + parser.add_argument("--repo", required=True, help="仓库名称") + parser.add_argument("--branch", default="master", help="分支名(默认:master)") + parser.add_argument( + "--base-date", + default=None, + help="统计基准日期 YYYY-MM-DD(默认:今天 UTC)", + ) + parser.add_argument("--weeks", type=int, default=4, help="统计周数(默认:4)") + parser.add_argument("--top", type=int, default=10, help="Top N 作者(默认:10)") + args = parser.parse_args() + + token = os.environ.get("GITHUB_TOKEN") + if args.base_date: + base = datetime.strptime(args.base_date, "%Y-%m-%d").replace(tzinfo=timezone.utc) + else: + base = datetime.now(tz=timezone.utc) + + weeks = build_weeks(base, args.weeks) + + print(f"# ZeroClaw 提交周报") + print(f"仓库: {args.owner}/{args.repo} 分支: {args.branch}") + print(f"基准日期: {base.strftime('%Y-%m-%d')} 统计周数: {args.weeks}") + print(f"\n正在拉取提交历史(可能需要数分钟)…") + + commits = fetch_commits(args.owner, args.repo, args.branch, token) + print(f"共拉取 {len(commits)} 条提交。\n") + analyze(commits, weeks, top_n=args.top) + + +if __name__ == "__main__": + main()