Path: blob/main/extensions/copilot/src/extension/conversation/node/githubPullRequestProviders.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { Disposable } from 'vscode';6import * as l10n from '@vscode/l10n';7import { IExtensionsService } from '../../../platform/extensions/common/extensionsService';8import { ILogService } from '../../../platform/log/common/logService';9import { IReviewService } from '../../../platform/review/common/reviewService';10import { DisposableStore } from '../../../util/vs/base/common/lifecycle';11import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';12import { Extension, Uri } from '../../../vscodeTypes';13import { API, RepositoryDescription } from '../../githubPullRequest';14import { GitHubPullRequestTitleAndDescriptionGenerator } from '../../prompt/node/githubPullRequestTitleAndDescriptionGenerator';15import { GitHubPullRequestReviewerCommentsProvider } from '../../review/node/githubPullRequestReviewerCommentsProvider';16import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';1718export class GitHubPullRequestProviders implements Disposable {19private gitHubExtensionApi: API | undefined;20protected readonly disposables: DisposableStore = new DisposableStore();2122constructor(23@ILogService protected readonly logService: ILogService,24@IInstantiationService private readonly instantiationService: IInstantiationService,25@IReviewService private readonly reviewService: IReviewService,26@IExtensionsService private readonly extensionService: IExtensionsService,27@IConfigurationService private _configurationService: IConfigurationService,28) {29this.initializeGitHubPRExtensionApi();30}31dispose() {32this.disposables.dispose();33}3435private getExtension(): Extension<API> | undefined {36return this.extensionService.getExtension('github.vscode-pull-request-github');37}3839private initializeGitHubPRExtensionApi() {40let githubPRExtension = this.getExtension();4142const initialize = async () => {43if (githubPRExtension) {44const extension = await githubPRExtension!.activate();45this.logService.info('Successfully activated the GitHub.vscode-pull-request-github extension.');4647this.gitHubExtensionApi = extension;48this.registerTitleAndDescriptionProvider();49this.registerReviewerCommentsProvider();50}51};5253if (githubPRExtension) {54initialize();55} else {56this.logService.info('GitHub.vscode-pull-request-github extension is not yet activated.');5758const listener = this.extensionService.onDidChange(() => {59githubPRExtension = this.getExtension();60if (githubPRExtension) {61initialize();62listener.dispose();63}64});65this.disposables.add(listener);66}6768this.disposables.add(this._configurationService.onDidChangeConfiguration(e => {69if (e.affectsConfiguration(ConfigKey.ReviewAgent.fullyQualifiedId)) {70this.registerReviewerCommentsProvider();71}72}));73}7475private titleAndDescriptionProvider: GitHubPullRequestTitleAndDescriptionGenerator | undefined;76private async registerTitleAndDescriptionProvider() {77if (!this.gitHubExtensionApi) {78return;79}80try {81if (!this.titleAndDescriptionProvider) {82this.titleAndDescriptionProvider = this.disposables.add(this.instantiationService.createInstance(GitHubPullRequestTitleAndDescriptionGenerator));83}84// This string "Copilot" needs to be in here. It's how we an tell which provider to use in the PR extension.85this.disposables.add(this.gitHubExtensionApi.registerTitleAndDescriptionProvider(l10n.t('Generate with Copilot'), this.titleAndDescriptionProvider));86this.logService.info('Successfully registered GitHub PR title and description provider.');87} catch (e) {88// Catch errors in case there's a breaking API change.89}90}9192private reviewerCommentsProvider: GitHubPullRequestReviewerCommentsProvider | undefined;93private reviewerCommentsRegistration: Disposable | undefined;94private async registerReviewerCommentsProvider() {95if (!this.gitHubExtensionApi) {96return;97}9899if (!this.reviewService.isReviewDiffEnabled()) {100if (this.reviewerCommentsRegistration) {101this.disposables.delete(this.reviewerCommentsRegistration);102this.reviewerCommentsRegistration = undefined;103}104return;105}106107if (this.reviewerCommentsRegistration) {108return;109}110111try {112if (!this.reviewerCommentsProvider) {113this.reviewerCommentsProvider = this.instantiationService.createInstance(GitHubPullRequestReviewerCommentsProvider);114}115this.reviewerCommentsRegistration = this.gitHubExtensionApi.registerReviewerCommentsProvider(l10n.t('Copilot'), this.reviewerCommentsProvider);116this.disposables.add(this.reviewerCommentsRegistration);117this.logService.info('Successfully registered GitHub PR reviewer comments provider.');118} catch (e) {119// Catch errors in case there's a breaking API change.120}121}122123public async getRepositoryDescription(uri: Uri): Promise<RepositoryDescription | undefined> {124try {125// Wait for gitHubExtensionApi to be initialized if not already126if (!this.gitHubExtensionApi) {127// Try to get and activate the extension if possible128const githubPRExtension = this.getExtension();129if (githubPRExtension) {130const extension = await githubPRExtension.activate();131this.gitHubExtensionApi = extension;132} else {133this.logService.warn('GitHub.vscode-pull-request-github extension API is not available.');134return undefined;135}136}137138if (!this.gitHubExtensionApi.getRepositoryDescription) {139return undefined;140}141142return await this.gitHubExtensionApi.getRepositoryDescription(uri);143} catch (error) {144this.logService.error('Failed to get repository description from GitHub.vscode-pull-request-github extension.', error);145return undefined;146}147}148}149150151