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

Commit a44defa

Browse files
authored
Merge pull request #353 from github/feature/pr/creation
Pull Request Creation
2 parents 4bd6706 + f7dc200 commit a44defa

Some content is hidden

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

46 files changed

+833
-819
lines changed

GitHubVS.sln

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Script", "Script", "{7B6C5F
5252
script\Require-CleanWorkTree.ps1 = script\Require-CleanWorkTree.ps1
5353
script\Run-NUnit.ps1 = script\Run-NUnit.ps1
5454
script\Run-XUnit.ps1 = script\Run-XUnit.ps1
55-
script\SolutionInfo.cs = script\SolutionInfo.cs
5655
script\Upload-DirectoryToS3.ps1 = script\Upload-DirectoryToS3.ps1
5756
EndProjectSection
5857
EndProject

src/GitHub.App/Api/ApiClient.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,20 @@ public IObservable<PullRequest> GetPullRequestsForRepository(string owner, strin
237237
SortDirection = SortDirection.Descending
238238
});
239239
}
240+
241+
public IObservable<PullRequest> CreatePullRequest(NewPullRequest pullRequest, string owner, string repo)
242+
{
243+
return gitHubClient.PullRequest.Create(owner, repo, pullRequest);
244+
}
245+
240246
public IObservable<Repository> GetRepositories()
241247
{
242248
return gitHubClient.Repository.GetAllForCurrent();
243249
}
250+
251+
public IObservable<Branch> GetBranches(string owner, string repo)
252+
{
253+
return gitHubClient.Repository.GetAllBranches(owner, repo);
254+
}
244255
}
245256
}

src/GitHub.App/Controllers/UIController.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ internal enum Trigger
105105
readonly IUIFactory factory;
106106
readonly IUIProvider uiProvider;
107107
readonly IRepositoryHosts hosts;
108-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
109108
readonly IConnectionManager connectionManager;
110109

111110
readonly CompositeDisposable disposables = new CompositeDisposable();
@@ -333,7 +332,8 @@ void ConfigureUIHandlingStates()
333332
.OnEntryFrom(triggers[Trigger.PRDetail], (arg, tr) => RunView(UIViewType.PRDetail, CalculateDirection(tr), arg))
334333
.PermitDynamic(Trigger.Next, () => Go(Trigger.Next))
335334
.PermitDynamic(Trigger.Cancel, () => Go(Trigger.Cancel))
336-
.PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish));
335+
.PermitDynamic(Trigger.Finish, () => Go(Trigger.Finish))
336+
.OnExit(() => DisposeView(activeFlow, UIViewType.PRDetail));
337337

338338
uiStateMachine.Configure(UIViewType.PRCreation)
339339
.OnEntry(tr => RunView(UIViewType.PRCreation, CalculateDirection(tr)))
@@ -622,6 +622,17 @@ void DisposeFlow(UIControllerFlow flow)
622622
list.Clear();
623623
}
624624

