Skip to content

Commit 9b228d0

Browse files
authored
Merge pull request #238 from mschoettle/review-comments
Add support for review comments and replies
2 parents 9fb9782 + ef23755 commit 9b228d0

File tree

1 file changed

+133
-12
lines changed

1 file changed

+133
-12
lines changed

src/githubHelper.ts

Lines changed: 133 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)