1818 */
1919
2020import { promises as fs } from "fs" ;
21+ import { execFile } from "child_process" ;
2122import { join } from "path" ;
2223
2324const version = process . argv [ 2 ] ;
@@ -83,6 +84,68 @@ function parsePrBody(body) {
8384 return entries ;
8485}
8586
87+ // --- Git + GitHub helpers for finding PR numbers ---
88+
89+ const REPO = "triggerdotdev/trigger.dev" ;
90+
91+ function gitExec ( args ) {
92+ return new Promise ( ( resolve , reject ) => {
93+ execFile ( "git" , args , { cwd : ROOT_DIR , maxBuffer : 1024 * 1024 } , ( err , stdout ) => {
94+ if ( err ) reject ( err ) ;
95+ else resolve ( stdout . trim ( ) ) ;
96+ } ) ;
97+ } ) ;
98+ }
99+
100+ async function getCommitForFile ( filePath ) {
101+ try {
102+ // Find the commit that added this file
103+ const sha = await gitExec ( [
104+ "log" ,
105+ "--diff-filter=A" ,
106+ "--format=%H" ,
107+ "--" ,
108+ filePath ,
109+ ] ) ;
110+ return sha . split ( "\n" ) [ 0 ] || null ;
111+ } catch {
112+ return null ;
113+ }
114+ }
115+
116+ async function getPrForCommit ( commitSha ) {
117+ const token = process . env . GITHUB_TOKEN || process . env . GH_TOKEN ;
118+ if ( ! token || ! commitSha ) return null ;
119+
120+ try {
121+ const res = await fetch (
122+ `https://api.github.com/repos/${ REPO } /commits/${ commitSha } /pulls` ,
123+ {
124+ headers : {
125+ Authorization : `token ${ token } ` ,
126+ Accept : "application/vnd.github.v3+json" ,
127+ } ,
128+ }
129+ ) ;
130+ if ( ! res . ok ) return null ;
131+
132+ const pulls = await res . json ( ) ;
133+ if ( ! pulls . length ) return null ;
134+
135+ // Prefer merged PRs, earliest merge first (same logic as @changesets/get-github-info)
136+ const sorted = pulls . sort ( ( a , b ) => {
137+ if ( ! a . merged_at && ! b . merged_at ) return 0 ;
138+ if ( ! a . merged_at ) return 1 ;
139+ if ( ! b . merged_at ) return - 1 ;
140+ return new Date ( a . merged_at ) - new Date ( b . merged_at ) ;
141+ } ) ;
142+
143+ return sorted [ 0 ] . number ;
144+ } catch {
145+ return null ;
146+ }
147+ }
148+
86149// --- Parse .server-changes/ files ---
87150
88151async function parseServerChanges ( ) {
@@ -96,15 +159,39 @@ async function parseServerChanges() {
96159 return entries ;
97160 }
98161
162+ // Collect file info and look up commits in parallel
163+ const fileData = [ ] ;
99164 for ( const file of files ) {
100165 if ( ! file . endsWith ( ".md" ) || file === "README.md" ) continue ;
101166
167+ const filePath = join ( ".server-changes" , file ) ;
102168 const content = await fs . readFile ( join ( dir , file ) , "utf-8" ) ;
103169 const parsed = parseFrontmatter ( content ) ;
104170 if ( ! parsed . body . trim ( ) ) continue ;
105171
172+ fileData . push ( { filePath, parsed } ) ;
173+ }
174+
175+ // Look up commits for all files in parallel
176+ const commits = await Promise . all (
177+ fileData . map ( ( f ) => getCommitForFile ( f . filePath ) )
178+ ) ;
179+
180+ // Look up PRs for all commits in parallel
181+ const prNumbers = await Promise . all ( commits . map ( ( sha ) => getPrForCommit ( sha ) ) ) ;
182+
183+ for ( let i = 0 ; i < fileData . length ; i ++ ) {
184+ const { parsed } = fileData [ i ] ;
185+ let text = parsed . body . trim ( ) ;
186+ const pr = prNumbers [ i ] ;
187+
188+ // Append PR link if we found one and it's not already in the text
189+ if ( pr && ! text . includes ( `#${ pr } ` ) ) {
190+ text += ` ([#${ pr } ](https://github.com/${ REPO } /pull/${ pr } ))` ;
191+ }
192+
106193 entries . push ( {
107- text : parsed . body . trim ( ) ,
194+ text,
108195 type : parsed . frontmatter . type || "improvement" ,
109196 area : parsed . frontmatter . area || "webapp" ,
110197 } ) ;
0 commit comments