async Task<StepExecutionState> IProgressStepOperation.Run(CancellationToken cancellationToken, IProgressStepExecutionEvents progressCallback)
        {
            if (this.ExecutionState != StepExecutionState.NotStarted)
            {
                throw new InvalidOperationException(ProgressResources.StepOperationWasAlreadyExecuted);
            }

            if (this.Cancellable && cancellationToken.IsCancellationRequested)
            {
                return this.ExecutionState = StepExecutionState.Cancelled;
            }

            VsTaskRunContext context = GetContext(this.Execution);

            StepExecutionState stepState = await VsThreadingHelper.RunTask<StepExecutionState>(this.controller, context,
                () =>
                {
                    DoStatefulExecution(progressCallback, cancellationToken);
                    return this.ExecutionState;
                },

                cancellationToken);

            return stepState;
        }
 Task<StepExecutionState> IProgressStepOperation.Run(CancellationToken cancellationToken, IProgressStepExecutionEvents executionNotify)
 {
     Assert.IsNotNull(cancellationToken, "cancellationToken is not expected to be null");
     Assert.IsNotNull(executionNotify, "executionNotify is not expected to be null");
     return Task.Factory.StartNew(() =>
     {
         this.ExecutionState = StepExecutionState.Executing;
         this.operation(cancellationToken, executionNotify);
         this.executed = true;
         return this.ExecutionState = this.ExecutionResult;
     });
 }
        /// <summary>
        /// Creates an instance of <see cref="DeterminateStepProgressNotifier"/>
        /// </summary>
        /// <param name="executionEvents">Required <see cref="IProgressStepExecutionEvents"/></param>
        /// <param name="numberOfIncrements">The number of predefined increments to the progress, at least one is expected.</param>
        public DeterminateStepProgressNotifier(IProgressStepExecutionEvents executionEvents, int numberOfIncrements)
        {
            if (executionEvents == null)
            {
                throw new ArgumentNullException(nameof(executionEvents));
            }

            if (numberOfIncrements < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(numberOfIncrements));
            }

            this.executionEvents = executionEvents;
            this.maxNumberOfIncrements = numberOfIncrements;
        }
        protected virtual void DoStatefulExecution(IProgressStepExecutionEvents progressCallback, CancellationToken cancellationToken)
        {
            try
            {
                Debug.Assert(this.ExecutionState == StepExecutionState.NotStarted, "Unexpected stated");
                if (this.Execution == StepExecution.ForegroundThread)
                {
                    ThreadHelper.ThrowIfNotOnUIThread();
                }
                else
                {
                    Debug.Assert(this.Execution == StepExecution.BackgroundThread, "Unexpected enum value: " + this.Execution);
                    ThreadHelper.ThrowIfOnUIThread();
                }

                this.ExecutionState = StepExecutionState.Executing;
                this.ExecuteOperation(cancellationToken, progressCallback);
                this.ExecutionState = StepExecutionState.Succeeded;
            }
            catch (OperationCanceledException)
            {
                this.ExecutionState = StepExecutionState.Cancelled;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString(), "DoStatefulExecution-Failed");
                if (ErrorHandler.IsCriticalException(ex))
                {
                    throw;
                }

                this.ExecutionState = StepExecutionState.Failed;

                Debug.Assert(this.controller.ErrorNotificationManager != null, "Expecting valid ErrorNotifier");
                if (this.controller.ErrorNotificationManager != null)
                {
                    this.controller.ErrorNotificationManager.Notify(ex);
                }
            }
        }
 internal /*for testing purposes*/ void EmitBindingCompleteMessage(IProgressStepExecutionEvents notifications)
 {
     var message = this.AllNuGetPackagesInstalled
         ? Strings.FinishedSolutionBindingWorkflowSuccessful
         : Strings.FinishedSolutionBindingWorkflowNotAllPackagesInstalled;
     notifications.ProgressChanged(message);
 }
