-
Notifications
You must be signed in to change notification settings - Fork 732
Expand file tree
/
Copy pathactivePullRequestTool.ts
More file actions
122 lines (103 loc) · 4.96 KB
/
activePullRequestTool.ts
File metadata and controls
122 lines (103 loc) · 4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import { FetchIssueResult } from './fetchIssueTool';
import { GitChangeType, InMemFileChange } from '../../common/file';
import { CommentEvent, EventType, ReviewEvent } from '../../common/timelineEvent';
import { PullRequestModel } from '../../github/pullRequestModel';
import { RepositoriesManager } from '../../github/repositoriesManager';
interface PullRequestToolParams {
refresh?: boolean;
}
export abstract class PullRequestTool implements vscode.LanguageModelTool<FetchIssueResult> {
constructor(
protected readonly folderManagers: RepositoriesManager
) { }
protected abstract _findActivePullRequest(): PullRequestModel | undefined;
protected abstract _confirmationTitle(): string;
private _getPullRequestLabel(pullRequest: PullRequestModel): string {
return `${pullRequest.title} (#${pullRequest.number})`;
}
async prepareInvocation(): Promise<vscode.PreparedToolInvocation> {
const pullRequest = this._findActivePullRequest();
if (!pullRequest) {
return {
pastTenseMessage: vscode.l10n.t('No active pull request'),
invocationMessage: vscode.l10n.t('Reading active pull request'),
confirmationMessages: { title: this._confirmationTitle(), message: vscode.l10n.t('Allow reading the details of the active pull request?') },
};
}
const label = this._getPullRequestLabel(pullRequest);
return {
pastTenseMessage: vscode.l10n.t('Read pull request "{0}"', label),
invocationMessage: vscode.l10n.t('Reading pull request "{0}"', label),
confirmationMessages: { title: this._confirmationTitle(), message: vscode.l10n.t('Allow reading the details of "{0}"?', label) },
};
}
async invoke(options: vscode.LanguageModelToolInvocationOptions<any>, _token: vscode.CancellationToken): Promise<vscode.ExtendedLanguageModelToolResult | undefined> {
let pullRequest = this._findActivePullRequest();
if (!pullRequest) {
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('There is no active pull request')]);
}
if ((options.input as PullRequestToolParams).refresh) {
await Promise.all([
pullRequest.githubRepository.getPullRequest(pullRequest.number),
pullRequest.getTimelineEvents(),
pullRequest.initializeReviewThreadCacheAndReviewComments(),
]);
}
const timeline = (pullRequest.timelineEvents && pullRequest.timelineEvents.length > 0) ? pullRequest.timelineEvents : await pullRequest.getTimelineEvents();
const reviewAndCommentEvents = timeline.filter((event): event is ReviewEvent | CommentEvent => event.event === EventType.Reviewed || event.event === EventType.Commented);
if ((pullRequest.comments.length === 0) && (reviewAndCommentEvents.length !== 0)) {
// Probably missing some comments
await pullRequest.initializeReviewThreadCacheAndReviewComments();
}
const pullRequestInfo = {
title: pullRequest.title,
body: pullRequest.body,
author: pullRequest.author,
assignees: pullRequest.assignees,
comments: pullRequest.comments.map(comment => {
return {
author: comment.user?.login,
body: comment.body,
commentState: comment.isResolved ? 'resolved' : 'unresolved',
file: comment.path
};
}),
timelineComments: reviewAndCommentEvents.map(event => {
return {
author: event.user?.login,
body: event.body,
commentType: event.event === EventType.Reviewed ? event.state : 'COMMENTED',
};
}),
state: pullRequest.state,
isDraft: pullRequest.isDraft ? 'is a draft and cannot be merged until marked as ready for review' : 'false',
changes: (await pullRequest.getFileChangesInfo()).map(change => {
if (change instanceof InMemFileChange) {
return change.diffHunks?.map(hunk => hunk.diffLines.map(line => line.raw).join('\n')).join('\n') || '';
} else {
return `File: ${change.fileName} was ${change.status === GitChangeType.ADD ? 'added' : change.status === GitChangeType.DELETE ? 'deleted' : 'modified'}.`;
}
}),
lastUpdatedAt: pullRequest.updatedAt.toLocaleString()
};
const result = new vscode.ExtendedLanguageModelToolResult([new vscode.LanguageModelTextPart(JSON.stringify(pullRequestInfo))]);
result.toolResultDetails = [vscode.Uri.parse(pullRequest.html_url)];
return result;
}
}
export class ActivePullRequestTool extends PullRequestTool {
public static readonly toolId = 'github-pull-request_activePullRequest';
protected _findActivePullRequest(): PullRequestModel | undefined {
const folderManager = this.folderManagers.folderManagers.find((manager) => manager.activePullRequest);
return folderManager?.activePullRequest;
}
protected _confirmationTitle(): string {
return vscode.l10n.t('Active Pull Request');
}
}