@@ -114,7 +114,8 @@ def get_changeset_metadata(changeset_path: Path) -> dict:
114
114
commit_hash = result .stdout .strip ().split ("\n " )[0 ]
115
115
metadata ["commit_hash" ] = commit_hash
116
116
117
- # Get the commit message to extract PR number
117
+
118
+ # Get the commit message to extract PR number and co-authors
118
119
msg_result = subprocess .run (
119
120
["git" , "log" , "-1" , "--format=%B" , commit_hash ],
120
121
capture_output = True ,
@@ -149,6 +150,35 @@ def get_changeset_metadata(changeset_path: Path) -> dict:
149
150
)
150
151
if gh_result .stdout .strip ():
151
152
metadata ["pr_author" ] = gh_result .stdout .strip ()
153
+
154
+ # Also try to get co-authors from PR commits
155
+ try :
156
+ # Get all commits in the PR
157
+ commits_result = subprocess .run (
158
+ [
159
+ "gh" ,
160
+ "api" ,
161
+ f"repos/{ git_info .get ('owner' , '' )} /"
162
+ f"{ git_info .get ('repo' , '' )} /pulls/{ pr_number } /commits" ,
163
+ "--jq" ,
164
+ ".[].author.login" ,
165
+ ],
166
+ capture_output = True ,
167
+ text = True ,
168
+ check = True ,
169
+ )
170
+ if commits_result .stdout .strip ():
171
+ # Get unique commit authors (excluding the PR author)
172
+ commit_authors = set (
173
+ commits_result .stdout .strip ().split ('\n ' )
174
+ )
175
+ commit_authors .discard (metadata .get ("pr_author" ))
176
+ commit_authors .discard ('' ) # Remove empty strings
177
+ if commit_authors :
178
+ metadata ["co_authors" ] = list (commit_authors )
179
+ except Exception :
180
+ pass
181
+
152
182
except Exception :
153
183
# If gh command fails, try to extract from commit author
154
184
author_result = subprocess .run (
@@ -168,6 +198,25 @@ def get_changeset_metadata(changeset_path: Path) -> dict:
168
198
if author_result .stdout .strip ():
169
199
metadata ["pr_author" ] = author_result .stdout .strip ()
170
200
201
+ # Extract co-authors from commit message if we don't already have
202
+ # them from GitHub API
203
+ if "co_authors" not in metadata :
204
+ co_authors = []
205
+ for line in commit_msg .split ('\n ' ):
206
+ co_author_match = re .match (
207
+ r'^Co-authored-by:\s*(.+?)\s*<.*>$' , line .strip ()
208
+ )
209
+ if co_author_match :
210
+ co_author_name = co_author_match .group (1 ).strip ()
211
+ if (
212
+ co_author_name
213
+ and co_author_name != metadata .get ("pr_author" )
214
+ ):
215
+ co_authors .append (co_author_name )
216
+
217
+ if co_authors :
218
+ metadata ["co_authors" ] = co_authors
219
+
171
220
except subprocess .CalledProcessError :
172
221
# If git commands fail, return empty metadata
173
222
pass
@@ -190,6 +239,7 @@ def format_changelog_entry(entry: dict, config: dict, pr_metadata: dict) -> str:
190
239
description = entry ["description" ]
191
240
pr_number = pr_metadata .get ("pr_number" )
192
241
pr_author = pr_metadata .get ("pr_author" )
242
+ co_authors = pr_metadata .get ("co_authors" , [])
193
243
commit_hash = pr_metadata .get ("commit_hash" , "" )[:7 ]
194
244
repo_url = pr_metadata .get ("repo_url" , "" )
195
245
@@ -205,8 +255,28 @@ def format_changelog_entry(entry: dict, config: dict, pr_metadata: dict) -> str:
205
255
parts .append (f"[`{ commit_hash } `]({ repo_url } /commit/{ commit_hash } )" )
206
256
207
257
# Add author thanks if available
258
+ authors_to_thank = []
208
259
if pr_author :
209
- parts .append (f"Thanks @{ pr_author } !" )
260
+ # Check if pr_author already contains @ symbol
261
+ if pr_author .startswith ("@" ):
262
+ authors_to_thank .append (pr_author )
263
+ else :
264
+ authors_to_thank .append (f"@{ pr_author } " )
265
+
266
+ # Add co-authors
267
+ for co_author in co_authors :
268
+ if co_author .startswith ("@" ):
269
+ authors_to_thank .append (co_author )
270
+ else :
271
+ authors_to_thank .append (f"@{ co_author } " )
272
+
273
+ if authors_to_thank :
274
+ if len (authors_to_thank ) == 1 :
275
+ parts .append (f"Thanks { authors_to_thank [0 ]} !" )
276
+ else :
277
+ # Format multiple authors nicely
278
+ all_but_last = ", " .join (authors_to_thank [:- 1 ])
279
+ parts .append (f"Thanks { all_but_last } and { authors_to_thank [- 1 ]} !" )
210
280
211
281
# Add description
212
282
parts .append (f"- { description } " )
0 commit comments