/// <summary>
        /// Will install the NuGet packages for the current managed projects.
        /// The packages that will be installed will be based on the information from <see cref="Analyzer.GetRequiredNuGetPackages"/>
        /// and is specific to the <see cref="RuleSet"/>.
        /// </summary>
        internal /*for testing purposes*/ void InstallPackages(IProgressController controller, CancellationToken token, IProgressStepExecutionEvents notificationEvents)
        {
            if (!this.NuGetPackages.Any())
            {
                return;
            }

            Debug.Assert(this.NuGetPackages.Count == this.NuGetPackages.Distinct().Count(), "Duplicate NuGet packages specified");

            if (!this.BindingProjects.Any())
            {
                Debug.Fail("Not expected to be called when there are no projects");
                return;
            }

            var projectNugets = this.BindingProjects
                                .SelectMany(bindingProject =>
            {
                var projectLanguage = Language.ForProject(bindingProject);

                List <NuGetPackageInfoResponse> nugetPackages;
                if (!this.NuGetPackages.TryGetValue(projectLanguage, out nugetPackages))
                {
                    var message = string.Format(Strings.BindingProjectLanguageNotMatchingAnyQualityProfileLanguage, bindingProject.Name);
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, message);
                    nugetPackages = new List <NuGetPackageInfoResponse>();
                }

                return(nugetPackages.Select(nugetPackage => new { Project = bindingProject, NugetPackage = nugetPackage }));
            })
                                .ToArray();

            DeterminateStepProgressNotifier progressNotifier = new DeterminateStepProgressNotifier(notificationEvents, projectNugets.Length);

            foreach (var projectNuget in projectNugets)
            {
                if (token.IsCancellationRequested)
                {
                    break;
                }

                string message = string.Format(CultureInfo.CurrentCulture, Strings.EnsuringNugetPackagesProgressMessage, projectNuget.NugetPackage.Id, projectNuget.Project.Name);
                VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, message);

                var isNugetInstallSuccessful = NuGetHelper.TryInstallPackage(this.host, projectNuget.Project, projectNuget.NugetPackage.Id, projectNuget.NugetPackage.Version);

                if (isNugetInstallSuccessful) // NuGetHelper.TryInstallPackage already displayed the error message so only take care of the success message
                {
                    message = string.Format(CultureInfo.CurrentCulture, Strings.SuccessfullyInstalledNugetPackageForProject, projectNuget.NugetPackage.Id, projectNuget.Project.Name);
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, message);
                }

                // TODO: SVS-33 (https://jira.sonarsource.com/browse/SVS-33) Trigger a Team Explorer warning notification to investigate the partial binding in the output window.
                this.AllNuGetPackagesInstalled &= isNugetInstallSuccessful;

                progressNotifier.NotifyIncrementedProgress(string.Empty);
            }
        }
        public void DeterminateStepProgressNotifier_IncrementProgress_ArgChecks()
        {
            // Arrange
            var testSubject = new DeterminateStepProgressNotifier(new ConfigurableProgressController(null), 11);

            Exceptions.Expect <ArgumentOutOfRangeException>(() => testSubject.IncrementProgress(0));
            Exceptions.Expect <ArgumentOutOfRangeException>(() => testSubject.IncrementProgress(-1));
            Exceptions.Expect <ArgumentOutOfRangeException>(() => testSubject.IncrementProgress(12));

            // Check successful case (the last valid one)
            testSubject.IncrementProgress(11);
            testSubject.CurrentValue.Should().Be(11);
        }
        public void DeterminateStepProgressNotifier_NotifyCurrentProgress()
        {
            // Arrange
            var       controller  = new ConfigurableProgressController(null);
            const int Steps       = 2;
            var       testSubject = new DeterminateStepProgressNotifier(controller, Steps);
            List <Tuple <string, double> > expectedProgress = new List <Tuple <string, double> >();

            // Act + Assert
            for (int i = 0; i < Steps; i++)
            {
                expectedProgress.Add(Tuple.Create("hello world " + i, 0.0));
                testSubject.NotifyCurrentProgress(expectedProgress.Last().Item1);

                testSubject.CurrentValue.Should().Be(0, "Should not change");
                controller.progressChanges.Should().Equal(expectedProgress);
            }
        }
        public void DeterminateStepProgressNotifier_IncrementProgress()
        {
            // Arrange
            var       controller  = new ConfigurableProgressController(null);
            const int Steps       = 227; // Quite a few values for which N * (1 / N) > 1.0
            var       testSubject = new DeterminateStepProgressNotifier(controller, Steps);
            List <Tuple <string, double> > expectedProgress = new List <Tuple <string, double> >();

            // Act + Assert
            int expectedValue = 0;
            int i             = 0;

            while (expectedValue < Steps)
            {
                int increment = i % 2 == 0 ? 2 : 1;
                i++;
                expectedValue += increment;
                testSubject.IncrementProgress(increment);

                testSubject.CurrentValue.Should().Be(expectedValue);
            }
        }
        public void DeterminateStepProgressNotifier_NotifyIncrementedProgress()
        {
            // Arrange
            var       controller  = new ConfigurableProgressController(null);
            const int Steps       = 11; // there are two numbers (9 and 11) for which N * (1 / N) > 1.0
            var       testSubject = new DeterminateStepProgressNotifier(controller, Steps);
            List <Tuple <string, double> > expectedProgress = new List <Tuple <string, double> >();

            // Act + Assert
            for (int i = 0; i < Steps; i++)
            {
                int    incrementedStepValue = i + 1;
                double progress             = incrementedStepValue == Steps ? 1.0 : (double)incrementedStepValue / Steps;
                expectedProgress.Add(Tuple.Create("hello world " + i, progress));

                testSubject.CurrentValue.Should().Be(i);
                testSubject.NotifyIncrementedProgress(expectedProgress.Last().Item1);
                testSubject.CurrentValue.Should().Be(incrementedStepValue);

                controller.progressChanges.Should().Equal(expectedProgress);
            }
        }
        internal /*for testing purposes*/ async System.Threading.Tasks.Task DownloadQualityProfileAsync(
            IProgressController controller, IProgressStepExecutionEvents notificationEvents, IEnumerable <Language> languages,
            CancellationToken cancellationToken)
        {
            Debug.Assert(controller != null);
            Debug.Assert(notificationEvents != null);

            var rulesets     = new Dictionary <Language, RuleSet>();
            var languageList = languages as IList <Language> ?? languages.ToList();
            DeterminateStepProgressNotifier notifier = new DeterminateStepProgressNotifier(notificationEvents, languageList.Count);

            notifier.NotifyCurrentProgress(Strings.DownloadingQualityProfileProgressMessage);

            foreach (var language in languageList)
            {
                var serverLanguage = language.ToServerLanguage();

                var qualityProfileInfo = await SafeServiceCall(
                    () => this.host.SonarQubeService.GetQualityProfileAsync(this.project.Key, serverLanguage, cancellationToken));

                if (qualityProfileInfo == null)
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, string.Format(Strings.SubTextPaddingFormat,
                                                                                     string.Format(Strings.CannotDownloadQualityProfileForLanguage, language.Name)));
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }
                this.QualityProfiles[language] = qualityProfileInfo;

                var roslynProfileExporter = await SafeServiceCall(
                    () => this.host.SonarQubeService.GetRoslynExportProfileAsync(qualityProfileInfo.Name, serverLanguage,
                                                                                 cancellationToken));

                if (roslynProfileExporter == null)
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, string.Format(Strings.SubTextPaddingFormat,
                                                                                     string.Format(Strings.QualityProfileDownloadFailedMessageFormat, qualityProfileInfo.Name,
                                                                                                   qualityProfileInfo.Key, language.Name)));
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }

                var tempRuleSetFilePath = Path.GetTempFileName();
                File.WriteAllText(tempRuleSetFilePath, roslynProfileExporter.Configuration.RuleSet.OuterXml);
                RuleSet ruleSet = RuleSet.LoadFromFile(tempRuleSetFilePath);

                if (ruleSet == null ||
                    ruleSet.Rules.Count == 0 ||
                    ruleSet.Rules.All(rule => rule.Action == RuleAction.None))
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, string.Format(Strings.SubTextPaddingFormat,
                                                                                     string.Format(Strings.NoSonarAnalyzerActiveRulesForQualityProfile, qualityProfileInfo.Name, language.Name)));
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }

                if (roslynProfileExporter.Deployment.NuGetPackages.Count == 0)
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, string.Format(Strings.SubTextPaddingFormat,
                                                                                     string.Format(Strings.NoNuGetPackageForQualityProfile, language.Name)));
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }

                this.NuGetPackages.Add(language, roslynProfileExporter.Deployment.NuGetPackages);

                // Remove/Move/Refactor code when XML ruleset file is no longer downloaded but the proper API is used to retrieve rules
                UpdateDownloadedSonarQubeQualityProfile(ruleSet, qualityProfileInfo);

                rulesets[language] = ruleSet;
                notifier.NotifyIncrementedProgress(string.Empty);

                VsShellUtils.WriteToSonarLintOutputPane(this.host, string.Format(Strings.SubTextPaddingFormat,
                                                                                 string.Format(Strings.QualityProfileDownloadSuccessfulMessageFormat, qualityProfileInfo.Name, qualityProfileInfo.Key, language.Name)));
            }

            // Set the rule set which should be available for the following steps
            foreach (var keyValue in rulesets)
            {
                this.Rulesets[keyValue.Key] = keyValue.Value;
            }
        }