Example #6
0
        /// <summary>
        /// Step operation that will throw an exception and cause the step to fail
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void Fail(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            throw new Exception();
        }
        internal /*for testing purposes*/ void DiscoverProjects(IProgressController controller, IProgressStepExecutionEvents notifications)
        {
            Debug.Assert(ThreadHelper.CheckAccess(), "Expected step to be run on the UI thread");

            notifications.ProgressChanged(Strings.DiscoveringSolutionProjectsProgressMessage);

            this.BindingProjects.UnionWith(this.projectSystem.GetFilteredSolutionProjects());

            this.InformAboutFilteredOutProjects();

            if (!this.BindingProjects.Any())
            {
                AbortWorkflow(controller, CancellationToken.None);
            }
        }
        private void InitializeSolutionBindingOnUIThread(IProgressStepExecutionEvents notificationEvents)
        {
            Debug.Assert(System.Windows.Application.Current?.Dispatcher.CheckAccess() ?? false, "Expected to run on UI thread");

            notificationEvents.ProgressChanged(Strings.RuleSetGenerationProgressMessage);

            this.solutionBindingOperation.RegisterKnownRuleSets(this.Rulesets);
            this.solutionBindingOperation.Initialize(this.BindingProjects, this.QualityProfiles);
        }
 public Task <StepExecutionState> RunAsync(System.Threading.CancellationToken cancellationToken, IProgressStepExecutionEvents executionNotify)
 {
     throw new NotImplementedException();
 }
Example #10
0
        internal /*for testing purposes*/ void DiscoverProjects(IProgressController controller, IProgressStepExecutionEvents notifications)
        {
            Debug.Assert(ThreadHelper.CheckAccess(), "Expected step to be run on the UI thread");

            notifications.ProgressChanged(Strings.DiscoveringSolutionProjectsProgressMessage);

            var patternFilteredProjects          = this.projectSystem.GetFilteredSolutionProjects();
            var pluginAndPatternFilteredProjects =
                patternFilteredProjects.Where(p => this.host.SupportedPluginLanguages.Contains(Language.ForProject(p)));

            this.BindingProjects.UnionWith(pluginAndPatternFilteredProjects);
            this.InformAboutFilteredOutProjects();

            if (!this.BindingProjects.Any())
            {
                AbortWorkflow(controller, CancellationToken.None);
            }
        }
        internal /*for testing purposes*/ void DownloadServiceParameters(IProgressController controller, CancellationToken token, IProgressStepExecutionEvents notifications)
        {
            Debug.Assert(this.ConnectedServer != null);

            // Should never realistically take more than 1 second to match against a project name
            var timeout = TimeSpan.FromSeconds(1);
            var defaultRegex = new Regex(ServerProperty.TestProjectRegexDefaultValue, RegexOptions.IgnoreCase, timeout);

            notifications.ProgressChanged(Strings.DownloadingServerSettingsProgessMessage);

            ServerProperty[] properties;
            if (!this.host.SonarQubeService.TryGetProperties(this.ConnectedServer, token, out properties) || token.IsCancellationRequested)
            {
                AbortWorkflow(controller, token);
                return;
            }

            var testProjRegexProperty = properties.FirstOrDefault(x => StringComparer.Ordinal.Equals(x.Key, ServerProperty.TestProjectRegexKey));

            // Using this older API, if the property hasn't been explicitly set no default value is returned.
            // http://jira.sonarsource.com/browse/SONAR-5891
            var testProjRegexPattern = testProjRegexProperty?.Value ?? ServerProperty.TestProjectRegexDefaultValue;

            Regex regex = null;
            if (testProjRegexPattern != null)
            {
                // Try and create regex from provided server pattern.
                // No way to determine a valid pattern other than attempting to construct
                // the Regex object.
                try
                {
                    regex = new Regex(testProjRegexPattern, RegexOptions.IgnoreCase, timeout);
                }
                catch (ArgumentException)
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.InvalidTestProjectRegexPattern, testProjRegexPattern);
                }
            }

            var projectFilter = this.host.GetService<IProjectSystemFilter>();
            projectFilter.AssertLocalServiceIsNotNull();
            projectFilter.SetTestRegex(regex ?? defaultRegex);
        }
 private void ExecuteNonCancellable(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     Assert.IsFalse(this.testController.IsCurrentStepCancellable, "Not expected to be cancellable");
 }
