public string WriteSolutionBinding(BoundSonarQubeProject binding)
        {
            if (binding == null)
            {
                throw new ArgumentNullException(nameof(binding));
            }

            ISourceControlledFileSystem sccFileSystem = this.serviceProvider.GetService<ISourceControlledFileSystem>();
            sccFileSystem.AssertLocalServiceIsNotNull();

            string configFile = this.GetSonarQubeConfigurationFilePath();
            if (string.IsNullOrWhiteSpace(configFile))
            {
                return null;
            }

            sccFileSystem.QueueFileWrite(configFile, () =>
            {
                if (this.WriteBindingInformation(configFile, binding))
                {
                    this.AddSolutionItemFile(configFile);
                    this.RemoveSolutionItemFile(configFile);
                    return true;
                }

                return false;
            });

            return configFile;
        }
        public void SolutionBindingSerializer_WriteSolutionBinding_ReadSolutionBinding()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var projectKey = "MyProject Key";
            var written = new BoundSonarQubeProject(serverUri, projectKey, creds);

            // Act (write)
            string output = testSubject.WriteSolutionBinding(written);
            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();
            Assert.IsNotNull(output, "Expected a real file");
            this.TestContext.AddResultFile(output);
            Assert.IsTrue(File.Exists(output), "Expected a real file");

            // Verify
            this.store.AssertHasCredentials(serverUri);

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Verify
            var newCreds = read.Credentials as BasicAuthCredentials;
            Assert.AreNotEqual(creds, newCreds, "Different credential instance were expected");
            Assert.AreEqual(creds.UserName, newCreds.UserName);
            Assert.AreEqual(creds.Password.ConvertToUnsecureString(), newCreds.Password.ConvertToUnsecureString());
            Assert.AreEqual(written.ServerUri, read.ServerUri);
            this.outputPane.AssertOutputStrings(0);
        }
        string ISolutionBindingSerializer.WriteSolutionBinding(BoundSonarQubeProject binding)
        {
            Assert.IsNotNull(binding, "Required argument");

            string filePath = this.WriteSolutionBindingAction?.Invoke(binding) ?? binding.ProjectKey;
            this.writtenFiles++;

            return filePath;
        }
        private static void WriteConfig(string configFile, BoundSonarQubeProject binding)
        {
            string directory = Path.GetDirectoryName(configFile);

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            File.WriteAllText(configFile, JsonHelper.Serialize(binding));
        }
Exemplo n.º 5
0
        public static ConnectionInformation CreateConnectionInformation(this BoundSonarQubeProject binding)
        {
            if (binding == null)
            {
                throw new ArgumentNullException(nameof(binding));
            }

            return(binding.Credentials == null ?
                   new ConnectionInformation(binding.ServerUri)
               : binding.Credentials.CreateConnectionInformation(binding.ServerUri));
        }
        private void WriteConfig(string configFile, BoundSonarQubeProject binding)
        {
            Debug.Assert(!string.IsNullOrWhiteSpace(configFile));
            string directory = Path.GetDirectoryName(configFile);

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            fileWrapper.WriteAllText(configFile, JsonHelper.Serialize(binding));
        }
        public void CreateConnectionInformation_NoCredentials()
        {
            // Setup
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey");

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Verify
            Assert.AreEqual(input.ServerUri, conn.ServerUri);
            Assert.IsNull(conn.UserName);
            Assert.IsNull(conn.Password);
        }
        private IEnumerable<Project> GetUnboundProjects(BoundSonarQubeProject binding)
        {
            if (binding == null)
            {
                return Enumerable.Empty<Project>();
            }

            var projectSystem = this.serviceProvider.GetService<IProjectSystemHelper>();
            projectSystem.AssertLocalServiceIsNotNull();

            // Reuse the binding information passed in to avoid reading it more than once
            return projectSystem.GetFilteredSolutionProjects().Except(this.GetBoundProjects(binding));
        }
        public void CreateConnectionInformation_BasicAuthCredentials()
        {
            // Setup
            var creds = new BasicAuthCredentials("UserName", "password".ConvertToSecureString());
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey", creds);

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Verify
            Assert.AreEqual(input.ServerUri, conn.ServerUri);
            Assert.AreEqual(creds.UserName, conn.UserName);
            Assert.AreEqual(creds.Password.ConvertToUnsecureString(), conn.Password.ConvertToUnsecureString());
        }
        private BoundSonarQubeProject ReadBindingInformation(string configFile)
        {
            BoundSonarQubeProject bound = this.SafeDeserializeConfigFile(configFile);

            if (bound != null)
            {
                Credential creds;
                if (bound?.ServerUri != null && this.credentialStore.ReadCredentials(bound.ServerUri, out creds))
                {
                    bound.Credentials = new BasicAuthCredentials(creds.Username, creds.Password);
                }
            }

            return(bound);
        }
