180 lines
6.1 KiB
Python
180 lines
6.1 KiB
Python
"""Weekly coding recap generator - ISO weeks, Gitea repos, brain excluded"""
|
|
import os, subprocess, datetime, json
|
|
from pathlib import Path
|
|
|
|
TOKEN_FILE = Path.home() / ".git-credentials"
|
|
TMPBASE = Path("/tmp/gitea_recap")
|
|
BRAIN_RECAP_DIR = Path.home() / "brain" / "areas" / "coding" / "recaps"
|
|
|
|
# Repos to track - code only, no brain
|
|
REPOS = [
|
|
"tactility","tactility_apps","mcp_screen","reyna-cli","mac_mcp",
|
|
"eink-dairy","eink-api","emulatedisplay","basic1",
|
|
"EMI-Backend","EMI-web","EMI-ExpoAPP","immich-emi",
|
|
"pico-8","whisper-translation","eink_api","mcp_screen"
|
|
]
|
|
# Deduplicate preserve order
|
|
REPOS = list(dict.fromkeys(REPOS))
|
|
|
|
def get_token():
|
|
try:
|
|
cred = TOKEN_FILE.read_text()
|
|
# format https://user:token@host
|
|
part = cred.split("://",1)[1]
|
|
token = part.split(":")[1].split("@")[0]
|
|
return token.strip()
|
|
except Exception as e:
|
|
print(f"no token: {e}")
|
|
return None
|
|
|
|
def ensure_clones(token):
|
|
TMPBASE.mkdir(exist_ok=True)
|
|
for repo in REPOS:
|
|
dest = TMPBASE / repo
|
|
url = f"https://adolforeyna:{token}@git.reynafamily.com/adolforeyna/{repo}.git"
|
|
if not dest.exists():
|
|
print(f"cloning {repo}")
|
|
subprocess.run(["git","clone","--quiet",url,str(dest)], capture_output=True, timeout=120)
|
|
else:
|
|
subprocess.run(["git","-C",str(dest),"fetch","--all","--quiet"], capture_output=True, timeout=60)
|
|
|
|
def get_commits_for_week(repo, since, until):
|
|
dest = TMPBASE / repo
|
|
if not dest.exists():
|
|
return []
|
|
cmd = ["git","-C",str(dest),"log","--all",
|
|
"--since",since,"--until",until,
|
|
"--pretty=format:%h|%ad|%an|%s","--date=short"]
|
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
|
|
if r.returncode!=0 or not r.stdout.strip():
|
|
return []
|
|
commits=[]
|
|
for line in r.stdout.strip().split("\n"):
|
|
if not line.strip(): continue
|
|
if "daily auto-sync" in line.lower(): continue
|
|
parts=line.split("|",3)
|
|
if len(parts)<4: continue
|
|
sha, date, author, msg = parts
|
|
# extra filter noise
|
|
if msg.lower().startswith("merge") and "auto-sync" in msg.lower():
|
|
continue
|
|
commits.append({"sha":sha,"date":date,"author":author,"msg":msg})
|
|
return commits
|
|
|
|
def generate_markdown(week_label, date_range, commits_by_repo, total):
|
|
since, until = date_range
|
|
front = f"""---
|
|
Date: {since} to {until}
|
|
Author: Hermes
|
|
Tags: [coding-recap, weekly, iso-{week_label}]
|
|
Week: {week_label}
|
|
Commits: {total}
|
|
ActiveRepos: {len([k for k,v in commits_by_repo.items() if v])}
|
|
---
|
|
|
|
# Weekly Coding Recap - {week_label} ({since} to {until})
|
|
|
|
## Summary
|
|
- **Total commits:** {total} coding commits (brain excluded, noise filtered)
|
|
- **Active repos:** {len([k for k,v in commits_by_repo.items() if v])}
|
|
- **Repos:** {', '.join([f"{k} ({len(v)})" for k,v in commits_by_repo.items() if v]) or 'none'}
|
|
|
|
"""
|
|
if total==0:
|
|
front += """## Highlights by Repo
|
|
- No code pushes this week.
|
|
|
|
## Themes
|
|
- Break / docs / planning week or local-only work not yet pushed.
|
|
|
|
## Metrics
|
|
- 0 commits pushed to Gitea code repos.
|
|
|
|
"""
|
|
return front
|
|
|
|
body = "## Highlights by Repo\n\n"
|
|
for repo, commits in commits_by_repo.items():
|
|
if not commits: continue
|
|
body += f"### {repo} ({len(commits)} commits)\n"
|
|
for c in commits[:12]:
|
|
body += f"- {c['sha']} {c['date']} {c['msg'][:120]}\n"
|
|
if len(commits)>12:
|
|
body += f"- ... and {len(commits)-12} more\n"
|
|
body += "\n"
|
|
|
|
# simple theme detection
|
|
keywords = []
|
|
all_msgs = " ".join([c['msg'] for commits in commits_by_repo.values() for c in commits]).lower()
|
|
if "mp3" in all_msgs: keywords.append("Mp3Player/app work")
|
|
if "audio" in all_msgs: keywords.append("audio pipeline")
|
|
if "mcp" in all_msgs or "websocket" in all_msgs: keywords.append("MCP/voice")
|
|
if "tactility" in all_msgs or "i2c" in all_msgs: keywords.append("Tactility drivers")
|
|
if "reyna-cli" in all_msgs: keywords.append("CLI tooling")
|
|
theme = ", ".join(keywords) if keywords else "general maintenance"
|
|
|
|
body += f"## Themes\n- Focus: {theme}\n\n"
|
|
body += f"## Metrics\n- {total} commits across {len([k for k,v in commits_by_repo.items() if v])} repos\n\n"
|
|
return front + body
|
|
|
|
def main():
|
|
token = get_token()
|
|
if not token:
|
|
print("Cannot get token")
|
|
return
|
|
|
|
ensure_clones(token)
|
|
|
|
# Determine previous ISO week (Mon-Sun) for cron
|
|
today = datetime.date.today()
|
|
# If called with --week override
|
|
import sys
|
|
if "--week-start" in sys.argv:
|
|
idx = sys.argv.index("--week-start")
|
|
start_str = sys.argv[idx+1]
|
|
start = datetime.date.fromisoformat(start_str)
|
|
end = start + datetime.timedelta(days=6)
|
|
else:
|
|
# previous week Mon-Sun
|
|
# today is Monday? For cron Monday 8am we want last week
|
|
# last Monday
|
|
last_monday = today - datetime.timedelta(days=today.weekday()+7)
|
|
start = last_monday
|
|
end = start + datetime.timedelta(days=6)
|
|
|
|
since = start.isoformat()
|
|
until = end.isoformat()
|
|
iso_year, iso_week, _ = start.isocalendar()
|
|
week_label = f"{iso_year}-W{iso_week:02d}"
|
|
|
|
print(f"Generating recap for {week_label} {since} to {until}")
|
|
|
|
commits_by_repo = {}
|
|
total=0
|
|
for repo in REPOS:
|
|
commits = get_commits_for_week(repo, since, until+" 23:59:59")
|
|
if commits:
|
|
commits_by_repo[repo]=commits
|
|
total+=len(commits)
|
|
else:
|
|
commits_by_repo[repo]=[]
|
|
|
|
md = generate_markdown(week_label, (since, until), {k:v for k,v in commits_by_repo.items() if v}, total)
|
|
|
|
BRAIN_RECAP_DIR.mkdir(parents=True, exist_ok=True)
|
|
out = BRAIN_RECAP_DIR / f"{week_label}.md"
|
|
out.write_text(md)
|
|
print(f"Wrote {out} ({total} commits)")
|
|
|
|
# update index
|
|
index_path = Path.home() / "brain" / "areas" / "coding.md"
|
|
if index_path.exists():
|
|
text = index_path.read_text()
|
|
# ensure entry exists - simple append logic handled by cron? just log
|
|
print(f"Index exists, please verify W{week_label} listed")
|
|
# git add? brain auto-sync will handle
|
|
print(md[:2000])
|
|
|
|
if __name__=="__main__":
|
|
main()
|