Example #13
0
        internal /*for testing purposes*/ void DiscoverProjects(IProgressController controller, IProgressStepExecutionEvents notifications)
        {
            Debug.Assert(ThreadHelper.CheckAccess(), "Expected step to be run on the UI thread");

            notifications.ProgressChanged(Strings.DiscoveringSolutionProjectsProgressMessage);

            this.BindingProjects.UnionWith(this.projectSystem.GetFilteredSolutionProjects());

            this.InformAboutFilteredOutProjects();

            if (!this.BindingProjects.Any())
            {
                AbortWorkflow(controller, CancellationToken.None);
            }
        }
Example #14
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;
                }
            }
        }
Example #15
0
        /// <summary>
        /// Step operation that will notify the progress
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void NotifyProgress(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            this.notifyProgressSequence.ForEach(t => notifier.ProgressChanged(t.Item1, t.Item2));
        }
Example #16
0
 public FixedStepsProgressAdapter(IProgressStepExecutionEvents executionEvents)
 {
     this.executionEvents = executionEvents ?? throw new ArgumentNullException(nameof(executionEvents));
 }
 Task <StepExecutionState> IProgressStepOperation.RunAsync(CancellationToken cancellationToken, IProgressStepExecutionEvents executionNotify)
 {
     cancellationToken.Should().NotBeNull("cancellationToken is not expected to be null");
     executionNotify.Should().NotBeNull("executionNotify is not expected to be null");
     return(Task.Factory.StartNew(() =>
     {
         this.ExecutionState = StepExecutionState.Executing;
         this.operation(cancellationToken, executionNotify);
         this.IsExecuted = true;
         return this.ExecutionState = this.ExecutionResult;
     }));
 }
 private void ExecuteAndVerify(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
 }
        /// <summary>
        /// Step operation that will notify the progress
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void NotifyProgress(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            this.notifyProgressSequence.ForEach(t => notifier.ProgressChanged(t.Item1, t.Item2));
        }
 private void ExecuteAndFail(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     throw new Exception("Boom");
 }
 private void ExecuteAndFail(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     throw new Exception("Boom");
 }
Example #22
0
        /// <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() || !this.settings.AllowNuGetPackageInstall)
            {
                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;
            }

            DeterminateStepProgressNotifier progressNotifier = new DeterminateStepProgressNotifier(notificationEvents, this.BindingProjects.Count * this.NuGetPackages.Count);

            foreach (var bindingProject in this.BindingProjects)
            {
                List <NuGetPackageInfo> nugetPackages;
                if (!this.NuGetPackages.TryGetValue(Language.ForProject(bindingProject), out nugetPackages))
                {
                    var message = string.Format(Strings.BindingProjectLanguageNotMatchingAnyQualityProfileLanguage, bindingProject.Name);
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, message);
                    continue;
                }

                foreach (var packageInfo in nugetPackages)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

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

                    var isNugetInstallSuccessful = NuGetHelper.TryInstallPackage(this.host, bindingProject, packageInfo.Id, packageInfo.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, packageInfo.Id, bindingProject.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);
                }
            }
        }
Example #23
0
 /// <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>
 public bool InstallPackages(ISet <Project> projectsToBind, IProgressController controller, IProgressStepExecutionEvents notificationEvents, CancellationToken token)
 {
     // Nothing to do - just return success
     this.logger.WriteLine(Strings.Bind_NuGetAnalyzersNoLongerInstalled);
     return(true);
 }
Example #24
0
 /// <summary>
 /// Step operation that doesn't do anything
 /// </summary>
 /// <param name="token">Cancellation token</param>
 /// <param name="notifier">Progress notifier</param>
 private void DoNothing(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     AssertOperationArgumentsAreNotNull(token, notifier);
 }
