PR Creation: Push local branches and handle forks properly #502
Ok, this is ready for a first pass at review. There's no progress bars yet while creating a PR, but the form is disabled while it's happening. If a PR is created from a fork to a branch upstream, the list won't show any PRs, which will certainly be confusing, so we need to show a messsage indicating the link to the newly created PR, which is not done yet.
Expected behaviour:
- The list of branches should show upstream branches (prefixed with owner of repo) and list of fork branches, if the repo is a fork. If it isn't, it should only show the repo branches, no prefix
- When creating a PR from a fork, it should select the upstream default branch.
- When creating a PR from a non-fork, it should select the repo's default branch
- When creating a PR targeting the same repo, the PR should show up on the list afterwards
- When creating a PR targeting an upstream branch, a message should show up linking to the new PR on the website (it's not listed) - this isn't happening yet
- While loading data, form should be disabled (might be too fast to see)
- While processing a PR creation, form should be disabled
| @@ -37,13 +37,12 @@ public string LocalRepositoryName | ||
| IAccount account, | ||
| IApiClient apiClient) | ||
| { | ||
| - return Observable.Defer(() => Observable.Return(activeRepository)) | ||
| - .SelectMany(r => apiClient.CreateRepository(newRepository, account.Login, account.IsUser) | ||
| - .Select(gitHubRepo => Tuple.Create(gitHubRepo, r))) | ||
| - .SelectMany(repo => gitClient.SetRemote(repo.Item2, "origin", new Uri(repo.Item1.CloneUrl)).Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.Push(repo.Item2, "master", "origin").Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.Fetch(repo.Item2, "origin").Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.SetTrackingBranch(repo.Item2, "master", "origin").Select(_ => repo.Item1)); | ||
| + return Observable.Defer(() => apiClient.CreateRepository(newRepository, account.Login, account.IsUser) | ||
| + .Select(remoteRepo => new { RemoteRepo = remoteRepo, LocalRepo = activeRepository })) |
|
Ooops, I forgot I included this. I've been meaning to clean up this tuple for ages and always end up not doing it. Oh well, now done.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| } | ||
| - } | ||
| + return Observable.Return(ret); |
|
This will return an observable that contains
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| - return null; | ||
| + if (!repo.Branches[sourceBranch.Name].IsTracking) | ||
| + await gitClient.SetTrackingBranch(repo, sourceBranch.Name, remote.Name); | ||
| + | ||
| + // delay things a bit to avoid a race between pushing a new branch and creating a PR on it | ||
| + if (Splat.ModeDetector.Current.InUnitTestRunner().GetValueOrDefault()) |
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| @@ -37,13 +37,12 @@ public string LocalRepositoryName | ||
| IAccount account, | ||
| IApiClient apiClient) | ||
| { | ||
| - return Observable.Defer(() => Observable.Return(activeRepository)) | ||
| - .SelectMany(r => apiClient.CreateRepository(newRepository, account.Login, account.IsUser) | ||
| - .Select(gitHubRepo => Tuple.Create(gitHubRepo, r))) | ||
| - .SelectMany(repo => gitClient.SetRemote(repo.Item2, "origin", new Uri(repo.Item1.CloneUrl)).Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.Push(repo.Item2, "master", "origin").Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.Fetch(repo.Item2, "origin").Select(_ => repo)) | ||
| - .SelectMany(repo => gitClient.SetTrackingBranch(repo.Item2, "master", "origin").Select(_ => repo.Item1)); | ||
| + return Observable.Defer(() => apiClient.CreateRepository(newRepository, account.Login, account.IsUser) | ||
| + .Select(remoteRepo => new { RemoteRepo = remoteRepo, LocalRepo = activeRepository })) | ||
| + .SelectMany(repo => gitClient.SetRemote(repo.LocalRepo, "origin", new Uri(repo.RemoteRepo.CloneUrl)).Select(_ => repo)) | ||
| + .SelectMany(repo => gitClient.Push(repo.LocalRepo, "master", "origin").Select(_ => repo)) | ||
| + .SelectMany(repo => gitClient.Fetch(repo.LocalRepo, "origin").Select(_ => repo)) | ||
| + .SelectMany(repo => gitClient.SetTrackingBranch(repo.LocalRepo, "master", "origin").Select(_ => repo.RemoteRepo)); |
|
Would the intention here would be clear as:
? The Actually no, ingore this:
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| TitleValidator = ReactivePropertyValidator.ForObservable(titleObs) | ||
| .IfNullOrEmpty(Resources.PullRequestCreationTitleValidatorEmpty); | ||
| var branchObs = this.WhenAny( | ||
| - x => x.TargetBranch, | ||
| - x => x.SourceBranch, | ||
| - (target, source) => new { Source = source.Value, Target = target.Value }) | ||
| - .Where(_ => initialized) | ||
| - .Merge(initializationComplete.Select(_ => new { Source = SourceBranch, Target = TargetBranch })); | ||
| + x => x.TargetBranch, | ||
| + x => x.SourceBranch, | ||
| + (target, source) => new { Source = source.Value, Target = target.Value }) | ||
| + .Where(_ => Initialized) | ||
| + .Merge(this.WhenAnyValue(x => x.Initialized).Where(x => x).Select(_ => new { Source = SourceBranch, Target = TargetBranch })); |
|
Good change to remove the
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| @@ -96,68 +119,93 @@ public class PullRequestCreationViewModel : BaseViewModel, IPullRequestCreationV | ||
| notifications.ShowError(error?.Message ?? ex.Message); | ||
| return Observable.Empty<IPullRequestModel>(); | ||
| })); | ||
| + isExecuting = CreatePullRequest.IsExecuting.ToProperty(this, x => x.IsExecuting); |
|
I really don't like having to have this
Oh, and then looking 3 lines below I see it is. I missed that previously, it would've answered my question.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| } | ||
| + public IReadOnlyList<IBranch> Branches => branchesList; |
|
Why are both
They were mutated at one point in this rewrite, but they're not anymore. I'll fixicate!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| @@ -10,7 +10,7 @@ public static class SimpleRepositoryModelExtensions | ||
| { | ||
| public static bool HasCommits(this ISimpleRepositoryModel repository) | ||
| { | ||
| - var repo = GitService.GitServiceHelper.GetRepo(repository.LocalPath); | ||
| + var repo = GitService.GitServiceHelper.GetRepository(repository.LocalPath); |
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| string Name { get; } | ||
| + ISimpleRepositoryModel Repository { get; set; } | ||
| + bool IsTracking { get; set; } | ||
| + string DisplayName { get; set; } |
|
Could some of these properties be made readonly? It kinda worries me to have them all read/write as it can be difficult to tell how they can change. In what circumstances can they change? Remnants of prototyping.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| } | ||
| bool IEquatable<SimpleRepositoryModel>.Equals(SimpleRepositoryModel other) | ||
| { | ||
| if (ReferenceEquals(this, other)) | ||
| return true; | ||
| - return other != null && String.Equals(Name, other.Name) && String.Equals(CloneUrl, other.CloneUrl) && String.Equals(LocalPath?.TrimEnd('\\'), other.LocalPath?.TrimEnd('\\'), StringComparison.CurrentCultureIgnoreCase); | ||
| + return other != null && String.Equals(Name, other.Name) && String.Equals(Owner, other.Owner) && String.Equals(CloneUrl, other.CloneUrl) && String.Equals(LocalPath?.TrimEnd('\\'), other.LocalPath?.TrimEnd('\\'), StringComparison.CurrentCultureIgnoreCase); |
|
Kinda worries me to see this long line copy/pasted in 2 places. Could you make
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
| /// <returns></returns> | ||
| - public static UriString GetOriginUri(IRepository repo) | ||
| + public UriString GetOriginUri(IRepository repo, string remote = "origin") |
|
This probably should now be called "GetRemoteUri" and shouldn't have "origin" in its doc comments any more.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
Ok, we're now showing notifications when a PR is created, with a link to the created PR on the website. If the PR is created upstream, it won't show up on the PR list but the user will be able to go to it so hopefully it won't be too confusing.
This is how it works (the url opened is wrong in this gif but that's already fixed)

| @@ -0,0 +1,14 @@ | ||
| +namespace GitHub.ViewModels | ||
| +{ | ||
| + public interface IInfoPanel | ||
| + { | ||
| + string Message { get; set; } | ||
| + MessageType MessageType { get; set; } | ||
| + } |
|
Interface probably not needed, but added it anyway to have a place to keep the
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
|
Fixes #501
When creating PRs, we should do the following