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