625+
void DisposeView(UIControllerFlow flow, UIViewType type)
626+
{
627+
var list = GetObjectsForFlow(flow);
628+
IUIPair uipair = null;
629+
if (list.TryGetValue(type, out uipair))
630+
{
631+
list.Remove(type);
632+
uipair.Dispose();
633+
}
634+
}
635+
625636
void RunView(UIViewType viewType, LoadDirection direction, ViewWithData arg = null)
626637
{
627638
if (requestedTarget?.ViewType == viewType)

src/GitHub.App/Extensions/AkavacheExtensions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,37 @@ static IObservable<T> GetAndFetchLatestFromIndex<T>(this IBlobCache This,
241241
.Replay().RefCount();
242242
}
243243

244+
/// <summary>
245+
/// This method adds a new object to the database and updates the
246+
/// corresponding index.
247+
/// </summary>
248+
/// <typeparam name="T"></typeparam>
249+
/// <param name="blobCache">The cache to retrieve the object from.</param>
250+
/// <param name="key">The key to look up the cache value with.</param>
251+
/// <param name="item">The item to add to the database</param>
252+
/// <param name="maxCacheDuration">
253+
/// The maximum age of a cache object before the object is treated as
254+
/// expired and unusable. Cache objects older than this will be treated
255+
/// as a cache miss.
256+
/// <returns></returns>
257+
public static IObservable<T> PutAndUpdateIndex<T>(this IBlobCache blobCache,
258+
string key,
259+
Func<IObservable<T>> fetchFunc,
260+
TimeSpan maxCacheDuration)
261+
where T : CacheItem
262+
{
263+
return Observable.Defer(() =>
264+
{
265+
var absoluteExpiration = blobCache.Scheduler.Now + maxCacheDuration;
266+
return blobCache.GetOrCreateObject(key, () => CacheIndex.Create(key))
267+
.SelectMany(index => fetchFunc()
268+
.Catch<T, Exception>(Observable.Throw<T>)
269+
.SelectMany(x => x.Save<T>(blobCache, key, absoluteExpiration))
270+
.Do(x => index.AddAndSave(blobCache, key, x, absoluteExpiration))
271+
);
272+
});
273+
}
274+
244275
static bool IsExpired(IBlobCache blobCache, DateTimeOffset itemCreatedAt, TimeSpan cacheDuration)
245276
{
246277
var elapsed = blobCache.Scheduler.Now - itemCreatedAt.ToUniversalTime();

src/GitHub.App/GitHub.App.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
<Compile Include="Factories\UIFactory.cs" />
128128
<Compile Include="GlobalSuppressions.cs" />
129129
<Compile Include="Infrastructure\LoggingConfiguration.cs" />
130+
<Compile Include="Models\BranchModel.cs" />
130131
<Compile Include="Models\PullRequestModel.cs" />
131132
<Compile Include="Resources.Designer.cs">
132133
<AutoGen>True</AutoGen>
@@ -144,6 +145,7 @@
144145
<Compile Include="Services\ImageDownloader.cs" />
145146
<Compile Include="Services\GitClient.cs" />
146147
<Compile Include="Services\ModelService.cs" />
148+
<Compile Include="Services\PullRequestService.cs" />
147149
<Compile Include="Services\RepositoryCloneService.cs" />
148150
<Compile Include="Extensions\FileExtensions.cs" />
149151
<Compile Include="Caches\CredentialCache.cs" />
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace GitHub.Models
2+
{
3+
public class BranchModel : IBranch
4+
{
5+
public BranchModel()
6+
{ }
7+
8+
public BranchModel(Octokit.Branch branch)
9+
{
10+
Name = branch.Name;
11+
}
12+
13+
public BranchModel(LibGit2Sharp.Branch branch)
14+
{
15+
Name = branch.FriendlyName;
16+
}
17+
18+
public string Name { get; set; }
19+
}
20+
}

src/GitHub.App/Models/PullRequestModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ public IAccount Assignee
141141
set { assignee = value; this.RaisePropertyChange(); }
142142
}
143143

144+
public ISimpleRepositoryModel Repository { get; }
145+
public IBranch Head { get; }
146+
public IBranch Base { get; }
144147

145148
[return: AllowNull] // nullguard thinks a string.Format can return null. sigh.
146149
public override string ToString()
Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
using System.Diagnostics.CodeAnalysis;
22
using GitHub.ViewModels;
33
using System.Collections.Generic;
4+
using GitHub.Models;
5+
using GitHub.Validation;
6+
using System;
7+
using System.Windows.Input;
8+
using ReactiveUI;
49

510
namespace GitHub.SampleData
611
{
@@ -9,27 +14,38 @@ public class PullRequestCreationViewModelDesigner : BaseViewModel, IPullRequestC
914
{
1015
public PullRequestCreationViewModelDesigner()
1116
{
12-
Branches = new List<string>()
17+
Branches = new List<IBranch>
1318
{
14-
"don/stub-ui",
15-
"feature/pr/views",
16-
"release-1.0.17.0"
17-
};
19+
new BranchModel { Name = "master" },
20+
new BranchModel { Name = "don/stub-ui" },
21+
new BranchModel { Name = "feature/pr/views" },
22+
new BranchModel { Name = "release-1.0.17.0" }
23+
}.AsReadOnly();
24+
25+
TargetBranch = new BranchModel { Name = "master" };
26+
SourceBranch = Branches[2];
1827

19-
CurrentBranchName = "fix-everything";
2028
SelectedAssignee = "Haacked (Phil Haack)";
21-
TargetBranchName = "master";
2229
Users = new List<string>()
2330
{
2431
"Haacked (Phil Haack)",
2532
"shana (Andreia Gaita)"
2633
};
2734
}
2835

29-
public string CurrentBranchName { get; set; }
36+
public IBranch SourceBranch { get; set; }
37+
public IBranch TargetBranch { get; set; }
38+
public IReadOnlyList<IBranch> Branches { get; set; }
39+
3040
public string SelectedAssignee { get; set; }
31-
public string TargetBranchName { get; set; }
32-
public List<string> Branches { get; set; }
3341
public List<string> Users { get; set; }
42+
43+
public IReactiveCommand<IPullRequestModel> CreatePullRequest { get; }
44+
45+
public string PRTitle { get; set; }
46+
47+
public ReactivePropertyValidator TitleValidator { get; }
48+
49+
public ReactivePropertyValidator BranchValidator { get; }
3450
}
3551
}

