Skip to content

Commit 645d843

Browse files
committed
Allow users to force refresh
per standup discussion, we should also allow the user to force a refresh Part of #7916
1 parent 6b4533b commit 645d843

8 files changed

Lines changed: 150 additions & 162 deletions

src/commands.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,6 @@ export function registerCommands(
427427
"pr.deleteLocalPullRequest.success" : {}
428428
*/
429429
telemetry.sendTelemetryEvent('pr.deleteLocalPullRequest.success');
430-
// fire and forget
431-
vscode.commands.executeCommand('pr.refreshList');
432430
}
433431
}),
434432
);
@@ -864,7 +862,7 @@ export function registerCommands(
864862
let newPR;
865863
if (value === yes) {
866864
try {
867-
newPR = await folderManager.mergePullRequest(pullRequest);
865+
newPR = await pullRequest.merge(folderManager.repository);
868866
return newPR;
869867
} catch (e) {
870868
vscode.window.showErrorMessage(`Unable to merge pull request. ${formatError(e)}`);

src/github/activityBarViewProvider.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
3232
) {
3333
super(extensionUri);
3434

35-
this._register(this._folderRepositoryManager.onDidMergePullRequest(_ => {
36-
this._postMessage({
37-
command: 'update-state',
38-
state: GithubItemStateEnum.Merged,
39-
});
40-
}));
41-
4235
this._register(vscode.commands.registerCommand('review.approve', (e: { body: string }) => this.approvePullRequestCommand(e)));
4336
this._register(vscode.commands.registerCommand('review.comment', (e: { body: string }) => this.submitReviewCommand(e)));
4437
this._register(vscode.commands.registerCommand('review.requestChanges', (e: { body: string }) => this.requestChangesCommand(e)));
@@ -466,24 +459,21 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
466459
this._replyMessage(message, { state: GithubItemStateEnum.Open });
467460
return;
468461
}
462+
try {
463+
const result = await this._item.merge(this._folderRepositoryManager.repository, title, description, method, email);
469464

470-
this._folderRepositoryManager
471-
.mergePullRequest(this._item, title, description, method, email)
472-
.then(result => {
473-
vscode.commands.executeCommand('pr.refreshList');
474-
475-
if (!result.merged) {
476-
vscode.window.showErrorMessage(vscode.l10n.t('Merging pull request failed: {0}', result?.message ?? ''));
477-
}
465+
if (!result.merged) {
466+
vscode.window.showErrorMessage(vscode.l10n.t('Merging pull request failed: {0}', result?.message ?? ''));
467+
}
478468

479-
this._replyMessage(message, {
480-
state: result.merged ? GithubItemStateEnum.Merged : GithubItemStateEnum.Open,
481-
});
482-
})
483-
.catch(e => {
484-
vscode.window.showErrorMessage(vscode.l10n.t('Unable to merge pull request. {0}', formatError(e)));
485-
this._throwError(message, '');
469+
this._replyMessage(message, {
470+
state: result.merged ? GithubItemStateEnum.Merged : GithubItemStateEnum.Open,
486471
});
472+
473+
} catch (e) {
474+
vscode.window.showErrorMessage(vscode.l10n.t('Unable to merge pull request. {0}', formatError(e)));
475+
this._throwError(message, '');
476+
}
487477
}
488478

489479
private _getHtmlForWebview() {

src/github/folderRepositoryManager.ts

Lines changed: 3 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { GitHubRemote, parseRemote, parseRepositoryRemotes, Remote } from '../co
2020
import {
2121
ALLOW_FETCH,
2222
AUTO_STASH,
23-
DEFAULT_MERGE_METHOD,
2423
GIT,
2524
POST_DONE,
2625
PR_SETTINGS_NAMESPACE,
@@ -30,7 +29,7 @@ import {
3029
UPSTREAM_REMOTE,
3130
} from '../common/settingKeys';
3231
import { ITelemetry } from '../common/telemetry';
33-
import { EventType, TimelineEvent } from '../common/timelineEvent';
32+
import { EventType } from '../common/timelineEvent';
3433
import { Schemes } from '../common/uri';
3534
import { batchPromiseAll, compareIgnoreCase, formatError, Predicate } from '../common/utils';
3635
import { PULL_REQUEST_OVERVIEW_VIEW_TYPE } from '../common/webview';
@@ -43,8 +42,8 @@ import { ConflictModel } from './conflictGuide';
4342
import { ConflictResolutionCoordinator } from './conflictResolutionCoordinator';
4443
import { Conflict, ConflictResolutionModel } from './conflictResolutionModel';
4544
import { CredentialStore } from './credentials';
46-
import { CopilotWorkingStatus, GitHubRepository, GraphQLError, GraphQLErrorType, ItemsData, PULL_REQUEST_PAGE_SIZE, PullRequestChangeEvent, PullRequestData, TeamReviewerRefreshKind, ViewerPermission } from './githubRepository';
47-
import { MergeMethod as GraphQLMergeMethod, MergePullRequestInput, MergePullRequestResponse, PullRequestResponse, PullRequestState } from './graphql';
45+
import { CopilotWorkingStatus, GitHubRepository, ItemsData, PULL_REQUEST_PAGE_SIZE, PullRequestChangeEvent, PullRequestData, TeamReviewerRefreshKind, ViewerPermission } from './githubRepository';
46+
import { PullRequestResponse, PullRequestState } from './graphql';
4847
import { IAccount, ILabel, IMilestone, IProject, IPullRequestsPagingOptions, Issue, ITeam, MergeMethod, PRType, PullRequestMergeability, RepoAccessAndMergeMethods, User } from './interface';
4948
import { IssueModel } from './issueModel';
5049
import { PullRequestGitHelper, PullRequestMetadata } from './pullRequestGitHelper';
@@ -55,7 +54,6 @@ import {
5554
getOverrideBranch,
5655
getPRFetchQuery,
5756
loginComparator,
58-
parseCombinedTimelineEvents,
5957
parseGraphQLPullRequest,
6058
teamComparator,
6159
variableSubstitution,
@@ -195,9 +193,6 @@ export class FolderRepositoryManager extends Disposable {
195193
private _repositoryPageInformation: Map<string, PageInformation> = new Map<string, PageInformation>();
196194
private _addedUpstreamCount: number = 0;
197195

198-
private _onDidMergePullRequest = this._register(new vscode.EventEmitter<void>());
199-
readonly onDidMergePullRequest = this._onDidMergePullRequest.event;
200-
201196
private _onDidChangeActivePullRequest = this._register(new vscode.EventEmitter<{ new: PullRequestModel | undefined, old: PullRequestModel | undefined }>());
202197
readonly onDidChangeActivePullRequest: vscode.Event<{ new: PullRequestModel | undefined, old: PullRequestModel | undefined }> = this._onDidChangeActivePullRequest.event;
203198
private _onDidChangeActiveIssue = this._register(new vscode.EventEmitter<void>());
@@ -1681,101 +1676,6 @@ export class FolderRepositoryManager extends Disposable {
16811676
return this._credentialStore.getCurrentUser(githubRepository.remote.authProviderId);
16821677
}
16831678

1684-
async mergePullRequest(
1685-
pullRequest: PullRequestModel,
1686-
title?: string,
1687-
description?: string,
1688-
method?: 'merge' | 'squash' | 'rebase',
1689-
email?: string,
1690-
): Promise<{ merged: boolean, message: string, timeline?: TimelineEvent[] }> {
1691-
Logger.debug(`Merging PR: ${pullRequest.number} method: ${method} for user: "${email}" - enter`, this.id);
1692-
const { mutate, schema } = await pullRequest.githubRepository.ensure();
1693-
1694-
const activePRSHA = this.activePullRequest && this.activePullRequest.head && this.activePullRequest.head.sha;
1695-
const workingDirectorySHA = this.repository.state.HEAD && this.repository.state.HEAD.commit;
1696-
const mergingPRSHA = pullRequest.head && pullRequest.head.sha;
1697-
const workingDirectoryIsDirty = this.repository.state.workingTreeChanges.length > 0;
1698-
let expectedHeadOid: string | undefined = pullRequest.head?.sha;
1699-
1700-
if (activePRSHA === mergingPRSHA) {
1701-
// We're on the branch of the pr being merged.
1702-
expectedHeadOid = workingDirectorySHA;
1703-
if (workingDirectorySHA !== mergingPRSHA) {
1704-
// We are looking at different commit than what will be merged
1705-
const { ahead } = this.repository.state.HEAD!;
1706-
const pluralMessage = vscode.l10n.t('You have {0} unpushed commits on this pull request branch.\n\nWould you like to proceed anyway?', ahead ?? 'unknown');
1707-
const singularMessage = vscode.l10n.t('You have 1 unpushed commit on this pull request branch.\n\nWould you like to proceed anyway?');
1708-
if (ahead &&
1709-
(await vscode.window.showWarningMessage(
1710-
ahead > 1 ? pluralMessage : singularMessage,
1711-
{ modal: true },
1712-
vscode.l10n.t('Yes'),
1713-
)) === undefined) {
1714-
1715-
return {
1716-
merged: false,
1717-
message: vscode.l10n.t('unpushed changes'),
1718-
};
1719-
}
1720-
}
1721-
1722-
if (workingDirectoryIsDirty) {
1723-
// We have made changes to the PR that are not committed
1724-
if (
1725-
(await vscode.window.showWarningMessage(
1726-
vscode.l10n.t('You have uncommitted changes on this pull request branch.\n\n Would you like to proceed anyway?'),
1727-
{ modal: true },
1728-
vscode.l10n.t('Yes'),
1729-
)) === undefined
1730-
) {
1731-
return {
1732-
merged: false,
1733-
message: vscode.l10n.t('uncommitted changes'),
1734-
};
1735-
}
1736-
}
1737-
}
1738-
const input: MergePullRequestInput = {
1739-
pullRequestId: pullRequest.graphNodeId,
1740-
commitHeadline: title,
1741-
commitBody: description,
1742-
expectedHeadOid,
1743-
authorEmail: email,
1744-
mergeMethod:
1745-
(method?.toUpperCase() ??
1746-
vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<'merge' | 'squash' | 'rebase'>(DEFAULT_MERGE_METHOD, 'merge')?.toUpperCase()) as GraphQLMergeMethod,
1747-
};
1748-
1749-
return mutate<MergePullRequestResponse>({
1750-
mutation: schema.MergePullRequest,
1751-
variables: {
1752-
input
1753-
}
1754-
})
1755-
.then(async (result) => {
1756-
Logger.debug(`Merging PR: ${pullRequest.number}} - done`, this.id);
1757-
1758-
/* __GDPR__
1759-
"pr.merge.success" : {}
1760-
*/
1761-
this.telemetry.sendTelemetryEvent('pr.merge.success');
1762-
this._onDidMergePullRequest.fire();
1763-
return { merged: true, message: '', timeline: await parseCombinedTimelineEvents(result.data?.mergePullRequest.pullRequest.timelineItems.nodes ?? [], await pullRequest.getCopilotTimelineEvents(pullRequest), pullRequest.githubRepository) };
1764-
})
1765-
.catch(e => {
1766-
/* __GDPR__
1767-
"pr.merge.failure" : {}
1768-
*/
1769-
this.telemetry.sendTelemetryErrorEvent('pr.merge.failure');
1770-
const graphQLErrors = e.graphQLErrors as GraphQLError[] | undefined;
1771-
if (graphQLErrors?.length && graphQLErrors.find(error => error.type === GraphQLErrorType.Unprocessable && error.message?.includes('Head branch was modified'))) {
1772-
return { merged: false, message: vscode.l10n.t('Head branch was modified. Pull, review, then try again.') };
1773-
} else {
1774-
throw e;
1775-
}
1776-
});
1777-
}
1778-
17791679
async deleteBranch(pullRequest: PullRequestModel) {
17801680
await pullRequest.githubRepository.deleteBranch(pullRequest);
17811681
}

src/github/pullRequestModel.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { GitChangeType, InMemFileChange, SlimFileChange } from '../common/file';
1616
import { GitHubRef } from '../common/githubRef';
1717
import Logger from '../common/logger';
1818
import { Remote } from '../common/remote';
19+
import { DEFAULT_MERGE_METHOD, PR_SETTINGS_NAMESPACE } from '../common/settingKeys';
1920
import { ITelemetry } from '../common/telemetry';
2021
import { ClosedEvent, EventType, ReviewEvent, TimelineEvent } from '../common/timelineEvent';
2122
import { resolvePath, Schemes, toGitHubCommitUri, toPRUri, toReviewUri } from '../common/uri';
@@ -25,7 +26,7 @@ import { OctokitCommon } from './common';
2526
import { ConflictResolutionModel } from './conflictResolutionModel';
2627
import { CredentialStore } from './credentials';
2728
import { FolderRepositoryManager } from './folderRepositoryManager';
28-
import { GitHubRepository } from './githubRepository';
29+
import { GitHubRepository, GraphQLError, GraphQLErrorType } from './githubRepository';
2930
import {
3031
AddCommentResponse,
3132
AddReactionResponse,
@@ -37,8 +38,11 @@ import {
3738
EnqueuePullRequestResponse,
3839
FileContentResponse,
3940
GetReviewRequestsResponse,
41+
MergeMethod as GraphQLMergeMethod,
4042
LatestReviewCommitResponse,
4143
MarkPullRequestReadyForReviewResponse,
44+
MergePullRequestInput,
45+
MergePullRequestResponse,
4246
PendingReviewIdResponse,
4347
PullRequestCommentsResponse,
4448
PullRequestFilesResponse,
@@ -374,6 +378,100 @@ export class PullRequestModel extends IssueModel<PullRequest> implements IPullRe
374378
return action;
375379
}
376380

381+
async merge(
382+
repository: Repository,
383+
title?: string,
384+
description?: string,
385+
method?: 'merge' | 'squash' | 'rebase',
386+
email?: string
387+
): Promise<{ merged: boolean, message: string, timeline?: TimelineEvent[] }> {
388+
Logger.debug(`Merging PR: ${this.number} method: ${method} for user: "${email}" - enter`, PullRequestModel.ID);
389+
const { mutate, schema } = await this.githubRepository.ensure();
390+
391+
const workingDirectorySHA = repository.state.HEAD?.commit;
392+
const mergingPRSHA = this.head?.sha;
393+
const workingDirectoryIsDirty = repository.state.workingTreeChanges.length > 0;
394+
let expectedHeadOid: string | undefined = this.head?.sha;
395+
396+
if (this.isActive) {
397+
// We're on the branch of the pr being merged.
398+
expectedHeadOid = workingDirectorySHA;
399+
if (workingDirectorySHA !== mergingPRSHA) {
400+
// We are looking at different commit than what will be merged
401+
const { ahead } = repository.state.HEAD!;
402+
const pluralMessage = vscode.l10n.t('You have {0} unpushed commits on this pull request branch.\n\nWould you like to proceed anyway?', ahead ?? 'unknown');
403+
const singularMessage = vscode.l10n.t('You have 1 unpushed commit on this pull request branch.\n\nWould you like to proceed anyway?');
404+
if (ahead &&
405+
(await vscode.window.showWarningMessage(
406+
ahead > 1 ? pluralMessage : singularMessage,
407+
{ modal: true },
408+
vscode.l10n.t('Yes'),
409+
)) === undefined) {
410+
411+
return {
412+
merged: false,
413+
message: vscode.l10n.t('unpushed changes'),
414+
};
415+
}
416+
}
417+
418+
if (workingDirectoryIsDirty) {
419+
// We have made changes to the PR that are not committed
420+
if (
421+
(await vscode.window.showWarningMessage(
422+
vscode.l10n.t('You have uncommitted changes on this pull request branch.\n\n Would you like to proceed anyway?'),
423+
{ modal: true },
424+
vscode.l10n.t('Yes'),
425+
)) === undefined
426+
) {
427+
return {
428+
merged: false,
429+
message: vscode.l10n.t('uncommitted changes'),
430+
};
431+
}
432+
}
433+
}
434+
const input: MergePullRequestInput = {
435+
pullRequestId: this.graphNodeId,
436+
commitHeadline: title,
437+
commitBody: description,
438+
expectedHeadOid,
439+
authorEmail: email,
440+
mergeMethod:
441+
(method?.toUpperCase() ??
442+
vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE).get<'merge' | 'squash' | 'rebase'>(DEFAULT_MERGE_METHOD, 'merge')?.toUpperCase()) as GraphQLMergeMethod,
443+
};
444+
445+
return mutate<MergePullRequestResponse>({
446+
mutation: schema.MergePullRequest,
447+
variables: {
448+
input
449+
}
450+
})
451+
.then(async (result) => {
452+
Logger.debug(`Merging PR: ${this.number} - done`, PullRequestModel.ID);
453+
454+
/* __GDPR__
455+
"pr.merge.success" : {}
456+
*/
457+
this._telemetry.sendTelemetryEvent('pr.merge.success');
458+
this._onDidChange.fire({ state: true });
459+
return { merged: true, message: '', timeline: await parseCombinedTimelineEvents(result.data?.mergePullRequest.pullRequest.timelineItems.nodes ?? [], await this.getCopilotTimelineEvents(this), this.githubRepository) };
460+
})
461+
.catch(e => {
462+
/* __GDPR__
463+
"pr.merge.failure" : {}
464+
*/
465+
this._telemetry.sendTelemetryErrorEvent('pr.merge.failure');
466+
const graphQLErrors = e.graphQLErrors as GraphQLError[] | undefined;
467+
if (graphQLErrors?.length && graphQLErrors.find(error => error.type === GraphQLErrorType.Unprocessable && error.message?.includes('Head branch was modified'))) {
468+
return { merged: false, message: vscode.l10n.t('Head branch was modified. Pull, review, then try again.') };
469+
} else {
470+
throw e;
471+
}
472+
});
473+
}
474+
377475
/**
378476
* Close the pull request.
379477
*/

0 commit comments

Comments
 (0)