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

Commit 48feb0b

Browse files
committed
Implement pull request creation and branch data
1 parent 5a743b3 commit 48feb0b

20 files changed

+803
-579
lines changed

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/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: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Diagnostics.CodeAnalysis;
22
using GitHub.ViewModels;
33
using System.Collections.Generic;
4+
using GitHub.Models;
45

56
namespace GitHub.SampleData
67
{
@@ -9,27 +10,30 @@ public class PullRequestCreationViewModelDesigner : BaseViewModel, IPullRequestC
910
{
1011
public PullRequestCreationViewModelDesigner()
1112
{
12-
Branches = new List<string>()
13+
Branches = new List<IBranch>
1314
{
14-
"don/stub-ui",
15-
"feature/pr/views",
16-
"release-1.0.17.0"
17-
};
15+
new BranchModel { Name = "master" },
16+
new BranchModel { Name = "don/stub-ui" },
17+
new BranchModel { Name = "feature/pr/views" },
18+
new BranchModel { Name = "release-1.0.17.0" }
19+
}.AsReadOnly();
20+
21+
TargetBranch = new BranchModel { Name = "master" };
22+
SourceBranch = Branches[2];
1823

19-
CurrentBranchName = "fix-everything";
2024
SelectedAssignee = "Haacked (Phil Haack)";
21-
TargetBranchName = "master";
2225
Users = new List<string>()
2326
{
2427
"Haacked (Phil Haack)",
2528
"shana (Andreia Gaita)"
2629
};
2730
}
2831

29-
public string CurrentBranchName { get; set; }
32+
public IBranch SourceBranch { get; set; }
33+
public IBranch TargetBranch { get; set; }
34+
public IReadOnlyList<IBranch> Branches { get; set; }
35+
3036
public string SelectedAssignee { get; set; }
31-
public string TargetBranchName { get; set; }
32-
public List<string> Branches { get; set; }
3337
public List<string> Users { get; set; }
3438
}
3539
}

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(IPullRequestModel pr, ISimpleRepositoryModel repository)
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(pr.Title, pr.Head.Name, pr.Base.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, IPullRequestModel pullRequest)
12+
{
13+
return host.ModelService.CreatePullRequest(pullRequest, repository);
14+
}
15+
}
16+
}
Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,61 @@
1-
using System.ComponentModel.Composition;
1+
using System;
2+
using System.ComponentModel.Composition;
23
using GitHub.Exports;
4+
using GitHub.Models;
5+
using System.Collections.Generic;
6+
using ReactiveUI;
7+
using GitHub.Services;
8+
using System.Reactive.Linq;
9+
using System.Collections.ObjectModel;
10+
using GitHub.Extensions.Reactive;
11+
using GitHub.UI;
12+
using System.Linq;
313

414
namespace GitHub.ViewModels
515
{
616
[ExportViewModel(ViewType = UIViewType.PRCreation)]
717
[PartCreationPolicy(CreationPolicy.NonShared)]
8-
class PullRequestCreationViewModel : BaseViewModel, IPullRequestCreationViewModel
18+
public class PullRequestCreationViewModel : BaseViewModel, IPullRequestCreationViewModel
919
{
20+
[ImportingConstructor]
21+
PullRequestCreationViewModel(
22+
IConnectionRepositoryHostMap connectionRepositoryHostMap, ITeamExplorerServiceHolder teservice)
23+
: this(connectionRepositoryHostMap.CurrentRepositoryHost, teservice.ActiveRepo)
24+
{}
25+
26+
public PullRequestCreationViewModel(IRepositoryHost repositoryHost, ISimpleRepositoryModel activeRepo)
27+
{
28+
repositoryHost.ModelService.GetBranches(activeRepo)
29+
.ToReadOnlyList()
30+
.ObserveOn(RxApp.MainThreadScheduler)
31+
.Subscribe(x => Branches = x);
32+
33+
var repo = GitService.GitServiceHelper.GetRepo(activeRepo.LocalPath);
34+
SourceBranch = new BranchModel(repo.Head);
35+
36+
// what do we do if there's no master?
37+
TargetBranch = new BranchModel { Name = "master" };
38+
}
39+
40+
IBranch targetBranch;
41+
public IBranch TargetBranch
42+
{
43+
get { return targetBranch; }
44+
set { this.RaiseAndSetIfChanged(ref targetBranch, value); }
45+
}
46+
47+
IBranch sourceBranch;
48+
public IBranch SourceBranch
49+
{
50+
get { return sourceBranch; }
51+
set { this.RaiseAndSetIfChanged(ref sourceBranch, value); }
52+
}
53+
54+
IReadOnlyList<IBranch> branches;
55+
public IReadOnlyList<IBranch> Branches
56+
{
57+
get { return branches; }
58+
set { this.RaiseAndSetIfChanged(ref branches, value); }
59+
}
1060
}
1161
}

src/GitHub.Exports.Reactive/Api/IApiClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ IObservable<ApplicationAuthorization> GetOrCreateApplicationAuthenticationCode(
3333
IObservable<LicenseMetadata> GetLicenses();
3434
IObservable<Unit> DeleteApplicationAuthorization(int id, string twoFactorAuthorizationCode);
3535
IObservable<PullRequest> GetPullRequestsForRepository(string owner, string name);
36+
IObservable<PullRequest> CreatePullRequest(NewPullRequest pullRequest, string owner, string repo);
37+
IObservable<Branch> GetBranches(string owner, string repo);
3638
IObservable<Repository> GetRepositories();
3739
}
3840
}

0 commit comments

Comments
 (0)