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

Commit fc57163

Browse files
committed
Merge branch 'master' into refactor/connections-master
Conflicts: src/GitHub.App/ViewModels/PullRequestCreationViewModel.cs test/UnitTests/GitHub.App/Caches/CredentialCacheTests.cs test/UnitTests/GitHub.App/Models/RepositoryHostTests.cs test/UnitTests/GitHub.App/ViewModels/PullRequestCreationViewModelTests.cs test/UnitTests/Helpers/TestLoginCache.cs
2 parents def6070 + 166cdc0 commit fc57163

File tree

92 files changed

+269
-44
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+269
-44
lines changed

GitHubVS.sln

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Meta", "Meta", "{72036B62-2
1313
README.md = README.md
1414
EndProjectSection
1515
EndProject
16-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "src\UnitTests\UnitTests.csproj", "{596595A6-2A3C-469E-9386-9E3767D863A5}"
16+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{596595A6-2A3C-469E-9386-9E3767D863A5}"
1717
EndProject
1818
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.UI", "src\GitHub.UI\GitHub.UI.csproj", "{346384DD-2445-4A28-AF22-B45F3957BD89}"
1919
EndProject
@@ -88,7 +88,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Splat-Portable", "submodule
8888
EndProject
8989
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CredentialManagement", "src\CredentialManagement\CredentialManagement.csproj", "{41A47C5B-C606-45B4-B83C-22B9239E4DA0}"
9090
EndProject
91-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrackingCollectionTests", "src\TrackingCollectionTests\TrackingCollectionTests.csproj", "{7B835A7D-CF94-45E8-B191-96F5A4FE26A8}"
91+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrackingCollectionTests", "test\TrackingCollectionTests\TrackingCollectionTests.csproj", "{7B835A7D-CF94-45E8-B191-96F5A4FE26A8}"
9292
EndProject
9393
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.TeamFoundation.14", "src\GitHub.TeamFoundation.14\GitHub.TeamFoundation.14.csproj", "{161DBF01-1DBF-4B00-8551-C5C00F26720D}"
9494
EndProject

install.cmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Configuration=%1
2-
@set path=%cd%\tools\VsixUtil;%path%
1+
@set Configuration=%1
2+
@if "%Configuration%" == "" echo Please specify Debug or Release
33
tools\VsixUtil\vsixutil /install "build\%Configuration%\GitHub.VisualStudio.vsix"
44
@echo Installed %Configuration% build of GitHub for Visual Studio

scripts/test.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ $env:PATH = "$$PSScriptRoot;$env:PATH"
3535
$exitcode = 0
3636

3737
Write-Output "Running Tracking Collection Tests..."
38-
Run-NUnit src TrackingCollectionTests $TimeoutDuration $config -AppVeyor:$AppVeyor
38+
Run-NUnit test TrackingCollectionTests $TimeoutDuration $config -AppVeyor:$AppVeyor
3939
if (!$?) {
4040
$exitcode = 1
4141
}
@@ -47,7 +47,7 @@ if (!$?) {
4747
}
4848

4949
Write-Output "Running UnitTests..."
50-
Run-XUnit src UnitTests $TimeoutDuration $config -AppVeyor:$AppVeyor
50+
Run-XUnit test UnitTests $TimeoutDuration $config -AppVeyor:$AppVeyor
5151
if (!$?) {
5252
$exitcode = 3
5353
}

src/GitHub.App/Services/GitClient.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel.Composition;
34
using System.IO;
45
using System.Linq;
56
using System.Threading.Tasks;
67
using GitHub.Extensions;
8+
using GitHub.Models;
79
using GitHub.Primitives;
810
using LibGit2Sharp;
911
using GitHub.Logging;
@@ -38,7 +40,6 @@ public GitClient(IGitHubCredentialProvider credentialProvider)
3840
public Task Pull(IRepository repository)
3941
{
4042
Guard.ArgumentNotNull(repository, nameof(repository));
41-
4243
return Task.Factory.StartNew(() =>
4344
{
4445
var signature = repository.Config.BuildSignature(DateTimeOffset.UtcNow);
@@ -474,6 +475,39 @@ public Task<bool> IsHeadPushed(IRepository repo)
474475
});
475476
}
476477

478+
public Task<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits(
479+
IRepository repo,
480+
string baseBranch,
481+
string compareBranch,
482+
int maxCommits)
483+
{
484+
return Task.Factory.StartNew(() =>
485+
{
486+
var baseCommit = repo.Lookup<Commit>(baseBranch);
487+
var compareCommit = repo.Lookup<Commit>(compareBranch);
488+
if (baseCommit == null || compareCommit == null)
489+
{
490+
var missingBranch = baseCommit == null ? baseBranch : compareBranch;
491+
throw new NotFoundException(missingBranch);
492+
}
493+
494+
var mergeCommit = repo.ObjectDatabase.FindMergeBase(baseCommit, compareCommit);
495+
var commitFilter = new CommitFilter
496+
{
497+
IncludeReachableFrom = baseCommit,
498+
ExcludeReachableFrom = mergeCommit,
499+
};
500+
501+
var commits = repo.Commits
502+
.QueryBy(commitFilter)
503+
.Take(maxCommits)
504+
.Select(c => new CommitMessage(c.Message))
505+
.ToList();
506+
507+
return (IReadOnlyList<CommitMessage>)commits;
508+
});
509+
}
510+
477511
static bool IsCanonical(string s)
478512
{
479513
Guard.ArgumentNotEmptyString(s, nameof(s));

src/GitHub.App/Services/PullRequestService.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ public IObservable<string> GetPullRequestTemplate(ILocalRepositoryModel reposito
8787
});
8888
}
8989

