@@ -17,6 +17,7 @@ export interface PRStatus {
1717 reviewDecision : "approved" | "changes_requested" | "review_required" | null ;
1818 title : string ;
1919 baseRefName : string ;
20+ url : string ;
2021}
2122
2223export interface RepoInfo {
@@ -241,7 +242,7 @@ export class GitHub {
241242 "view" ,
242243 String ( prNumber ) ,
243244 "--json" ,
244- "number,state,reviewDecision,title,baseRefName" ,
245+ "number,state,reviewDecision,title,baseRefName,url " ,
245246 ] ,
246247 { cwd : this . cwd } ,
247248 ) ;
@@ -262,6 +263,7 @@ export class GitHub {
262263 reviewDecision : data . reviewDecision ?. toLowerCase ( ) ?? null ,
263264 title : data . title ,
264265 baseRefName : data . baseRefName ,
266+ url : data . url ,
265267 } ) ;
266268 } catch ( e ) {
267269 return err (
@@ -325,74 +327,151 @@ export class GitHub {
325327 }
326328 }
327329
330+ async updatePR (
331+ prNumber : number ,
332+ options : { title ?: string ; body ?: string ; base ?: string } ,
333+ ) : Promise < Result < void > > {
334+ const args = [ "pr" , "edit" , String ( prNumber ) ] ;
335+ if ( options . title ) {
336+ args . push ( "--title" , options . title ) ;
337+ }
338+ if ( options . body ) {
339+ args . push ( "--body" , options . body ) ;
340+ }
341+ if ( options . base ) {
342+ args . push ( "--base" , options . base ) ;
343+ }
344+
345+ try {
346+ const result = await this . executor . execute ( "gh" , args , { cwd : this . cwd } ) ;
347+ if ( result . exitCode !== 0 ) {
348+ return err (
349+ createError ( "COMMAND_FAILED" , `gh pr edit failed: ${ result . stderr } ` ) ,
350+ ) ;
351+ }
352+ return ok ( undefined ) ;
353+ } catch ( e ) {
354+ return err ( createError ( "COMMAND_FAILED" , `gh pr edit failed: ${ e } ` ) ) ;
355+ }
356+ }
357+
328358 async updatePRBase ( prNumber : number , newBase : string ) : Promise < Result < void > > {
359+ return this . updatePR ( prNumber , { base : newBase } ) ;
360+ }
361+
362+ async createPR ( options : {
363+ head : string ;
364+ title ?: string ;
365+ body ?: string ;
366+ base ?: string ;
367+ draft ?: boolean ;
368+ } ) : Promise < Result < { url : string ; number : number } > > {
369+ const args = [ "pr" , "create" , "--head" , options . head ] ;
370+ if ( options . title ) {
371+ args . push ( "--title" , options . title ) ;
372+ }
373+ if ( options . body ) {
374+ args . push ( "--body" , options . body ) ;
375+ }
376+ if ( options . base ) {
377+ args . push ( "--base" , options . base ) ;
378+ }
379+ if ( options . draft ) {
380+ args . push ( "--draft" ) ;
381+ }
382+
329383 try {
330- const result = await this . executor . execute (
331- "gh" ,
332- [ "pr" , "edit" , String ( prNumber ) , "--base" , newBase ] ,
333- { cwd : this . cwd } ,
334- ) ;
384+ const result = await this . executor . execute ( "gh" , args , {
385+ cwd : this . cwd ,
386+ } ) ;
335387
336388 if ( result . exitCode !== 0 ) {
337389 return err (
338390 createError (
339391 "COMMAND_FAILED" ,
340- `Failed to update PR base : ${ result . stderr } ` ,
392+ `gh pr create failed : ${ result . stderr } ` ,
341393 ) ,
342394 ) ;
343395 }
344396
345- return ok ( undefined ) ;
346- } catch ( e ) {
347- return err (
348- createError ( "COMMAND_FAILED" , `Failed to update PR base: ${ e } ` ) ,
397+ const urlMatch = result . stdout . match (
398+ / h t t p s : \/ \/ g i t h u b \. c o m \/ [ ^ \s ] + \/ p u l l \/ ( \d + ) / ,
349399 ) ;
400+ const url = urlMatch ? urlMatch [ 0 ] : result . stdout . trim ( ) ;
401+ const number = urlMatch ? Number . parseInt ( urlMatch [ 1 ] , 10 ) : 0 ;
402+
403+ return ok ( { url, number } ) ;
404+ } catch ( e ) {
405+ return err ( createError ( "COMMAND_FAILED" , `gh pr create failed: ${ e } ` ) ) ;
350406 }
351407 }
352408
353409 async getPRForBranch ( branchName : string ) : Promise < Result < PRStatus | null > > {
410+ const result = await this . batchGetPRsForBranches ( [ branchName ] ) ;
411+ if ( ! result . ok ) return result ;
412+ return ok ( result . value . get ( branchName ) ?? null ) ;
413+ }
414+
415+ async batchGetPRsForBranches (
416+ branchNames : string [ ] ,
417+ ) : Promise < Result < Map < string , PRStatus > > > {
418+ if ( branchNames . length === 0 ) {
419+ return ok ( new Map ( ) ) ;
420+ }
421+
354422 try {
355423 const result = await this . executor . execute (
356424 "gh" ,
357425 [
358426 "pr" ,
359427 "list" ,
360- "--head " ,
361- branchName ,
428+ "--state " ,
429+ "all" ,
362430 "--json" ,
363- "number,state,reviewDecision,title,baseRefName" ,
431+ "number,state,reviewDecision,title,baseRefName,headRefName,url " ,
364432 "--limit" ,
365- "1 " ,
433+ "100 " ,
366434 ] ,
367435 { cwd : this . cwd } ,
368436 ) ;
369437
370438 if ( result . exitCode !== 0 ) {
371439 return err (
372- createError (
373- "COMMAND_FAILED" ,
374- `Failed to find PR for branch: ${ result . stderr } ` ,
375- ) ,
440+ createError ( "COMMAND_FAILED" , `Failed to list PRs: ${ result . stderr } ` ) ,
376441 ) ;
377442 }
378443
379- const prs = JSON . parse ( result . stdout ) ;
380- if ( prs . length === 0 ) {
381- return ok ( null ) ;
444+ const prs = JSON . parse ( result . stdout ) as Array < {
445+ number : number ;
446+ state : string ;
447+ reviewDecision : string | null ;
448+ title : string ;
449+ baseRefName : string ;
450+ headRefName : string ;
451+ url : string ;
452+ } > ;
453+
454+ const branchSet = new Set ( branchNames ) ;
455+ const prMap = new Map < string , PRStatus > ( ) ;
456+
457+ for ( const pr of prs ) {
458+ if ( branchSet . has ( pr . headRefName ) ) {
459+ prMap . set ( pr . headRefName , {
460+ number : pr . number ,
461+ state : pr . state . toLowerCase ( ) as "open" | "closed" | "merged" ,
462+ reviewDecision :
463+ ( pr . reviewDecision ?. toLowerCase ( ) as PRStatus [ "reviewDecision" ] ) ??
464+ null ,
465+ title : pr . title ,
466+ baseRefName : pr . baseRefName ,
467+ url : pr . url ,
468+ } ) ;
469+ }
382470 }
383471
384- const data = prs [ 0 ] ;
385- return ok ( {
386- number : data . number ,
387- state : data . state . toLowerCase ( ) as "open" | "closed" | "merged" ,
388- reviewDecision : data . reviewDecision ?. toLowerCase ( ) ?? null ,
389- title : data . title ,
390- baseRefName : data . baseRefName ,
391- } ) ;
472+ return ok ( prMap ) ;
392473 } catch ( e ) {
393- return err (
394- createError ( "COMMAND_FAILED" , `Failed to find PR for branch: ${ e } ` ) ,
395- ) ;
474+ return err ( createError ( "COMMAND_FAILED" , `Failed to list PRs: ${ e } ` ) ) ;
396475 }
397476 }
398477}
0 commit comments