Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions src/@types/vscode.proposed.chatParticipantAdditions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,19 +573,14 @@ declare module 'vscode' {
}

/**
* Represents an auto-mode model routing resolution. Displayed as a collapsible
* widget in the chat stream showing which model was selected and why.
* Explains what the "Auto" model routed a turn to, as a single status line.
* Push a part without a model for the in-flight state, then a resolved one.
* Auto may route several times in a turn; each route gets its own row.
*/
export class ChatResponseAutoModeResolutionPart {
/** The model ID that was selected by the router */
resolvedModel: string;
/** The user-facing display name of the resolved model */
resolvedModelName: string;
/** The router's classification label */
predictedLabel: string;
/** Confidence score (0-1) from the router */
confidence: number;
constructor(resolvedModel: string, resolvedModelName: string, predictedLabel: string, confidence: number);
/** The model the router picked, or `undefined` while routing is in flight. */
resolvedModel: { id: string; name: string } | undefined;
constructor(resolvedModel?: { id: string; name: string });
}

export interface ChatResponseStream {
Expand Down
15 changes: 7 additions & 8 deletions src/github/activityBarViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { IComment } from '../common/comment';
import { emojify, ensureEmojis } from '../common/emoji';
import { disposeAll } from '../common/lifecycle';
import Logger from '../common/logger';
import { CHECKOUT_DEFAULT_BRANCH, CHECKOUT_PULL_REQUEST_BASE_BRANCH, DELETE_BRANCH_AFTER_MERGE, POST_DONE, PR_SETTINGS_NAMESPACE } from '../common/settingKeys';
import { CHECKOUT_DEFAULT_BRANCH, CHECKOUT_PULL_REQUEST_BASE_BRANCH, POST_DONE, PR_SETTINGS_NAMESPACE } from '../common/settingKeys';
import { ReviewEvent, TimelineEvent } from '../common/timelineEvent';
import { formatError } from '../common/utils';
import { generateUuid } from '../common/uuid';
Expand Down Expand Up @@ -486,18 +486,17 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W

if (!result.merged) {
vscode.window.showErrorMessage(vscode.l10n.t('Merging pull request failed: {0}', result?.message ?? ''));
} else {
// Check if auto-delete branch setting is enabled
const deleteBranchAfterMerge = vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<boolean>(DELETE_BRANCH_AFTER_MERGE, false);
if (deleteBranchAfterMerge) {
// Automatically delete the branch after successful merge
await PullRequestReviewCommon.autoDeleteBranchesAfterMerge(this._folderRepositoryManager, this._item);
}
}

this._replyMessage(message, {
state: result.merged ? GithubItemStateEnum.Merged : GithubItemStateEnum.Open,
});
if (result.merged) {
const branchDeletionMessage = await PullRequestReviewCommon.handleBranchDeletionAfterMerge(this._folderRepositoryManager, this._item);
if (branchDeletionMessage) {
this._postMessage(branchDeletionMessage);
}
}

} catch (e) {
vscode.window.showErrorMessage(vscode.l10n.t('Unable to merge pull request. {0}', formatError(e)));
Expand Down
14 changes: 7 additions & 7 deletions src/github/pullRequestOverview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -857,13 +857,6 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel<PullRequestMode

if (!result.merged) {
vscode.window.showErrorMessage(`Merging pull request failed: ${result.message}`);
} else {
// Check if auto-delete branch setting is enabled
const deleteBranchAfterMerge = vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<boolean>(DELETE_BRANCH_AFTER_MERGE, false);
if (deleteBranchAfterMerge) {
// Automatically delete the branch after successful merge
await PullRequestReviewCommon.autoDeleteBranchesAfterMerge(this._folderRepositoryManager, this._item);
}
}

const mergeResult: MergeResult = {
Expand All @@ -872,6 +865,13 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel<PullRequestMode
events: result.timeline
};
this._replyMessage(message, mergeResult);
if (result.merged) {
const branchDeletionMessage = await PullRequestReviewCommon.handleBranchDeletionAfterMerge(this._folderRepositoryManager, this._item);
if (branchDeletionMessage) {
this.refreshPanel();
this._postMessage(branchDeletionMessage);
}
}
} catch (e) {
vscode.window.showErrorMessage(`Unable to merge pull request. ${formatError(e)}`);
this._throwError(message, '');
Expand Down
17 changes: 16 additions & 1 deletion src/github/pullRequestReviewCommon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { IAccount, isITeam, ITeam, MergeMethod, PullRequestMergeability, reviewe
import { BranchInfo } from './pullRequestGitHelper';
import { PullRequestModel } from './pullRequestModel';
import { ConvertToDraftReply, PullRequest, ReadyForReviewReply, ReviewType, SubmitReviewReply } from './views';
import { DEFAULT_DELETION_METHOD, PR_SETTINGS_NAMESPACE, SELECT_LOCAL_BRANCH, SELECT_REMOTE, SELECT_WORKTREE } from '../common/settingKeys';
import Logger from '../common/logger';
import { DEFAULT_DELETION_METHOD, DELETE_BRANCH_AFTER_MERGE, PR_SETTINGS_NAMESPACE, SELECT_LOCAL_BRANCH, SELECT_REMOTE, SELECT_WORKTREE } from '../common/settingKeys';
import { ReviewEvent, TimelineEvent } from '../common/timelineEvent';
import { Schemes } from '../common/uri';
import { formatError } from '../common/utils';
Expand Down Expand Up @@ -406,6 +407,20 @@ export namespace PullRequestReviewCommon {
}
}

export async function handleBranchDeletionAfterMerge(folderRepositoryManager: FolderRepositoryManager, item: PullRequestModel): Promise<{ command: string, branchTypes: string[] } | undefined> {
try {
const deleteBranchAfterMerge = vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<boolean>(DELETE_BRANCH_AFTER_MERGE, false);
if (deleteBranchAfterMerge) {
await autoDeleteBranchesAfterMerge(folderRepositoryManager, item);
} else if ((await item.githubRepository.getMetadata()).delete_branch_on_merge) {
const result = await deleteBranch(folderRepositoryManager, item);
return result.isReply ? undefined : result.message;
}
} catch (e) {
Logger.error(`Branch cleanup after merge failed: ${formatError(e)}`, 'PullRequestReviewCommon');
}
}
Comment thread
alexr00 marked this conversation as resolved.

async function performBranchDeletion(folderRepositoryManager: FolderRepositoryManager, item: PullRequestModel, defaultBranch: string, branchInfo: BranchInfo, selectedActions: SelectedAction[]): Promise<string[]> {
const isBranchActive = item.equals(folderRepositoryManager.activePullRequest) || (folderRepositoryManager.repository.state.HEAD?.name && folderRepositoryManager.repository.state.HEAD.name === branchInfo?.branch);
const deletedBranchTypes: string[] = [];
Expand Down
41 changes: 40 additions & 1 deletion src/test/github/pullRequestOverview.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { GitApiImpl } from '../../api/api1';
import { CredentialStore } from '../../github/credentials';
import { GitHubServerType } from '../../common/authentication';
import { GitHubRemote } from '../../common/remote';
import { CheckState } from '../../github/interface';
import { CheckState, GithubItemStateEnum } from '../../github/interface';
import { CreatePullRequestHelper } from '../../view/createPullRequestHelper';
import { RepositoriesManager } from '../../github/repositoriesManager';
import { MockThemeWatcher } from '../mocks/mockThemeWatcher';
Expand Down Expand Up @@ -189,4 +189,43 @@ describe('PullRequestOverview', function () {
assert.strictEqual(panel1!.getCurrentTitle(), '#2000 New feature');
});
});

