Skip to content

Commit 91c71cd

Browse files
ci: add GitHub Action to auto-update README Recent Updates
Add a workflow that regenerates the Recent Updates section from git history on every push to main that touches .md files. Includes a Python script that reads git log, strips conventional-commit prefixes, deduplicates, and replaces the section via regex.
1 parent eea4ebe commit 91c71cd

File tree

3 files changed

+131
-5
lines changed

3 files changed

+131
-5
lines changed

.github/scripts/update_recent.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
"""Regenerate the 'Recent Updates' section of README.md from git history."""
3+
4+
import re
5+
import subprocess
6+
import sys
7+
8+
9+
def get_recent_md_commits(count=10):
10+
"""Return the most recent commits that added or modified .md files."""
11+
result = subprocess.run(
12+
[
13+
"git", "log", "--no-merges",
14+
"--diff-filter=AM",
15+
"--format=%ad\t%s",
16+
"--date=short",
17+
"--", "*.md",
18+
],
19+
capture_output=True,
20+
text=True,
21+
check=True,
22+
)
23+
24+
prefix_re = re.compile(
25+
r"^(feat|fix|docs|refactor|test|chore|perf|ci|build|style)(\(.+?\))?:\s*",
26+
re.IGNORECASE,
27+
)
28+
29+
seen = set()
30+
entries = []
31+
for line in result.stdout.strip().splitlines():
32+
if not line or "[skip ci]" in line:
33+
continue
34+
parts = line.split("\t", 1)
35+
if len(parts) != 2:
36+
continue
37+
date, subject = parts
38+
subject = prefix_re.sub("", subject).strip()
39+
key = f"{date}\t{subject}"
40+
if key in seen:
41+
continue
42+
seen.add(key)
43+
entries.append(f"- **{date}** — {subject}")
44+
if len(entries) >= count:
45+
break
46+
47+
return entries
48+
49+
50+
def update_readme(entries):
51+
"""Replace the Recent Updates block in README.md, write only if changed."""
52+
path = "README.md"
53+
with open(path, "r", encoding="utf-8") as f:
54+
content = f.read()
55+
56+
block = "\n".join(entries)
57+
58+
pattern = re.compile(r"(## Recent Updates\n).*?(\n---)", re.DOTALL)
59+
if not pattern.search(content):
60+
print("ERROR: Could not find Recent Updates section in README.md", file=sys.stderr)
61+
sys.exit(1)
62+
63+
updated = pattern.sub(rf"\g<1>\n{block}\n\2", content)
64+
65+
if updated == content:
66+
print("README.md is already up to date.")
67+
return
68+
69+
with open(path, "w", encoding="utf-8") as f:
70+
f.write(updated)
71+
print("README.md updated with latest Recent Updates.")
72+
73+
74+
def main():
75+
entries = get_recent_md_commits()
76+
if not entries:
77+
print("No qualifying commits found; leaving README.md unchanged.")
78+
return
79+
update_readme(entries)
80+
81+
82+
if __name__ == "__main__":
83+
main()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Update README Recent Updates
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- '**/*.md'
8+
- '.github/scripts/update_recent.py'
9+
- '.github/workflows/update-readme.yml'
10+
11+
permissions:
12+
contents: write
13+
14+
concurrency:
15+
group: update-readme
16+
cancel-in-progress: true
17+
18+
jobs:
19+
update-readme:
20+
runs-on: ubuntu-latest
21+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Update Recent Updates section
28+
run: python3 .github/scripts/update_recent.py
29+
30+
- name: Commit and push if changed
31+
run: |
32+
git diff --quiet README.md && exit 0
33+
git config user.name "github-actions[bot]"
34+
git config user.email "github-actions[bot]@users.noreply.github.com"
35+
git add README.md
36+
git commit -m "docs: update Recent Updates section [skip ci]"
37+
git pull --rebase
38+
git push

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ Documentation for the Bristol version of the UK Met Office Unified Model.
1515

1616
## Recent Updates
1717

18-
- **2026-02-27** — Added [CMIP7 outcomes page](CMIP7_outcomes.md) and QR code
19-
- **2026-02-26** — Updated CMIP7 Ozone v2.0 data
20-
- **2026-02-23** — Updated [University HPC](University_HPC.md) and [Model install](Model_install.md) guides
21-
- **2026-02-20** — Added PPE validation heatmap and regional bias sections for xqjc candidates
22-
- **2026-02-20** — Added [terrestrial ensemble tuning](CMIP7_soil_ensembles.md) documentation
18+
- **2026-03-02** — Add key updates and recent updates sections to README
19+
- **2026-02-27** — Add CMIP7 outcomes page and QR code
20+
- **2026-02-26** — Update CMIP7 Ozone v2.0 data
21+
- **2026-02-23** — Update University_HPC.md
22+
- **2026-02-23** — Update Model_install.md
23+
- **2026-02-20** — Add regional bias sections for all 6 xqjc candidates, folded by default
24+
- **2026-02-20** — Add bias annotations to validation results tables
25+
- **2026-02-20** — Add PPE validation heatmap for xqjcg candidates
26+
- **2026-02-20** — Add terrestrial ensemble tuning documentation
27+
- **2026-02-19** — Document aerosol mods, conflicts, and xqhug/xqhum experiments
2328

2429
---
2530
[How to edit these pages](Editing_guide.md)

0 commit comments

Comments
 (0)