internal /* for testing */ static bool ShouldMergeAnalysisSettings(string language, AnalysisConfig config, Common.ILogger logger) { Debug.Assert(!string.IsNullOrEmpty(language)); Debug.Assert(config != null); // See https://github.com/SonarSource/sonar-scanner-msbuild/issues/561 // Legacy behaviour is to overwrite. // The new (SQ 7.4+) behaviour is to merge only if sonar.[LANGUAGE].roslyn.ignoreIssues is false. var serverVersion = config?.FindServerVersion(); if (serverVersion == null || serverVersion < new Version("7.4")) { logger.LogInfo(Resources.AnalyzerSettings_ExternalIssueNotSupported, SonarProduct.GetSonarProductToLog(config?.SonarQubeHostUrl)); return(false); } var settingName = $"sonar.{language}.roslyn.ignoreIssues"; var settingInFile = config.GetSettingOrDefault(settingName, includeServerSettings: true, defaultValue: "false"); if (bool.TryParse(settingInFile, out var ignoreExternalRoslynIssues)) { logger.LogDebug(Resources.AnalyzerSettings_ImportAllSettingValue, settingName, ignoreExternalRoslynIssues.ToString().ToLowerInvariant()); return(!ignoreExternalRoslynIssues); } else { logger.LogWarning(Resources.AnalyzerSettings_InvalidValueForImportAll, settingName, settingInFile); return(false); } }
public bool TryWriteProperties(PropertiesWriter writer, out IEnumerable <ProjectData> allProjects) { var projects = ProjectLoader.LoadFrom(analysisConfig.SonarOutputDir); if (!projects.Any()) { logger.LogError(Resources.ERR_NoProjectInfoFilesFound, SonarProduct.GetSonarProductToLog(analysisConfig.SonarQubeHostUrl)); allProjects = Enumerable.Empty <ProjectData>(); return(false); } var projectsWithoutGuid = projects.Where(p => p.ProjectGuid == Guid.Empty).ToList(); if (projectsWithoutGuid.Count > 0) { logger.LogWarning(Resources.WARN_EmptyProjectGuids, string.Join(", ", projectsWithoutGuid.Select(p => p.FullPath))); } var projectDirectories = projects.Select(p => p.GetDirectory()).ToList(); var analysisProperties = analysisConfig.ToAnalysisProperties(logger); FixSarifAndEncoding(projects, analysisProperties); allProjects = projects.GroupBy(p => p.ProjectGuid).Select(ToProjectData).ToList(); var validProjects = allProjects.Where(p => p.Status == ProjectInfoValidity.Valid).ToList(); if (validProjects.Count == 0) { logger.LogError(Resources.ERR_NoValidProjectInfoFiles, SonarProduct.GetSonarProductToLog(analysisConfig.SonarQubeHostUrl)); return(false); } var rootProjectBaseDir = ComputeRootProjectBaseDir(projectDirectories); if (rootProjectBaseDir == null || !rootProjectBaseDir.Exists) { logger.LogError(Resources.ERR_ProjectBaseDirDoesNotExist); return(false); } var rootModuleFiles = PutFilesToRightModuleOrRoot(validProjects, rootProjectBaseDir); PostProcessProjectStatus(validProjects); if (rootModuleFiles.Count == 0 && validProjects.All(p => p.Status == ProjectInfoValidity.NoFilesToAnalyze)) { logger.LogError(Resources.ERR_NoValidProjectInfoFiles, SonarProduct.GetSonarProductToLog(analysisConfig.SonarQubeHostUrl)); return(false); } writer.WriteSonarProjectInfo(rootProjectBaseDir); writer.WriteSharedFiles(rootModuleFiles); validProjects.ForEach(writer.WriteSettingsForProject); // Handle global settings writer.WriteGlobalSettings(analysisProperties); return(true); }
public override bool Execute() { var logger = new MSBuildLoggerAdapter(Log); var config = TaskUtilities.TryGetConfig(AnalysisConfigDir, logger); var languageSettings = GetLanguageSpecificSettings(config); if (languageSettings == null) { // Early-out: we don't have any settings for the current language. // Preserve the default existing behaviour of only preserving the original list of additional files but clearing the analyzers. RuleSetFilePath = null; AdditionalFilePaths = OriginalAdditionalFiles; return(!Log.HasLoggedErrors); } TaskOutputs outputs; // We analyze test projects since MMF-2297 / SQ 8.9. C#/VB.NET plugin <= 8.20 bundled with SQ <= 8.8 would ignore results on test projects anyway. if (IsTestProject && (ExcludeTestProjects() || !IsTestAnalysisSupported())) { // Special case: to provide colorization etc for code in test projects, we need to run only the SonarC#/VB analyzers, with all of the non-utility rules turned off // See [MMF-486]: https://jira.sonarsource.com/browse/MMF-486 Log.LogMessage(MessageImportance.Low, Resources.AnalyzerSettings_ConfiguringTestProjectAnalysis); outputs = CreateDeactivatedProjectSettings(languageSettings); } else { if (ShouldMergeAnalysisSettings(Language, config, logger)) { Log.LogMessage(MessageImportance.Low, Resources.AnalyzerSettings_MergingSettings); outputs = CreateMergedAnalyzerSettings(languageSettings); } else { Log.LogMessage(MessageImportance.Low, Resources.AnalyzerSettings_OverwritingSettings); outputs = CreateLegacyProductProjectSettings(languageSettings); } } ApplyTaskOutput(outputs); return(!Log.HasLoggedErrors); bool ExcludeTestProjects() => config.GetAnalysisSettings(false).TryGetValue(ExcludeTestProjectsSettingId, out var excludeTestProjects) && excludeTestProjects.Equals("true", StringComparison.OrdinalIgnoreCase); bool IsTestAnalysisSupported() { var version = config.FindServerVersion(); return(SonarProduct.IsSonarCloud(config.SonarQubeHostUrl, version) || version >= new Version(8, 9)); } }
[DataRow(false, "https://sonarcloud.io", "9.0")] // SC is defined as "Version 8.0" public void IsSonarCloud(bool expected, string host, string version) => SonarProduct.IsSonarCloud(host, new Version(version)).Should().Be(expected);
public void GetSonarProductToLog(string host, string expectedName) => SonarProduct.GetSonarProductToLog(host).Should().Be(expectedName);
/// <summary> /// Locates the ProjectInfo.xml files and uses the information in them to generate /// a sonar-scanner properties file /// </summary> /// <returns>Information about each of the project info files that was processed, together with /// the full path to generated file. /// Note: the path to the generated file will be null if the file could not be generated.</returns> public ProjectInfoAnalysisResult GenerateFile() { var projectPropertiesPath = Path.Combine(analysisConfig.SonarOutputDir, ProjectPropertiesFileName); logger.LogDebug(Resources.MSG_GeneratingProjectProperties, projectPropertiesPath, SonarProduct.GetSonarProductToLog(analysisConfig.SonarQubeHostUrl)); var result = new ProjectInfoAnalysisResult(); var writer = new PropertiesWriter(analysisConfig, logger); var success = TryWriteProperties(writer, out IEnumerable <ProjectData> projects); if (success) { var contents = writer.Flush(); File.WriteAllText(projectPropertiesPath, contents, Encoding.ASCII); logger.LogDebug(Resources.DEBUG_DumpSonarProjectProperties, contents); result.FullPropertiesFilePath = projectPropertiesPath; } else { logger.LogInfo(Resources.MSG_PropertiesGenerationFailed); } result.Projects.AddRange(projects); return(result); }
private void LogDuplicateGuidWarning(Guid projectGuid, string projectPath) => logger.LogWarning(Resources.WARN_DuplicateProjectGuid, projectGuid, projectPath, SonarProduct.GetSonarProductToLog(analysisConfig.SonarQubeHostUrl));
private void LogStartupSettings(AnalysisConfig config, ITeamBuildSettings settings) { var configFileName = config == null ? string.Empty : config.FileName; logger.LogDebug(Resources.MSG_LoadingConfig, configFileName, config != null ? SonarProduct.GetSonarProductToLog(config.SonarQubeHostUrl) : "Sonar"); switch (settings.BuildEnvironment) { case BuildEnvironment.LegacyTeamBuild: logger.LogDebug(Resources.SETTINGS_InLegacyTeamBuild); break; case BuildEnvironment.TeamBuild: logger.LogDebug(Resources.SETTINGS_InTeamBuild); break; case BuildEnvironment.NotTeamBuild: logger.LogDebug(Resources.SETTINGS_NotInTeamBuild); break; default: break; } logger.LogDebug(Resources.SETTING_DumpSettings, settings.AnalysisBaseDirectory, settings.BuildDirectory, settings.SonarBinDirectory, settings.SonarConfigDirectory, settings.SonarOutputDirectory, settings.AnalysisConfigFilePath); }
private async Task <bool> IsSonarCloud() => SonarProduct.IsSonarCloud(this.serverUrl, await GetServerVersion());