Skip to content

Commit 92971a8

Browse files
osortegaalexr00
andauthored
API for repository description (#7066)
* API for repository description * Failing * Test updates * Review comments * Revert yarn.lock * Passing URI to API * Review comments * Only use folder manager for the file, api doc --------- Co-authored-by: Alex Ross <38270282+alexr00@users.noreply.github.com>
1 parent 215e0b6 commit 92971a8

8 files changed

Lines changed: 69 additions & 14 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3909,7 +3909,7 @@
39093909
],
39103910
"toolReferenceName": "activePullRequest",
39113911
"displayName": "%languageModelTools.github-pull-request_activePullRequest.displayName%",
3912-
"modelDescription": "Get information about the active or current GitHub pull request (PR). This information includes: comments, files changed, pull request title + description, pull request state, pull request status checks/CI and coding agent session logs if the pull request was opened by Copilot. When asked about the active or current pull request, do this first!",
3912+
"modelDescription": "Get comprehensive information about the active or current GitHub pull request (PR). This includes the PR title, full description, list of changed files, review comments, PR state, and status checks/CI results. For PRs created by Copilot, it also includes the session logs which indicate the development process and decisions made by the coding agent. When asked about the active or current pull request, do this first! Use this tool for any request related to \"current changes,\" \"pull request details,\" \"what changed,\" \"PR status,\" or similar queries even if the user does not explicitly mention \"pull request.\"",
39133913
"icon": "$(git-pull-request)",
39143914
"canBeReferencedInPrompt": true,
39153915
"userDescription": "%languageModelTools.github-pull-request_activePullRequest.description%",

src/api/api.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,18 @@ export interface ReviewerCommentsProvider {
257257
provideReviewerComments(context: { repositoryRoot: string, commitMessages: string[], patches: { patch: string, fileUri: string, previousFileUri?: string }[] }, token: CancellationToken): Promise<ReviewerComments>;
258258
}
259259

260+
export interface RepositoryDescription {
261+
owner: string;
262+
repositoryName: string;
263+
defaultBranch: string;
264+
pullRequest?: {
265+
title: string;
266+
url: string;
267+
number: number;
268+
id: number;
269+
};
270+
}
271+
260272
export interface API {
261273
/**
262274
* Register a [git provider](#IGit)
@@ -280,4 +292,13 @@ export interface API {
280292
* Register a PR reviewer comments provider.
281293
*/
282294
registerReviewerCommentsProvider(title: string, provider: ReviewerCommentsProvider): Disposable;
295+
296+
/**
297+
* Get the repository description for a given URI, where the URI is a subpath of one of the workspace folders.
298+
* This includes the owner, repository name, default branch,
299+
* and pull request information (if applicable).
300+
*
301+
* @returns A promise that resolves to a `RepositoryDescription` object or `undefined` if no repository is found.
302+
*/
303+
getRepositoryDescription(uri: vscode.Uri): Promise<RepositoryDescription | undefined>;
283304
}

src/api/api1.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { APIState, PublishEvent } from '../@types/git';
88
import { Disposable } from '../common/lifecycle';
99
import Logger from '../common/logger';
1010
import { TernarySearchTree } from '../common/utils';
11+
import { RepositoriesManager } from '../github/repositoriesManager';
1112
import { API, IGit, PostCommitCommandsProvider, Repository, ReviewerCommentsProvider, TitleAndDescriptionProvider } from './api';
1213

