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

Commit cb5f307

Browse files
committed
Implement pull request creation and branch data
1 parent 441545d commit cb5f307

20 files changed

+801
-578
lines changed

src/GitHub.App/Api/ApiClient.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,5 +237,15 @@ public IObservable<PullRequest> GetPullRequestsForRepository(string owner, strin
237237
SortDirection = SortDirection.Descending
238238
});
239239
}
240+
241+
public IObservable<Branch> GetBranches(string owner, string repo)
242+
{
243+
return gitHubClient.Repository.GetAllBranches(owner, repo);
244+
}
245+
246+
public IObservable<PullRequest> CreatePullRequest(NewPullRequest pullRequest, string owner, string repo)
247+
{
248+
return gitHubClient.PullRequest.Create(owner, repo, pullRequest);
249+
}
240250
}
241251
}

src/GitHub.App/Extensions/AkavacheExtensions.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,37 @@ static IObservable<T> GetAndFetchLatestFromIndex<T>(this IBlobCache This,
234234
return cache.Merge(fetch).Replay().RefCount();
235235
}
236236

237+
/// <summary>
238+
/// This method adds a new object to the database and updates the
239+
/// corresponding index.
240+
/// </summary>
241+
/// <typeparam name="T"></typeparam>
242+
/// <param name="blobCache">The cache to retrieve the object from.</param>
243+
/// <param name="key">The key to look up the cache value with.</param>
244+
/// <param name="item">The item to add to the database</param>
245+
/// <param name="maxCacheDuration">
246+
/// The maximum age of a cache object before the object is treated as
247+
/// expired and unusable. Cache objects older than this will be treated
248+
/// as a cache miss.
249+
/// <returns></returns>
250+
public static IObservable<T> PutAndUpdateIndex<T>(this IBlobCache blobCache,
251+
string key,
252+
Func<IObservable<T>> fetchFunc,
253+
TimeSpan maxCacheDuration)
254+
where T : CacheItem
255+
{
256+
return Observable.Defer(() =>
257+
{
258+
var absoluteExpiration = blobCache.Scheduler.Now + maxCacheDuration;
259+
return blobCache.GetOrCreateObject(key, () => CacheIndex.Create(key))
260+
.SelectMany(index => fetchFunc()
261+
.Catch<T, Exception>(Observable.Throw<T>)
262+
.SelectMany(x => x.Save<T>(blobCache, key, absoluteExpiration))
263+
.Do(x => index.AddAndSave(blobCache, key, x, absoluteExpiration))
264+
);
265+
});
266+
}
267+
237268
static bool IsExpired(IBlobCache blobCache, DateTimeOffset itemCreatedAt, TimeSpan cacheDuration)
238269
{
239270
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
@@ -128,6 +128,7 @@
128128
<Compile Include="Factories\UIFactory.cs" />
129129
<Compile Include="GlobalSuppressions.cs" />
130130
<Compile Include="Infrastructure\LoggingConfiguration.cs" />
131+
<Compile Include="Models\BranchModel.cs" />
131132
<Compile Include="Models\PullRequestModel.cs" />
132133
<Compile Include="Resources.Designer.cs">
133134
<AutoGen>True</AutoGen>
@@ -145,6 +146,7 @@
145146
<Compile Include="Services\ImageDownloader.cs" />
146147
<Compile Include="Services\GitClient.cs" />
147148
<Compile Include="Services\ModelService.cs" />
149+
<Compile Include="Services\PullRequestService.cs" />
148150
<Compile Include="Services\RepositoryCloneService.cs" />
149151
<Compile Include="Extensions\FileExtensions.cs" />
150152
<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
@@ -126,6 +126,9 @@ public IAccount Assignee
126126
set { assignee = value; this.RaisePropertyChange(); }
127127
}
128128

129+
public ISimpleRepositoryModel Repository { get; }
130+
public IBranch Head { get; }
131+
public IBranch Base { get; }
129132

130133
[return: AllowNull] // nullguard thinks a string.Format can return null. sigh.
131134
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
@@ -171,6 +171,24 @@ public ITrackingCollection<IPullRequestModel> GetPullRequests(ISimpleRepositoryM
171171
return collection;
172172
}
173173

174+
public IObservable<IPullRequestModel> CreatePullRequest(IPullRequestModel pr, ISimpleRepositoryModel repository)
175+
{
176+
var keyobs = GetUserFromCache()
177+
.Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|pr", user.Login, repository.Name));
178+
179+
return Observable.Defer(() => keyobs
180+
.SelectMany(key =>
181+
hostCache.PutAndUpdateIndex(key, () =>
182+
apiClient.CreatePullRequest(new NewPullRequest(pr.Title, pr.Head.Name, pr.Base.Name),
183+
repository.CloneUrl.Owner,
184+
repository.CloneUrl.RepositoryName)
185+
.Select(PullRequestCacheItem.Create),
186+
TimeSpan.FromMinutes(30))
187+
)
188+
.Select(Create)
189+
);
190+
}
191+
174192
public IObservable<Unit> InvalidateAll()
175193
{
176194
return hostCache.InvalidateAll().ContinueAfter(() => hostCache.Vacuum());
@@ -234,12 +252,22 @@ IObservable<IReadOnlyList<IRepositoryModel>> GetOrganizationRepositories(string
234252
});
235253
}
236254

255+
public IObservable<IBranch> GetBranches(ISimpleRepositoryModel repo)
256+
{
257+
var keyobs = GetUserFromCache()
258+
.Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|branch", user.Login, repo.Name));
259+
260+
return Observable.Defer(() => keyobs
261+
.SelectMany(key => apiClient.GetBranches(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName)))
262+
.Select(Create);
263+
}
264+
237265
static LicenseItem Create(LicenseCacheItem licenseCacheItem)
238266
{
239267
return new LicenseItem(licenseCacheItem.Key, licenseCacheItem.Name);
240268
}
241269

242-
Models.Account Create(AccountCacheItem accountCacheItem)
270+
IAccount Create(AccountCacheItem accountCacheItem)
243271
{
244272
return new Models.Account(
245273
accountCacheItem.Login,
@@ -275,6 +303,11 @@ IPullRequestModel Create(PullRequestCacheItem prCacheItem)
275303
};
276304
}
277305

306+
IBranch Create(Branch branch)
307+
{
308+
return new BranchModel(branch);
309+
}
310+
278311
public IObservable<Unit> InsertUser(AccountCacheItem user)
279312
{
280313
return hostCache.InsertObject("user", user);
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,5 +33,7 @@ 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
}
3739
}

0 commit comments

Comments
 (0)