src/GitHub.App/Services/ModelService.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,24 @@ public ITrackingCollection<IRepositoryModel> GetRepositories(ITrackingCollection
199199
return collection;
200200
}
201201

202+
public IObservable<IPullRequestModel> CreatePullRequest(ISimpleRepositoryModel repository, string title, IBranch source, IBranch target)
203+
{
204+
var keyobs = GetUserFromCache()
205+
.Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}:{2}", CacheIndex.PRPrefix, user.Login, repository.Name));
206+
207+
return Observable.Defer(() => keyobs
208+
.SelectMany(key =>
209+
hostCache.PutAndUpdateIndex(key, () =>
210+
apiClient.CreatePullRequest(new NewPullRequest(title, source.Name, target.Name),
211+
repository.CloneUrl.Owner,
212+
repository.CloneUrl.RepositoryName)
213+
.Select(PullRequestCacheItem.Create),
214+
TimeSpan.FromMinutes(30))
215+
)
216+
.Select(Create)
217+
);
218+
}
219+
202220
public IObservable<Unit> InvalidateAll()
203221
{
204222
return hostCache.InvalidateAll().ContinueAfter(() => hostCache.Vacuum());
@@ -262,6 +280,16 @@ IObservable<IReadOnlyList<IRepositoryModel>> GetOrganizationRepositories(string
262280
});
263281
}
264282

283+
public IObservable<IBranch> GetBranches(ISimpleRepositoryModel repo)
284+
{
285+
var keyobs = GetUserFromCache()
286+
.Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|branch", user.Login, repo.Name));
287+
288+
return Observable.Defer(() => keyobs
289+
.SelectMany(key => apiClient.GetBranches(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName)))
290+
.Select(Create);
291+
}
292+
265293
static GitIgnoreItem Create(GitIgnoreCacheItem item)
266294
{
267295
return GitIgnoreItem.Create(item.Name);
@@ -272,7 +300,7 @@ static LicenseItem Create(LicenseCacheItem licenseCacheItem)
272300
return new LicenseItem(licenseCacheItem.Key, licenseCacheItem.Name);
273301
}
274302

275-
Models.Account Create(AccountCacheItem accountCacheItem)
303+
IAccount Create(AccountCacheItem accountCacheItem)
276304
{
277305
return new Models.Account(
278306
accountCacheItem.Login,
@@ -313,6 +341,11 @@ IPullRequestModel Create(PullRequestCacheItem prCacheItem)
313341
};
314342
}
315343

344+
IBranch Create(Branch branch)
345+
{
346+
return new BranchModel(branch);
347+
}
348+
316349

317350
public IObservable<Unit> InsertUser(AccountCacheItem user)
318351
{
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.ComponentModel.Composition;
3+
using GitHub.Models;
4+
5+
namespace GitHub.Services
6+
{
7+
[Export(typeof(IPullRequestService))]
8+
[PartCreationPolicy(CreationPolicy.Shared)]
9+
public class PullRequestService : IPullRequestService
10+
{
11+
public IObservable<IPullRequestModel> CreatePullRequest(IRepositoryHost host, ISimpleRepositoryModel repository, string title, IBranch source, IBranch target)
12+
{
13+
return host.ModelService.CreatePullRequest(repository, title, source, target);
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)