From 5089874cd6e06a3e5923e2dd7385a7014cd1abd2 Mon Sep 17 00:00:00 2001 From: farmyobutu5233 Date: Sun, 5 Jul 2026 12:25:02 +0000 Subject: [PATCH] =?UTF-8?q?feat(repro-audit):=20=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=8D=95=E4=BB=93=E5=A4=B1=E8=B4=A5=E5=AE=B9?= =?UTF-8?q?=E9=94=99=E5=B9=B6=E5=88=97=E5=85=A5=E6=B1=87=E6=80=BB=EF=BC=9B?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=205=20=E4=BB=93=E5=BA=93=E7=9C=9F=E5=AE=9E?= =?UTF-8?q?=E6=89=B9=E9=87=8F=20demo=20=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../examples/demo-outputs/repos-batch.txt | 6 +++++ ...epro-audit-steph1-Awesome-Paper-Crawler.md | 17 +++++++++++++ .../demo-outputs/repro-audit-summary.md | 12 ++++++++++ .../repro-audit/scripts/repro_audit.py | 24 ++++++++++++------- .../research/repro-audit/tests/test_audit.py | 5 ++++ 5 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 examples/research/repro-audit/examples/demo-outputs/repos-batch.txt create mode 100644 examples/research/repro-audit/examples/demo-outputs/repro-audit-steph1-Awesome-Paper-Crawler.md create mode 100644 examples/research/repro-audit/examples/demo-outputs/repro-audit-summary.md diff --git a/examples/research/repro-audit/examples/demo-outputs/repos-batch.txt b/examples/research/repro-audit/examples/demo-outputs/repos-batch.txt new file mode 100644 index 0000000..84f20b1 --- /dev/null +++ b/examples/research/repro-audit/examples/demo-outputs/repos-batch.txt @@ -0,0 +1,6 @@ +# 真实科研相关仓库批量复现性审计清单 +GengzhaoWang/UAV-Paper +momomym/paper-summarizer +zhaoyihan/paper-data-redundancy +steph1/Awesome-Paper-Crawler +datawhalechina/paper-chart-tutorial diff --git a/examples/research/repro-audit/examples/demo-outputs/repro-audit-steph1-Awesome-Paper-Crawler.md b/examples/research/repro-audit/examples/demo-outputs/repro-audit-steph1-Awesome-Paper-Crawler.md new file mode 100644 index 0000000..8d99e1d --- /dev/null +++ b/examples/research/repro-audit/examples/demo-outputs/repro-audit-steph1-Awesome-Paper-Crawler.md @@ -0,0 +1,17 @@ +# 科研复现性审计报告:steph1/Awesome-Paper-Crawler(ref: 默认分支) + +**总分:8/100 — 等级 D(复现困难)** + +| 检查项 | 得分 | 证据 | 建议 | +|--------|------|------|------| +| README 与运行说明 | 8/15 | README=README.md;运行/复现章节=未检出 | 补充 README 并加入 How to run / 复现步骤章节 | +| 开源许可证 | 0/15 | 许可证文件=缺失 | 添加 LICENSE 文件(科研代码推荐 MIT/Apache-2.0/BSD) | +| 引用信息 | 0/10 | CITATION 文件=无;README 引用章节=无 | 添加 CITATION.cff 或在 README 中给出 BibTeX | +| 依赖清单(环境固化) | 0/15 | 依赖文件=缺失 | 添加 requirements.txt / environment.yml 等依赖清单并固定版本 | +| 运行入口 | 0/10 | 入口=未检出 | 提供 Makefile / run.sh / main.py 等一键运行入口 | +| 数据可得性说明 | 0/10 | 数据目录=无;README 数据说明=无 | 在 README 中说明数据集来源、获取方式与预处理步骤 | +| 测试/验证代码 | 0/10 | 测试目录=无 | 添加 tests/ 验证关键结果可复算 | +| 版本发布(成果固化) | 0/15 | release 数=0 | 为论文对应的代码状态打 tag 并创建 release | + +--- +*由 repro-audit 生成(确定性检查,同输入同输出)。* \ No newline at end of file diff --git a/examples/research/repro-audit/examples/demo-outputs/repro-audit-summary.md b/examples/research/repro-audit/examples/demo-outputs/repro-audit-summary.md new file mode 100644 index 0000000..233c8cd --- /dev/null +++ b/examples/research/repro-audit/examples/demo-outputs/repro-audit-summary.md @@ -0,0 +1,12 @@ +# 批量复现性审计汇总 + +| 仓库 | 得分 | 等级 | +|------|------|------| +| momomym/paper-summarizer | 58/100 | C(存在明显缺口) | +| GengzhaoWang/UAV-Paper | 8/100 | D(复现困难) | +| steph1/Awesome-Paper-Crawler | 8/100 | D(复现困难) | + +## 无法审计的仓库 + +- datawhalechina/paper-chart-tutorial:gitlink-cli repo +tree --owner datawhalechina --repo paper-chart-tutorial --format json 失败: [-2] 你访问的文件不存在 +- zhaoyihan/paper-data-redundancy:gitlink-cli repo +tree --owner zhaoyihan --repo paper-data-redundancy --format json 失败: [-2] 你访问的文件不存在 diff --git a/examples/research/repro-audit/scripts/repro_audit.py b/examples/research/repro-audit/scripts/repro_audit.py index a0dacfd..baff289 100644 --- a/examples/research/repro-audit/scripts/repro_audit.py +++ b/examples/research/repro-audit/scripts/repro_audit.py @@ -205,13 +205,16 @@ def read_repos_file(path): return repos -def render_summary(rows): - """批量审计汇总表(确定性:按得分降序、同分按名称)。""" +def render_summary(rows, failures=()): + """批量审计汇总表(确定性:按得分降序、同分按名称;失败仓库单独列出)。""" rows = sorted(rows, key=lambda r: (-r[1], r[0])) lines = ["# 批量复现性审计汇总", "", "| 仓库 | 得分 | 等级 |", "|------|------|------|"] for name, total in rows: grade = next(g for t, g in GRADE if total >= t) lines.append(f"| {name} | {total}/100 | {grade} |") + if failures: + lines += ["", "## 无法审计的仓库", ""] + lines += [f"- {name}:{reason}" for name, reason in sorted(failures)] return "\n".join(lines) + "\n" @@ -233,17 +236,22 @@ def main(): out_dir.mkdir(parents=True, exist_ok=True) if args.repos_file: - rows = [] + rows, failures = [], [] for owner, repo in read_repos_file(args.repos_file): - total = audit_repo(owner, repo, args.ref, out_dir, args.cli, - apply_issue=args.apply, echo=False) - rows.append((f"{owner}/{repo}", total)) - summary = render_summary(rows) + name = f"{owner}/{repo}" + try: + total = audit_repo(owner, repo, args.ref, out_dir, args.cli, + apply_issue=args.apply, echo=False) + rows.append((name, total)) + except RuntimeError as exc: + print(f"跳过 {name}:{exc}", file=sys.stderr) + failures.append((name, str(exc))) + summary = render_summary(rows, failures) summary_path = out_dir / "repro-audit-summary.md" summary_path.write_text(summary, encoding="utf-8") print(summary) print(f"汇总已保存:{summary_path}", file=sys.stderr) - return 0 if all(t >= 70 for _, t in rows) else 2 + return 0 if not failures and all(t >= 70 for _, t in rows) else 2 total = audit_repo(args.owner, args.repo, args.ref, out_dir, args.cli, apply_issue=args.apply) diff --git a/examples/research/repro-audit/tests/test_audit.py b/examples/research/repro-audit/tests/test_audit.py index 762127f..85047ae 100644 --- a/examples/research/repro-audit/tests/test_audit.py +++ b/examples/research/repro-audit/tests/test_audit.py @@ -89,6 +89,11 @@ class AuditTest(unittest.TestCase): self.assertIn("A(可复现性良好)", rows[0]) self.assertIn("D(复现困难)", rows[2]) + def test_render_summary_lists_failures(self): + summary = render_summary([("o/ok", 80)], failures=[("o/broken", "仓库树读取失败")]) + self.assertIn("## 无法审计的仓库", summary) + self.assertIn("- o/broken:仓库树读取失败", summary) + if __name__ == "__main__": unittest.main()