从Git提交记录和日历中自动提取信息,一键生成结构化团队周报。
项目背景
每周五下午,团队负责人最头疼的事就是催周报。有人拖到周日晚上才交,有人写三行字糊弄过去。手动汇总更是折磨——打开每个人的文件,复制粘贴,调整格式,改一天就过去了。
有没有办法让周报自动生成?
这个项目的目标是用Python脚本,从Git提交记录和日历中自动提取本周工作信息,生成一份结构清晰、可直接发送的HTML周报。
技术选型
- Python 3.10+:主力语言
- GitPython:读取Git仓库提交历史
- Jinja2:HTML模板渲染
- smtplib + email:邮件发送(可选)
- Cron / GitHub Actions:定时触发
不需要数据库,不需要前端框架。纯Python脚本,跑在任意服务器上即可。
实现步骤
第一步:安装依赖
pip install gitpython jinja2
第二步:创建HTML模板
在项目目录新建 report.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
body { font-family: -apple-system, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #333; }
h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
.member { background: #f8f9fa; border-left: 4px solid #3498db; padding: 15px; margin: 15px 0; }
.member h3 { margin-top: 0; color: #2c3e50; }
.commit { padding: 5px 0; border-bottom: 1px solid #eee; }
.time { color: #888; font-size: 0.85em; }
.tag { display: inline-block; background: #e8f4fd; color: #2980b9; padding: 2px 8px; border-radius: 3px; font-size: 0.8em; margin-right: 5px; }
</style>
</head>
<body>
<h1>📊 团队周报 — {{ week_label }}</h1>
<p>生成时间:{{ generated_at }}</p>
{% for member in members %}
<div class="member">
<h3>{{ member.name }}</h3>
<p><strong>本周完成:</strong></p>
{% for commit in member.commits %}
<div class="commit">
{% for tag in commit.tags %}<span class="tag">{{ tag }}</span>{% endfor %}
{{ commit.message }}
<span class="time">{{ commit.date }}</span>
</div>
{% endfor %}
{% if member.summary %}
<p><strong>总结:</strong>{{ member.summary }}</p>
{% endif %}
</div>
{% endfor %}
</body>
</html>
第三步:编写核心脚本
创建 generate_report.py:
import git
import os
from datetime import datetime, timedelta
from jinja2 import Environment, FileSystemLoader
import smtplib
from email.mime.text import MIMEText
def get_week_range():
"""获取本周一到周日的日期范围"""
today = datetime.now()
monday = today - timedelta(days=today.weekday())
sunday = monday + timedelta(days=6)
return monday, sunday, f"{monday.strftime('%m/%d')}-{sunday.strftime('%m/%d')}"
def parse_commit_tags(message):
"""从提交信息中提取标签"""
tags = []
if "[feat]" in message or "[feature]" in message:
tags.append("功能")
elif "[fix]" in message:
tags.append("修复")
elif "[docs]" in message:
tags.append("文档")
elif "[refactor]" in message:
tags.append("重构")
elif "[perf]" in message:
tags.append("性能")
else:
tags.append("其他")
return tags
def collect_member_commits(repo_path, member_name, week_start, week_end):
"""收集某成员在指定时间范围内的提交"""
repo = git.Repo(repo_path)
commits = []
for commit in repo.iter_commits(
author=member_name,
since=week_start,
until=week_end,
max_count=50
):
msg = str(commit.message).strip()
date_str = commit.committed_datetime.strftime("%Y-%m-%d %H:%M")
commits.append({
"message": msg,
"date": date_str,
"tags": parse_commit_tags(msg)
})
# 按时间倒序排列
commits.sort(key=lambda x: x["date"], reverse=True)
return commits[:20] # 每人最多显示20条
def generate_report(members_data, week_label):
"""使用模板生成HTML周报"""
env = Environment(loader=FileSystemLoader("."))
template = env.get_template("report.html")
now = datetime.now().strftime("%Y-%m-%d %H:%M")
return template.render(
members=members_data,
week_label=week_label,
generated_at=now
)
def send_email(html_content, subject, to_addrs):
"""发送邮件(可选功能)"""
msg = MIMEText(html_content, "html", "utf-8")
msg["Subject"] = subject
msg["From"] = "report@navbox.com.cn"
msg["To"] = ", ".join(to_addrs)
with smtplib.SMTP("smtp.example.com", 587) as server:
server.starttls()
server.login("user", "password")
server.send_message(msg)
# ==================== 配置区域 ====================
REPO_PATH = "/home/ubuntu/my-project" # Git仓库路径
MEMBERS = [
{"name": "张三", "summary": "本周完成了用户权限模块的重构,修复了3个线上bug"},
{"name": "李四", "summary": "完成了支付接口的联调,写了完整的API文档"},
{"name": "王五", "summary": "优化了首页加载速度,性能提升约40%"},
]
# ==================================================
if __name__ == "__main__":
week_start, week_end, week_label = get_week_range()
print(f"📅 报告周期: {week_label}")
members_data = []
for member in MEMBERS:
commits = collect_member_commits(REPO_PATH, member["name"], week_start, week_end)
members_data.append({
"name": member["name"],
"commits": commits,
"summary": member.get("summary", "")
})
print(f" ✅ {member['name']}: {len(commits)} 条提交记录")
html = generate_report(members_data, week_label)
with open("weekly_report.html", "w", encoding="utf-8") as f:
f.write(html)
print("✅ 周报已生成: weekly_report.html")
# 取消注释以启用邮件发送
# send_email(html, f"团队周报 {week_label}", ["manager@example.com"])
# print("📧 邮件已发送")
第四步:配置定时任务
用Cron实现每周六凌晨自动运行:
crontab -e
添加以下行:
0 9 * * 6 cd ~/my-project && python generate_report.py
这样每周六早上9点自动生成并保存为 weekly_report.html,你可以直接打开查看或配置邮件自动发送。
如果用GitHub Actions,可以在 .github/workflows/weekly-report.yml 中配置:
name: Weekly Report
on:
schedule:
- cron: '0 1 * * 6' # 周六 UTC 01:00 = 北京 09:00
workflow_dispatch: # 也支持手动触发
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install gitpython jinja2
- run: python generate_report.py
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: weekly-report
path: weekly_report.html
运行效果
脚本执行后会在项目根目录生成 weekly_report.html,效果如下:
- 顶部显示报告周期和生成时间
- 每位成员一个独立卡片,左侧蓝色边框
- 每条提交记录带彩色标签(功能/修复/文档/重构/性能)
- 支持手动填写的本周总结段落
- 样式简洁,直接在浏览器打开即可查看
如果需要群发,取消邮件发送部分的注释,填入SMTP配置即可。
优化方向
对接飞书/钉钉机器人:把生成步骤改成直接推送到群组消息,省去手动打开文件的环节。用
requests库调 webhook 就行。多仓库聚合:团队通常有多个Git仓库,修改脚本遍历多个
repo_path,按仓库分组展示。PR/MR 数据:如果代码托管在GitHub/Gitee,可以通过API拉取本周合并的PR列表,比提交记录更有业务含义。
数据看板:把周报数据存入SQLite,用Flask做一个简单的查询页面,可以按人/按仓库/按时间筛选统计。
AI润色:接入本地Ollama,让模型根据提交记录自动生成更自然的总结文字,减少人工填写 summary 的负担。
完整代码已开源在 GitHub。 Fork 后修改配置区的仓库路径和成员列表就能直接用。
这篇文章对你有帮助吗?