@@ -1087,6 +1087,67 @@ export class GithubHelper {
10871087
10881088 // ----------------------------------------------------------------------------
10891089
1090+ /**
1091+ * Creates the information required for a new review comment.
1092+ * See: https://docs.github.com/en/rest/pulls/comments?apiVersion=2022-11-28#create-a-review-comment-for-a-pull-request
1093+ */
1094+ static createReviewCommentInformation ( position , repoLink : string ) : object {
1095+ if (
1096+ ! repoLink ||
1097+ ! repoLink . startsWith ( gitHubLocation ) ||
1098+ ! position ||
1099+ ! position . head_sha ||
1100+ ! position . line_range
1101+ ) {
1102+ throw new Error ( `Position is invalid: ${ JSON . stringify ( position ) } ` ) ;
1103+ }
1104+
1105+ let head_sha = position . head_sha ;
1106+ let side = '' ;
1107+ let path = '' ;
1108+
1109+ if (
1110+ ( position . new_line && position . new_path ) ||
1111+ ( position . old_line && position . old_path )
1112+ ) {
1113+ if ( ! position . old_line || ! position . old_path ) {
1114+ side = 'RIGHT' ;
1115+ path = position . new_path ;
1116+ } else {
1117+ side = 'LEFT' ;
1118+ path = position . old_path ;
1119+ // use the start_sha since the head_sha does not contain the line anymore
1120+ // head_sha = position.start_sha;
1121+ }
1122+ }
1123+
1124+ // figure out new commit
1125+ const cherry_picked_commit = settings . commitMap [ head_sha ] ;
1126+ if ( cherry_picked_commit ) {
1127+ head_sha = cherry_picked_commit ;
1128+ }
1129+
1130+ const start = position . line_range . start ;
1131+ const end = position . line_range . end ;
1132+ const start_line = start . type === 'new' ? start . new_line : start . old_line ;
1133+ const end_line = end . type === 'new' ? end . new_line : end . old_line ;
1134+
1135+ let data = {
1136+ commit_id : head_sha ,
1137+ path : path ,
1138+ side : side ,
1139+ line : end_line ,
1140+ } ;
1141+
1142+ // deal with multi-line comments
1143+ if ( start_line != end_line ) {
1144+ data [ 'start_line' ] = start_line ;
1145+ data [ 'start_side' ] = side ;
1146+ }
1147+
1148+ return data ;
1149+ }
1150+
10901151 /**
10911152 * Create comments for the pull request
10921153 * @param pullRequest the GitHub pull request object
@@ -1097,6 +1158,7 @@ export class GithubHelper {
10971158 mergeRequest : GitLabMergeRequest
10981159 ) : Promise < void > {
10991160 console . log ( '\tMigrating pull request comments...' ) ;
1161+ const repoLink = `${ this . githubUrl } /${ this . githubOwner } /${ this . githubRepo } ` ;
11001162
11011163 if ( ! mergeRequest . iid ) {
11021164 console . log (
@@ -1108,15 +1170,14 @@ export class GithubHelper {
11081170 let discussions = await this . gitlabHelper . getAllMergeRequestDiscussions (
11091171 mergeRequest . iid
11101172 ) ;
1111-
1173+
11121174 // if there are no notes, then there is nothing to do!
11131175 if ( discussions . length === 0 ) {
11141176 console . log (
11151177 `\t...no pull request comments available, nothing to migrate.`
11161178 ) ;
11171179 return ;
11181180 }
1119-
11201181 // Sort notes in ascending order of when they were created (by id)
11211182 discussions = discussions . sort ( ( a , b ) => a . notes [ 0 ] . id - b . notes [ 0 ] . id ) ;
11221183
@@ -1135,13 +1196,22 @@ export class GithubHelper {
11351196 else {
11361197 // console.log('Processing discussion:');
11371198 let discussionBody = '**Discussion in GitLab:**\n\n' ;
1138-
1199+ let reviewComments = [ ] ;
1200+
11391201 for ( let note of discussion . notes ) {
11401202 if ( this . checkIfNoteCanBeSkipped ( note . body ) ) {
11411203 nrOfSkippedNotes ++ ;
11421204 continue ;
11431205 }
11441206
1207+ if ( note . type === 'DiffNote' ) {
1208+ reviewComments . push ( {
1209+ body : await this . convertIssuesAndComments ( note . body , note , true , false ) ,
1210+ ...GithubHelper . createReviewCommentInformation ( note . position , repoLink ) ,
1211+ } ) ;
1212+ }
1213+
1214+ // create regular comment either way, in case the review comment cannot be created
11451215 const add_line_ref = discussion . notes . indexOf ( note ) === 0 ;
11461216 let bodyConverted = await this . convertIssuesAndComments ( note . body , note , true , add_line_ref ) ;
11471217 discussionBody += bodyConverted ;
@@ -1152,18 +1222,69 @@ export class GithubHelper {
11521222 await utils . sleep ( this . delayInMs ) ;
11531223
11541224 if ( ! settings . dryRun ) {
1155- await this . githubApi . issues
1156- . createComment ( {
1225+ let create_regular_comment = true ;
1226+ if ( reviewComments . length > 0 ) {
1227+ create_regular_comment = false ;
1228+ const first_comment = reviewComments [ 0 ] ;
1229+
1230+ let new_review_comment = await this . githubApi . pulls . createReviewComment ( {
11571231 owner : this . githubOwner ,
11581232 repo : this . githubRepo ,
1159- issue_number : pullRequest . number ,
1160- body : discussionBody ,
1161- } )
1162- . catch ( x => {
1163- console . error ( 'could not create GitHub issue comment!' ) ;
1164- console . error ( x ) ;
1165- process . exit ( 1 ) ;
1233+ pull_number : pullRequest . number ,
1234+ ...first_comment ,
1235+ } ) . catch ( x => {
1236+ let use_fallback = false ;
1237+ if ( x . status === 422 ) {
1238+ if ( x . response . data . message === 'Validation Failed' ) {
1239+ let validation_error = x . response . data . errors [ 0 ] ;
1240+ if ( validation_error . message . endsWith ( ' is not part of the pull request' ) ) {
1241+ // fall back to creating a regular comment for the discussion
1242+ create_regular_comment = true ;
1243+ use_fallback = true ;
1244+ console . log ( 'fallback to regular comment' ) ;
1245+ }
1246+ }
1247+ }
1248+
1249+ if ( ! use_fallback ) {
1250+ console . error ( 'could not create GitHub pull request review comment!' ) ;
1251+ console . error ( x ) ;
1252+ process . exit ( 1 ) ;
1253+ }
11661254 } ) ;
1255+
1256+ if ( ! create_regular_comment ) {
1257+ for ( let reviewComment of reviewComments . slice ( 1 ) ) {
1258+ // await utils.sleep(this.delayInMs);
1259+ this . githubApi . pulls . createReplyForReviewComment ( {
1260+ owner : this . githubOwner ,
1261+ repo : this . githubRepo ,
1262+ pull_number : pullRequest . number ,
1263+ comment_id : ( new_review_comment as { data : { id : number } } ) . data . id ,
1264+ body : reviewComment . body ,
1265+ } ) . catch ( x => {
1266+ console . error ( 'could not create GitHub reply for pull request review comment!' ) ;
1267+ console . error ( x ) ;
1268+ process . exit ( 1 ) ;
1269+ } ) ;
1270+ }
1271+ }
1272+ }
1273+
1274+ if ( create_regular_comment ) {
1275+ await this . githubApi . issues
1276+ . createComment ( {
1277+ owner : this . githubOwner ,
1278+ repo : this . githubRepo ,
1279+ issue_number : pullRequest . number ,
1280+ body : discussionBody ,
1281+ } )
1282+ . catch ( x => {
1283+ console . error ( 'could not create GitHub issue comment!' ) ;
1284+ console . error ( x ) ;
1285+ process . exit ( 1 ) ;
1286+ } ) ;
1287+ }
11671288 }
11681289 }
11691290 }
0 commit comments