Skip to content

Commit 3435f61

Browse files
committed
Try out comment-outside-the-diff
Fixes #3305
1 parent f049098 commit 3435f61

File tree

7 files changed

+98
-27
lines changed

7 files changed

+98
-27
lines changed

src/github/credentials.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ const link = (url: string, token: string) =>
576576
headers: {
577577
...headers,
578578
authorization: token ? `Bearer ${token}` : '',
579-
Accept: 'application/vnd.github.merge-info-preview'
579+
Accept: 'application/vnd.github.merge-info-preview',
580+
'GraphQL-Features': 'graphql_pr_comment_positioning'
580581
},
581582
})).concat(
582583
createHttpLink({

src/github/graphql.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@ export interface ReviewThread {
273273
}
274274
}]
275275
};
276+
positioning?: {
277+
__typename: string;
278+
startLine?: number;
279+
endLine?: number;
280+
line?: number;
281+
}
276282
}
277283

278284
export interface TimelineEventsResponse {

src/github/pullRequestModel.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,26 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
742742
const pendingReviewId = await this.getPendingReviewId();
743743

744744
const { mutate, schema } = await this.githubRepository.ensure();
745+
746+
let linePositioning: any;
747+
let multilinePositioning: any;
748+
if (startLine === endLine && startLine !== undefined) {
749+
linePositioning = {
750+
line: startLine,
751+
path: commentPath,
752+
commitOid: this.head?.sha
753+
};
754+
} else if (startLine !== undefined && endLine !== undefined) {
755+
multilinePositioning = {
756+
startLine,
757+
endLine,
758+
startPath: commentPath,
759+
endPath: commentPath,
760+
startCommitOid: this.head?.sha,
761+
endCommitOid: this.head?.sha
762+
};
763+
}
764+
745765
const { data } = await mutate<AddReviewThreadResponse>({
746766
mutation: schema.AddReviewThread,
747767
variables: {
@@ -753,7 +773,9 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
753773
startLine: startLine === endLine ? undefined : startLine,
754774
line: (endLine === undefined) ? 0 : endLine,
755775
side,
756-
subjectType: (startLine === undefined || endLine === undefined) ? SubjectType.FILE : SubjectType.LINE
776+
subjectType: (startLine === undefined || endLine === undefined) ? SubjectType.FILE : SubjectType.LINE,
777+
linePositioning,
778+
multilinePositioning
757779
}
758780
}
759781
}, { mutation: schema.LegacyAddReviewThread, deleteProps: ['subjectType'] });
@@ -772,7 +794,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
772794
}
773795

774796
const thread = data.addPullRequestReviewThread.thread;
775-
const newThread = parseGraphQLReviewThread(thread, this.githubRepository);
797+
const newThread = parseGraphQLReviewThread(thread, this.githubRepository, this.head?.sha);
776798
if (!this._reviewThreadsCache) {
777799
this._reviewThreadsCache = [];
778800
}
@@ -1453,7 +1475,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
14531475
}
14541476