Exemplo n.º 11
0
        private BoundSonarQubeProject ReadBindingInformation(string configFile)
        {
            BoundSonarQubeProject bound = this.SafeDeserializeConfigFile(configFile);

            if (bound?.ServerUri != null)
            {
                var credentials = this.credentialStore.ReadCredentials(bound.ServerUri);
                if (credentials != null)
                {
                    bound.Credentials = new BasicAuthCredentials(credentials.Username,
                                                                 credentials.Password.ToSecureString());
                }
            }

            return(bound);
        }
        public void BoundSonarQubeProject_Serialization()
        {
            // Setup
            var serverUri = new Uri("https://finding-nemo.org");
            var projectKey = "MyProject Key";
            var testSubject = new BoundSonarQubeProject(serverUri, projectKey, new BasicAuthCredentials("used", "pwd".ConvertToSecureString()));

            // Act (serialize + de-serialize)
            string data = JsonHelper.Serialize(testSubject);
            BoundSonarQubeProject deserialized = JsonHelper.Deserialize<BoundSonarQubeProject>(data);

            // Verify
            Assert.AreNotSame(testSubject, deserialized);
            Assert.AreEqual(testSubject.ProjectKey, deserialized.ProjectKey);
            Assert.AreEqual(testSubject.ServerUri, deserialized.ServerUri);
            Assert.IsNull(deserialized.Credentials);
        }
