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

Commit 98a9696

Browse files
committed
Merge branch 'grokys/maintainer-workflow' of https://github.com/github/VisualStudio into don/status-polish
2 parents c0005a0 + 4f2d950 commit 98a9696

File tree

11 files changed

+797
-107
lines changed

11 files changed

+797
-107
lines changed

src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ public PullRequestDetailViewModelDesigner()
6969
public CheckoutMode CheckoutMode { get; set; }
7070
public string CheckoutError { get; set; }
7171
public int CommitsBehind { get; set; }
72+
public string CheckoutDisabledMessage { get; set; }
7273

7374
public ReactiveCommand<Unit> Checkout { get; }
7475
public ReactiveCommand<object> OpenOnGitHub { get; }
76+
public ReactiveCommand<object> OpenFile { get; }
7577
public ReactiveCommand<object> ToggleChangedFilesView { get; }
7678
public ReactiveCommand<object> ToggleOpenChangedFileAction { get; }
79+
public ReactiveCommand<object> ViewOpenFile { get; }
7780
}
7881
}

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: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Reactive;
1515
using System.Collections.Generic;
1616
using LibGit2Sharp;
17+
using PullRequest = Octokit.PullRequest;
1718

1819
namespace GitHub.Services
1920
{
@@ -83,14 +84,33 @@ public IObservable<string> GetPullRequestTemplate(ILocalRepositoryModel reposito
8384
});
8485
}
8586

87+
public IObservable<bool> CleanForCheckout(ILocalRepositoryModel repository)
88+
{
89+
var repo = gitService.GetRepository(repository.LocalPath);
90+
return Observable.Return(!repo.RetrieveStatus().IsDirty);
91+
}
92+
8693
public IObservable<Unit> FetchAndCheckout(ILocalRepositoryModel repository, int pullRequestNumber, string localBranchName)
8794
{
8895
return DoFetchAndCheckout(repository, pullRequestNumber, localBranchName).ToObservable();
8996
}
9097

91-
public string GetDefaultLocalBranchName(int pullRequestNumber, string pullRequestTitle)
98+
public IObservable<string> GetDefaultLocalBranchName(ILocalRepositoryModel repository, int pullRequestNumber, string pullRequestTitle)
9299
{
93-
return "pr/" + pullRequestNumber + "-" + GetSafeBranchName(pullRequestTitle);
100+
return Observable.Defer(() =>
101+
{
102+
var initial = "pr/" + pullRequestNumber + "-" + GetSafeBranchName(pullRequestTitle);
103+
var current = initial;
104+
var repo = gitService.GetRepository(repository.LocalPath);
105+
var index = 2;
106+
107+
while (repo.Branches[current] != null)
108+
{
109+
current = initial + '-' + index++;
110+
}
111+
112+
return Observable.Return(current);
113+
});
94114
}
95115

96116
public IObservable<HistoryDivergence> CalculateHistoryDivergence(ILocalRepositoryModel repository, int pullRequestNumber)
@@ -117,43 +137,92 @@ public IObservable<HistoryDivergence> CalculateHistoryDivergence(ILocalRepositor
117137
});
118138
}
119139

120-
public IObservable<IBranch> GetLocalBranches(ILocalRepositoryModel repository, int number)
140+
public IObservable<IBranch> GetLocalBranches(ILocalRepositoryModel repository, PullRequest pullRequest)
121141
{
122142
return Observable.Defer(() =>
123143
{
124144
var repo = gitService.GetRepository(repository.LocalPath);
125-
var result = GetLocalBranchesInternal(repo, number).Select(x => new BranchModel(x, repository));
145+
var result = GetLocalBranchesInternal(repository, repo, pullRequest).Select(x => new BranchModel(x, repository));
126146
return result.ToObservable();
127147
});
128148
}
129149

