Skip to content

Commit 6dca75e

Browse files
Add documentation and tests for changelog automation
Co-authored-by: saulshanabrook <[email protected]>
1 parent 6365379 commit 6dca75e

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed

.github/CHANGELOG_AUTOMATION.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Automatic Changelog Generation
2+
3+
This repository automatically generates changelog entries for new PRs using a GitHub Action.
4+
5+
## How it works
6+
7+
1. **Trigger**: When a PR is opened or edited
8+
2. **Processing**: The action runs a Python script that:
9+
- Parses the `docs/changelog.md` file
10+
- Finds the "## UNRELEASED" section
11+
- Adds a new entry with format: `- PR_TITLE [#PR_NUMBER](PR_URL)`
12+
- Checks for duplicates to avoid repeated entries
13+
3. **Update**: Commits the changes back to the PR branch
14+
15+
## Files
16+
17+
- `.github/workflows/update-changelog.yml` - GitHub Action workflow
18+
- `.github/scripts/update_changelog.py` - Python script that updates the changelog
19+
20+
## Safety features
21+
22+
- Only runs for PRs from the same repository (not forks)
23+
- Prevents infinite loops by excluding commits made by GitHub Action
24+
- Includes duplicate detection
25+
- Proper error handling and logging
26+
27+
## Manual usage
28+
29+
You can also run the script manually:
30+
31+
```bash
32+
python .github/scripts/update_changelog.py \
33+
--pr-number="123" \
34+
--pr-title="My PR Title" \
35+
--pr-url="https://github.com/egraphs-good/egglog-python/pull/123"
36+
```
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simple test for the changelog update script.
4+
"""
5+
6+
import os
7+
import tempfile
8+
import sys
9+
from pathlib import Path
10+
11+
# Add the scripts directory to the path
12+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))
13+
14+
from update_changelog import update_changelog, find_unreleased_section
15+
16+
17+
def test_find_unreleased_section():
18+
"""Test finding the unreleased section."""
19+
lines = [
20+
"# Changelog\n",
21+
"\n",
22+
"## UNRELEASED\n",
23+
"\n",
24+
"- Some existing entry\n",
25+
"\n",
26+
"## 1.0.0\n",
27+
"- Released version\n"
28+
]
29+
30+
unreleased_start, content_start = find_unreleased_section(lines)
31+
assert unreleased_start == 2, f"Expected unreleased_start=2, got {unreleased_start}"
32+
assert content_start == 4, f"Expected content_start=4, got {content_start}"
33+
print("✓ find_unreleased_section test passed")
34+
35+
36+
def test_update_changelog():
37+
"""Test updating the changelog."""
38+
# Create a temporary changelog file
39+
changelog_content = """# Changelog
40+
41+
## UNRELEASED
42+
43+
- Existing entry
44+
45+
## 1.0.0
46+
47+
- Released version
48+
"""
49+
50+
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
51+
f.write(changelog_content)
52+
temp_path = f.name
53+
54+
try:
55+
# Update the changelog
56+
result = update_changelog(temp_path, "999", "Test PR", "https://example.com/pr/999")
57+
assert result == True, "update_changelog should return True on success"
58+
59+
# Read the updated content
60+
with open(temp_path, 'r') as f:
61+
updated_content = f.read()
62+
63+
# Check that the entry was added
64+
assert "- Test PR [#999](https://example.com/pr/999)" in updated_content
65+
66+
# Check that it was added in the right place (after UNRELEASED)
67+
lines = updated_content.split('\n')
68+
unreleased_idx = lines.index("## UNRELEASED")
69+
entry_idx = None
70+
for i, line in enumerate(lines):
71+
if "Test PR [#999]" in line:
72+
entry_idx = i
73+
break
74+
75+
assert entry_idx is not None, "Entry should be found"
76+
assert entry_idx > unreleased_idx, "Entry should be after UNRELEASED section"
77+
78+
# Test duplicate detection
79+
result2 = update_changelog(temp_path, "999", "Test PR", "https://example.com/pr/999")
80+
assert result2 == False, "update_changelog should return False for duplicates"
81+
82+
print("✓ update_changelog test passed")
83+
84+
finally:
85+
# Clean up
86+
os.unlink(temp_path)
87+
88+
89+
def main():
90+
"""Run all tests."""
91+
print("Running changelog automation tests...")
92+
93+
test_find_unreleased_section()
94+
test_update_changelog()
95+
96+
print("✓ All tests passed!")
97+
98+
99+
if __name__ == '__main__':
100+
main()

.github/workflows/update-changelog.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
with:
2828
python-version: '3.12'
2929

30+
- name: Test changelog script
31+
run: python .github/scripts/test_update_changelog.py
32+
3033
- name: Update changelog
3134
run: |
3235
python .github/scripts/update_changelog.py \

0 commit comments

Comments
 (0)