14551477
private setReviewThreadCacheFromRaw(raw: ReviewThread[]): IReviewThread[] {
1456-
const reviewThreads: IReviewThread[] = raw.map(thread => parseGraphQLReviewThread(thread, this.githubRepository));
1478+
const reviewThreads: IReviewThread[] = raw.map(thread => parseGraphQLReviewThread(thread, this.githubRepository, this.head?.sha));
14571479
const oldReviewThreads = this._reviewThreadsCache ?? [];
14581480
this._reviewThreadsCache = reviewThreads;
14591481
this.diffThreads(oldReviewThreads, reviewThreads);
@@ -2105,7 +2127,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
21052127

21062128
const index = this._reviewThreadsCache?.findIndex(thread => thread.id === threadId) ?? -1;
21072129
if (index > -1) {
2108-
const thread = parseGraphQLReviewThread(data.resolveReviewThread.thread, this.githubRepository);
2130+
const thread = parseGraphQLReviewThread(data.resolveReviewThread.thread, this.githubRepository, this.head?.sha);
21092131
this._reviewThreadsCache?.splice(index, 1, thread);
21102132
this._onDidChangeReviewThreads.fire({ added: [], changed: [thread], removed: [] });
21112133
}
@@ -2148,7 +2170,7 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
21482170

21492171
const index = this._reviewThreadsCache?.findIndex(thread => thread.id === threadId) ?? -1;
21502172
if (index > -1) {
2151-
const thread = parseGraphQLReviewThread(data.unresolveReviewThread.thread, this.githubRepository);
2173+
const thread = parseGraphQLReviewThread(data.unresolveReviewThread.thread, this.githubRepository, this.head?.sha);
21522174
this._reviewThreadsCache?.splice(index, 1, thread);
21532175
this._onDidChangeReviewThreads.fire({ added: [], changed: [thread], removed: [] });
21542176
}

src/github/queriesShared.gql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,16 @@ query PullRequestComments($owner: String!, $name: String!, $number: Int!, $after
576576
...ReviewComment
577577
}
578578
}
579+
positioning {
580+
__typename
581+
... on MultilineComment {
582+
startLine
583+
endLine
584+
}
585+
... on LineComment {
586+
line
587+
}
588+
}
579589
}
580590
pageInfo {
581591
hasNextPage

src/github/utils.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,29 @@ export function convertGraphQLEventType(text: string) {
510510
}
511511
}
512512