describe('mergePullRequest', function () {
it('prompts to delete the local branch when GitHub deletes branches after merge', async function () {
repo.buildMetadata(repository => repository.delete_branch_on_merge!(true));
repo.addGraphQLPullRequest(builder => {
builder.pullRequest(response => {
response.repository(r => {
r.pullRequest(pr => pr.number(1000));
});
});
});

const prItem = convertRESTPullRequestToRawPullRequest(new PullRequestBuilder().number(1000).build(), repo);
const prModel = new PullRequestModel(credentialStore, telemetry, repo, remote, prItem);
const identity = { owner: prModel.remote.owner, repo: prModel.remote.repositoryName, number: prModel.number };
await PullRequestOverviewPanel.createOrShow(telemetry, EXTENSION_URI, pullRequestManager, identity, prModel);

const panel = PullRequestOverviewPanel.findPanel(identity.owner, identity.repo, identity.number)!;
sinon.stub(prModel, 'merge').resolves({ merged: true, message: '', timeline: [] });
sinon.stub(pullRequestManager, 'getBranchNameForPullRequest').resolves({
branch: 'new-feature',
createdForPullRequest: false,
});
sinon.stub(pullRequestManager, 'getPullRequestRepositoryDefaultBranch').resolves('main');
const showQuickPick = sinon.stub(vscode.window, 'showQuickPick').resolves(undefined);
const replyMessage = sinon.stub(panel as any, '_replyMessage');

await (panel as any).mergePullRequest({
command: 'pr.merge',
args: { title: '', description: '', method: 'squash' },
});

assert.strictEqual(showQuickPick.calledOnce, true);
const actions = showQuickPick.firstCall.args[0] as readonly (vscode.QuickPickItem & { type: string })[];
assert.strictEqual(actions.some(action => action.type === 'local'), true);
assert.strictEqual(replyMessage.firstCall.args[1].state, GithubItemStateEnum.Merged);
sinon.assert.callOrder(replyMessage, showQuickPick);
});
});
});