@@ -35,13 +35,26 @@ export type OpenSocketFixPrOptions = {
3535 ghsaDetails ?: Map < string , GhsaDetails > | undefined
3636}
3737
38+ export type OpenPrResult =
39+ | { ok : true ; pr : OctokitResponse < Pr > }
40+ | { ok : false ; reason : 'already_exists' ; error : RequestError }
41+ | {
42+ ok : false
43+ reason : 'validation_error'
44+ error : RequestError
45+ details : string
46+ }
47+ | { ok : false ; reason : 'permission_denied' ; error : RequestError }
48+ | { ok : false ; reason : 'network_error' ; error : RequestError }
49+ | { ok : false ; reason : 'unknown' ; error : Error }
50+
3851export async function openSocketFixPr (
3952 owner : string ,
4053 repo : string ,
4154 branch : string ,
4255 ghsaIds : string [ ] ,
4356 options ?: OpenSocketFixPrOptions | undefined ,
44- ) : Promise < OctokitResponse < Pr > | undefined > {
57+ ) : Promise < OpenPrResult > {
4558 const { baseBranch = 'main' , ghsaDetails } = {
4659 __proto__ : null ,
4760 ...options ,
@@ -59,25 +72,51 @@ export async function openSocketFixPr(
5972 body : getSocketFixPullRequestBody ( ghsaIds , ghsaDetails ) ,
6073 }
6174 debugDir ( 'inspect' , { octokitPullsCreateParams } )
62- return await octokit . pulls . create ( octokitPullsCreateParams )
75+ const pr = await octokit . pulls . create ( octokitPullsCreateParams )
76+ return { ok : true , pr }
6377 } catch ( e ) {
64- let message = `Failed to open pull request`
65- const errors =
66- e instanceof RequestError
67- ? ( e . response ?. data as any ) ?. [ 'errors' ]
68- : undefined
69- if ( Array . isArray ( errors ) && errors . length ) {
70- const details = errors
71- . map (
72- d =>
73- `- ${ d . message ?. trim ( ) ?? `${ d . resource } .${ d . field } (${ d . code } )` } ` ,
78+ // Handle RequestError from Octokit.
79+ if ( e instanceof RequestError ) {
80+ const errors = ( e . response ?. data as any ) ?. [ 'errors' ]
81+ const errorMessages = Array . isArray ( errors )
82+ ? errors . map (
83+ d => d . message ?. trim ( ) ?? `${ d . resource } .${ d . field } (${ d . code } )` ,
84+ )
85+ : [ ]
86+
87+ // Check for "PR already exists" error.
88+ if (
89+ errorMessages . some ( msg =>
90+ msg . toLowerCase ( ) . includes ( 'pull request already exists' ) ,
7491 )
75- . join ( '\n' )
76- message += `:\n${ details } `
92+ ) {
93+ debugFn ( 'error' , 'Failed to open pull request: already exists' )
94+ return { ok : false , reason : 'already_exists' , error : e }
95+ }
96+
97+ // Check for validation errors (e.g., no commits between branches).
98+ if ( errors && errors . length > 0 ) {
99+ const details = errorMessages . map ( d => `- ${ d } ` ) . join ( '\n' )
100+ debugFn ( 'error' , `Failed to open pull request:\n${ details } ` )
101+ return { ok : false , reason : 'validation_error' , error : e , details }
102+ }
103+
104+ // Check HTTP status codes.
105+ if ( e . status === 403 || e . status === 401 ) {
106+ debugFn ( 'error' , 'Failed to open pull request: permission denied' )
107+ return { ok : false , reason : 'permission_denied' , error : e }
108+ }
109+
110+ if ( e . status && e . status >= 500 ) {
111+ debugFn ( 'error' , 'Failed to open pull request: network error' )
112+ return { ok : false , reason : 'network_error' , error : e }
113+ }
77114 }
78- debugFn ( 'error' , message )
115+
116+ // Unknown error.
117+ debugFn ( 'error' , `Failed to open pull request: ${ e } ` )
118+ return { ok : false , reason : 'unknown' , error : e as Error }
79119 }
80- return undefined
81120}
82121
83122export type GQL_MERGE_STATE_STATUS =
0 commit comments