@@ -92,6 +92,99 @@ def get_pr_metadata() -> dict:
92
92
return metadata
93
93
94
94
95
+ def get_changeset_metadata (changeset_path : Path ) -> dict :
96
+ """Get PR metadata for a specific changeset file.
97
+
98
+ Finds the commit that introduced the changeset and extracts metadata.
99
+ """
100
+ metadata = {}
101
+ git_info = get_git_info ()
102
+ metadata ["repo_url" ] = git_info .get ("repo_url" , "" )
103
+
104
+ try :
105
+ # Find the commit that introduced this changeset file
106
+ result = subprocess .run (
107
+ ["git" , "log" , "--format=%H" , "--diff-filter=A" , "--" , str (changeset_path )],
108
+ capture_output = True ,
109
+ text = True ,
110
+ check = True ,
111
+ )
112
+
113
+ if result .stdout .strip ():
114
+ commit_hash = result .stdout .strip ().split ("\n " )[0 ]
115
+ metadata ["commit_hash" ] = commit_hash
116
+
117
+ # Get the commit message to extract PR number
118
+ msg_result = subprocess .run (
119
+ ["git" , "log" , "-1" , "--format=%B" , commit_hash ],
120
+ capture_output = True ,
121
+ text = True ,
122
+ check = True ,
123
+ )
124
+
125
+ commit_msg = msg_result .stdout .strip ()
126
+
127
+ # Extract PR number from commit message (common patterns)
128
+ # Pattern 1: (#123)
129
+ # Pattern 2: Merge pull request #123
130
+ pr_match = re .search (r"(?:#|pull request #)(\d+)" , commit_msg )
131
+ if pr_match :
132
+ pr_number = pr_match .group (1 )
133
+ metadata ["pr_number" ] = pr_number
134
+
135
+ # Try to get PR author using GitHub CLI if available
136
+ try :
137
+ gh_result = subprocess .run (
138
+ [
139
+ "gh" ,
140
+ "api" ,
141
+ f"repos/{ git_info .get ('owner' , '' )} /"
142
+ f"{ git_info .get ('repo' , '' )} /pulls/{ pr_number } " ,
143
+ "--jq" ,
144
+ ".user.login" ,
145
+ ],
146
+ capture_output = True ,
147
+ text = True ,
148
+ check = True ,
149
+ )
150
+ if gh_result .stdout .strip ():
151
+ metadata ["pr_author" ] = gh_result .stdout .strip ()
152
+ except Exception :
153
+ # If gh command fails, try to extract from commit author
154
+ author_result = subprocess .run (
155
+ ["git" , "log" , "-1" , "--format=%an" , commit_hash ],
156
+ capture_output = True ,
157
+ text = True ,
158
+ )
159
+ if author_result .stdout .strip ():
160
+ metadata ["pr_author" ] = author_result .stdout .strip ()
161
+ else :
162
+ # No PR number found, use commit author
163
+ author_result = subprocess .run (
164
+ ["git" , "log" , "-1" , "--format=%an" , commit_hash ],
165
+ capture_output = True ,
166
+ text = True ,
167
+ )
168
+ if author_result .stdout .strip ():
169
+ metadata ["pr_author" ] = author_result .stdout .strip ()
170
+
171
+ except subprocess .CalledProcessError :
172
+ # If git commands fail, return empty metadata
173
+ pass
174
+
175
+ # Fall back to environment variables if no specific metadata found
176
+ if not metadata .get ("pr_number" ):
177
+ metadata ["pr_number" ] = os .environ .get ("PR_NUMBER" , "" )
178
+ if not metadata .get ("pr_author" ):
179
+ metadata ["pr_author" ] = os .environ .get ("PR_AUTHOR" , "" )
180
+ if not metadata .get ("commit_hash" ):
181
+ metadata ["commit_hash" ] = os .environ .get (
182
+ "COMMIT_SHA" , git_info .get ("commit" , "" )
183
+ )
184
+
185
+ return metadata
186
+
187
+
95
188
def format_changelog_entry (entry : dict , config : dict , pr_metadata : dict ) -> str :
96
189
"""Format a single changelog entry with PR and commit info."""
97
190
description = entry ["description" ]
@@ -156,7 +249,12 @@ def generate_changelog_section(
156
249
157
250
# Add each entry
158
251
for entry in grouped [change_type ]:
159
- lines .append (format_changelog_entry (entry , config , pr_metadata ))
252
+ # Get metadata specific to this changeset if available
253
+ if "filepath" in entry :
254
+ changeset_metadata = get_changeset_metadata (entry ["filepath" ])
255
+ else :
256
+ changeset_metadata = pr_metadata
257
+ lines .append (format_changelog_entry (entry , config , changeset_metadata ))
160
258
161
259
lines .append ("" )
162
260
@@ -252,7 +350,12 @@ def process_changesets_for_changelog() -> tuple[list[dict], str]:
252
350
package_changes [package ] = {"changes" : [], "descriptions" : []}
253
351
package_changes [package ]["changes" ].append (change_type )
254
352
package_changes [package ]["descriptions" ].append (
255
- {"type" : change_type , "description" : desc , "changeset" : filepath .name }
353
+ {
354
+ "type" : change_type ,
355
+ "description" : desc ,
356
+ "changeset" : filepath .name ,
357
+ "filepath" : filepath ,
358
+ }
256
359
)
257
360
258
361
# Process each package
0 commit comments