Example #1
0
        public PullRequestListViewModel(
            IRepositoryHost repositoryHost,
            ILocalRepositoryModel repository,
            IPackageSettings settings)
        {
            this.repositoryHost = repositoryHost;
            this.repository     = repository;
            this.settings       = settings;

            Title = Resources.PullRequestsNavigationItemText;

            this.listSettings = settings.UIState
                                .GetOrCreateRepositoryState(repository.CloneUrl)
                                .PullRequests;

            States = new List <PullRequestState> {
                new PullRequestState {
                    IsOpen = true, Name = "Open"
                },
                new PullRequestState {
                    IsOpen = false, Name = "Closed"
                },
                new PullRequestState {
                    Name = "All"
                }
            };

            trackingAuthors = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAssignees = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                  OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAuthors.Subscribe();
            trackingAssignees.Subscribe();

            Authors   = trackingAuthors.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAuthor));
            Assignees = trackingAssignees.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAssignee));

            PullRequests          = new TrackingCollection <IPullRequestModel>();
            pullRequests.Comparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            pullRequests.NewerComparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            this.WhenAny(x => x.SelectedState, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(s => UpdateFilter(s, SelectedAssignee, SelectedAuthor));

            this.WhenAny(x => x.SelectedAssignee, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
            .Subscribe(a => UpdateFilter(SelectedState, a, SelectedAuthor));

            this.WhenAny(x => x.SelectedAuthor, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
            .Subscribe(a => UpdateFilter(SelectedState, SelectedAssignee, a));

            SelectedState   = States.FirstOrDefault(x => x.Name == listSettings.SelectedState) ?? States[0];
            OpenPullRequest = ReactiveCommand.Create();
            OpenPullRequest.Subscribe(DoOpenPullRequest);
            CreatePullRequest = ReactiveCommand.Create();
            CreatePullRequest.Subscribe(_ => DoCreatePullRequest());
        }
        public GistCreationViewModel(
            IRepositoryHost repositoryHost,
            ISelectedTextProvider selectedTextProvider,
            IGistPublishService gistPublishService,
            IUsageTracker usageTracker)
        {
            Title = Resources.CreateGistTitle;
            apiClient = repositoryHost.ApiClient;
            this.gistPublishService = gistPublishService;
            this.usageTracker = usageTracker;

            FileName = VisualStudio.Services.GetFileNameFromActiveDocument() ?? Resources.DefaultGistFileName;
            SelectedText = selectedTextProvider.GetSelectedText();

            // This class is only instantiated after we are logged into to a github account, so we should be safe to grab the first one here as the defaut.
            account = repositoryHost.ModelService.GetAccounts()
                .FirstAsync()
                .Select(a => a.First())
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToProperty(this, vm => vm.Account);

            var canCreateGist = this.WhenAny( 
                x => x.FileName,
                fileName => !String.IsNullOrEmpty(fileName.Value));

            CreateGist = ReactiveCommand.CreateAsyncObservable(canCreateGist, OnCreateGist);
        }
Example #3
0
        public GistCreationViewModel(
            IRepositoryHost repositoryHost,
            ISelectedTextProvider selectedTextProvider,
            IGistPublishService gistPublishService)
        {
            Title     = Resources.CreateGistTitle;
            apiClient = repositoryHost.ApiClient;
            this.gistPublishService = gistPublishService;

            FileName     = VisualStudio.Services.GetFileNameFromActiveDocument() ?? Resources.DefaultGistFileName;
            SelectedText = selectedTextProvider.GetSelectedText();

            // This class is only instantiated after we are logged into to a github account, so we should be safe to grab the first one here as the defaut.
            account = repositoryHost.ModelService.GetAccounts()
                      .FirstAsync()
                      .Select(a => a.First())
                      .ObserveOn(RxApp.MainThreadScheduler)
                      .ToProperty(this, vm => vm.Account);

            var canCreateGist = this.WhenAny(
                x => x.FileName,
                fileName => !String.IsNullOrEmpty(fileName.Value));

            CreateGist = ReactiveCommand.CreateAsyncObservable(canCreateGist, OnCreateGist);
        }
        async Task <IPullRequestModel> PushAndCreatePR(IRepositoryHost host,
                                                       ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
                                                       IBranch sourceBranch, IBranch targetBranch,
                                                       string title, string body)
        {
            var repo = await Task.Run(() => gitService.GetRepository(sourceRepository.LocalPath));

            var remote = await gitClient.GetHttpRemote(repo, "origin");

            await gitClient.Push(repo, sourceBranch.Name, remote.Name);

            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())
            {
                await Task.Delay(TimeSpan.FromSeconds(5));
            }

            var ret = await host.ModelService.CreatePullRequest(sourceRepository, targetRepository, sourceBranch, targetBranch, title, body);

            usageTracker.IncrementUpstreamPullRequestCount();
            return(ret);
        }
        public StartPageCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem)
        {
            this.operatingSystem = operatingSystem;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);

            var baseRepositoryPath = this.WhenAny(
                x => x.BaseRepositoryPath,
                x => x.SelectedRepository,
                (x, y) => x.Value);

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath)
                                          .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                                          .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                                          .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                                          .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid)
                                          .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);

            canClone     = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.Create(canCloneObservable);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
        }
Example #6
0
        public IObservable <Unit> LogOut(IRepositoryHost host)
        {
            Guard.ArgumentNotNull(host, nameof(host));

            var address  = host.Address;
            var isDotCom = HostAddress.GitHubDotComHostAddress == address;

            return(host.LogOut()
                   .ObserveOn(RxApp.MainThreadScheduler)
                   .Do(result =>
            {
                // reset the logged out host property to null
                // it'll know what to do
                if (isDotCom)
                {
                    GitHubHost = null;
                }
                else
                {
                    EnterpriseHost = null;
                }
                connectionManager.RemoveConnection(address);
                RepositoryHostFactory.Remove(host);
            }));
        }
Example #7
0
        public PullRequestListViewModel(
            IRepositoryHost repositoryHost,
            ILocalRepositoryModel repository,
            IPackageSettings settings)
        {
            this.repositoryHost = repositoryHost;
            this.repository     = repository;
            this.settings       = settings;

            this.listSettings = settings.UIState
                                .GetOrCreateRepositoryState(repository.CloneUrl)
                                .PullRequests;

            openPullRequestCommand = ReactiveCommand.Create();
            openPullRequestCommand.Subscribe(_ =>
            {
                VisualStudio.Services.DefaultExportProvider.GetExportedValue <IVisualStudioBrowser>().OpenUrl(repositoryHost.Address.WebUri);
            });

            States = new List <PullRequestState> {
                new PullRequestState {
                    IsOpen = true, Name = "Open"
                },
                new PullRequestState {
                    IsOpen = false, Name = "Closed"
                },
                new PullRequestState {
                    Name = "All"
                }
            };

            trackingAuthors = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAssignees = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                  OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAuthors.Subscribe();
            trackingAssignees.Subscribe();

            Authors   = trackingAuthors.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAuthor));
            Assignees = trackingAssignees.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAssignee));

            PullRequests          = new TrackingCollection <IPullRequestModel>();
            pullRequests.Comparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            pullRequests.NewerComparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            this.WhenAny(x => x.SelectedState, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(s => UpdateFilter(s, SelectedAssignee, SelectedAuthor));

            this.WhenAny(x => x.SelectedAssignee, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
            .Subscribe(a => UpdateFilter(SelectedState, a, SelectedAuthor));

            this.WhenAny(x => x.SelectedAuthor, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
            .Subscribe(a => UpdateFilter(SelectedState, SelectedAssignee, a));

            SelectedState = States.FirstOrDefault(x => x.Name == listSettings.SelectedState) ?? States[0];
        }
        public RepositoryCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem,
            INotificationService notificationService,
            IUsageTracker usageTracker)
        {
            this.repositoryHost = repositoryHost;
            this.cloneService = cloneService;
            this.operatingSystem = operatingSystem;
            this.notificationService = notificationService;
            this.usageTracker = usageTracker;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);

            Repositories = new TrackingCollection<IRemoteRepositoryModel>();
            repositories.ProcessingDelay = TimeSpan.Zero;
            repositories.Comparer = OrderedComparer<IRemoteRepositoryModel>.OrderBy(x => x.Owner).ThenBy(x => x.Name).Compare;
            repositories.Filter = FilterRepository;
            repositories.NewerComparer = OrderedComparer<IRemoteRepositoryModel>.OrderByDescending(x => x.UpdatedAt).Compare;

            filterTextIsEnabled = this.WhenAny(x => x.IsLoading,
                loading => loading.Value || repositories.UnfilteredCount > 0 && !LoadingFailed)
                .ToProperty(this, x => x.FilterTextIsEnabled);

            this.WhenAny(x => x.IsLoading, x => x.LoadingFailed,
                (loading, failed) => !loading.Value && !failed.Value && repositories.UnfilteredCount == 0)
                .Subscribe(x => NoRepositoriesFound = x);

            this.WhenAny(x => x.FilterText, x => x.Value)
                .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase)
                .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler)
                .Subscribe(_ => repositories.Filter = FilterRepository);

            var baseRepositoryPath = this.WhenAny(
                x => x.BaseRepositoryPath,
                x => x.SelectedRepository,
                (x, y) => x.Value);

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath)
                .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid)
                .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);
            canClone = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
                .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
            NoRepositoriesFound = true;
        }
Example #9
0
        public RepositoryCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem,
            INotificationService notificationService)
        {
            this.repositoryHost      = repositoryHost;
            this.cloneService        = cloneService;
            this.operatingSystem     = operatingSystem;
            this.notificationService = notificationService;

            Title                   = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);
            Repositories            = new ReactiveList <IRepositoryModel>();
            loadRepositoriesCommand = ReactiveCommand.CreateAsyncObservable(OnLoadRepositories);
            isLoading               = this.WhenAny(x => x.LoadingFailed, x => x.Value)
                                      .CombineLatest(loadRepositoriesCommand.IsExecuting, (failed, loading) => !failed && loading)
                                      .ToProperty(this, x => x.IsLoading);
            loadRepositoriesCommand.Subscribe(Repositories.AddRange);
            filterTextIsEnabled = this.WhenAny(x => x.Repositories.Count, x => x.Value > 0)
                                  .ToProperty(this, x => x.FilterTextIsEnabled);
            noRepositoriesFound = this.WhenAny(x => x.FilterTextIsEnabled, x => x.IsLoading, x => x.LoadingFailed
                                               , (any, loading, failed) => !any.Value && !loading.Value && !failed.Value)
                                  .ToProperty(this, x => x.NoRepositoriesFound);

            var filterResetSignal = this.WhenAny(x => x.FilterText, x => x.Value)
                                    .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase)
                                    .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler);

            FilteredRepositories = Repositories.CreateDerivedCollection(
                x => x,
                filter: FilterRepository,
                signalReset: filterResetSignal
                );

            var baseRepositoryPath = this.WhenAny(
                x => x.BaseRepositoryPath,
                x => x.SelectedRepository,
                (x, y) => x.Value);

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath)
                                          .IfNullOrEmpty("Please enter a repository path")
                                          .IfTrue(x => x.Length > 200, "Path too long")
                                          .IfContainsInvalidPathChars("Path contains invalid characters")
                                          .IfPathNotRooted("Please enter a valid path")
                                          .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);

            canClone     = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
        }
        public PullRequestListViewModel(IRepositoryHost repositoryHost, ISimpleRepositoryModel repository)
        {
            this.repositoryHost = repositoryHost;
            this.repository     = repository;

            openPullRequestCommand = ReactiveCommand.Create();
            openPullRequestCommand.Subscribe(_ =>
            {
                VisualStudio.Services.DefaultExportProvider.GetExportedValue <IVisualStudioBrowser>().OpenUrl(repositoryHost.Address.WebUri);
            });

            States = new List <PullRequestState> {
                new PullRequestState {
                    IsOpen = true, Name = "Open"
                },
                new PullRequestState {
                    IsOpen = false, Name = "Closed"
                },
                new PullRequestState {
                    Name = "All"
                }
            };
            SelectedState = States[0];

            this.WhenAny(x => x.SelectedState, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(s => UpdateFilter(s, SelectedAssignee, SelectedAuthor));

            this.WhenAny(x => x.SelectedAssignee, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(a => UpdateFilter(SelectedState, a, SelectedAuthor));

            this.WhenAny(x => x.SelectedAuthor, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(a => UpdateFilter(SelectedState, SelectedAssignee, a));

            trackingAuthors = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAssignees = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                  OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAuthors.Subscribe();
            trackingAssignees.Subscribe();

            Authors = trackingAuthors.CreateListenerCollection(new List <IAccount> {
                EmptyUser
            });
            Assignees = trackingAssignees.CreateListenerCollection(new List <IAccount> {
                EmptyUser
            });

            PullRequests          = new TrackingCollection <IPullRequestModel>();
            pullRequests.Comparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            pullRequests.Filter        = (pr, i, l) => pr.IsOpen;
            pullRequests.NewerComparer = OrderedComparer <IPullRequestModel> .OrderByDescending(x => x.UpdatedAt).Compare;
        }
Example #11
0
        protected IConnection SetupConnection(IServiceProvider provider, IRepositoryHosts hosts,
                                              IRepositoryHost host)
        {
            var connection = provider.GetConnection();

            connection.Login().Returns(Observable.Return(connection));
            hosts.LookupHost(connection.HostAddress).Returns(host);
            host.IsLoggedIn.Returns(true);
            return(connection);
        }
        public PullRequestListViewModel(
            IRepositoryHost repositoryHost,
            ILocalRepositoryModel repository,
            IPackageSettings settings)
        {
            this.repositoryHost = repositoryHost;
            this.repository = repository;
            this.settings = settings;

            Title = Resources.PullRequestsNavigationItemText;

            this.listSettings = settings.UIState
                .GetOrCreateRepositoryState(repository.CloneUrl)
                .PullRequests;

            openPullRequestCommand = ReactiveCommand.Create();
            openPullRequestCommand.Subscribe(_ =>
            {
                VisualStudio.Services.DefaultExportProvider.GetExportedValue<IVisualStudioBrowser>().OpenUrl(repositoryHost.Address.WebUri);
            });

            States = new List<PullRequestState> {
                new PullRequestState { IsOpen = true, Name = "Open" },
                new PullRequestState { IsOpen = false, Name = "Closed" },
                new PullRequestState { Name = "All" }
            };

            trackingAuthors = new TrackingCollection<IAccount>(Observable.Empty<IAccount>(),
                OrderedComparer<IAccount>.OrderByDescending(x => x.Login).Compare);
            trackingAssignees = new TrackingCollection<IAccount>(Observable.Empty<IAccount>(),
                OrderedComparer<IAccount>.OrderByDescending(x => x.Login).Compare);
            trackingAuthors.Subscribe();
            trackingAssignees.Subscribe();

            Authors = trackingAuthors.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAuthor));
            Assignees = trackingAssignees.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAssignee));

            PullRequests = new TrackingCollection<IPullRequestModel>();
            pullRequests.Comparer = OrderedComparer<IPullRequestModel>.OrderByDescending(x => x.UpdatedAt).Compare;
            pullRequests.NewerComparer = OrderedComparer<IPullRequestModel>.OrderByDescending(x => x.UpdatedAt).Compare;

            this.WhenAny(x => x.SelectedState, x => x.Value)
                .Where(x => PullRequests != null)
                .Subscribe(s => UpdateFilter(s, SelectedAssignee, SelectedAuthor));

            this.WhenAny(x => x.SelectedAssignee, x => x.Value)
                .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
                .Subscribe(a => UpdateFilter(SelectedState, a, SelectedAuthor));

            this.WhenAny(x => x.SelectedAuthor, x => x.Value)
                .Where(x => PullRequests != null && x != EmptyUser && IsLoaded)
                .Subscribe(a => UpdateFilter(SelectedState, SelectedAssignee, a));

            SelectedState = States.FirstOrDefault(x => x.Name == listSettings.SelectedState) ?? States[0];
        }
Example #13
0
    static RepositoryCloneViewModel GetVM(IRepositoryHost repositoryHost, IRepositoryCloneService cloneService,
                                          IOperatingSystem os, INotificationService notificationService, IUsageTracker usageTracker)
    {
        var vm = new RepositoryCloneViewModel(
            repositoryHost,
            cloneService,
            os);

        vm.Initialize(null);
        return(vm);
    }
 static RepositoryCloneViewModel GetVM(IRepositoryHost repositoryHost, IRepositoryCloneService cloneService,
     IOperatingSystem os, INotificationService notificationService, IUsageTracker usageTracker)
 {
     var vm = new RepositoryCloneViewModel(
         repositoryHost,
         cloneService,
         os,
         notificationService,
         usageTracker);
     vm.Initialize(null);
     return vm;
 }
        public RepositoryCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem,
            IVSServices vsServices)
        {
            this.repositoryHost  = repositoryHost;
            this.cloneService    = cloneService;
            this.operatingSystem = operatingSystem;
            this.vsServices      = vsServices;

            Title                   = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);
            Repositories            = new ReactiveList <IRepositoryModel>();
            loadRepositoriesCommand = ReactiveCommand.CreateAsyncObservable(OnLoadRepositories);
            isLoading               = this.WhenAny(x => x.LoadingFailed, x => x.Value)
                                      .CombineLatest(loadRepositoriesCommand.IsExecuting, (failed, loading) => !failed && loading)
                                      .ToProperty(this, x => x.IsLoading);
            loadRepositoriesCommand.Subscribe(Repositories.AddRange);
            filterTextIsEnabled = this.WhenAny(x => x.Repositories.Count, x => x.Value > 0)
                                  .ToProperty(this, x => x.FilterTextIsEnabled);
            noRepositoriesFound = this.WhenAny(x => x.FilterTextIsEnabled, x => x.IsLoading, x => x.LoadingFailed
                                               , (any, loading, failed) => !any.Value && !loading.Value && !failed.Value)
                                  .ToProperty(this, x => x.NoRepositoriesFound);

            var filterResetSignal = this.WhenAny(x => x.FilterText, x => x.Value)
                                    .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase)
                                    .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler);

            FilteredRepositories = Repositories.CreateDerivedCollection(
                x => x,
                filter: FilterRepository,
                signalReset: filterResetSignal
                );

            BaseRepositoryPathValidator = this.CreateBaseRepositoryPathValidator();

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);

            canClone     = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
        }
        public RepositoryCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem,
            INotificationService notificationService)
        {
            this.repositoryHost = repositoryHost;
            this.cloneService = cloneService;
            this.operatingSystem = operatingSystem;
            this.notificationService = notificationService;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);
            Repositories = new ReactiveList<IRepositoryModel>();
            loadRepositoriesCommand = ReactiveCommand.CreateAsyncObservable(OnLoadRepositories);
            isLoading = this.WhenAny(x => x.LoadingFailed, x => x.Value)
                .CombineLatest(loadRepositoriesCommand.IsExecuting, (failed, loading) => !failed && loading)
                .ToProperty(this, x => x.IsLoading);
            loadRepositoriesCommand.Subscribe(Repositories.AddRange);
            filterTextIsEnabled = this.WhenAny(x => x.Repositories.Count, x => x.Value > 0)
                .ToProperty(this, x => x.FilterTextIsEnabled);
            noRepositoriesFound = this.WhenAny(x => x.FilterTextIsEnabled, x => x.IsLoading, x => x.LoadingFailed
                , (any, loading, failed) => !any.Value && !loading.Value && !failed.Value)
                .ToProperty(this, x => x.NoRepositoriesFound);

            var filterResetSignal = this.WhenAny(x => x.FilterText, x => x.Value)
                .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase)
                .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler);

            FilteredRepositories = Repositories.CreateDerivedCollection(
                x => x,
                filter: FilterRepository,
                signalReset: filterResetSignal
            );

            BaseRepositoryPathValidator = this.CreateBaseRepositoryPathValidator();

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);
            canClone = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
                .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
        }
        public IObservable <IPullRequestModel> CreatePullRequest(IRepositoryHost host,
                                                                 ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
                                                                 IBranch sourceBranch, IBranch targetBranch,
                                                                 string title, string body
                                                                 )
        {
            Extensions.Guard.ArgumentNotNull(host, nameof(host));
            Extensions.Guard.ArgumentNotNull(sourceRepository, nameof(sourceRepository));
            Extensions.Guard.ArgumentNotNull(targetRepository, nameof(targetRepository));
            Extensions.Guard.ArgumentNotNull(sourceBranch, nameof(sourceBranch));
            Extensions.Guard.ArgumentNotNull(targetBranch, nameof(targetBranch));
            Extensions.Guard.ArgumentNotNull(title, nameof(title));
            Extensions.Guard.ArgumentNotNull(body, nameof(body));

            return(PushAndCreatePR(host, sourceRepository, targetRepository, sourceBranch, targetBranch, title, body).ToObservable());
        }
Example #18
0
        public IObservable<IPullRequestModel> CreatePullRequest(IRepositoryHost host,
            ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
            IBranch sourceBranch, IBranch targetBranch,
            string title, string body
        )
        {
            Extensions.Guard.ArgumentNotNull(host, nameof(host));
            Extensions.Guard.ArgumentNotNull(sourceRepository, nameof(sourceRepository));
            Extensions.Guard.ArgumentNotNull(targetRepository, nameof(targetRepository));
            Extensions.Guard.ArgumentNotNull(sourceBranch, nameof(sourceBranch));
            Extensions.Guard.ArgumentNotNull(targetBranch, nameof(targetBranch));
            Extensions.Guard.ArgumentNotNull(title, nameof(title));
            Extensions.Guard.ArgumentNotNull(body, nameof(body));

            return PushAndCreatePR(host, sourceRepository, targetRepository, sourceBranch, targetBranch, title, body).ToObservable();
        }
Example #19
0
        public IObservable <Unit> LogOut(IRepositoryHost host)
        {
            var address  = host.Address;
            var isDotCom = HostAddress.GitHubDotComHostAddress == address;

            return(host.LogOut()
                   .Do(result =>
            {
                // reset the logged out host property to null
                // it'll know what to do
                if (isDotCom)
                {
                    GitHubHost = null;
                }
                else
                {
                    EnterpriseHost = null;
                }
                connectionManager.RemoveConnection(address);
                RepositoryHostFactory.Remove(host);
            }));
        }
        public StartPageCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem,
            INotificationService notificationService,
            IUsageTracker usageTracker)
        {
            this.cloneService = cloneService;
            this.operatingSystem = operatingSystem;
            this.notificationService = notificationService;
            this.usageTracker = usageTracker;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);

            var baseRepositoryPath = this.WhenAny(
                x => x.BaseRepositoryPath,
                x => x.SelectedRepository,
                (x, y) => x.Value);

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath)
                .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid)
                .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);
            canClone = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
                .Subscribe();
            BaseRepositoryPath = cloneService.DefaultClonePath;
        }
Example #21
0
    public void CreatePullRequestAllArgsMandatory()
    {
        var serviceProvider = Substitutes.ServiceProvider;
        var service         = new PullRequestService(Substitute.For <IGitClient>(), serviceProvider.GetGitService(), serviceProvider.GetOperatingSystem(), Substitute.For <IUsageTracker>());

        IRepositoryHost       host       = null;
        ILocalRepositoryModel sourceRepo = null;
        ILocalRepositoryModel targetRepo = null;
        string  title  = null;
        string  body   = null;
        IBranch source = null;
        IBranch target = null;

        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        host = serviceProvider.GetRepositoryHosts().GitHubHost;
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        sourceRepo = new LocalRepositoryModel("name", new GitHub.Primitives.UriString("http://github.com/github/stuff"), "c:\\path");
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        targetRepo = new LocalRepositoryModel("name", new GitHub.Primitives.UriString("http://github.com/github/stuff"), "c:\\path");
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        title = "a title";
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        body = "a body";
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        source = new BranchModel("source", sourceRepo);
        Assert.Throws <ArgumentNullException>(() => service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body));

        target = new BranchModel("target", targetRepo);
        var pr = service.CreatePullRequest(host, sourceRepo, targetRepo, source, target, title, body);

        Assert.NotNull(pr);
    }
        public PullRequestCreationViewModel(IRepositoryHost repositoryHost, ILocalRepositoryModel activeRepo,
            IPullRequestService service, INotificationService notifications)
        {
            Extensions.Guard.ArgumentNotNull(repositoryHost, nameof(repositoryHost));
            Extensions.Guard.ArgumentNotNull(activeRepo, nameof(activeRepo));
            Extensions.Guard.ArgumentNotNull(service, nameof(service));
            Extensions.Guard.ArgumentNotNull(notifications, nameof(notifications));

            this.repositoryHost = repositoryHost;

            var obs = repositoryHost.ApiClient.GetRepository(activeRepo.Owner, activeRepo.Name)
                .Select(r => new RemoteRepositoryModel(r))
                .PublishLast();
            disposables.Add(obs.Connect());
            githubObs = obs;

            githubRepository = githubObs.ToProperty(this, x => x.GitHubRepository);

            this.WhenAnyValue(x => x.GitHubRepository)
                .WhereNotNull()
                .Subscribe(r =>
            {
                TargetBranch = r.IsFork ? r.Parent.DefaultBranch : r.DefaultBranch;
            });

            SourceBranch = activeRepo.CurrentBranch;
            service.GetPullRequestTemplate(activeRepo)
                .Subscribe(x => Description = x ?? String.Empty, () => Description = Description ?? String.Empty);

            this.WhenAnyValue(x => x.Branches)
                .WhereNotNull()
                .Where(_ => TargetBranch != null)
                .Subscribe(x =>
                {
                    if (!x.Any(t => t.Equals(TargetBranch)))
                        TargetBranch = GitHubRepository.IsFork ? GitHubRepository.Parent.DefaultBranch : GitHubRepository.DefaultBranch;
                });

            SetupValidators();

            var whenAnyValidationResultChanges = this.WhenAny(
                x => x.TitleValidator.ValidationResult,
                x => x.BranchValidator.ValidationResult,
                x => x.IsBusy,
                (x, y, z) => (x.Value?.IsValid ?? false) && (y.Value?.IsValid ?? false) && !z.Value);

            this.WhenAny(x => x.BranchValidator.ValidationResult, x => x.GetValue())
                .WhereNotNull()
                .Where(x => !x.IsValid && x.DisplayValidationError)
                .Subscribe(x => notifications.ShowError(BranchValidator.ValidationResult.Message));

            createPullRequest = ReactiveCommand.CreateAsyncObservable(whenAnyValidationResultChanges,
                _ => service
                    .CreatePullRequest(repositoryHost, activeRepo, TargetBranch.Repository, SourceBranch, TargetBranch, PRTitle, Description ?? String.Empty)
                    .Catch<IPullRequestModel, Exception>(ex =>
                    {
                        log.Error(ex);

                        //TODO:Will need a uniform solution to HTTP exception message handling
                        var apiException = ex as ApiValidationException;
                        var error = apiException?.ApiError?.Errors?.FirstOrDefault();
                        notifications.ShowError(error?.Message ?? ex.Message);
                        return Observable.Empty<IPullRequestModel>();
                    }))
            .OnExecuteCompleted(pr =>
            {
                notifications.ShowMessage(String.Format(CultureInfo.CurrentCulture, Resources.PRCreatedUpstream, SourceBranch.DisplayName, TargetBranch.Repository.Owner + "/" + TargetBranch.Repository.Name + "#" + pr.Number,
                    TargetBranch.Repository.CloneUrl.ToRepositoryUrl().Append("pull/" + pr.Number)));
            });

            isExecuting = CreatePullRequest.IsExecuting.ToProperty(this, x => x.IsExecuting);

            this.WhenAnyValue(x => x.Initialized, x => x.GitHubRepository, x => x.Description, x => x.IsExecuting)
                .Select(x => !(x.Item1 && x.Item2 != null && x.Item3 != null && !x.Item4))
                .Subscribe(x => IsBusy = x);
        }
        public PullRequestCreationViewModel(IRepositoryHost repositoryHost, ISimpleRepositoryModel activeRepo,
                                            IPullRequestService service, INotificationService notifications)
        {
            Extensions.Guard.ArgumentNotNull(repositoryHost, nameof(repositoryHost));
            Extensions.Guard.ArgumentNotNull(activeRepo, nameof(activeRepo));
            Extensions.Guard.ArgumentNotNull(service, nameof(service));
            Extensions.Guard.ArgumentNotNull(notifications, nameof(notifications));

            this.repositoryHost = repositoryHost;

            var obs = repositoryHost.ApiClient.GetRepository(activeRepo.Owner, activeRepo.Name)
                      .Select(r => new RepositoryModel(r))
                      .PublishLast();

            disposables.Add(obs.Connect());
            githubObs = obs;

            githubRepository = githubObs.ToProperty(this, x => x.GitHubRepository);

            this.WhenAnyValue(x => x.GitHubRepository)
            .WhereNotNull()
            .Subscribe(r =>
            {
                TargetBranch = r.IsFork ? r.Parent.DefaultBranch : r.DefaultBranch;
            });

            SourceBranch = activeRepo.CurrentBranch;
            service.GetPullRequestTemplate(activeRepo)
            .Subscribe(x => Description = x ?? String.Empty, () => Description = Description ?? String.Empty);

            this.WhenAnyValue(x => x.Branches)
            .WhereNotNull()
            .Where(_ => TargetBranch != null)
            .Subscribe(x =>
            {
                if (!x.Any(t => t.Equals(TargetBranch)))
                {
                    TargetBranch = GitHubRepository.IsFork ? GitHubRepository.Parent.DefaultBranch : GitHubRepository.DefaultBranch;
                }
            });

            SetupValidators();

            var whenAnyValidationResultChanges = this.WhenAny(
                x => x.TitleValidator.ValidationResult,
                x => x.BranchValidator.ValidationResult,
                x => x.IsBusy,
                (x, y, z) => (x.Value?.IsValid ?? false) && (y.Value?.IsValid ?? false) && !z.Value);

            this.WhenAny(x => x.BranchValidator.ValidationResult, x => x.GetValue())
            .WhereNotNull()
            .Where(x => !x.IsValid && x.DisplayValidationError)
            .Subscribe(x => notifications.ShowError(BranchValidator.ValidationResult.Message));

            createPullRequest = ReactiveCommand.CreateAsyncObservable(whenAnyValidationResultChanges,
                                                                      _ => service
                                                                      .CreatePullRequest(repositoryHost, activeRepo, TargetBranch.Repository, SourceBranch, TargetBranch, PRTitle, Description ?? String.Empty)
                                                                      .Catch <IPullRequestModel, Exception>(ex =>
            {
                log.Error(ex);

                //TODO:Will need a uniform solution to HTTP exception message handling
                var apiException = ex as ApiValidationException;
                var error        = apiException?.ApiError?.Errors?.FirstOrDefault();
                notifications.ShowError(error?.Message ?? ex.Message);
                return(Observable.Empty <IPullRequestModel>());
            }))

                                .OnExecuteCompleted(pr =>
            {
                notifications.ShowMessage(String.Format(CultureInfo.CurrentCulture, Resources.PRCreatedUpstream, TargetBranch.Id,
                                                        TargetBranch.Repository.CloneUrl.ToRepositoryUrl().Append("pull/" + pr.Number)));
            });

            isExecuting = CreatePullRequest.IsExecuting.ToProperty(this, x => x.IsExecuting);

            this.WhenAnyValue(x => x.Initialized, x => x.GitHubRepository, x => x.Description, x => x.IsExecuting)
            .Select(x => !(x.Item1 && x.Item2 != null && x.Item3 != null && !x.Item4))
            .Subscribe(x => IsBusy = x);
        }
 public ConnectionRepositoryHostMap(IRepositoryHost repositoryHost)
 {
     CurrentRepositoryHost = repositoryHost;
 }
 public void Remove(IRepositoryHost host)
 {
     hosts.Remove(host);
 }
Example #26
0
 public ConnectionRepositoryHostMap(IRepositoryHost repositoryHost)
 {
     CurrentRepositoryHost = repositoryHost;
 }
Example #27
0
        public PullRequestListViewModel(
            IRepositoryHost repositoryHost,
            ILocalRepositoryModel repository,
            IPackageSettings settings,
            IVisualStudioBrowser visualStudioBrowser)
        {
            Guard.ArgumentNotNull(repositoryHost, nameof(repositoryHost));
            Guard.ArgumentNotNull(repository, nameof(repository));
            Guard.ArgumentNotNull(settings, nameof(settings));
            Guard.ArgumentNotNull(visualStudioBrowser, nameof(visualStudioBrowser));

            constructing             = true;
            this.repositoryHost      = repositoryHost;
            this.localRepository     = repository;
            this.settings            = settings;
            this.visualStudioBrowser = visualStudioBrowser;

            Title = Resources.PullRequestsNavigationItemText;

            this.listSettings = settings.UIState
                                .GetOrCreateRepositoryState(repository.CloneUrl)
                                .PullRequests;

            States = new List <PullRequestState> {
                new PullRequestState {
                    IsOpen = true, Name = "Open"
                },
                new PullRequestState {
                    IsOpen = false, Name = "Closed"
                },
                new PullRequestState {
                    Name = "All"
                }
            };

            trackingAuthors = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAssignees = new TrackingCollection <IAccount>(Observable.Empty <IAccount>(),
                                                                  OrderedComparer <IAccount> .OrderByDescending(x => x.Login).Compare);
            trackingAuthors.Subscribe();
            trackingAssignees.Subscribe();

            Authors   = trackingAuthors.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAuthor));
            Assignees = trackingAssignees.CreateListenerCollection(EmptyUser, this.WhenAnyValue(x => x.SelectedAssignee));

            CreatePullRequests();

            this.WhenAny(x => x.SelectedState, x => x.Value)
            .Where(x => PullRequests != null)
            .Subscribe(s => UpdateFilter(s, SelectedAssignee, SelectedAuthor));

            this.WhenAny(x => x.SelectedAssignee, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser)
            .Subscribe(a => UpdateFilter(SelectedState, a, SelectedAuthor));

            this.WhenAny(x => x.SelectedAuthor, x => x.Value)
            .Where(x => PullRequests != null && x != EmptyUser)
            .Subscribe(a => UpdateFilter(SelectedState, SelectedAssignee, a));

            this.WhenAnyValue(x => x.SelectedRepository)
            .Skip(1)
            .Subscribe(_ => ResetAndLoad());

            SelectedState   = States.FirstOrDefault(x => x.Name == listSettings.SelectedState) ?? States[0];
            OpenPullRequest = ReactiveCommand.Create();
            OpenPullRequest.Subscribe(DoOpenPullRequest);
            CreatePullRequest = ReactiveCommand.Create();
            CreatePullRequest.Subscribe(_ => DoCreatePullRequest());

            OpenPullRequestOnGitHub = ReactiveCommand.Create();
            OpenPullRequestOnGitHub.Subscribe(x => DoOpenPullRequestOnGitHub((int)x));

            constructing = false;
        }
Example #28
0
        public PullRequestCreationViewModel(IRepositoryHost repositoryHost, ILocalRepositoryModel activeRepo,
                                            IPullRequestService service, INotificationService notifications)
        {
            Extensions.Guard.ArgumentNotNull(repositoryHost, nameof(repositoryHost));
            Extensions.Guard.ArgumentNotNull(activeRepo, nameof(activeRepo));
            Extensions.Guard.ArgumentNotNull(service, nameof(service));
            Extensions.Guard.ArgumentNotNull(notifications, nameof(notifications));

            this.repositoryHost = repositoryHost;
            activeLocalRepo     = activeRepo;

            var obs = repositoryHost.ApiClient.GetRepository(activeRepo.Owner, activeRepo.Name)
                      .Select(r => new RemoteRepositoryModel(r))
                      .PublishLast();

            disposables.Add(obs.Connect());
            githubObs = obs;

            githubRepository = githubObs.ToProperty(this, x => x.GitHubRepository);

            this.WhenAnyValue(x => x.GitHubRepository)
            .WhereNotNull()
            .Subscribe(r =>
            {
                TargetBranch = r.IsFork ? r.Parent.DefaultBranch : r.DefaultBranch;
            });

            SourceBranch = activeRepo.CurrentBranch;

            this.WhenAnyValue(x => x.Branches)
            .WhereNotNull()
            .Where(_ => TargetBranch != null)
            .Subscribe(x =>
            {
                if (!x.Any(t => t.Equals(TargetBranch)))
                {
                    TargetBranch = GitHubRepository.IsFork ? GitHubRepository.Parent.DefaultBranch : GitHubRepository.DefaultBranch;
                }
            });

            SetupValidators();

            var uniqueCommits = this.WhenAnyValue(
                x => x.SourceBranch,
                x => x.TargetBranch)
                                .Where(x => x.Item1 != null && x.Item2 != null)
                                .Select(branches =>
            {
                var baseBranch    = branches.Item1.Name;
                var compareBranch = branches.Item2.Name;

                // We only need to get max two commits for what we're trying to achieve here.
                // If there's no commits we want to block creation of the PR, if there's one commits
                // we wan't to use its commit message as the PR title/body and finally if there's more
                // than one we'll use the branch name for the title.
                return(service.GetMessagesForUniqueCommits(activeRepo, baseBranch, compareBranch, maxCommits: 2)
                       .Catch <IReadOnlyList <CommitMessage>, Exception>(ex =>
                {
                    log.Warning(ex, "Could not load unique commits");
                    return Observable.Empty <IReadOnlyList <CommitMessage> >();
                }));
            })
                                .Switch()
                                .ObserveOn(RxApp.MainThreadScheduler)
                                .Replay(1)
                                .RefCount();

            var whenAnyValidationResultChanges = this.WhenAny(
                x => x.TitleValidator.ValidationResult,
                x => x.BranchValidator.ValidationResult,
                x => x.IsBusy,
                (x, y, z) => (x.Value?.IsValid ?? false) && (y.Value?.IsValid ?? false) && !z.Value);

            this.WhenAny(x => x.BranchValidator.ValidationResult, x => x.GetValue())
            .WhereNotNull()
            .Where(x => !x.IsValid && x.DisplayValidationError)
            .Subscribe(x => notifications.ShowError(BranchValidator.ValidationResult.Message));

            CreatePullRequest = ReactiveCommand.CreateAsyncObservable(whenAnyValidationResultChanges,
                                                                      _ => service
                                                                      .CreatePullRequest(repositoryHost, activeRepo, TargetBranch.Repository, SourceBranch, TargetBranch, PRTitle, Description ?? String.Empty)
                                                                      .Catch <IPullRequestModel, Exception>(ex =>
            {
                log.Error(ex, "Error creating pull request");

                //TODO:Will need a uniform solution to HTTP exception message handling
                var apiException = ex as ApiValidationException;
                var error        = apiException?.ApiError?.Errors?.FirstOrDefault();
                notifications.ShowError(error?.Message ?? ex.Message);
                return(Observable.Empty <IPullRequestModel>());
            }))
                                .OnExecuteCompleted(pr =>
            {
                notifications.ShowMessage(String.Format(CultureInfo.CurrentCulture, Resources.PRCreatedUpstream, SourceBranch.DisplayName, TargetBranch.Repository.Owner + "/" + TargetBranch.Repository.Name + "#" + pr.Number,
                                                        TargetBranch.Repository.CloneUrl.ToRepositoryUrl().Append("pull/" + pr.Number)));
            });

            isExecuting = CreatePullRequest.IsExecuting.ToProperty(this, x => x.IsExecuting);

            this.WhenAnyValue(x => x.Initialized, x => x.GitHubRepository, x => x.Description, x => x.IsExecuting)
            .Select(x => !(x.Item1 && x.Item2 != null && x.Item3 != null && !x.Item4))
            .Subscribe(x => IsBusy = x);

            Observable.CombineLatest(
                this.WhenAnyValue(x => x.SourceBranch),
                uniqueCommits,
                service.GetPullRequestTemplate(activeRepo).DefaultIfEmpty(string.Empty),
                (compare, commits, template) => new { compare, commits, template })
            .Subscribe(x =>
            {
                var prTitle       = string.Empty;
                var prDescription = string.Empty;

                if (x.commits.Count == 1)
                {
                    prTitle       = x.commits[0].Summary;
                    prDescription = x.commits[0].Details;
                }
                else
                {
                    prTitle = x.compare.Name.Humanize();
                }

                if (!string.IsNullOrWhiteSpace(x.template))
                {
                    if (!string.IsNullOrEmpty(prDescription))
                    {
                        prDescription += "\n\n";
                    }
                    prDescription += x.template;
                }

                PRTitle     = prTitle;
                Description = prDescription;
            });
        }
Example #29
0
        public RepositoryCreationViewModel(
            IRepositoryHost repositoryHost,
            IOperatingSystem operatingSystem,
            IRepositoryCreationService repositoryCreationService,
            IAvatarProvider avatarProvider)
        {
            this.repositoryHost            = repositoryHost;
            this.operatingSystem           = operatingSystem;
            this.repositoryCreationService = repositoryCreationService;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CreateTitle, repositoryHost.Title);
            SelectedGitIgnoreTemplate = GitIgnoreItem.None;
            SelectedLicense           = LicenseItem.None;

            accounts = repositoryHost.ModelService.GetAccounts()
                       .ObserveOn(RxApp.MainThreadScheduler)
                       .ToProperty(this, vm => vm.Accounts, initialValue: new ReadOnlyCollection <IAccount>(new IAccount[] {}));

            this.WhenAny(x => x.Accounts, x => x.Value)
            .WhereNotNull()
            .Where(accts => accts.Any())
            .Subscribe(accts => {
                var selectedAccount = accts.FirstOrDefault();
                if (selectedAccount != null)
                {
                    SelectedAccount = accts.FirstOrDefault();
                }
            });

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());

            BaseRepositoryPathValidator = this.CreateBaseRepositoryPathValidator();

            var nonNullRepositoryName = this.WhenAny(
                x => x.RepositoryName,
                x => x.BaseRepositoryPath,
                (x, y) => x.Value)
                                        .WhereNotNull();

            RepositoryNameValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                                      .IfNullOrEmpty(Resources.RepositoryNameValidatorEmpty)
                                      .IfTrue(x => x.Length > 100, Resources.RepositoryNameValidatorTooLong)
                                      .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            SafeRepositoryNameWarningValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                                                 .Add(repoName =>
            {
                var parsedReference = GetSafeRepositoryName(repoName);
                return(parsedReference != repoName ? String.Format(CultureInfo.CurrentCulture, Resources.SafeRepositoryNameWarning, parsedReference) : null);
            });

            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();

            CreateRepository = InitializeCreateRepositoryCommand();

            canKeepPrivate = CanKeepPrivateObservable.CombineLatest(CreateRepository.IsExecuting,
                                                                    (canKeep, publishing) => canKeep && !publishing)
                             .ToProperty(this, x => x.CanKeepPrivate);

            isCreating = CreateRepository.IsExecuting
                         .ToProperty(this, x => x.IsCreating);

            gitIgnoreTemplates = repositoryHost.ModelService.GetGitIgnoreTemplates()
                                 .ObserveOn(RxApp.MainThreadScheduler)
                                 .ToProperty(this, x => x.GitIgnoreTemplates, initialValue: new GitIgnoreItem[] { });

            this.WhenAny(x => x.GitIgnoreTemplates, x => x.Value)
            .WhereNotNull()
            .Where(ignores => ignores.Any())
            .Subscribe(ignores =>
            {
                SelectedGitIgnoreTemplate = ignores.FirstOrDefault(
                    template => template.Name.Equals("VisualStudio", StringComparison.OrdinalIgnoreCase));
            });

            licenses = repositoryHost.ModelService.GetLicenses()
                       .ObserveOn(RxApp.MainThreadScheduler)
                       .ToProperty(this, x => x.Licenses, initialValue: new LicenseItem[] { });

            BaseRepositoryPath = repositoryCreationService.DefaultClonePath;
        }
 public void Remove(IRepositoryHost host)
 {
     hosts.Remove(host);
 }
Example #31
0
        public RepositoryCreationViewModel(
            IRepositoryHost repositoryHost,
            IOperatingSystem operatingSystem,
            IRepositoryCreationService repositoryCreationService,
            IUsageTracker usageTracker)
        {
            this.repositoryHost            = repositoryHost;
            this.operatingSystem           = operatingSystem;
            this.repositoryCreationService = repositoryCreationService;
            this.usageTracker = usageTracker;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CreateTitle, repositoryHost.Title);
            SelectedGitIgnoreTemplate = GitIgnoreItem.None;
            SelectedLicense           = LicenseItem.None;

            accounts = repositoryHost.ModelService.GetAccounts()
                       .ObserveOn(RxApp.MainThreadScheduler)
                       .ToProperty(this, vm => vm.Accounts, initialValue: new ReadOnlyCollection <IAccount>(new IAccount[] {}));

            this.WhenAny(x => x.Accounts, x => x.Value)
            .Select(accts => accts?.FirstOrDefault())
            .WhereNotNull()
            .Subscribe(a => SelectedAccount = a);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(this.WhenAny(x => x.BaseRepositoryPath, x => x.Value))
                                          .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                                          .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                                          .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                                          .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid);

            var nonNullRepositoryName = this.WhenAny(
                x => x.RepositoryName,
                x => x.BaseRepositoryPath,
                (x, y) => x.Value)
                                        .WhereNotNull();

            RepositoryNameValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                                      .IfNullOrEmpty(Resources.RepositoryNameValidatorEmpty)
                                      .IfTrue(x => x.Length > 100, Resources.RepositoryNameValidatorTooLong)
                                      .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            SafeRepositoryNameWarningValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                                                 .Add(repoName =>
            {
                var parsedReference = GetSafeRepositoryName(repoName);
                return(parsedReference != repoName ? String.Format(CultureInfo.CurrentCulture, Resources.SafeRepositoryNameWarning, parsedReference) : null);
            });

            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();

            CreateRepository = InitializeCreateRepositoryCommand();

            canKeepPrivate = CanKeepPrivateObservable.CombineLatest(CreateRepository.IsExecuting,
                                                                    (canKeep, publishing) => canKeep && !publishing)
                             .ToProperty(this, x => x.CanKeepPrivate);

            isCreating = CreateRepository.IsExecuting
                         .ToProperty(this, x => x.IsCreating);

            GitIgnoreTemplates = TrackingCollection.CreateListenerCollectionAndRun(
                repositoryHost.ModelService.GetGitIgnoreTemplates(),
                new[] { GitIgnoreItem.None },
                OrderedComparer <GitIgnoreItem> .OrderByDescending(item => GitIgnoreItem.IsRecommended(item.Name)).Compare,
                x =>
            {
                if (x.Name.Equals("VisualStudio", StringComparison.OrdinalIgnoreCase))
                {
                    SelectedGitIgnoreTemplate = x;
                }
            });

            Licenses = TrackingCollection.CreateListenerCollectionAndRun(
                repositoryHost.ModelService.GetLicenses(),
                new[] { LicenseItem.None },
                OrderedComparer <LicenseItem> .OrderByDescending(item => LicenseItem.IsRecommended(item.Name)).Compare);

            BaseRepositoryPath = repositoryCreationService.DefaultClonePath;
        }
Example #32
0
        public RepositoryCloneViewModel(
            IRepositoryHost repositoryHost,
            IRepositoryCloneService cloneService,
            IOperatingSystem operatingSystem)
        {
            Guard.ArgumentNotNull(repositoryHost, nameof(repositoryHost));
            Guard.ArgumentNotNull(cloneService, nameof(cloneService));
            Guard.ArgumentNotNull(operatingSystem, nameof(operatingSystem));

            this.repositoryHost  = repositoryHost;
            this.operatingSystem = operatingSystem;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title);

            Repositories = new TrackingCollection <IRemoteRepositoryModel>();
            repositories.ProcessingDelay = TimeSpan.Zero;
            repositories.Comparer        = OrderedComparer <IRemoteRepositoryModel> .OrderBy(x => x.Owner).ThenBy(x => x.Name).Compare;

            repositories.Filter        = FilterRepository;
            repositories.NewerComparer = OrderedComparer <IRemoteRepositoryModel> .OrderByDescending(x => x.UpdatedAt).Compare;

            filterTextIsEnabled = this.WhenAny(x => x.IsBusy,
                                               loading => loading.Value || repositories.UnfilteredCount > 0 && !LoadingFailed)
                                  .ToProperty(this, x => x.FilterTextIsEnabled);

            this.WhenAny(
                x => x.repositories.UnfilteredCount,
                x => x.IsBusy,
                x => x.LoadingFailed,
                (unfilteredCount, loading, failed) =>
            {
                if (loading.Value)
                {
                    return(false);
                }

                if (failed.Value)
                {
                    return(false);
                }

                return(unfilteredCount.Value == 0);
            })
            .Subscribe(x =>
            {
                NoRepositoriesFound = x;
            });

            this.WhenAny(x => x.FilterText, x => x.Value)
            .DistinctUntilChanged(StringComparer.OrdinalIgnoreCase)
            .Throttle(TimeSpan.FromMilliseconds(100), RxApp.MainThreadScheduler)
            .Subscribe(_ => repositories.Filter = FilterRepository);

            var baseRepositoryPath = this.WhenAny(
                x => x.BaseRepositoryPath,
                x => x.SelectedRepository,
                (x, y) => x.Value);

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath)
                                          .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                                          .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                                          .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                                          .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid)
                                          .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            var canCloneObservable = this.WhenAny(
                x => x.SelectedRepository,
                x => x.BaseRepositoryPathValidator.ValidationResult.IsValid,
                (x, y) => x.Value != null && y.Value);

            canClone     = canCloneObservable.ToProperty(this, x => x.CanClone);
            CloneCommand = ReactiveCommand.Create(canCloneObservable);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());
            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
            .Subscribe();
            BaseRepositoryPath  = cloneService.DefaultClonePath;
            NoRepositoriesFound = true;
        }
        public RepositoryCreationViewModel(
            IRepositoryHost repositoryHost,
            IOperatingSystem operatingSystem,
            IRepositoryCreationService repositoryCreationService,
            IUsageTracker usageTracker)
        {
            this.repositoryHost = repositoryHost;
            this.operatingSystem = operatingSystem;
            this.repositoryCreationService = repositoryCreationService;
            this.usageTracker = usageTracker;

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CreateTitle, repositoryHost.Title);
            SelectedGitIgnoreTemplate = GitIgnoreItem.None;
            SelectedLicense = LicenseItem.None;

            accounts = repositoryHost.ModelService.GetAccounts()
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToProperty(this, vm => vm.Accounts, initialValue: new ReadOnlyCollection<IAccount>(new IAccount[] {}));

            this.WhenAny(x => x.Accounts, x => x.Value)
                .Select(accts => accts?.FirstOrDefault())
                .WhereNotNull()
                .Subscribe(a => SelectedAccount = a);

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());

            BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(this.WhenAny(x => x.BaseRepositoryPath, x => x.Value))
                .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty)
                .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong)
                .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters)
                .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid);

            var nonNullRepositoryName = this.WhenAny(
                x => x.RepositoryName,
                x => x.BaseRepositoryPath,
                (x, y) => x.Value)
                .WhereNotNull();

            RepositoryNameValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                .IfNullOrEmpty(Resources.RepositoryNameValidatorEmpty)
                .IfTrue(x => x.Length > 100, Resources.RepositoryNameValidatorTooLong)
                .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists);

            SafeRepositoryNameWarningValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                .Add(repoName =>
                {
                    var parsedReference = GetSafeRepositoryName(repoName);
                    return parsedReference != repoName ? String.Format(CultureInfo.CurrentCulture, Resources.SafeRepositoryNameWarning, parsedReference) : null;
                });

            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
                .Subscribe();

            CreateRepository = InitializeCreateRepositoryCommand();

            canKeepPrivate = CanKeepPrivateObservable.CombineLatest(CreateRepository.IsExecuting,
                (canKeep, publishing) => canKeep && !publishing)
                .ToProperty(this, x => x.CanKeepPrivate);

            isCreating = CreateRepository.IsExecuting
                .ToProperty(this, x => x.IsCreating);

            GitIgnoreTemplates = TrackingCollection.CreateListenerCollectionAndRun(
                repositoryHost.ModelService.GetGitIgnoreTemplates(),
                new[] { GitIgnoreItem.None },
                OrderedComparer<GitIgnoreItem>.OrderByDescending(item => GitIgnoreItem.IsRecommended(item.Name)).Compare,
                x =>
                {
                    if (x.Name.Equals("VisualStudio", StringComparison.OrdinalIgnoreCase))
                        SelectedGitIgnoreTemplate = x;
                });

            Licenses = TrackingCollection.CreateListenerCollectionAndRun(
                repositoryHost.ModelService.GetLicenses(),
                new[] { LicenseItem.None },
                OrderedComparer<LicenseItem>.OrderByDescending(item => LicenseItem.IsRecommended(item.Name)).Compare);

            BaseRepositoryPath = repositoryCreationService.DefaultClonePath;
        }
        public RepositoryCreationViewModel(
            IRepositoryHost repositoryHost,
            IOperatingSystem operatingSystem,
            IRepositoryCreationService repositoryCreationService,
            IAvatarProvider avatarProvider)
        {
            this.repositoryHost = repositoryHost;
            this.operatingSystem = operatingSystem;
            this.repositoryCreationService = repositoryCreationService;

            Title = string.Format(CultureInfo.CurrentCulture, "Create a {0} Repository", repositoryHost.Title);
            SelectedGitIgnoreTemplate = GitIgnoreItem.None;
            SelectedLicense = LicenseItem.None;

            accounts = repositoryHost.ModelService.GetAccounts()
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToProperty(this, vm => vm.Accounts, initialValue: new ReadOnlyCollection<IAccount>(new IAccount[] {}));
            
            this.WhenAny(x => x.Accounts, x => x.Value)
                .WhereNotNull()
                .Where(accts => accts.Any())
                .Subscribe(accts => {
                    var selectedAccount = accts.FirstOrDefault();
                    if (selectedAccount != null)
                    {
                        SelectedAccount = accts.FirstOrDefault();
                    }
                });

            browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog());

            BaseRepositoryPathValidator = this.CreateBaseRepositoryPathValidator();

            var nonNullRepositoryName = this.WhenAny(
                x => x.RepositoryName,
                x => x.BaseRepositoryPath,
                (x, y) => x.Value)
                .WhereNotNull();

            RepositoryNameValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                .IfNullOrEmpty("Please enter a repository name")
                .IfTrue(x => x.Length > 100, "Repository name must be fewer than 100 characters")
                .IfTrue(IsAlreadyRepoAtPath, "Repository with same name already exists at this location");

            SafeRepositoryNameWarningValidator = ReactivePropertyValidator.ForObservable(nonNullRepositoryName)
                .Add(repoName =>
                {
                    var parsedReference = GetSafeRepositoryName(repoName);
                    return parsedReference != repoName ? "Will be created as " + parsedReference : null;
                });

            this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value)
                .Subscribe();

            CreateRepository = InitializeCreateRepositoryCommand();

            canKeepPrivate = CanKeepPrivateObservable.CombineLatest(CreateRepository.IsExecuting,
                (canKeep, publishing) => canKeep && !publishing)
                .ToProperty(this, x => x.CanKeepPrivate);

            isCreating = CreateRepository.IsExecuting
                .ToProperty(this, x => x.IsCreating);

            gitIgnoreTemplates = repositoryHost.ModelService.GetGitIgnoreTemplates()
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToProperty(this, x => x.GitIgnoreTemplates, initialValue: new GitIgnoreItem[] { });

            this.WhenAny(x => x.GitIgnoreTemplates, x => x.Value)
                .WhereNotNull()
                .Where(ignores => ignores.Any())
                .Subscribe(ignores =>
                {
                    SelectedGitIgnoreTemplate = ignores.FirstOrDefault(
                        template => template.Name.Equals("VisualStudio", StringComparison.OrdinalIgnoreCase));
                });

            licenses = repositoryHost.ModelService.GetLicenses()
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToProperty(this, x => x.Licenses, initialValue: new LicenseItem[] { });

            BaseRepositoryPath = repositoryCreationService.DefaultClonePath;
        }
Example #35
0
        async Task<IPullRequestModel> PushAndCreatePR(IRepositoryHost host,
            ILocalRepositoryModel sourceRepository, IRepositoryModel targetRepository,
            IBranch sourceBranch, IBranch targetBranch,
            string title, string body)
        {
            var repo = await Task.Run(() => gitService.GetRepository(sourceRepository.LocalPath));
            var remote = await gitClient.GetHttpRemote(repo, "origin");
            await gitClient.Push(repo, sourceBranch.Name, remote.Name);

            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())
                await Task.Delay(TimeSpan.FromSeconds(5));

            var ret = await host.ModelService.CreatePullRequest(sourceRepository, targetRepository, sourceBranch, targetBranch, title, body);
            await usageTracker.IncrementUpstreamPullRequestCount();
            return ret;
        }
 public IObservable<Unit> LogOut(IRepositoryHost host)
 {
     var address = host.Address;
     var isDotCom = HostAddress.GitHubDotComHostAddress == address;
     return host.LogOut()
         .Do(result =>
         {
             // reset the logged out host property to null
             // it'll know what to do
             if (isDotCom)
                 GitHubHost = null;
             else
                 EnterpriseHost = null;
             connectionManager.RemoveConnection(address);
             disposables.Remove(host);
         });
 }