513-
export function parseGraphQLReviewThread(thread: GraphQL.ReviewThread, githubRepository: GitHubRepository): IReviewThread {
513+
export function parseGraphQLReviewThread(thread: GraphQL.ReviewThread, githubRepository: GitHubRepository, headCommitOid?: string): IReviewThread {
514+
let startLine: number = 0;
515+
let endLine: number = 0;
516+
if (thread.positioning) {
517+
if (thread.positioning.__typename === 'MultilineComment') {
518+
startLine = thread.positioning.startLine!;
519+
endLine = thread.positioning.endLine!;
520+
} else if (thread.positioning.__typename === 'LineComment') {
521+
startLine = thread.positioning.line!;
522+
endLine = thread.positioning.line!;
523+
}
524+
} else {
525+
startLine = thread.startLine ?? thread.line;
526+
endLine = thread.line;
527+
}
528+
529+
// There's a bug with comments outside the diff where they always show as outdated. Try to work around that.
530+
let isOutdated = thread.isOutdated;
531+
if (isOutdated && headCommitOid && thread.comments.nodes.length > 0 &&
532+
thread.comments.nodes.every(comment => comment.commit.oid === headCommitOid)) {
533+
isOutdated = false;
534+
}
535+
514536
return {
515537
id: thread.id,
516538
prReviewDatabaseId: thread.comments.edges && thread.comments.edges.length ?
@@ -520,13 +542,13 @@ export function parseGraphQLReviewThread(thread: GraphQL.ReviewThread, githubRep
520542
viewerCanResolve: thread.viewerCanResolve,
521543
viewerCanUnresolve: thread.viewerCanUnresolve,
522544
path: thread.path,
523-
startLine: thread.startLine ?? thread.line,
524-
endLine: thread.line,
545+
startLine,
546+
endLine,
525547
originalStartLine: thread.originalStartLine ?? thread.originalLine,
526548
originalEndLine: thread.originalLine,
527549
diffSide: thread.diffSide,
528-
isOutdated: thread.isOutdated,
529-
comments: thread.comments.nodes.map(comment => parseGraphQLComment(comment, thread.isResolved, thread.isOutdated, githubRepository)),
550+
isOutdated,
551+
comments: thread.comments.nodes.map(comment => parseGraphQLComment(comment, thread.isResolved, isOutdated, githubRepository)),
530552
subjectType: thread.subjectType ?? SubjectType.LINE
531553
};
532554
}

src/view/reviewCommentController.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
CommentReactionHandler,
3232
createVSCodeCommentThreadForReviewThread,
3333
getRepositoryForFile,
34+
isEnterprise,
3435
isFileInRepo,
3536
setReplyAuthor,
3637
threadRange,
@@ -522,25 +523,29 @@ export class ReviewCommentController extends CommentControllerBase implements Co
522523
const ranges: vscode.Range[] = [];
523524

524525
if (matchedFile) {
525-
const diffHunks = await matchedFile.changeModel.diffHunks();
526-
if ((matchedFile.status === GitChangeType.RENAME) && (diffHunks.length === 0)) {
527-
Logger.debug('No commenting ranges: File was renamed with no diffs.', ReviewCommentController.ID);
528-
return { ranges: [], enableFileComments: true };
529-
}
526+
if (!isEnterprise(this._folderRepoManager.activePullRequest.remote.authProviderId)) {
527+
ranges.push(new vscode.Range(0, 0, document.lineCount - 1, document.lineAt(document.lineCount - 1).text.length - 1));
528+
} else {
529+
const diffHunks = await matchedFile.changeModel.diffHunks();
530+
if ((matchedFile.status === GitChangeType.RENAME) && (diffHunks.length === 0)) {
531+
Logger.debug('No commenting ranges: File was renamed with no diffs.', ReviewCommentController.ID);
532+
return { ranges: [], enableFileComments: true };
533+
}
530534

531-
const contentDiff = await this.getContentDiff(document.uri, matchedFile.fileName);
535+
const contentDiff = await this.getContentDiff(document.uri, matchedFile.fileName);
532536

533-
for (let i = 0; i < diffHunks.length; i++) {
534-
const diffHunk = diffHunks[i];
535-
const start = mapOldPositionToNew(contentDiff, diffHunk.newLineNumber, document.lineCount);
536-
const end = mapOldPositionToNew(contentDiff, diffHunk.newLineNumber + diffHunk.newLength - 1, document.lineCount);
537-
if (start > 0 && end > 0) {
538-
ranges.push(new vscode.Range(start - 1, 0, end - 1, 0));
537+
for (let i = 0; i < diffHunks.length; i++) {
538+
const diffHunk = diffHunks[i];
539+
const start = mapOldPositionToNew(contentDiff, diffHunk.newLineNumber, document.lineCount);
540+
const end = mapOldPositionToNew(contentDiff, diffHunk.newLineNumber + diffHunk.newLength - 1, document.lineCount);
541+
if (start > 0 && end > 0) {
542+
ranges.push(new vscode.Range(start - 1, 0, end - 1, 0));
543+
}
539544
}
540-
}
541545

542-
if (ranges.length === 0) {
543-
Logger.debug('No commenting ranges: File has diffs, but they could not be mapped to current lines.', ReviewCommentController.ID);
546+
if (ranges.length === 0) {
547+
Logger.debug('No commenting ranges: File has diffs, but they could not be mapped to current lines.', ReviewCommentController.ID);
548+
}
544549
}
545550
} else {
546551
Logger.debug('No commenting ranges: File does not match any of the files in the review.', ReviewCommentController.ID);

src/view/treeNodes/pullRequestNode.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { getIconForeground, getListErrorForeground, getListWarningForeground, ge
2222
import { DirectoryTreeNode } from './directoryTreeNode';
2323
import { InMemFileChangeNode, RemoteFileChangeNode } from './fileChangeNode';
2424
import { TreeNode, TreeNodeParent } from './treeNode';
25+
import { isEnterprise } from '../../github/utils';
2526
import { NotificationsManager } from '../../notifications/notificationsManager';
2627
import { PrsTreeModel } from '../prsTreeModel';
2728

@@ -411,7 +412,11 @@ export class PRNode extends TreeNode implements vscode.CommentingRangeProvider2
411412
return undefined;
412413
}
413414

414-
return { ranges: getCommentingRanges(await fileChange.changeModel.diffHunks(), params.isBase, PRNode.ID), enableFileComments: true };
415+
if (isEnterprise(this.pullRequestModel.remote.authProviderId)) {
416+
return { ranges: getCommentingRanges(await fileChange.changeModel.diffHunks(), params.isBase, PRNode.ID), enableFileComments: true };
417+
} else {
418+
return { ranges: [(new vscode.Range(0, 0, document.lineCount - 1, document.lineAt(document.lineCount).text.length))], enableFileComments: true };
419+
}
415420
}
416421

417422
return undefined;

0 commit comments

Comments
 (0)