1314
export const enum RefType {
@@ -78,6 +79,11 @@ export class GitApiImpl extends Disposable implements API, IGit {
7879
private static _handlePool: number = 0;
7980
private _providers = new Map<number, IGit>();
8081

82+
public constructor(
83+
private readonly repositoriesManager: RepositoriesManager) {
84+
super();
85+
}
86+
8187
public get repositories(): Repository[] {
8288
const ret: Repository[] = [];
8389

@@ -220,4 +226,26 @@ export class GitApiImpl extends Disposable implements API, IGit {
220226
getReviewerCommentsProvider(): { title: string, provider: ReviewerCommentsProvider } | undefined {
221227
return this._reviewerCommentsProviders.size > 0 ? this._reviewerCommentsProviders.values().next().value : undefined;
222228
}
229+
230+
async getRepositoryDescription(uri: vscode.Uri) {
231+
const folderManagerForRepo = this.repositoriesManager.getManagerForFile(uri);
232+
233+
if (folderManagerForRepo && folderManagerForRepo.gitHubRepositories.length > 0) {
234+
const repositoryMetadata = await folderManagerForRepo.gitHubRepositories[0].getMetadata();
235+
const pullRequest = folderManagerForRepo.activePullRequest;
236+
if (repositoryMetadata) {
237+
return {
238+
owner: repositoryMetadata.owner.login,
239+
repositoryName: repositoryMetadata.name,
240+
defaultBranch: repositoryMetadata.default_branch,
241+
pullRequest: pullRequest ? {
242+
title: pullRequest.title,
243+
url: pullRequest.html_url,
244+
number: pullRequest.number,
245+
id: pullRequest.id
246+
} : undefined
247+
};
248+
}
249+
}
250+
}
223251
}

src/extension.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,14 +287,11 @@ export async function activate(context: vscode.ExtensionContext): Promise<GitApi
287287
// initialize resources
288288
Resource.initialize(context);
289289
Logger.debug('Creating API implementation.', 'Activation');
290-
const apiImpl = new GitApiImpl();
291290

292291
telemetry = new ExperimentationTelemetry(new TelemetryReporter(ingestionKey));
293292
context.subscriptions.push(telemetry);
294293

295-
await deferredActivate(context, apiImpl, showPRController);
296-
297-
return apiImpl;
294+
return await deferredActivate(context, showPRController);
298295
}
299296

300297
async function setGitSettingContexts(context: vscode.ExtensionContext) {
@@ -378,7 +375,7 @@ async function deferredActivateRegisterBuiltInGitProvider(context: vscode.Extens
378375
}
379376
}
380377

381-
async function deferredActivate(context: vscode.ExtensionContext, apiImpl: GitApiImpl, showPRController: ShowPullRequest) {
378+
async function deferredActivate(context: vscode.ExtensionContext, showPRController: ShowPullRequest) {
382379
Logger.debug('Initializing state.', 'Activation');
383380
PersistentState.init(context);
384381
await migrate(context);
@@ -392,6 +389,12 @@ async function deferredActivate(context: vscode.ExtensionContext, apiImpl: GitAp
392389
const showBadge = (vscode.env.appHost === 'desktop');
393390
await credentialStore.create(showBadge ? undefined : { silent: true });
394391

392+
const reposManager = new RepositoriesManager(credentialStore, telemetry);
393+
context.subscriptions.push(reposManager);
394+
// API
395+
const apiImpl = new GitApiImpl(reposManager);
396+
context.subscriptions.push(apiImpl);
397+
395398
deferredActivateRegisterBuiltInGitProvider(context, apiImpl, credentialStore);
396399

397400
Logger.debug('Registering live share git provider.', 'Activation');
@@ -402,8 +405,6 @@ async function deferredActivate(context: vscode.ExtensionContext, apiImpl: GitAp
402405
context.subscriptions.push(apiImpl);
403406

404407
Logger.debug('Creating tree view.', 'Activation');
405-
const reposManager = new RepositoriesManager(credentialStore, telemetry);
406-
context.subscriptions.push(reposManager);
407408

408409
const copilotRemoteAgentManager = new CopilotRemoteAgentManager(credentialStore, reposManager);
409410
context.subscriptions.push(copilotRemoteAgentManager);
@@ -432,6 +433,7 @@ async function deferredActivate(context: vscode.ExtensionContext, apiImpl: GitAp
432433
context.subscriptions.push(vscode.workspace.registerFileSystemProvider(Schemes.Pr, inMemPRFileSystemProvider, { isReadonly: readOnlyMessage }));
433434

434435
await init(context, apiImpl, credentialStore, repositories, prTree, liveshareApiPromise, showPRController, reposManager, createPrHelper, copilotRemoteAgentManager);
436+
return apiImpl;
435437
}
436438

437439
export async function deactivate() {

src/test/github/folderRepositoryManager.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { MockExtensionContext } from '../mocks/mockExtensionContext';
2222
import { Uri } from 'vscode';
2323
import { GitHubServerType } from '../../common/authentication';
2424
import { CreatePullRequestHelper } from '../../view/createPullRequestHelper';
25+
import { RepositoriesManager } from '../../github/repositoriesManager';
2526

2627
describe('PullRequestManager', function () {
2728
let sinon: SinonSandbox;
@@ -36,7 +37,8 @@ describe('PullRequestManager', function () {
3637
const repository = new MockRepository();
3738
const context = new MockExtensionContext();
3839
const credentialStore = new CredentialStore(telemetry, context);
39-
manager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(), credentialStore, new CreatePullRequestHelper());
40+
const repositoriesManager = new RepositoriesManager(credentialStore, telemetry);
41+
manager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(repositoriesManager), credentialStore, new CreatePullRequestHelper());
4042
});
4143

4244
afterEach(function () {

src/test/github/pullRequestOverview.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { GitHubServerType } from '../../common/authentication';
2424
import { GitHubRemote } from '../../common/remote';
2525
import { CheckState } from '../../github/interface';
2626
import { CreatePullRequestHelper } from '../../view/createPullRequestHelper';
27+
import { RepositoriesManager } from '../../github/repositoriesManager';
2728

2829
const EXTENSION_URI = vscode.Uri.joinPath(vscode.Uri.file(__dirname), '../../..');
2930

@@ -45,7 +46,8 @@ describe('PullRequestOverview', function () {
4546
telemetry = new MockTelemetry();
4647
credentialStore = new CredentialStore(telemetry, context);
4748
const createPrHelper = new CreatePullRequestHelper();
48-
pullRequestManager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(), credentialStore, createPrHelper);
49+
const repositoriesManager = new RepositoriesManager(credentialStore, telemetry);
50+
pullRequestManager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(repositoriesManager), credentialStore, createPrHelper);
4951

5052
const url = 'https://github.com/aaa/bbb';
5153
remote = new GitHubRemote('origin', url, new Protocol(url), GitHubServerType.GitHubDotCom);

src/test/view/prsTree.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('GitHub Pull Requests view', function () {
103103
it('has no children when repositories have not yet been initialized', async function () {
104104
const repository = new MockRepository();
105105
repository.addRemote('origin', 'git@github.com:aaa/bbb');
106-
reposManager.insertFolderManager(new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(), credentialStore, createPrHelper));
106+
reposManager.insertFolderManager(new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(reposManager), credentialStore, createPrHelper));
107107
provider.initialize([], credentialStore);
108108

109109
const rootNodes = await provider.getChildren();
@@ -113,7 +113,7 @@ describe('GitHub Pull Requests view', function () {
113113
it('opens the viewlet and displays the default categories', async function () {
114114
const repository = new MockRepository();
115115
repository.addRemote('origin', 'git@github.com:aaa/bbb');
116-
reposManager.insertFolderManager(new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(), credentialStore, createPrHelper));
116+
reposManager.insertFolderManager(new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(reposManager), credentialStore, createPrHelper));
117117
sinon.stub(credentialStore, 'isAuthenticated').returns(true);
118118
await reposManager.folderManagers[0].updateRepositories();
119119
provider.initialize([], credentialStore);
@@ -183,7 +183,7 @@ describe('GitHub Pull Requests view', function () {
183183

184184
await repository.createBranch('non-pr-branch', false);
185185

186-
const manager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(), credentialStore, createPrHelper);
186+
const manager = new FolderRepositoryManager(0, context, repository, telemetry, new GitApiImpl(reposManager), credentialStore, createPrHelper);
187187
reposManager.insertFolderManager(manager);
188188
sinon.stub(manager, 'createGitHubRepository').callsFake((r, cs) => {
189189
assert.deepStrictEqual(r, remote);

src/test/view/reviewCommentController.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('ReviewCommentController', function () {
8080
const activePrViewCoordinator = new WebviewViewCoordinator(context);
8181
const createPrHelper = new CreatePullRequestHelper();
8282
Resource.initialize(context);
83-
gitApiImpl = new GitApiImpl();
83+
gitApiImpl = new GitApiImpl(reposManager);
8484
manager = new FolderRepositoryManager(0, context, repository, telemetry, gitApiImpl, credentialStore, createPrHelper);
8585
reposManager.insertFolderManager(manager);
8686
const tree = new PullRequestChangesTreeDataProvider(gitApiImpl, reposManager);

0 commit comments

Comments
 (0)