1- name : Draft Release
1+ name : Release Drafter
22
33on :
44 push :
55 branches :
66 - main
7+ pull_request :
8+ types : [opened, reopened, synchronize]
79
810permissions :
9- contents : write
11+ contents : read
1012
1113jobs :
12- draft_release :
14+ update_release_draft :
15+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
16+ permissions :
17+ contents : write
18+ pull-requests : write
1319 runs-on : ubuntu-latest
1420 steps :
1521 - name : Checkout repository
1622 uses : actions/checkout@v6
1723 with :
1824 fetch-depth : 0
1925
20- - name : Get version from manifest
21- id : version
26+ - name : Set up Python
27+ uses : actions/setup-python@v6
28+ with :
29+ python-version : ' 3.14'
30+
31+ - name : Install victron-mqtt library
32+ run : pip install victron-mqtt
33+
34+ - name : Find previous release tag
35+ id : prev_tag
36+ env :
37+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
2238 run : |
23- version=$(jq -r .version custom_components/victron_mqtt/manifest.json)
24- echo "version=$version" >> $GITHUB_OUTPUT
39+ prev=$(gh release list --json tagName,isDraft -q '[.[] | select(.isDraft | not)] | .[0].tagName')
40+ echo "Previous release tag: $prev"
41+ echo "tag=$prev" >> $GITHUB_OUTPUT
2542
26- - name : Create or update draft release
43+ - name : Get commit messages since previous tag
2744 env :
2845 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
2946 run : |
30- tag="v${{ steps.version.outputs.version }}"
31- # Check if a draft release already exists for this tag
32- existing=$(gh release list --json tagName,isDraft -q ".[] | select(.tagName == \"$tag\" and .isDraft) | .tagName")
33- if [ -n "$existing" ]; then
34- gh release edit "$tag" --draft --generate-notes
47+ prev_tag="${{ steps.prev_tag.outputs.tag }}"
48+ if [ -z "$prev_tag" ]; then
49+ prev_tag=$(git rev-list --max-parents=0 HEAD)
50+ fi
51+ COMMITS=$(git log "$prev_tag"..HEAD --pretty=format:"- %s" | head -20)
52+ echo "COMMITS<<EOF" >> $GITHUB_ENV
53+ echo "$COMMITS" >> $GITHUB_ENV
54+ echo "EOF" >> $GITHUB_ENV
55+
56+ # Collect unique commit authors as GitHub usernames
57+ AUTHORS=$(git log "$prev_tag"..HEAD --pretty=format:"%an" | sort -u | while read -r name; do
58+ email=$(git log --author="$name" --pretty=format:"%ae" -1)
59+ username=$(echo "$email" | sed -n 's/.*+\(.*\)@users.noreply.github.com/\1/p')
60+ if [ -n "$username" ]; then
61+ echo "@$username"
62+ else
63+ username=$(gh api "/search/users?q=$email+in:email" --jq '.items[0].login' 2>/dev/null || true)
64+ if [ -n "$username" ] && [ "$username" != "null" ]; then
65+ echo "@$username"
66+ else
67+ echo "@$name"
68+ fi
69+ fi
70+ done | sort -u | tr '\n' ' ')
71+ echo "AUTHORS=$AUTHORS" >> $GITHUB_ENV
72+
73+ - name : Detect breaking changes
74+ id : breaking
75+ run : |
76+ prev_tag="${{ steps.prev_tag.outputs.tag }}"
77+ if [ -z "$prev_tag" ]; then
78+ echo "found=false" >> $GITHUB_OUTPUT
79+ exit 0
80+ fi
81+
82+ git show "${prev_tag}:victron_mqtt.json" > old.json 2>/dev/null || true
83+ if [ ! -f old.json ] || [ ! -s old.json ]; then
84+ echo "found=false" >> $GITHUB_OUTPUT
85+ exit 0
86+ fi
87+
88+ set +e
89+ breaking_output=$(python -m victron_mqtt.utils.detect_breaking_changes old.json victron_mqtt.json 2>/dev/null)
90+ exit_code=$?
91+ set -e
92+
93+ rm -f old.json
94+
95+ if [ $exit_code -eq 1 ] && [ -n "$breaking_output" ]; then
96+ echo "found=true" >> $GITHUB_OUTPUT
97+ echo "content<<EOF" >> $GITHUB_OUTPUT
98+ echo "$breaking_output" >> $GITHUB_OUTPUT
99+ echo "EOF" >> $GITHUB_OUTPUT
35100 else
36- gh release create "$tag" --draft --generate-notes --title "$tag"
37- fi
101+ echo "found=false" >> $GITHUB_OUTPUT
102+ fi
103+
104+ - uses : release-drafter/release-drafter@v7
105+ env :
106+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
107+
108+ - name : Enhance draft release notes
109+ env :
110+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
111+ run : |
112+ DRAFT_TAG=$(gh release list --limit 50 --json isDraft,tagName -q '[.[] | select(.isDraft)] | .[0].tagName')
113+ if [ -z "$DRAFT_TAG" ] || [ "$DRAFT_TAG" = "null" ]; then
114+ echo "No draft release found"
115+ exit 0
116+ fi
117+
118+ BODY=$(gh release view "$DRAFT_TAG" --json body -q .body)
119+
120+ if [ -n "$COMMITS" ]; then
121+ export BODY
122+ BODY=$(python3 -c "
123+ import os, re
124+ body = os.environ['BODY']
125+ commits = os.environ['COMMITS']
126+ authors = os.environ.get('AUTHORS', '').strip()
127+
128+ # Remove release-drafter's empty placeholders
129+ body = body.replace('No changes\n', '').replace('No changes', '')
130+ body = body.replace('No contributors\n', '').replace('No contributors', '')
131+
132+ # Split body into sections
133+ parts = re.split(r'(## [^\n]+)', body)
134+
135+ # Modify section contents
136+ for i, part in enumerate(parts):
137+ if part.strip() == '## Changes' and i + 1 < len(parts):
138+ existing = parts[i + 1].strip()
139+ # Remove lone asterisk (release-drafter empty placeholder)
140+ if existing == '*':
141+ existing = ''
142+ items = []
143+ if existing:
144+ items.append(existing)
145+ items.append(commits)
146+ parts[i + 1] = '\n\n' + '\n'.join(items) + '\n\n'
147+ elif part.strip() == '## Contributors' and i + 1 < len(parts):
148+ existing = parts[i + 1].strip()
149+ if not existing and authors:
150+ parts[i + 1] = '\n\n' + authors + '\n'
151+
152+ body = ''.join(parts)
153+
154+ if '## Contributors' not in body and authors:
155+ body = body.rstrip() + '\n\n## Contributors\n\n' + authors
156+
157+ print(body.rstrip())
158+ ")
159+ fi
160+
161+ # Prepend breaking changes
162+ if [ "${{ steps.breaking.outputs.found }}" = "true" ]; then
163+ breaking_section="${{ steps.breaking.outputs.content }}"
164+ BODY="${breaking_section}
165+
166+ ${BODY}"
167+ fi
168+
169+ gh release edit "$DRAFT_TAG" --notes "$BODY"
170+
171+ autolabeler :
172+ if : github.event_name == 'pull_request'
173+ permissions :
174+ contents : read
175+ pull-requests : write
176+ runs-on : ubuntu-latest
177+ steps :
178+ - uses : release-drafter/release-drafter@v7
179+ env :
180+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments