Esempio n. 1
0
        public async Task InitializeAsync(IConnection connection)
        {
            modelService = await modelServiceFactory.CreateAsync(connection);

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CreateTitle, connection.HostAddress.Title);

            accounts = 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);

            GitIgnoreTemplates = TrackingCollection.CreateListenerCollectionAndRun(
                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(
                modelService.GetLicenses(),
                new[] { LicenseItem.None },
                OrderedComparer <LicenseItem> .OrderByDescending(item => LicenseItem.IsRecommended(item.Name)).Compare);
        }
        public async Task InitializeAsync(LocalRepositoryModel repository, IConnection connection)
        {
            modelService = await modelServiceFactory.CreateAsync(connection);

            activeLocalRepo = repository;
            SourceBranch    = gitService.GetBranch(repository);

            var obs = modelService.ApiClient.GetRepository(repository.Owner, repository.Name)
                      .Select(r => CreateRemoteRepositoryModel(r))
                      .PublishLast();

            disposables.Add(obs.Connect());
            var 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;
            });

            githubObs.SelectMany(r =>
            {
                var b = Observable.Empty <BranchModel>();
                if (r.IsFork)
                {
                    b = modelService.GetBranches(r.Parent).Select(x =>
                    {
                        return(x);
                    });
                }
                return(b.Concat(modelService.GetBranches(r)));
            })
            .ToList()
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x =>
            {
                Branches    = x.ToList();
                Initialized = true;
            });

            var draftKey = GetDraftKey();

            await LoadInitialState(draftKey).ConfigureAwait(true);

            this.WhenAnyValue(
                x => x.PRTitle,
                x => x.Description,
                (t, d) => new PullRequestDraft {
                Title = t, Body = d
            })
            .Throttle(TimeSpan.FromSeconds(1), timerScheduler)
            .Subscribe(x => draftStore.UpdateDraft(draftKey, string.Empty, x));

            Initialized = true;
        }
Esempio n. 3
0
        public async Task InitializeAsync(IConnection connection)
        {
            var modelService = await modelServiceFactory.CreateAsync(connection);

            apiClient = modelService.ApiClient;

            // 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 = modelService.GetAccounts()
                      .FirstAsync()
                      .Select(a => a.First())
                      .ObserveOn(RxApp.MainThreadScheduler)
                      .ToProperty(this, vm => vm.Account);
        }
Esempio n. 4
0
        public async Task InitializeAsync(IConnection connection)
        {
            modelService = await modelServiceFactory.CreateAsync(connection).ConfigureAwait(true);

            Title = string.Format(CultureInfo.CurrentCulture, Resources.CreateTitle, connection.HostAddress.Title);

            accounts = modelService.GetAccounts()
                       .ObserveOn(RxApp.MainThreadScheduler)
                       .ToProperty(this, vm => vm.Accounts, initialValue: new ReadOnlyCollection <IAccount>(Array.Empty <IAccount>()));

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

            modelService.GetGitIgnoreTemplates()
            .Where(x => x != null)
            .ToList()
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x =>
            {
                var sorted = x
                             .Distinct()
                             .OrderByDescending(item => item.Recommended)
                             .ThenBy(item => item.Name);
                GitIgnoreTemplates = new[] { GitIgnoreItem.None }.Concat(sorted).ToList();

                SelectedGitIgnoreTemplate = GitIgnoreTemplates
                                            .FirstOrDefault(i => i?.Name.Equals("VisualStudio", StringComparison.OrdinalIgnoreCase) == true);
            });

            modelService.GetLicenses()
            .Where(x => x != null)
            .ToList()
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x =>
            {
                var sorted = x
                             .Distinct()
                             .OrderByDescending(item => item.Recommended)
                             .ThenBy(item => item.Key);
                Licenses = new[] { LicenseItem.None }.Concat(sorted).ToList();
            });
        }
Esempio n. 5
0
        public GistCreationViewModel(
            IConnection connection,
            IModelServiceFactory modelServiceFactory,
            ISelectedTextProvider selectedTextProvider,
            IGistPublishService gistPublishService,
            IUsageTracker usageTracker)
        {
            Guard.ArgumentNotNull(connection, nameof(connection));
            Guard.ArgumentNotNull(selectedTextProvider, nameof(selectedTextProvider));
            Guard.ArgumentNotNull(gistPublishService, nameof(gistPublishService));
            Guard.ArgumentNotNull(usageTracker, nameof(usageTracker));

            Title = Resources.CreateGistTitle;
            this.gistPublishService = gistPublishService;
            this.usageTracker       = usageTracker;

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

            var modelService = modelServiceFactory.CreateBlocking(connection);

            apiClient = modelService.ApiClient;

            // 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 = 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);
        }
        public RepositoryCreationViewModel(
            IConnection connection,
            IModelServiceFactory modelServiceFactory,
            IOperatingSystem operatingSystem,
            IRepositoryCreationService repositoryCreationService,
            IUsageTracker usageTracker)
        {
            Guard.ArgumentNotNull(connection, nameof(connection));
            Guard.ArgumentNotNull(modelServiceFactory, nameof(modelServiceFactory));
            Guard.ArgumentNotNull(operatingSystem, nameof(operatingSystem));
            Guard.ArgumentNotNull(repositoryCreationService, nameof(repositoryCreationService));
            Guard.ArgumentNotNull(usageTracker, nameof(usageTracker));

            this.operatingSystem           = operatingSystem;
            this.repositoryCreationService = repositoryCreationService;
            this.usageTracker = usageTracker;

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

            modelService = modelServiceFactory.CreateBlocking(connection);

            accounts = 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(
                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(
                modelService.GetLicenses(),
                new[] { LicenseItem.None },
                OrderedComparer <LicenseItem> .OrderByDescending(item => LicenseItem.IsRecommended(item.Name)).Compare);

            BaseRepositoryPath = repositoryCreationService.DefaultClonePath;
        }
        public async Task InitializeAsync(ILocalRepositoryModel sourceRepository, IAccount destinationAccount, IConnection connection)
        {
            var modelService = await modelServiceFactory.CreateAsync(connection);

            apiClient = modelService.ApiClient;

            DestinationAccount = destinationAccount;

            SourceRepository      = sourceRepository;
            DestinationRepository = new RemoteRepositoryModel(
                0,
                sourceRepository.Name,
                CreateForkUri(sourceRepository.CloneUrl, destinationAccount.Login),
                false,
                true,
                destinationAccount,
                null);
        }
        public PullRequestCreationViewModel(
            IConnection connection,
            IModelServiceFactory modelServiceFactory,
            ILocalRepositoryModel activeRepo,
            IPullRequestService service,
            INotificationService notifications)
        {
            Guard.ArgumentNotNull(connection, nameof(connection));
            Guard.ArgumentNotNull(modelServiceFactory, nameof(modelServiceFactory));
            Guard.ArgumentNotNull(activeRepo, nameof(activeRepo));
            Guard.ArgumentNotNull(service, nameof(service));
            Guard.ArgumentNotNull(notifications, nameof(notifications));

            activeLocalRepo = activeRepo;
            modelService    = modelServiceFactory.CreateBlocking(connection);

            var obs = modelService.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(modelService, 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;
            });
        }
 public Task InitializeAsync(LocalRepositoryModel sourceRepository, IAccount destinationAccount, IConnection connection)
 {
     return(Task.CompletedTask);
 }
Esempio n. 10
0
        public async Task InitializeAsync(ILocalRepositoryModel repository, IConnection connection)
        {
            modelService = await modelServiceFactory.CreateAsync(connection);

            activeLocalRepo = repository;
            SourceBranch    = repository.CurrentBranch;

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

            disposables.Add(obs.Connect());
            var 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;
            });

            githubObs.SelectMany(r =>
            {
                var b = Observable.Empty <IBranch>();
                if (r.IsFork)
                {
                    b = modelService.GetBranches(r.Parent).Select(x =>
                    {
                        return(x);
                    });
                }
                return(b.Concat(modelService.GetBranches(r)));
            })
            .ToList()
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(x =>
            {
                Branches    = x.ToList();
                Initialized = true;
            });

            SourceBranch = activeLocalRepo.CurrentBranch;

            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(activeLocalRepo, 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();

            Observable.CombineLatest(
                this.WhenAnyValue(x => x.SourceBranch),
                uniqueCommits,
                service.GetPullRequestTemplate(repository).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;
            });

            Initialized = true;
        }