Skip to content

Commit 47336bf

Browse files
authored
Merge pull request #229 from mschoettle/use-discussions
Use discussions instad of notes
2 parents 3380fa9 + 90d0082 commit 47336bf

File tree

2 files changed

+180
-18
lines changed

2 files changed

+180
-18
lines changed

src/githubHelper.ts

Lines changed: 158 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as utils from './utils';
44
import { Octokit as GitHubApi, RestEndpointMethodTypes } from '@octokit/rest';
55
import { Endpoints } from '@octokit/types';
66
import {
7+
GitLabDiscussion,
8+
GitLabDiscussionNote,
79
GitlabHelper,
810
GitLabIssue,
911
GitLabMergeRequest,
@@ -561,6 +563,85 @@ export class GithubHelper {
561563
);
562564
return comments;
563565
}
566+
567+
/**
568+
*
569+
* @param discussions
570+
* @returns Comments ready for requestImportIssue()
571+
*/
572+
async processDiscussionsIntoComments(
573+
discussions: GitLabDiscussion[]
574+
): Promise<CommentImport[]> {
575+
if (!discussions || !discussions.length) {
576+
console.log(`\t...no comments available, nothing to migrate.`);
577+
return [];
578+
}
579+
580+
let comments: CommentImport[] = [];
581+
582+
// sort notes in ascending order of when they were created (by id)
583+
discussions = discussions.sort((a, b) => Number.parseInt(a.id) - Number.parseInt(b.id));
584+
585+
let nrOfMigratedNotes = 0;
586+
let nrOfSkippedNotes = 0;
587+
for (let discussion of discussions) {
588+
let discussionComments = [];
589+
590+
for (let note of discussion.notes) {
591+
if (this.checkIfNoteCanBeSkipped(note.body)) {
592+
nrOfSkippedNotes++;
593+
continue;
594+
}
595+
596+
let username = note.author.username as string;
597+
this.users.add(username);
598+
let userIsPoster =
599+
(settings.usermap &&
600+
settings.usermap[username] ===
601+
settings.github.token_owner) ||
602+
username === settings.github.token_owner;
603+
604+
// only add line ref for first note of discussion
605+
const add_line_ref = discussion.notes.indexOf(note) === 0;
606+
607+
discussionComments.push({
608+
created_at: note.created_at,
609+
body: await this.convertIssuesAndComments(
610+
note.body,
611+
note,
612+
!userIsPoster || !note.body,
613+
add_line_ref,
614+
),
615+
});
616+
617+
nrOfMigratedNotes++;
618+
}
619+
620+
// Combine notes for discussion into one comment
621+
if (discussionComments.length == 1) {
622+
comments.push(discussionComments[0]);
623+
}
624+
else if (discussionComments.length > 1) {
625+
let combinedBody = '**Discussion in GitLab:**\n\n';
626+
let first_created_at = discussionComments[0].created_at;
627+
628+
combinedBody += discussionComments.map(comment => comment.body).join('\n\n');
629+
630+
comments.push({
631+
created_at: first_created_at,
632+
body: combinedBody,
633+
});
634+
}
635+
}
636+
637+
console.log(
638+
`\t...Done creating discussion comments (migrated ${nrOfMigratedNotes} comments, skipped ${
639+
nrOfSkippedNotes
640+
} comments)`
641+
);
642+
return comments;
643+
}
644+
564645
/**
565646
* Calls the preview API for issue importing
566647
*
@@ -691,7 +772,7 @@ export class GithubHelper {
691772
* Return false when it got skipped, otherwise true.
692773
*/
693774
async processNote(
694-
note: GitLabNote,
775+
note: GitLabNote | GitLabDiscussionNote,
695776
githubIssue: Pick<GitHubIssue | GitHubPullRequest, 'number'>
696777
) {
697778
if (this.checkIfNoteCanBeSkipped(note.body)) return false;
@@ -966,10 +1047,10 @@ export class GithubHelper {
9661047
'\t...this is a placeholder for a deleted GitLab merge request, no comments are created.'
9671048
);
9681049
} else {
969-
let notes = await this.gitlabHelper.getAllMergeRequestNotes(
1050+
let discussions = await this.gitlabHelper.getAllMergeRequestDiscussions(
9701051
mergeRequest.iid
9711052
);
972-
comments = await this.processNotesIntoComments(notes);
1053+
comments = await this.processDiscussionsIntoComments(discussions);
9731054
}
9741055

9751056
return this.requestImportIssue(props, comments);
@@ -1010,30 +1091,72 @@ export class GithubHelper {
10101091
return Promise.resolve();
10111092
}
10121093

1013-
let notes = await this.gitlabHelper.getAllMergeRequestNotes(
1094+
let discussions = await this.gitlabHelper.getAllMergeRequestDiscussions(
10141095
mergeRequest.iid
10151096
);
10161097

10171098
// if there are no notes, then there is nothing to do!
1018-
if (notes.length === 0) {
1099+
if (discussions.length === 0) {
10191100
console.log(
10201101
`\t...no pull request comments available, nothing to migrate.`
10211102
);
10221103
return;
10231104
}
10241105

10251106
// Sort notes in ascending order of when they were created (by id)
1026-
notes = notes.sort((a, b) => a.id - b.id);
1107+
discussions = discussions.sort((a, b) => a.notes[0].id - b.notes[0].id);
10271108

10281109
let nrOfMigratedNotes = 0;
1029-
for (let note of notes) {
1030-
const gotMigrated = await this.processNote(note, pullRequest);
1031-
if (gotMigrated) nrOfMigratedNotes++;
1110+
let nrOfSkippedNotes = 0;
1111+
for (let discussion of discussions) {
1112+
if (discussion.individual_note) {
1113+
const gotMigrated = await this.processNote(discussion.notes[0], pullRequest);
1114+
if (gotMigrated) {
1115+
nrOfMigratedNotes++;
1116+
}
1117+
else {
1118+
nrOfSkippedNotes++;
1119+
}
1120+
}
1121+
else {
1122+
// console.log('Processing discussion:');
1123+
let discussionBody = '**Discussion in GitLab:**\n\n';
1124+
1125+
for (let note of discussion.notes) {
1126+
if (this.checkIfNoteCanBeSkipped(note.body)) {
1127+
nrOfSkippedNotes++;
1128+
continue;
1129+
}
1130+
1131+
const add_line_ref = discussion.notes.indexOf(note) === 0;
1132+
let bodyConverted = await this.convertIssuesAndComments(note.body, note, true, add_line_ref);
1133+
discussionBody += bodyConverted;
1134+
discussionBody += '\n\n';
1135+
nrOfMigratedNotes++;
1136+
}
1137+
1138+
await utils.sleep(this.delayInMs);
1139+
1140+
if (!settings.dryRun) {
1141+
await this.githubApi.issues
1142+
.createComment({
1143+
owner: this.githubOwner,
1144+
repo: this.githubRepo,
1145+
issue_number: pullRequest.number,
1146+
body: discussionBody,
1147+
})
1148+
.catch(x => {
1149+
console.error('could not create GitHub issue comment!');
1150+
console.error(x);
1151+
process.exit(1);
1152+
});
1153+
}
1154+
}
10321155
}
10331156

10341157
console.log(
10351158
`\t...Done creating pull request comments (migrated ${nrOfMigratedNotes} pull request comments, skipped ${
1036-
notes.length - nrOfMigratedNotes
1159+
nrOfSkippedNotes
10371160
} pull request comments)`
10381161
);
10391162
}
@@ -1159,8 +1282,9 @@ export class GithubHelper {
11591282
*/
11601283
async convertIssuesAndComments(
11611284
str: string,
1162-
item: GitLabIssue | GitLabMergeRequest | GitLabNote | MilestoneImport,
1163-
add_line: boolean = true
1285+
item: GitLabIssue | GitLabMergeRequest | GitLabNote | MilestoneImport | GitLabDiscussionNote,
1286+
add_line: boolean = true,
1287+
add_line_ref: boolean = true,
11641288
): Promise<string> {
11651289
// A note on implementation:
11661290
// We don't convert project names once at the beginning because otherwise
@@ -1176,7 +1300,7 @@ export class GithubHelper {
11761300
settings.projectmap !== null &&
11771301
Object.keys(settings.projectmap).length > 0;
11781302

1179-
if (add_line) str = GithubHelper.addMigrationLine(str, item, repoLink);
1303+
if (add_line) str = GithubHelper.addMigrationLine(str, item, repoLink, add_line_ref);
11801304
let reString = '';
11811305

11821306
// Store usernames found in the text
@@ -1348,7 +1472,7 @@ export class GithubHelper {
13481472
* Adds a line of text at the beginning of a comment that indicates who, when
13491473
* and from GitLab.
13501474
*/
1351-
static addMigrationLine(str: string, item: any, repoLink: string): string {
1475+
static addMigrationLine(str: string, item: any, repoLink: string, add_line_ref: boolean = true): string {
13521476
if (!item || !item.author || !item.author.username || !item.created_at) {
13531477
return str;
13541478
}
@@ -1368,11 +1492,12 @@ export class GithubHelper {
13681492
dateformatOptions
13691493
);
13701494

1371-
const attribution = `In GitLab by @${item.author.username} on ${formattedDate}`;
1495+
const attribution = `***In GitLab by @${item.author.username} on ${formattedDate}:***`;
13721496
const lineRef =
1373-
item && item.position
1497+
item && item.position && add_line_ref
13741498
? GithubHelper.createLineRef(item.position, repoLink)
13751499
: '';
1500+
13761501
const summary = attribution + (lineRef ? `\n\n${lineRef}` : '');
13771502

13781503
return `${summary}\n\n${str}`;
@@ -1392,7 +1517,7 @@ export class GithubHelper {
13921517
return '';
13931518
}
13941519
const base_sha = position.base_sha;
1395-
const head_sha = position.head_sha;
1520+
let head_sha = position.head_sha;
13961521
var path = '';
13971522
var line = '';
13981523
var slug = '';
@@ -1416,7 +1541,22 @@ export class GithubHelper {
14161541
}
14171542
// Mention the file and line number. If we can't get this for some reason then use the commit id instead.
14181543
const ref = path && line ? `${path} line ${line}` : `${head_sha}`;
1419-
return `Commented on [${ref}](${repoLink}/compare/${base_sha}..${head_sha}${slug})\n\n`;
1544+
let lineRef = `Commented on [${ref}](${repoLink}/compare/${base_sha}..${head_sha}${slug})\n\n`;
1545+
1546+
if (position.line_range.start.type === 'new') {
1547+
const startLine = position.line_range.start.new_line;
1548+
const endLine = position.line_range.end.new_line;
1549+
const lineRange = (startLine !== endLine) ? `L${startLine}-L${endLine}` : `L${startLine}`;
1550+
lineRef += `${repoLink}/blob/${head_sha}/${path}#${lineRange}\n\n`;
1551+
}
1552+
else {
1553+
const startLine = position.line_range.start.old_line;
1554+
const endLine = position.line_range.end.old_line;
1555+
const lineRange = (startLine !== endLine) ? `L${startLine}-L${endLine}` : `L${startLine}`;
1556+
lineRef += `${repoLink}/blob/${head_sha}/${path}#${lineRange}\n\n`;
1557+
}
1558+
1559+
return lineRef;
14201560
}
14211561

14221562
/**

src/gitlabHelper.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Gitlab } from '@gitbeaker/node';
22
import {
3+
DiscussionNote,
4+
DiscussionSchema,
35
IssueSchema,
46
MergeRequestSchema,
57
MilestoneSchema,
@@ -9,6 +11,8 @@ import {
911
import { GitlabSettings } from './settings';
1012
import axios from 'axios';
1113

14+
export type GitLabDiscussion = DiscussionSchema;
15+
export type GitLabDiscussionNote = DiscussionNote;
1216
export type GitLabIssue = IssueSchema;
1317
export type GitLabNote = NoteSchema;
1418
export type GitLabUser = Omit<UserSchema, 'created_at'>;
@@ -163,4 +167,22 @@ export class GitlabHelper {
163167
return [];
164168
}
165169
}
170+
171+
/**
172+
* Gets all notes for a given merge request.
173+
*/
174+
async getAllMergeRequestDiscussions(pullRequestIid: number): Promise<GitLabDiscussion[]> {
175+
try {
176+
return this.gitlabApi.MergeRequestDiscussions.all(
177+
this.gitlabProjectId,
178+
pullRequestIid,
179+
{}
180+
);
181+
} catch (err) {
182+
console.error(
183+
`Could not fetch notes for GitLab merge request #${pullRequestIid}.`
184+
);
185+
return [];
186+
}
187+
}
166188
}

0 commit comments

Comments
 (0)