Exemplo n.º 13
0
        private bool WriteBindingInformation(string configFile, BoundSonarQubeProject binding)
        {
            if (this.SafePerformFileSystemOperation(() => WriteConfig(configFile, binding)))
            {
                BasicAuthCredentials credentials = binding.Credentials as BasicAuthCredentials;
                if (credentials != null)
                {
                    Debug.Assert(credentials.UserName != null, "User name is not expected to be null");
                    Debug.Assert(credentials.Password != null, "Password name is not expected to be null");

                    var creds = new Credential(credentials.UserName, credentials.Password.ToUnsecureString());
                    this.credentialStore.WriteCredentials(binding.ServerUri, creds);
                }
                return(true);
            }

            return(false);
        }
        private BoundSonarQubeProject ReadBindingInformation(string configFile)
        {
            BoundSonarQubeProject bound = this.SafeDeserializeConfigFile(configFile);

            if (bound?.ServerUri != null)
            {
                var credentials = this.store.ReadCredentials(bound.ServerUri);
                if (credentials != null)
                {
                    bound.Credentials = new BasicAuthCredentials(credentials.Username,
                                                                 credentials.Password.ToSecureString());
                }
            }

            Debug.Assert(!bound?.Profiles?.ContainsKey(Core.Language.Unknown) ?? true,
                         "Not expecting the deserialized binding config to contain the profile for an unknown language");

            return(bound);
        }
        private IEnumerable<Project> GetBoundProjects(BoundSonarQubeProject binding)
        {
            if (binding == null)
            {
                return Enumerable.Empty<Project>();
            }

            var projectSystem = this.serviceProvider.GetService<IProjectSystemHelper>();
            projectSystem.AssertLocalServiceIsNotNull();

            // Projects will be using the same solution ruleset in most of the cases,
            // projects could have multiple configurations all of which using the same rule set,
            // we want to minimize the number of disk operations since the
            // method ca be called from the UI thread, hence this short-lived cache
            Dictionary<string, RuleSet> cache = new Dictionary<string, RuleSet>(StringComparer.OrdinalIgnoreCase);

            // Note: we will still may end up analyzing the same project rule set
            // but that should in marginal since it will be already loaded into memory

            // Reuse the binding information passed in to avoid reading it more than once
            return projectSystem.GetFilteredSolutionProjects()
                .Where(p => this.IsFullyBoundProject(cache, binding, p));
        }
        private static void WriteConfig(string configFile, BoundSonarQubeProject binding)
        {
            string directory = Path.GetDirectoryName(configFile);
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            File.WriteAllText(configFile, JsonHelper.Serialize(binding));
        }
        /// <summary>
        /// Update
        /// </summary>
        /// <param name="customInfoBarMessage">Optional. If provided than this will be the message that will appear in info bar, otherwise a standard one will appear instead</param>
        private void UpdateRequired(string customInfoBarMessage = null)
        {
            this.AssertOnUIThread();
            IInfoBarManager manager = this.host.GetMefService<IInfoBarManager>();
            if (manager == null)
            {
                Debug.Fail("Cannot find IInfoBarManager");
                return;
            }

            this.currentErrorWindowInfoBar = manager.AttachInfoBar(
                ErrorListToolWindowGuid,
                customInfoBarMessage ?? Strings.SonarLintInfoBarUnboundProjectsMessage,
                Strings.SonarLintInfoBarUpdateCommandText,
                KnownMonikers.RuleWarning);

            if (this.currentErrorWindowInfoBar == null)
            {
                this.OutputMessage(Strings.SonarLintFailedToAttachInfoBarToErrorList);
                Debug.Fail("Failed to add an info bar to the error list tool window");
            }
            else
            {
                TelemetryLoggerAccessor.GetLogger(this.host)?.ReportEvent(TelemetryEvent.ErrorListInfoBarShow);

                this.currentErrorWindowInfoBar.Closed += this.CurrentErrorWindowInfoBar_Closed;
                this.currentErrorWindowInfoBar.ButtonClick += this.CurrentErrorWindowInfoBar_ButtonClick;

                // Need to capture the current binding information since the user can change the binding
                // and running the Update should just no-op in that case.
                var solutionBinding = this.host.GetService<ISolutionBindingSerializer>();
                solutionBinding.AssertLocalServiceIsNotNull();

                this.infoBarBinding = solutionBinding.ReadSolutionBinding();
            }
        }
        private bool IsFullyBoundProject(Dictionary<string, RuleSet> cache, BoundSonarQubeProject binding, Project project)
        {
            Debug.Assert(binding != null);
            Debug.Assert(project != null);

            // If solution is not bound/has a missing ruleset, no need to go further
            RuleSet sonarQubeRuleSet = this.FindSonarQubeSolutionRuleSet(cache, binding, project);
            if (sonarQubeRuleSet == null)
            {
                return false;
            }

            var ruleSetInfoProvider = this.serviceProvider.GetService<ISolutionRuleSetsInformationProvider>();
            ruleSetInfoProvider.AssertLocalServiceIsNotNull();

            RuleSetDeclaration[] declarations = ruleSetInfoProvider.GetProjectRuleSetsDeclarations(project).ToArray();
            return declarations.Length > 0 // Need at least one
                && declarations.All(declaration => this.IsRuleSetBound(cache, project, declaration, sonarQubeRuleSet));
        }
        private bool WriteBindingInformation(string configFile, BoundSonarQubeProject binding)
        {
            if (this.SafePerformFileSystemOperation(() => WriteConfig(configFile, binding)))
            {
                BasicAuthCredentials credentials = binding.Credentials as BasicAuthCredentials;
                if (credentials != null)
                {
                    Debug.Assert(credentials.UserName != null, "User name is not expected to be null");
                    Debug.Assert(credentials.Password != null, "Password name is not expected to be null");

                    var creds = new Credential(credentials.UserName, credentials.Password);
                    this.credentialStore.WriteCredentials(binding.ServerUri, creds);
                }
                return true;
            }

            return false;
        }
            private bool IsUpdateRequired(BoundSonarQubeProject binding, IEnumerable<Language> projectLanguages, CancellationToken token)
            {
                Debug.Assert(binding != null);

                ConnectionInformation connection = binding.CreateConnectionInformation();
                Dictionary<Language, QualityProfile> newProfiles;
                if (!this.TryGetLatestProfiles(binding, projectLanguages, token, connection, out newProfiles))
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SonarLintProfileCheckFailed);
                    return false; // Error, can't proceed
                }

                if (!newProfiles.Keys.All(binding.Profiles.ContainsKey))
                {
                    VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SonarLintProfileCheckSolutionRequiresMoreProfiles);
                    return true; // Missing profile, refresh
                }

                foreach (var keyValue in binding.Profiles)
                {
                    Language language = keyValue.Key;
                    ApplicableQualityProfile oldProfileInfo = keyValue.Value;

                    if (!newProfiles.ContainsKey(language))
                    {
                        // Not a relevant profile, we should just ignore it.
                        continue;
                    }

                    QualityProfile newProfileInfo = newProfiles[language];
                    if (this.HasProfileChanged(newProfileInfo, oldProfileInfo))
                    {
                        return true;
                    }
                }

                VsShellUtils.WriteToSonarLintOutputPane(this.host, Strings.SonarLintProfileCheckQualityProfileIsUpToDate);
                return false; // Up-to-date
            }
            private bool TryGetLatestProfiles(BoundSonarQubeProject binding, IEnumerable<Language> projectLanguages, CancellationToken token, ConnectionInformation connection, out Dictionary<Language, QualityProfile> newProfiles)
            {
                newProfiles = new Dictionary<Language, QualityProfile>();
                foreach (Language language in projectLanguages)
                {
                    QualityProfile profile;
                    if (this.host.SonarQubeService.TryGetQualityProfile(connection, new ProjectInformation { Key = binding.ProjectKey }, language, token, out profile))
                    {
                        newProfiles[language] = profile;
                    }
                    else
                    {
                        return false; // Failed
                    }
                }

                return true;
            }
        public void SolutionBindingSerializer_ReadSolutionBinding_InvalidData()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var projectKey = "MyProject Key";
            var written = new BoundSonarQubeProject(serverUri, projectKey, creds);
            string output = testSubject.WriteSolutionBinding(written);
            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();
            Assert.IsNotNull(output, "Expected a real file");
            File.WriteAllText(output, "bla bla bla: bla");

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Verify
            Assert.IsNull(read, "Not expecting any binding information in case of error");
            this.outputPane.AssertOutputStrings(1);
        }
            public EventDrivenBindingUpdate(IHost host, BoundSonarQubeProject binding)
            {
                Debug.Assert(host != null);
                Debug.Assert(binding != null);

                this.host = host;
                this.binding = binding;
            }
        public void SolutionBindingSerializer_WriteSolutionBinding_IOError()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var projectKey = "MyProject Key";
            var written = new BoundSonarQubeProject(serverUri, projectKey, creds);
            string output = testSubject.WriteSolutionBinding(written);
            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();

            using (new FileStream(output, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                // Act (write again)
                string output2 = testSubject.WriteSolutionBinding(written);
                this.sourceControlledFileSystem.WritePendingErrorsExpected();

                // Verify
                Assert.AreEqual(output, output2, "Same output is expected");
                this.outputPane.AssertOutputStrings(1);
            }
        }
        private void ClearCurrentInfoBar()
        {
            this.CancelQualityProfileProcessing();

            this.infoBarBinding = null;
            this.currentErrorWindowInfoBarHandlingClick = false;
            if (this.currentErrorWindowInfoBar == null)
            {
                return;
            }

            this.currentErrorWindowInfoBar.Closed -= this.CurrentErrorWindowInfoBar_Closed;
            this.currentErrorWindowInfoBar.ButtonClick -= this.CurrentErrorWindowInfoBar_ButtonClick;

            IInfoBarManager manager = this.host.GetMefService<IInfoBarManager>();
            if (manager == null) // Could be null during shut down
            {
                return;
            }

            manager.DetachInfoBar(this.currentErrorWindowInfoBar);
            this.currentErrorWindowInfoBar = null;
        }
        private void ConfigureValidSonarQubeServiceWrapper(BoundSonarQubeProject binding, DateTime? timestamp, string qualityProfileKey, params Language[] expectedLanguageProfiles)
        {
            var sqService = new ConfigurableSonarQubeServiceWrapper();
            this.host.SonarQubeService = sqService;

            sqService.AllowConnections = true;
            sqService.ExpectedConnection = binding.CreateConnectionInformation();
            sqService.ExpectedProjectKey = binding.ProjectKey;

            foreach (Language language in expectedLanguageProfiles)
            {
                sqService.ReturnProfile[language] = new QualityProfile
                {
                    Key = qualityProfileKey,
                    Language = SonarQubeServiceWrapper.GetServerLanguageKey(language),
                    QualityProfileTimestamp = timestamp
                };
            }
        }
        private RuleSet FindSonarQubeSolutionRuleSet(Dictionary<string, RuleSet> cache, BoundSonarQubeProject binding, Project project)
        {
            var ruleSetInfoProvider = this.serviceProvider.GetService<ISolutionRuleSetsInformationProvider>();
            ruleSetInfoProvider.AssertLocalServiceIsNotNull();

            string expectedSolutionRuleSet = ruleSetInfoProvider.CalculateSolutionSonarQubeRuleSetFilePath(
                         binding.ProjectKey,
                         Language.ForProject(project));

            RuleSet solutionRuleSet;
            if (!cache.TryGetValue(expectedSolutionRuleSet, out solutionRuleSet))
            {
                var ruleSetSerializer = this.serviceProvider.GetService<IRuleSetSerializer>();
                ruleSetSerializer.AssertLocalServiceIsNotNull();

                solutionRuleSet = ruleSetSerializer.LoadRuleSet(expectedSolutionRuleSet);
                cache[expectedSolutionRuleSet] = solutionRuleSet;
            }

            return solutionRuleSet;
        }
        public void SolutionBindingSerializer_WriteSolutionBinding_AddConfigFileToSolutionItemsFolder()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var projectKey = "MyProject Key";
            var toWrite = new BoundSonarQubeProject(serverUri, projectKey, creds);
            ProjectMock solutionProject = (ProjectMock)this.projectSystemHelper.SolutionItemsProject;

            // Act
            string output = testSubject.WriteSolutionBinding(toWrite);

            // Verify that not actually done anything until the pending files were written
            this.store.AssertHasNoCredentials(serverUri);
            Assert.IsFalse(solutionProject.Files.ContainsKey(output), "Not expected to be added to solution items folder just yet");

            // Act (write pending)
            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();

            // Verify
            this.store.AssertHasCredentials(serverUri);
            Assert.IsTrue(solutionProject.Files.ContainsKey(output), "File {0} was not added to project", output);

            // Act (write again)
            string output2 = testSubject.WriteSolutionBinding(toWrite);
            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();

            // Verify
            Assert.AreEqual(output, output2, "Should be the same file");
            this.store.AssertHasCredentials(serverUri);
            Assert.IsTrue(solutionProject.Files.ContainsKey(output), "File {0} should remain in the project", output);
        }
        private void ExecuteUpdate(BoundSonarQubeProject binding)
        {
            Debug.Assert(binding != null);

            EventDrivenBindingUpdate binder = new EventDrivenBindingUpdate(this.host, binding);

            EventHandler<BindingRequestResult> onFinished = null;
            onFinished = (o, result) =>
            {
                // Resume click handling (if applicable)
                this.currentErrorWindowInfoBarHandlingClick = false;

                binder.Finished -= onFinished;
                switch (result)
                {
                    case BindingRequestResult.CommandIsBusy:
                        // Might be building/debugging/etc...
                        // Need to click 'Update' again to retry.
                        this.OutputMessage(Strings.SonarLintInfoBarUpdateCommandIsBusyRetry);
                        break;
                    case BindingRequestResult.NoActiveSection:
                        // We drive the process via the active section, we can proceed without it.
                        // Need to click 'Update' again.
                        // This is case is fairly unlikely, so just writing to the output window will be enough
                        this.OutputMessage(Strings.SonarLintInfoBarUpdateCommandRetryNoActiveSection);
                        break;
                    case BindingRequestResult.StartedUpdating:
                    case BindingRequestResult.RequestIsIrrelevant:
                        this.ClearCurrentInfoBar();
                        break;
                    default:
                        Debug.Fail($"Unexpected result: {result}");
                        break;
                }
            };

            binder.Finished += onFinished;
            binder.ConnectAndBind();
        }
        public void SolutionBindingSerializer_WriteSolutionBinding_ReadSolutionBinding_OnRealStore()
        {
            // Setup
            var testSubject = new SolutionBindingSerializer(this.serviceProvider);
            var serverUri = new Uri("http://xxx.www.zzz/yyy:9000");
            var projectKey = "MyProject Key";
            testSubject.Store.DeleteCredentials(serverUri);

            // Case 1: has credentials
            var creds = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var written = new BoundSonarQubeProject(serverUri, projectKey, creds);

            // Act (write + read)
            BoundSonarQubeProject read = null;
            try
            {
                testSubject.WriteSolutionBinding(written);
                this.sourceControlledFileSystem.WritePendingNoErrorsExpected();
                read = testSubject.ReadSolutionBinding();
            }
            finally
            {
                testSubject.Store.DeleteCredentials(serverUri);
            }

            // Verify
            var newCreds = read.Credentials as BasicAuthCredentials;
            Assert.AreNotEqual(creds, newCreds, "Different credential instance were expected");
            Assert.AreEqual(creds.UserName, newCreds.UserName);
            Assert.AreEqual(creds.Password.ConvertToUnsecureString(), newCreds?.Password.ConvertToUnsecureString());
            Assert.AreEqual(written.ServerUri, read.ServerUri);
            this.outputPane.AssertOutputStrings(0);

            // Case 2: has not credentials (anonymous)
            creds = null;
            written = new BoundSonarQubeProject(serverUri, projectKey, creds);

            // Act (write + read)
            read = null;
            try
            {
                testSubject.WriteSolutionBinding(written);
                read = testSubject.ReadSolutionBinding();
            }
            finally
            {
                testSubject.Store.DeleteCredentials(serverUri);
            }

            // Verify
            Assert.IsNull(read.Credentials);
            Assert.AreEqual(written.ServerUri, read.ServerUri);
            this.outputPane.AssertOutputStrings(0);
        }
        public bool Save(string filePath, BoundSonarQubeProject project)
        {
            var serializedProject = Serialize(project);

            return(SafePerformFileSystemOperation(() => WriteConfig(filePath, serializedProject)));
        }
        /// <summary>
        /// Will bend add/edit the binding information for next time usage
        /// </summary>
        private void PendBindingInformation(ConnectionInformation connInfo)
        {
            Debug.Assert(this.qualityProfileMap != null, "Initialize was expected to be called first");

            var binding = this.serviceProvider.GetService<ISolutionBindingSerializer>();
            binding.AssertLocalServiceIsNotNull();

            BasicAuthCredentials credentials = connection.UserName == null ? null : new BasicAuthCredentials(connInfo.UserName, connInfo.Password);

            Dictionary<Language, ApplicableQualityProfile> map = new Dictionary<Language, ApplicableQualityProfile>();

            foreach (var keyValue in this.qualityProfileMap)
            {
                map[keyValue.Key] = new ApplicableQualityProfile
                {
                    ProfileKey = keyValue.Value.Key,
                    ProfileTimestamp = keyValue.Value.QualityProfileTimestamp
                };
            }

            var bound = new BoundSonarQubeProject(connInfo.ServerUri, this.sonarQubeProjectKey, credentials);
            bound.Profiles = map;

            binding.WriteSolutionBinding(bound);
        }