Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 18535d5

Browse files
committed
Re-checkout PR branch when there are local changes.
When a user commits local changes to a local branch (causing `CheckoutMode.InvalidState`) and clicks "checkout to new branch", unmark the current branch as a PR branch and check out a new branch.
1 parent 6934e3f commit 18535d5

File tree

6 files changed

+66
-7
lines changed

6 files changed

+66
-7
lines changed

src/GitHub.App/Services/GitClient.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,20 @@ public Task SetTrackingBranch(IRepository repository, string branchName, string
113113
});
114114
}
115115

116-
public Task<Remote> GetHttpRemote(IRepository repo, string remote)
116+
public Task UnsetConfig(IRepository repository, string key)
117117
{
118+
Guard.ArgumentNotEmptyString(key, nameof(key));
119+
118120
return Task.Factory.StartNew(() =>
119121
{
122+
repository.Config.Unset(key);
123+
});
124+
}
120125

126+
public Task<Remote> GetHttpRemote(IRepository repo, string remote)
127+
{
128+
return Task.Factory.StartNew(() =>
129+
{
121130
var uri = GitService.GitServiceHelper.GetRemoteUri(repo, remote);
122131
var remoteName = uri.IsHypertextTransferProtocol ? remote : remote + "-http";
123132
var ret = repo.Network.Remotes[remoteName];

src/GitHub.App/Services/PullRequestService.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ public IObservable<Unit> SwitchToBranch(ILocalRepositoryModel repository, int nu
157157
});
158158
}
159159

160+
public IObservable<Unit> UnmarkLocalBranch(ILocalRepositoryModel repository)
161+
{
162+
return Observable.Defer(async () =>
163+
{
164+
var repo = gitService.GetRepository(repository.LocalPath);
165+
var configKey = $"branch.{repo.Head.FriendlyName}.ghfvs-pr";
166+
await gitClient.UnsetConfig(repo, configKey);
167+
return Observable.Return(Unit.Default);
168+
});
169+
}
170+
160171
async Task DoFetchAndCheckout(ILocalRepositoryModel repository, int pullRequestNumber, string localBranchName)
161172
{
162173
var repo = gitService.GetRepository(repository.LocalPath);

src/GitHub.App/ViewModels/PullRequestDetailViewModel.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,12 @@ IObservable<Unit> DoCheckout(object unused)
466466
case CheckoutMode.Switch:
467467
operation = pullRequestsService.SwitchToBranch(repository, Number);
468468
break;
469+
case CheckoutMode.InvalidState:
470+
operation = pullRequestsService
471+
.UnmarkLocalBranch(repository)
472+
.SelectMany(_ => pullRequestsService.GetDefaultLocalBranchName(repository, Number, Title))
473+
.SelectMany(x => pullRequestsService.FetchAndCheckout(repository, Number, x));
474+
break;
469475
default:
470476
Debug.Fail("Invalid CheckoutMode in PullRequestDetailViewModel.DoCheckout.");
471477
operation = Observable.Empty<Unit>();

src/GitHub.Exports.Reactive/Services/IGitClient.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ public interface IGitClient
6969
/// <returns></returns>
7070
Task SetTrackingBranch(IRepository repository, string branchName, string remoteName);
7171

72+
/// <summary>
73+
/// Unsets the configuration key in the local config.
74+
/// </summary>
75+
/// <param name="repository">The repository</param>
76+
/// <param name="key">The configuration key. Keys are in the form 'section.name'.</param>
77+
/// <returns></returns>
78+
Task UnsetConfig(IRepository repository, string key);
79+
7280
Task<Remote> GetHttpRemote(IRepository repo, string remote);
7381
}
7482
}

src/GitHub.Exports.Reactive/Services/IPullRequestService.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ IObservable<IPullRequestModel> CreatePullRequest(IRepositoryHost host,
6060
/// <returns></returns>
6161
IObservable<HistoryDivergence> CalculateHistoryDivergence(ILocalRepositoryModel repository, int pullRequestNumber);
6262

63+
/// <summary>
64+
/// Removes any association between the current branch and a pull request.
65+
/// </summary>
66+
/// <param name="repository">The repository.</param>
67+
/// <returns></returns>
68+
IObservable<Unit> UnmarkLocalBranch(ILocalRepositoryModel repository);
69+
6370
IObservable<string> GetPullRequestTemplate(ILocalRepositoryModel repository);
6471
}
6572
}

src/UnitTests/GitHub.App/ViewModels/PullRequestDetailViewModelTests.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,7 @@ public async Task CheckoutNeedsPullShouldCallService()
207207

208208
target.Item1.Checkout.Execute(null);
209209

210-
var unused = target.Item2.Received()
211-
.FetchAndCheckout(Arg.Any<ILocalRepositoryModel>(), target.Item1.Number, "pr/123");
210+
var unused = target.Item2.Received().FetchAndCheckout(Arg.Any<ILocalRepositoryModel>(), target.Item1.Number, "pr/123");
212211
}
213212

214213
[Fact]
@@ -224,8 +223,7 @@ public async Task CheckoutSwitchShouldCallService()
224223

225224
target.Item1.Checkout.Execute(null);
226225

227-
var unused = target.Item2.Received()
228-
.SwitchToBranch(Arg.Any<ILocalRepositoryModel>(), 1);
226+
var unused = target.Item2.Received().SwitchToBranch(Arg.Any<ILocalRepositoryModel>(), 1);
229227
}
230228

231229
[Fact]
@@ -241,8 +239,28 @@ public async Task CheckoutFetchShouldCallService()
241239

242240
target.Item1.Checkout.Execute(null);
243241

244-
var unused = target.Item2.Received()
245-
.FetchAndCheckout(Arg.Any<ILocalRepositoryModel>(), target.Item1.Number, "pr/1-foo");
242+
var unused = target.Item2.Received().FetchAndCheckout(Arg.Any<ILocalRepositoryModel>(), target.Item1.Number, "pr/1-foo");
243+
}
244+
245+
[Fact]
246+
public async Task CheckoutInvalidStateShouldCallService()
247+
{
248+
var target = CreateTargetAndService(
249+
currentBranch: "pr/123",
250+
existingPrBranch: "pr/123",
251+
aheadBy: 1);
252+
253+
target.Item2.GetDefaultLocalBranchName(Arg.Any<ILocalRepositoryModel>(), 1, Arg.Any<string>())
254+
.Returns(Observable.Return("pr/1-foo"));
255+
256+
await target.Item1.Load(CreatePullRequest(), new PullRequestFile[0]);
257+
258+
Assert.Equal(CheckoutMode.InvalidState, target.Item1.CheckoutMode);
259+
260+
target.Item1.Checkout.Execute(null);
261+
262+
var unused = target.Item2.Received().UnmarkLocalBranch(Arg.Any<ILocalRepositoryModel>());
263+
unused = target.Item2.Received().FetchAndCheckout(Arg.Any<ILocalRepositoryModel>(), target.Item1.Number, "pr/1-foo");
246264
}
247265

248266
PullRequestDetailViewModel CreateTarget(

0 commit comments

Comments
 (0)