44 push :
55 branches :
66 - main
7+ paths :
8+ - ' python/**'
9+ - ' .github/workflows/python.yml'
710 pull_request :
811 types : [opened, synchronize, reopened]
12+ paths :
13+ - ' python/**'
14+ - ' .github/workflows/python.yml'
915 workflow_dispatch :
1016 inputs :
1117 bump_type :
@@ -26,10 +32,46 @@ concurrency:
2632 cancel-in-progress : true
2733
2834jobs :
35+ # === CHANGELOG CHECK - only runs on PRs ===
36+ changelog :
37+ name : Changelog Fragment Check
38+ runs-on : ubuntu-latest
39+ if : github.event_name == 'pull_request'
40+ steps :
41+ - uses : actions/checkout@v4
42+ with :
43+ fetch-depth : 0
44+
45+ - name : Check for changelog fragments
46+ run : |
47+ # Get list of fragment files (excluding README)
48+ FRAGMENTS=$(find python/changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l)
49+
50+ # Get changed files in PR
51+ CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
52+
53+ # Check if any Python source files changed
54+ SOURCE_CHANGED=$(echo "$CHANGED_FILES" | grep -E "^python/(links_client/|tests/|pyproject\.toml)" | wc -l)
55+
56+ if [ "$SOURCE_CHANGED" -gt 0 ] && [ "$FRAGMENTS" -eq 0 ]; then
57+ echo "::warning::No changelog fragment found. Please add a changelog entry in python/changelog.d/"
58+ echo ""
59+ echo "To create a changelog fragment:"
60+ echo " Create a new .md file in python/changelog.d/ with your changes"
61+ echo ""
62+ echo "See python/changelog.d/README.md for more information."
63+ # Note: This is a warning, not a failure, to allow flexibility
64+ exit 0
65+ fi
66+
67+ echo "✓ Changelog check passed"
68+
2969 # Test Python
3070 test-python :
3171 name : Test Python
3272 runs-on : ubuntu-latest
73+ needs : [changelog]
74+ if : always() && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || needs.changelog.result == 'success' || needs.changelog.result == 'skipped')
3375 steps :
3476 - uses : actions/checkout@v4
3577
70112 name : Build Package
71113 runs-on : ubuntu-latest
72114 needs : [test-python]
115+ if : always() && needs.test-python.result == 'success'
73116 steps :
74117 - uses : actions/checkout@v4
75118
@@ -101,7 +144,7 @@ jobs:
101144 auto-release :
102145 name : Auto Release
103146 needs : [test-python, build]
104- if : github.event_name == 'push' && github.ref == 'refs/heads/main'
147+ if : github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.test-python.result == 'success' && needs.build.result == 'success'
105148 runs-on : ubuntu-latest
106149 permissions :
107150 contents : write
@@ -191,7 +234,7 @@ jobs:
191234 - name : Install dependencies
192235 run : |
193236 python -m pip install --upgrade pip
194- pip install build twine bump2version
237+ pip install build twine
195238
196239 - name : Configure git
197240 run : |
@@ -233,18 +276,71 @@ jobs:
233276
234277 echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
235278
279+ - name : Collect changelog fragments
280+ run : |
281+ cd python
282+ # Check if there are any fragments to collect
283+ FRAGMENTS=$(find changelog.d -name "*.md" ! -name "README.md" 2>/dev/null | wc -l)
284+ if [ "$FRAGMENTS" -gt 0 ]; then
285+ echo "Found $FRAGMENTS changelog fragment(s)"
286+
287+ # Create or update CHANGELOG.md
288+ if [ ! -f CHANGELOG.md ]; then
289+ echo "# Changelog" > CHANGELOG.md
290+ echo "" >> CHANGELOG.md
291+ fi
292+
293+ # Insert new version section at the top (after the header)
294+ VERSION="${{ steps.version.outputs.new_version }}"
295+ DATE=$(date +%Y-%m-%d)
296+
297+ # Create temp file with new content
298+ {
299+ echo "# Changelog"
300+ echo ""
301+ echo "## $VERSION ($DATE)"
302+ echo ""
303+ # Concatenate all fragment files
304+ for f in changelog.d/*.md; do
305+ if [ "$(basename "$f")" != "README.md" ]; then
306+ cat "$f"
307+ echo ""
308+ fi
309+ done
310+ # Append old changelog content (skip the header)
311+ if [ -f CHANGELOG.md ]; then
312+ tail -n +3 CHANGELOG.md
313+ fi
314+ } > CHANGELOG.tmp
315+
316+ mv CHANGELOG.tmp CHANGELOG.md
317+
318+ # Delete collected fragments
319+ find changelog.d -name "*.md" ! -name "README.md" -delete
320+ echo "Changelog fragments collected and deleted"
321+ else
322+ echo "No changelog fragments found, skipping collection"
323+ fi
324+
236325 - name : Commit version bump
237326 id : commit
238327 run : |
239- git add python/pyproject.toml
240- git commit -m "Python ${{ steps.version.outputs.new_version }}" \
241- -m "" \
242- -m "${{ github.event.inputs.description || 'Manual release' }}" \
243- -m "" \
244- -m "🤖 Generated with [Claude Code](https://claude.com/claude-code)"
245-
246- git push origin main
247- echo "version_committed=true" >> $GITHUB_OUTPUT
328+ git add python/pyproject.toml python/CHANGELOG.md python/changelog.d/
329+
330+ # Check if there are changes to commit
331+ if git diff --staged --quiet; then
332+ echo "No changes to commit"
333+ echo "version_committed=false" >> $GITHUB_OUTPUT
334+ else
335+ git commit -m "Python ${{ steps.version.outputs.new_version }}" \
336+ -m "" \
337+ -m "${{ github.event.inputs.description || 'Manual release' }}" \
338+ -m "" \
339+ -m "🤖 Generated with [Claude Code](https://claude.com/claude-code)"
340+
341+ git push origin main
342+ echo "version_committed=true" >> $GITHUB_OUTPUT
343+ fi
248344
249345 - name : Build package
250346 if : steps.commit.outputs.version_committed == 'true'
0 commit comments