130-
public IObservable<Unit> SwitchToBranch(ILocalRepositoryModel repository, int number)
150+
public bool IsPullRequestFromFork(ILocalRepositoryModel repository, PullRequest pullRequest)
131151
{
132-
return Observable.Defer(() =>
152+
var sourceUrl = new UriString(pullRequest.Head.Repository.CloneUrl);
153+
return sourceUrl.ToRepositoryUrl() != repository.CloneUrl.ToRepositoryUrl();
154+
}
155+
156+
public IObservable<Unit> SwitchToBranch(ILocalRepositoryModel repository, PullRequest pullRequest)
157+
{
158+
return Observable.Defer(async () =>
133159
{
134160
var repo = gitService.GetRepository(repository.LocalPath);
135-
var branch = GetLocalBranchesInternal(repo, number).First();
136-
gitClient.Checkout(repo, branch);
161+
var branchName = GetLocalBranchesInternal(repository, repo, pullRequest).First();
162+
163+
await gitClient.Fetch(repo, "origin");
164+
165+
var branch = repo.Branches[branchName];
166+
167+
if (branch == null)
168+
{
169+
var trackedBranchName = $"refs/remotes/origin/" + branchName;
170+
var trackedBranch = repo.Branches[trackedBranchName];
171+
172+
if (trackedBranch != null)
173+
{
174+
branch = repo.CreateBranch(branchName, trackedBranch.Tip);
175+
await gitClient.SetTrackingBranch(repo, branchName, trackedBranchName);
176+
}
177+
else
178+
{
179+
throw new InvalidOperationException($"Could not find branch '{trackedBranchName}'.");
180+
}
181+
}
182+
183+
await gitClient.Checkout(repo, branchName);
184+
137185
return Observable.Empty<Unit>();
138186
});
139187
}
140188

189+
public IObservable<Unit> UnmarkLocalBranch(ILocalRepositoryModel repository)
190+
{
191+
return Observable.Defer(async () =>
192+
{
193+
var repo = gitService.GetRepository(repository.LocalPath);
194+
var configKey = $"branch.{repo.Head.FriendlyName}.ghfvs-pr";
195+
await gitClient.UnsetConfig(repo, configKey);
196+
return Observable.Return(Unit.Default);
197+
});
198+
}
199+
141200
async Task DoFetchAndCheckout(ILocalRepositoryModel repository, int pullRequestNumber, string localBranchName)
142201
{
143202
var repo = gitService.GetRepository(repository.LocalPath);
144-
var configKey = $"branch.{BranchNameToConfigKey(localBranchName)}.ghfvs-pr";
203+
var configKey = $"branch.{localBranchName}.ghfvs-pr";
145204
await gitClient.Fetch(repo, "origin", new[] { $"refs/pull/{pullRequestNumber}/head:{localBranchName}" });
146205
await gitClient.Checkout(repo, localBranchName);
147206
await gitClient.SetConfig(repo, configKey, pullRequestNumber.ToString());
148207
}
149208

150-
IEnumerable<string> GetLocalBranchesInternal(IRepository repository, int number)
209+
IEnumerable<string> GetLocalBranchesInternal(
210+
ILocalRepositoryModel localRepository,
211+
IRepository repository,
212+
PullRequest pullRequest)
151213
{
152-
var pr = number.ToString();
153-
return repository.Config
154-
.Select(x => new { Branch = BranchCapture.Match(x.Key).Groups["branch"].Value, Value = x.Value })
155-
.Where(x => !string.IsNullOrWhiteSpace(x.Branch) && x.Value == pr)
156-
.Select(x => ConfigKeyToBranchName(x.Branch));
214+
if (!IsPullRequestFromFork(localRepository, pullRequest))
215+
{
216+
return new[] { pullRequest.Head.Ref };
217+
}
218+
else
219+
{
220+
var pr = pullRequest.Number.ToString(CultureInfo.InvariantCulture);
221+
return repository.Config
222+
.Select(x => new { Branch = BranchCapture.Match(x.Key).Groups["branch"].Value, Value = x.Value })
223+
.Where(x => !string.IsNullOrWhiteSpace(x.Branch) && x.Value == pr)
224+
.Select(x => x.Branch);
225+
}
157226
}
158227

159228
async Task<IPullRequestModel> PushAndCreatePR(IRepositoryHost host,
@@ -191,23 +260,19 @@ void EnsurePullRefSpecExists(IRepository repo)
191260

192261
static string GetSafeBranchName(string name)
193262
{
194-
var before = InvalidBranchCharsRegex.Replace(name, "-");
263+
var before = InvalidBranchCharsRegex.Replace(name, "-").TrimEnd('-');
195264

196265
for (;;)
197266
{
198267
string after = before.Replace("--", "-");
199268

200269
if (after == before)
201270
{
202-
return before.ToLower(CultureInfo.InvariantCulture);
271+
return before.ToLower(CultureInfo.CurrentCulture);
203272
}
204273

205274
before = after;
206275
}
207276
}
208-
209-
static string BranchNameToConfigKey(string name) => name.Replace("/", ".");
210-
211-
static string ConfigKeyToBranchName(string name) => name.Replace(".", "/");
212277
}
213278
}

0 commit comments

Comments
 (0)