Beispiel #7
0
        internal /*for testing purposes*/ void DownloadQualityProfile(IProgressController controller, CancellationToken cancellationToken, IProgressStepExecutionEvents notificationEvents, IEnumerable <Language> languages)
        {
            Debug.Assert(controller != null);
            Debug.Assert(notificationEvents != null);

            bool failed       = false;
            var  rulesets     = new Dictionary <Language, RuleSet>();
            var  languageList = languages as IList <Language> ?? languages.ToList();
            DeterminateStepProgressNotifier notifier = new DeterminateStepProgressNotifier(notificationEvents, languageList.Count);

            notifier.NotifyCurrentProgress(Strings.DownloadingQualityProfileProgressMessage);
            foreach (var language in languageList)
            {
                QualityProfile qualityProfileInfo;
                if (!host.SonarQubeService.TryGetQualityProfile(this.connectionInformation, this.project, language, cancellationToken, out qualityProfileInfo))
                {
                    failed = true;
                    InformAboutQualityProfileToDownload(qualityProfileInfo.Name, qualityProfileInfo.Key, language.Name, true);
                    break;
                }
                this.QualityProfiles[language] = qualityProfileInfo;

                RoslynExportProfile export;
                if (!this.host.SonarQubeService.TryGetExportProfile(this.connectionInformation, qualityProfileInfo, language, cancellationToken, out export))
                {
                    failed = true;
                    InformAboutQualityProfileToDownload(qualityProfileInfo.Name, qualityProfileInfo.Key, language.Name, true);
                    break;
                }
                this.NuGetPackages.Add(language, export.Deployment.NuGetPackages);

                var tempRuleSetFilePath = Path.GetTempFileName();
                File.WriteAllText(tempRuleSetFilePath, export.Configuration.RuleSet.OuterXml);
                RuleSet ruleSet = RuleSet.LoadFromFile(tempRuleSetFilePath);

                // Remove/Move/Refactor code when XML ruleset file is no longer downloaded but the proper API is used to retrieve rules
                UpdateDownloadedSonarQubeQualityProfile(ruleSet, qualityProfileInfo);

                rulesets[language] = ruleSet;
                notifier.NotifyIncrementedProgress(string.Empty);
                if (rulesets[language] == null)
                {
                    failed = true;
                    InformAboutQualityProfileToDownload(qualityProfileInfo.Name, qualityProfileInfo.Key, language.Name, true);
                    break;
                }

                InformAboutQualityProfileToDownload(qualityProfileInfo.Name, qualityProfileInfo.Key, language.Name, false);
            }

            if (failed)
            {
                this.AbortWorkflow(controller, cancellationToken);
            }
            else
            {
                // Set the rule set which should be available for the following steps
                foreach (var keyValue in rulesets)
                {
                    this.Rulesets[keyValue.Key] = keyValue.Value;
                }
            }
        }