90+
public IObservable<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits(
91+
ILocalRepositoryModel repository,
92+
string baseBranch,
93+
string compareBranch,
94+
int maxCommits)
95+
{
96+
return Observable.Defer(() =>
97+
{
98+
var repo = gitService.GetRepository(repository.LocalPath);
99+
return gitClient.GetMessagesForUniqueCommits(repo, baseBranch, compareBranch, maxCommits).ToObservable();
100+
});
101+
}
102+
90103
public IObservable<bool> IsWorkingDirectoryClean(ILocalRepositoryModel repository)
91104
{
92105
var repo = gitService.GetRepository(repository.LocalPath);

src/GitHub.App/ViewModels/PullRequestCreationViewModel.cs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ public PullRequestCreationViewModel(
7979
});
8080

8181
SourceBranch = activeRepo.CurrentBranch;
82-
service.GetPullRequestTemplate(activeRepo)
83-
.Subscribe(x => Description = x ?? String.Empty, () => Description = Description ?? String.Empty);
8482

8583
this.WhenAnyValue(x => x.Branches)
8684
.WhereNotNull()
@@ -93,6 +91,31 @@ public PullRequestCreationViewModel(
9391

9492
SetupValidators();
9593

94+
var uniqueCommits = this.WhenAnyValue(
95+
x => x.SourceBranch,
96+
x => x.TargetBranch)
97+
.Where(x => x.Item1 != null && x.Item2 != null)
98+
.Select(branches =>
99+
{
100+
var baseBranch = branches.Item1.Name;
101+
var compareBranch = branches.Item2.Name;
102+
103+
// We only need to get max two commits for what we're trying to achieve here.
104+
// If there's no commits we want to block creation of the PR, if there's one commits
105+
// we wan't to use its commit message as the PR title/body and finally if there's more
106+
// than one we'll use the branch name for the title.
107+
return service.GetMessagesForUniqueCommits(activeRepo, baseBranch, compareBranch, maxCommits: 2)
108+
.Catch<IReadOnlyList<CommitMessage>, Exception>(ex =>
109+
{
110+
log.Warning(ex, "Could not load unique commits");
111+
return Observable.Empty<IReadOnlyList<CommitMessage>>();
112+
});
113+
})
114+
.Switch()
115+
.ObserveOn(RxApp.MainThreadScheduler)
116+
.Replay(1)
117+
.RefCount();
118+
96119
var whenAnyValidationResultChanges = this.WhenAny(
97120
x => x.TitleValidator.ValidationResult,
98121
x => x.BranchValidator.ValidationResult,
@@ -128,6 +151,37 @@ public PullRequestCreationViewModel(
128151
this.WhenAnyValue(x => x.Initialized, x => x.GitHubRepository, x => x.Description, x => x.IsExecuting)
129152
.Select(x => !(x.Item1 && x.Item2 != null && x.Item3 != null && !x.Item4))
130153
.Subscribe(x => IsBusy = x);
154+
155+
Observable.CombineLatest(
156+
this.WhenAnyValue(x => x.SourceBranch),
157+
uniqueCommits,
158+
service.GetPullRequestTemplate(activeRepo).DefaultIfEmpty(string.Empty),
159+
(compare, commits, template) => new { compare, commits, template })
160+
.Subscribe(x =>
161+
{
162+
var prTitle = string.Empty;
163+
var prDescription = string.Empty;
164+
165+
if (x.commits.Count == 1)
166+
{
167+
prTitle = x.commits[0].Summary;
168+
prDescription = x.commits[0].Details;
169+
}
170+
else
171+
{
172+
prTitle = x.compare.Name.Humanize();
173+
}
174+
175+
if (!string.IsNullOrWhiteSpace(x.template))
176+
{
177+
if (!string.IsNullOrEmpty(prDescription))
178+
prDescription += "\n\n";
179+
prDescription += x.template;
180+
}
181+
182+
PRTitle = prTitle;
183+
Description = prDescription;
184+
});
131185
}
132186

133187
public override void Initialize(ViewWithData data = null)

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Threading.Tasks;
33
using LibGit2Sharp;
44
using GitHub.Primitives;
5+
using System.Collections.Generic;
6+
using GitHub.Models;
57

68
namespace GitHub.Services
79
{
@@ -204,5 +206,21 @@ public interface IGitClient
204206
/// <param name="repository">The repository.</param>
205207
/// <returns></returns>
206208
Task<bool> IsHeadPushed(IRepository repo);
209+
210+
/// <summary>
211+
/// Gets the unique commits from <paramref name="compareBranch"/> to the merge base of
212+
/// <paramref name="baseBranch"/> and <paramref name="compareBranch"/> and returns their
213+
/// commit messages.
214+
/// </summary>
215+
/// <param name="repository">The repository.</param>
216+
/// <param name="baseBranch">The base branch to find a merge base with.</param>
217+
/// <param name="compareBranch">The compare branch to find a merge base with.</param>
218+
/// <param name="maxCommits">The maximum number of commits to return.</param>
219+
/// <returns>An enumerable of unique commits from the merge base to the compareBranch.</returns>
220+
Task<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits(
221+
IRepository repo,
222+
string baseBranch,
223+
string compareBranch,
224+
int maxCommits);
207225
}
208226
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Reactive;
34
using System.Text;
5+
using System.Threading.Tasks;
46
using GitHub.Models;
57
using LibGit2Sharp;
68
using Octokit;
@@ -157,5 +159,21 @@ IObservable<string> ExtractFile(
157159
IObservable<Unit> RemoveUnusedRemotes(ILocalRepositoryModel repository);
158160

159161
IObservable<string> GetPullRequestTemplate(ILocalRepositoryModel repository);
162+
163+
/// <summary>
164+
/// Gets the unique commits from <paramref name="compareBranch"/> to the merge base of
165+
/// <paramref name="baseBranch"/> and <paramref name="compareBranch"/> and returns their
166+
/// commit messages.
167+
/// </summary>
168+
/// <param name="repository">The repository.</param>
169+
/// <param name="baseBranch">The base branch to find a merge base with.</param>
170+
/// <param name="compareBranch">The compare branch to find a merge base with.</param>
171+
/// <param name="maxCommits">The maximum number of commits to return.</param>
172+
/// <returns>An enumerable of unique commits from the merge base to the compareBranch.</returns>
173+
IObservable<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits(
174+
ILocalRepositoryModel repository,
175+
string baseBranch,
176+
string compareBranch,
177+
int maxCommits);
160178
}
161179
}

src/GitHub.Exports/GitHub.Exports.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
<ItemGroup>
140140
<Compile Include="Exports\ExportForProcess.cs" />
141141
<Compile Include="GitHubLogicException.cs" />
142+
<Compile Include="Models\CommitMessage.cs" />
142143
<Compile Include="Models\DiffChangeType.cs" />
143144
<Compile Include="Models\DiffChunk.cs" />
144145
<Compile Include="Models\DiffLine.cs" />
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Linq;
3+
4+
namespace GitHub.Models
5+
{
6+
public class CommitMessage : IEquatable<CommitMessage>
7+
{
8+
public string Summary { get; private set; }
9+
public string Details { get; private set; }
10+
public string FullMessage { get; private set; }
11+
12+
/// <summary>
13+
/// This is for mocking porpoises.
14+
/// http://cl.ly/image/0q2A2W0U3O2t
15+
/// </summary>
16+
public CommitMessage() { }
17+
18+
public CommitMessage(string fullMessage)
19+
{
20+
if (string.IsNullOrEmpty(fullMessage)) return;
21+
22+
var lines = fullMessage.Replace("\r\n", "\n").Split('\n');
23+
Summary = lines.FirstOrDefault();
24+
25+
FullMessage = fullMessage;
26+
var detailsLines = lines
27+
.Skip(1)
28+
.SkipWhile(string.IsNullOrEmpty)
29+
.ToList();
30+
Details = detailsLines.Any(x => !string.IsNullOrWhiteSpace(x))
31+
? string.Join(Environment.NewLine, detailsLines).Trim()
32+
: null;
33+
}
34+
35+
public bool Equals(CommitMessage other)
36+
{
37+
if (ReferenceEquals(other, null))
38+
{
39+
return false;
40+
}
41+
42+
return string.Equals(Summary, other.Summary)
43+
&& string.Equals(Details, other.Details);
44+
}
45+
46+
public override bool Equals(object obj)
47+
{
48+
return Equals(obj as CommitMessage);
49+
}
50+
51+
public override int GetHashCode()
52+
{
53+
return Tuple.Create(Summary, Details).GetHashCode();
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)