Example #25
0
        async Task <StepExecutionState> IProgressStepOperation.Run(CancellationToken cancellationToken, IProgressStepExecutionEvents progressCallback)
        {
            if (this.ExecutionState != StepExecutionState.NotStarted)
            {
                throw new InvalidOperationException(ProgressResources.StepOperationWasAlreadyExecuted);
            }

            if (this.Cancellable && cancellationToken.IsCancellationRequested)
            {
                return(this.ExecutionState = StepExecutionState.Cancelled);
            }

            VsTaskRunContext context = GetContext(this.Execution);

            StepExecutionState stepState = await VsThreadingHelper.RunTask <StepExecutionState>(this.controller, context,
                                                                                                () =>
            {
                DoStatefulExecution(progressCallback, cancellationToken);
                return(this.ExecutionState);
            },

                                                                                                cancellationToken);

            return(stepState);
        }
 private void ExecuteAndVerify(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
 }
        internal /* for testing purposes */ async Task ConnectionStepAsync(ConnectionInformation connection,
                                                                           IProgressController controller, IProgressStepExecutionEvents notifications, CancellationToken cancellationToken)
        {
            this.host.ActiveSection?.UserNotifications?.HideNotification(NotificationIds.FailedToConnectId);
            this.host.ActiveSection?.UserNotifications?.HideNotification(NotificationIds.BadSonarQubePluginId);

            notifications.ProgressChanged(connection.ServerUri.ToString());

            try
            {
                notifications.ProgressChanged(Strings.ConnectionStepValidatinCredentials);
                if (!this.host.SonarQubeService.IsConnected)
                {
                    await this.host.SonarQubeService.ConnectAsync(connection, cancellationToken);
                }

                if (connection.Organization == null)
                {
                    var hasOrgs = await this.host.SonarQubeService.HasOrganizations(cancellationToken);

                    if (hasOrgs)
                    {
                        notifications.ProgressChanged(Strings.ConnectionStepRetrievingOrganizations);
                        var organizations = await this.host.SonarQubeService.GetAllOrganizationsAsync(cancellationToken);

                        connection.Organization = AskUserToSelectOrganizationOnUIThread(organizations);
                        if (connection.Organization == null)                                // User clicked cancel
                        {
                            AbortWithMessage(notifications, controller, cancellationToken); // TODO: Might be worth throwing
                            return;
                        }
                    }
                }

                // Persist the credentials on successful connection to SonarQube, unless
                // the connection is anonymous
                if (!string.IsNullOrEmpty(connection.UserName) &&
                    !string.IsNullOrEmpty(connection.Password.ToUnsecureString()))
                {
                    this.credentialStore.WriteCredentials(
                        connection.ServerUri,
                        new Credential(connection.UserName, connection.Password.ToUnsecureString()));
                }

                var isCompatible = await this.AreSolutionProjectsAndSonarQubePluginsCompatibleAsync(controller, notifications,
                                                                                                    cancellationToken);

                if (!isCompatible)
                {
                    return; // Message is already displayed by the method
                }

                this.ConnectedServer = connection;

                notifications.ProgressChanged(Strings.ConnectionStepRetrievingProjects);
                var projects = await this.host.SonarQubeService.GetAllProjectsAsync(connection.Organization?.Key,
                                                                                    cancellationToken);

                // The SonarQube client will limit the number of returned projects to 10K (hard limit on SonarQube side)
                // but will no longer fail when trying to retrieve more. In the case where the project we want to bind to
                // is not in the list and the binding was already done and the key is not null then we manually
                // forge and add a new project to the list.
                if (!string.IsNullOrWhiteSpace(this.host.VisualStateManager.BoundProjectKey) &&
                    projects.Count == 10000 &&
                    !projects.Any(p => p.Key == this.host.VisualStateManager.BoundProjectKey))
                {
                    this.host.Logger.WriteLine($"The project with key '{this.host.VisualStateManager.BoundProjectKey}' is not part of the first ten thousand projects. The binding process will continue assuming it was found.");
                    this.host.Logger.WriteLine("Note that if the project key does not actually exist on the server the binding will fail at a later stage.");

                    // We have to create a new list because the collection returned by the service as a fixed size
                    projects = new List <SonarQubeProject>(projects);
                    // Let's put the new item first in the collection to ease finding it.
                    projects.Insert(0, new SonarQubeProject(this.host.VisualStateManager.BoundProjectKey,
                                                            this.host.VisualStateManager.BoundProjectName ?? this.host.VisualStateManager.BoundProjectKey));
                }

                this.OnProjectsChanged(connection, projects);
                notifications.ProgressChanged(Strings.ConnectionResultSuccess);
            }
            catch (HttpRequestException e)
            {
                // For some errors we will get an inner exception which will have a more specific information
                // that we would like to show i.e.when the host could not be resolved
                var innerException = e.InnerException as System.Net.WebException;
                this.host.Logger.WriteLine(CoreStrings.SonarQubeRequestFailed, e.Message, innerException?.Message);
                AbortWithMessage(notifications, controller, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                // Canceled or timeout
                this.host.Logger.WriteLine(CoreStrings.SonarQubeRequestTimeoutOrCancelled);
                AbortWithMessage(notifications, controller, cancellationToken);
            }
            catch (Exception ex)
            {
                this.host.Logger.WriteLine(CoreStrings.SonarQubeRequestFailed, ex.Message, null);
                AbortWithMessage(notifications, controller, cancellationToken);
            }
        }
 private void ExecuteNonCancellable(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     Assert.IsFalse(this.testController.IsCurrentStepCancellable, "Not expected to be cancellable");
 }
        private async Task <bool> AreSolutionProjectsAndSonarQubePluginsCompatibleAsync(IProgressController controller,
                                                                                        IProgressStepExecutionEvents notifications, CancellationToken cancellationToken)
        {
            notifications.ProgressChanged(Strings.DetectingSonarQubePlugins);

            var plugins = await this.host.SonarQubeService.GetAllPluginsAsync(cancellationToken);

            var csharpOrVbNetProjects     = new HashSet <EnvDTE.Project>(this.projectSystem.GetSolutionProjects());
            var supportedPluginsLanguages = MinimumSupportedSonarQubePlugin.All
                                            .Where(supportedPlugin => IsSonarQubePluginSupported(plugins, supportedPlugin, host.Logger))
                                            .SelectMany(lang => lang.Languages);

            this.host.SupportedPluginLanguages.UnionWith(new HashSet <Language>(supportedPluginsLanguages));

            // If any of the projects can be bound then return success
            if (csharpOrVbNetProjects.Select(ProjectToLanguageMapper.GetLanguageForProject)
                .Any(this.host.SupportedPluginLanguages.Contains))
            {
                return(true);
            }

            string errorMessage = GetPluginProjectMismatchErrorMessage(csharpOrVbNetProjects);

            this.host.ActiveSection?.UserNotifications?.ShowNotificationError(errorMessage, NotificationIds.BadSonarQubePluginId, null);
            this.host.Logger.WriteLine(Strings.SubTextPaddingFormat, errorMessage);
            notifications.ProgressChanged(Strings.ConnectionResultFailure);

            AbortWorkflow(controller, cancellationToken);
            return(false);
        }
Example #30
0
        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 WebServiceHelper.SafeServiceCall(() =>
                                                                                this.host.SonarQubeService.GetQualityProfileAsync(
                                                                                    this.bindingArgs.ProjectKey, this.bindingArgs.Connection.Organization?.Key, serverLanguage, cancellationToken),
                                                                                this.host.Logger);

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

                var roslynProfileExporter = await WebServiceHelper.SafeServiceCall(() =>
                                                                                   this.host.SonarQubeService.GetRoslynExportProfileAsync(qualityProfileInfo.Name,
                                                                                                                                          this.bindingArgs.Connection.Organization?.Key, serverLanguage, cancellationToken),
                                                                                   this.host.Logger);

                if (roslynProfileExporter == null)
                {
                    this.host.Logger.WriteLine(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))
                {
                    this.host.Logger.WriteLine(string.Format(Strings.SubTextPaddingFormat,
                                                             string.Format(Strings.NoSonarAnalyzerActiveRulesForQualityProfile, qualityProfileInfo.Name, language.Name)));
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }

                if (!this.NuGetBindingOperation.ProcessExport(language, roslynProfileExporter))
                {
                    this.AbortWorkflow(controller, cancellationToken);
                    return;
                }

                // 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);

                this.host.Logger.WriteLine(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;
            }
        }
        internal /*for testing purposes*/ void DiscoverProjects(IProgressController controller, IProgressStepExecutionEvents notifications)
        {
            Debug.Assert(ThreadHelper.CheckAccess(), "Expected step to be run on the UI thread");

            notifications.ProgressChanged(Strings.DiscoveringSolutionProjectsProgressMessage, double.NaN);

            this.BindingProjects.UnionWith(this.projectSystem.GetFilteredSolutionProjects());

            this.InformAboutFilteredOutProjects(this.projectSystem.GetSolutionProjects().Except(this.BindingProjects));

            if (!this.BindingProjects.Any())
            {
                VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.NoProjectsApplicableForBinding);
                AbortWorkflow(controller, CancellationToken.None);
            }
        }
        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;
                }
            }
        }
        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>();
            DeterminateStepProgressNotifier notifier = new DeterminateStepProgressNotifier(notificationEvents, languages.Count());

            foreach (var language in languages)
            {
                notifier.NotifyCurrentProgress(string.Format(CultureInfo.CurrentCulture, Strings.DownloadingQualityProfileProgressMessage, language.Name));

                QualityProfile qualityProfileInfo;
                if (!host.SonarQubeService.TryGetQualityProfile(this.connectionInformation, this.project, language, cancellationToken, out qualityProfileInfo))
                {
                    failed = true;
                    break;
                }
                this.QualityProfiles[language] = qualityProfileInfo;

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

                this.NuGetPackages.AddRange(export.Deployment.NuGetPackages);

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

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

            if (failed)
            {
                VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.QualityProfileDownloadFailedMessage);
                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;
                }

                notifier.NotifyCurrentProgress(Strings.QualityProfileDownloadedSuccessfulMessage);
            }
        }
        /// <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;
            }

            DeterminateStepProgressNotifier progressNotifier = new DeterminateStepProgressNotifier(notificationEvents, this.BindingProjects.Count * this.NuGetPackages.Count);
            foreach (var bindingProject in this.BindingProjects)
            {
                List<NuGetPackageInfo> nugetPackages;
                if (!this.NuGetPackages.TryGetValue(Language.ForProject(bindingProject), out nugetPackages))
                {
                    var message = string.Format(Strings.BindingProjectLanguageNotMatchingAnyQualityProfileLanguage, bindingProject.Name);
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, message);
                    continue;
                }

                foreach (var packageInfo in nugetPackages)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

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

                    var isNugetInstallSuccessful = NuGetHelper.TryInstallPackage(this.host, bindingProject, packageInfo.Id, packageInfo.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, packageInfo.Id, bindingProject.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);
                }
            }
        }
        /// <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;
            }

            DeterminateStepProgressNotifier progressNotifier = new DeterminateStepProgressNotifier(notificationEvents, this.BindingProjects.Count * this.NuGetPackages.Count);
            foreach (var project in this.BindingProjects)
            {
                foreach (var packageInfo in this.NuGetPackages)
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    string message = string.Format(CultureInfo.CurrentCulture, Strings.EnsuringNugetPackagesProgressMessage, packageInfo.Id, project.Name);
                    progressNotifier.NotifyCurrentProgress(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 &= NuGetHelper.TryInstallPackage(this.host, project, packageInfo.Id, packageInfo.Version);

                    progressNotifier.NotifyIncrementedProgress(string.Empty);
                }
            }
        }
 private static void AssertOperationArgumentsAreNotNull(CancellationToken token, IProgressStepExecutionEvents callback)
 {
     Assert.IsNotNull(token, "CancellationToken is expected not to be null");
     Assert.IsNotNull(callback, "IProgressStepExecutionEvents is expected not to be null");
 }
 /// <summary>
 /// Step operation that doesn't do anything
 /// </summary>
 /// <param name="token">Cancellation token</param>
 /// <param name="notifier">Progress notifier</param>
 private void DoNothing(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     AssertOperationArgumentsAreNotNull(token, notifier);
 }
        private bool VerifyCSharpPlugin(IProgressController controller, CancellationToken cancellationToken, ConnectionInformation connection, IProgressStepExecutionEvents notifications)
        {
            ServerPlugin[] plugins;
            if (!this.host.SonarQubeService.TryGetPlugins(connection, cancellationToken, out plugins))
            {
                notifications.ProgressChanged(cancellationToken.IsCancellationRequested ? Strings.ConnectionResultCancellation : Strings.ConnectionResultFailure, double.NaN);
                this.host.ActiveSection?.UserNotifications?.ShowNotificationError(Strings.ConnectionFailed, NotificationIds.FailedToConnectId, this.parentCommand);

                AbortWorkflow(controller, cancellationToken);
                return false;
            }

            var csPlugin = plugins.FirstOrDefault(x => StringComparer.Ordinal.Equals(x.Key, ServerPlugin.CSharpPluginKey));
            if (string.IsNullOrWhiteSpace(csPlugin?.Version) || VersionHelper.Compare(csPlugin.Version, ServerPlugin.CSharpPluginMinimumVersion) < 0)
            {
                string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.ServerDoesNotHaveCorrectVersionOfCSharpPlugin, ServerPlugin.CSharpPluginMinimumVersion);

                this.host.ActiveSection?.UserNotifications?.ShowNotificationError(errorMessage, NotificationIds.BadServerPluginId, null);
                notifications.ProgressChanged(errorMessage, double.NaN);
                notifications.ProgressChanged(Strings.ConnectionResultFailure, double.NaN);

                AbortWorkflow(controller, cancellationToken);
                return false;
            }

            return true;
        }
        /// <summary>
        /// Step operation that verifies that the controller is started but not finished
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void VerifyControllerExecuting(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            Assert.IsTrue(this.testSubject.IsStarted, "Expected to be started");
            Assert.IsFalse(this.testSubject.IsFinished, "Not expected to be finished");
        }
 private void ExecuteAndNotify(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     for (int i = 0; i < DeterminateLoops; i++)
     {
         notifier.ProgressChanged(i.ToString(), (double)(i + 1) / (double)DeterminateLoops);
     }
 }
        /// <summary>
        /// Step operation that will abort and throw cancellation exception
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void Cancel(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            Assert.IsTrue(this.testSubject.TryAbort(), "Expected to abort");
            token.ThrowIfCancellationRequested();
        }
 private void ExecuteAndCancell(CancellationToken token, IProgressStepExecutionEvents notifier)
 {
     VerificationHelper.CheckState(this.testSubject, StepExecutionState.Executing);
     Assert.IsTrue(this.testController.IsCurrentStepCancellable, "Expected to be cancellable");
     this.testController.Cancel();
     token.ThrowIfCancellationRequested();
 }
        /// <summary>
        /// Step operation that will request to cancel in a cancellable step
        /// </summary>
        /// <remarks>Simulates an attempt to cancel during cancellable step execution</remarks>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void RequestToCancelAccepted(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            Assert.IsTrue(this.testSubject.CanAbort, "Should be able to abort");
            Assert.IsTrue(this.testSubject.TryAbort(), "Aborting should succeed");
        }
 /// <summary>
 /// Executes the operation
 /// </summary>
 /// <param name="cancellationToken">Cancellation token</param>
 /// <param name="progressCallback">The callback instance to use when executing the operation</param>
 protected void ExecuteOperation(CancellationToken cancellationToken, IProgressStepExecutionEvents progressCallback)
 {
     this.definition.Operation(cancellationToken, progressCallback);
 }
        /// <summary>
        /// Step operation that will request to cancel but the step is cannot be canceled
        /// </summary>
        /// <remarks>Simulates an attempt to cancel during non-cancellable step execution</remarks>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void RequestToCancelIgnored(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            Assert.IsFalse(this.testSubject.CanAbort, "Should not be able to abort");
            Assert.IsFalse(this.testSubject.TryAbort(), "Aborting should fail");
        }
        internal /* for testing purposes */ void ConnectionStep(IProgressController controller, CancellationToken cancellationToken, ConnectionInformation connection, IProgressStepExecutionEvents notifications)
        {
            this.host.ActiveSection?.UserNotifications?.HideNotification(NotificationIds.FailedToConnectId);
            this.host.ActiveSection?.UserNotifications?.HideNotification(NotificationIds.BadServerPluginId);

            notifications.ProgressChanged(connection.ServerUri.ToString());

            if (!this.VerifyDotNetPlugins(controller, cancellationToken, connection, notifications))
            {
                return;
            }

            this.ConnectedServer = connection;

            ProjectInformation[] projects;
            if (!this.host.SonarQubeService.TryGetProjects(connection, cancellationToken, out projects))
            {
                notifications.ProgressChanged(cancellationToken.IsCancellationRequested ? Strings.ConnectionResultCancellation : Strings.ConnectionResultFailure);
                this.host.ActiveSection?.UserNotifications?.ShowNotificationError(Strings.ConnectionFailed, NotificationIds.FailedToConnectId, this.parentCommand);

                AbortWorkflow(controller, cancellationToken);
                return;
            }

            this.OnProjectsChanged(connection, projects);
            notifications.ProgressChanged(Strings.ConnectionResultSuccess);
        }
        /// <summary>
        /// Step operation that will throw an exception and cause the step to fail
        /// </summary>
        /// <param name="token">Cancellation token</param>
        /// <param name="notifier">Progress notifier</param>
        private void Fail(CancellationToken token, IProgressStepExecutionEvents notifier)
        {
            AssertOperationArgumentsAreNotNull(token, notifier);

            throw new Exception();
        }
        private bool VerifyDotNetPlugins(IProgressController controller, CancellationToken cancellationToken, ConnectionInformation connection, IProgressStepExecutionEvents notifications)
        {
            notifications.ProgressChanged(Strings.DetectingServerPlugins);

            ServerPlugin[] plugins;
            if (!this.host.SonarQubeService.TryGetPlugins(connection, cancellationToken, out plugins))
            {
                notifications.ProgressChanged(cancellationToken.IsCancellationRequested ? Strings.ConnectionResultCancellation : Strings.ConnectionResultFailure);
                this.host.ActiveSection?.UserNotifications?.ShowNotificationError(Strings.ConnectionFailed, NotificationIds.FailedToConnectId, this.parentCommand);

                AbortWorkflow(controller, cancellationToken);
                return false;
            }

            IsCSharpPluginSupported = VerifyPluginSupport(plugins, MinimumSupportedServerPlugin.CSharp);
            IsVBNetPluginSupported = VerifyPluginSupport(plugins, MinimumSupportedServerPlugin.VbNet);

            var projects = this.projectSystem.GetSolutionProjects().ToList();
            var anyCSharpProject = projects.Any(p => MinimumSupportedServerPlugin.CSharp.ISupported(p));
            var anyVbNetProject = projects.Any(p => MinimumSupportedServerPlugin.VbNet.ISupported(p));

            string errorMessage;
            if ((IsCSharpPluginSupported && anyCSharpProject) ||
                (IsVBNetPluginSupported && anyVbNetProject))
            {
                return true;
            }
            else if (!IsCSharpPluginSupported && !IsVBNetPluginSupported)
            {
                errorMessage = Strings.ServerHasNoSupportedPluginVersion;
            }
            else if (projects.Count == 0)
            {
                errorMessage = Strings.SolutionContainsNoSupportedProject;
            }
            else if (IsCSharpPluginSupported && !anyCSharpProject)
            {
                errorMessage = string.Format(Strings.OnlySupportedPluginHasNoProjectInSolution, Language.CSharp.Name);
            }
            else
            {
                errorMessage = string.Format(Strings.OnlySupportedPluginHasNoProjectInSolution, Language.VBNET.Name);
            }

            this.host.ActiveSection?.UserNotifications?.ShowNotificationError(errorMessage, NotificationIds.BadServerPluginId, null);
            VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SubTextPaddingFormat, errorMessage);
            notifications.ProgressChanged(Strings.ConnectionResultFailure);

            AbortWorkflow(controller, cancellationToken);
            return false;
        }
Example #49
0
 private static void AssertOperationArgumentsAreNotNull(CancellationToken token, IProgressStepExecutionEvents callback)
 {
     token.Should().NotBeNull("CancellationToken is expected not to be null");
     callback.Should().NotBeNull("IProgressStepExecutionEvents is expected not to be null");
 }