Path: blob/main/extensions/copilot/src/extension/intents/vscode-node/fixTestFailureContributions.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 * as l10n from '@vscode/l10n';6import * as vscode from 'vscode';7import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';8import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';9import { ITestFailure, ITestProvider } from '../../../platform/testing/common/testProvider';10import { mapFindFirst } from '../../../util/vs/base/common/arraysFind';11import { Disposable, DisposableStore } from '../../../util/vs/base/common/lifecycle';12import { Intent } from '../../common/constants';13import { IExtensionContribution } from '../../common/contributions';141516export class FixTestFailureContribution extends Disposable implements IExtensionContribution {17constructor(18@ITestProvider testProvider: ITestProvider,19@ITelemetryService telemetryService: ITelemetryService,20@IConfigurationService configurationService: IConfigurationService,21) {22super();23const store = this._register(new DisposableStore());24registerTestMessageSparkles(store, telemetryService, testProvider);25registerTestFailureCodeAction(testProvider, configurationService, store);26}27}2829type FixCommandArgs = { message: vscode.TestMessage; test: vscode.TestItem | vscode.TestResultSnapshot; source?: 'sparkles' | 'testResultsPanel' | 'retry' };3031function registerTestMessageSparkles(store: DisposableStore, telemetryService: ITelemetryService, testProvider: ITestProvider) {32function getLastFailureForItemOrChildren(item: vscode.TestItem): ITestFailure | undefined {33const failure = testProvider.getLastFailureFor(item);34return failure || mapFindFirst(item.children, ([, item]) => getLastFailureForItemOrChildren(item));35}3637store.add(vscode.commands.registerCommand('github.copilot.tests.fixTestFailure.fromInline', (item: vscode.TestItem) => {38const failure = getLastFailureForItemOrChildren(item);39if (failure) {40openFixChat({41message: failure.task.messages[0],42test: failure.snapshot,43source: 'testResultsPanel',44});45}46}));4748store.add(vscode.commands.registerCommand('github.copilot.tests.fixTestFailure', openFixChat));4950async function openFixChat(args: FixCommandArgs) {51if (!args.test.uri) {52return; // should not happen based on context keys53}5455/* __GDPR__56"intent.fixTestFailure.actioned" : {57"owner": "connor4312",58"comment": "Reports when we show a ",59"source": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Where the action was taken" }60}61*/62telemetryService.sendMSFTTelemetryEvent('intent.fixTestFailure.actioned', {63source: args.source ?? 'testResultsPanel',64});6566const doc = await vscode.workspace.openTextDocument(args.test.uri);67await vscode.window.showTextDocument(doc, {68preserveFocus: false, // must transfer focus so editor chat starts at the right place69preview: true,70selection: args.test.range ? new vscode.Range(args.test.range.start, args.test.range.start) : undefined71});7273await vscode.commands.executeCommand('vscode.editorChat.start', {74message: `/${Intent.Fix} the #testFailure`,75autoSend: true,76});77}78}7980function registerTestFailureCodeAction(testProvider: ITestProvider, configurationService: IConfigurationService, store: DisposableStore) {81store.add(vscode.languages.registerCodeActionsProvider('*', {82provideCodeActions(document, range, context, token) {83const copilotCodeActionsEnabled = configurationService.getConfig(ConfigKey.EnableCodeActions);84if (!copilotCodeActionsEnabled) {85return;86}8788const test = testProvider.getFailureAtPosition(document.uri, range.start);89if (!test) {90return undefined;91}9293const ca = new vscode.CodeAction(l10n.t('Fix test failure'), vscode.CodeActionKind.QuickFix);94ca.isAI = true;95ca.command = {96title: l10n.t('Fix test failure'),97command: 'github.copilot.tests.fixTestFailure',98arguments: [{99message: test.task.messages[0],100test: test.snapshot,101source: 'sparkles',102} satisfies FixCommandArgs]103};104return [ca];105},106}));107}108109110111