public void AnalysisConfig_Serialization_InvalidFileName()
        {
            // 0. Setup
            AnalysisConfig config = new AnalysisConfig();

            // 1a. Missing file name - save
            AssertException.Expects<ArgumentNullException>(() => config.Save(null));
            AssertException.Expects<ArgumentNullException>(() => config.Save(string.Empty));
            AssertException.Expects<ArgumentNullException>(() => config.Save("\r\t "));

            // 1b. Missing file name - load
            AssertException.Expects<ArgumentNullException>(() => ProjectInfo.Load(null));
            AssertException.Expects<ArgumentNullException>(() => ProjectInfo.Load(string.Empty));
            AssertException.Expects<ArgumentNullException>(() => ProjectInfo.Load("\r\t "));
        }
        [WorkItem(120)] // Regression test for http://jira.sonarsource.com/browse/SONARMSBRU-120
        public void AnalysisConfig_SharedReadAllowed()
        {
            // 0. Setup
            string testFolder = TestUtils.CreateTestSpecificFolder(this.TestContext);
            string filePath = Path.Combine(testFolder, "config.txt");

            AnalysisConfig config = new AnalysisConfig();
            config.Save(filePath);

            using (FileStream lockingStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                AnalysisConfig.Load(filePath);
            }
        }
        private AnalysisConfig SaveAndReloadConfig(AnalysisConfig original, string outputFileName)
        {
            Assert.IsFalse(File.Exists(outputFileName), "Test error: file should not exist at the start of the test. File: {0}", outputFileName);
            original.Save(outputFileName);
            Assert.IsTrue(File.Exists(outputFileName), "Failed to create the output file. File: {0}", outputFileName);
            this.TestContext.AddResultFile(outputFileName);

            AnalysisConfig reloaded = AnalysisConfig.Load(outputFileName);
            Assert.IsNotNull(reloaded, "Reloaded analysis config should not be null");

            AssertExpectedValues(original, reloaded);
            return reloaded;
        }
        public void Roslyn_Settings_ValidSetup()
        {
            // Arrange

            // Set the config directory so the targets know where to look for the analysis config file
            var confDir = TestUtils.CreateTestSpecificFolder(TestContext, "config");

            // Create a valid config file containing analyzer settings
            var expectedAssemblies      = new string[] { "c:\\data\\config.analyzer1.dll", "c:\\config2.dll" };
            var analyzerAdditionalFiles = new string[] { "c:\\config.1.txt", "c:\\config.2.txt" };

            var config = new AnalysisConfig();

            var analyzerSettings = new AnalyzerSettings
            {
                Language              = "cs",
                RuleSetFilePath       = "d:\\my.ruleset",
                AnalyzerAssemblyPaths = expectedAssemblies.ToList(),
                AdditionalFilePaths   = analyzerAdditionalFiles.ToList()
            };

            config.AnalyzersSettings = new List <AnalyzerSettings>
            {
                analyzerSettings
            };

            var configFilePath = Path.Combine(confDir, FileConstants.ConfigFileName);

            config.Save(configFilePath);

            // Create the project
            var properties = new WellKnownProjectProperties
            {
                SonarQubeConfigPath         = confDir,
                ResolvedCodeAnalysisRuleset = "c:\\should.be.overridden.ruleset"
            };

            var projectRoot = CreateValidProjectSetup(properties);

            projectRoot.AddItem(TargetProperties.AnalyzerItemType, "should.be.removed.analyzer1.dll");
            projectRoot.AddItem(TargetProperties.AnalyzerItemType, "c:\\should.be.removed.analyzer2.dll");

            var notRemovedAdditionalFiles = new string[] { "should.not.be.removed.additional1.txt", "should.not.be.removed.additional2.txt" };

            foreach (var notRemovedAdditionalFile in notRemovedAdditionalFiles)
            {
                projectRoot.AddItem(TargetProperties.AdditionalFilesItemType, notRemovedAdditionalFile);
            }

            projectRoot.Save(); // re-save the modified project

            // Act
            var result = BuildRunner.BuildTargets(TestContext, projectRoot.FullPath,
                                                  TargetConstants.OverrideRoslynAnalysisTarget);

            var projectSpecificConfFilePath   = result.GetCapturedPropertyValue(TargetProperties.ProjectConfFilePath);
            var expectedRoslynAdditionalFiles = new string[] { projectSpecificConfFilePath }
            .Concat(analyzerAdditionalFiles)
            .Concat(notRemovedAdditionalFiles)
            .ToArray();

            // Assert
            result.AssertTargetExecuted(TargetConstants.OverrideRoslynAnalysisTarget);
            result.AssertTargetExecuted(TargetConstants.SetRoslynAnalysisPropertiesTarget);
            result.BuildSucceeded.Should().BeTrue();

            // Check the error log and ruleset properties are set
            AssertErrorLogIsSetBySonarQubeTargets(result);
            AssertExpectedResolvedRuleset(result, "d:\\my.ruleset");
            AssertExpectedItemValuesExists(result, TargetProperties.AdditionalFilesItemType, expectedRoslynAdditionalFiles);
            AssertExpectedItemValuesExists(result, TargetProperties.AnalyzerItemType, expectedAssemblies);

            AssertWarningsAreNotTreatedAsErrorsNorIgnored(result);
        }
예제 #5
0
        /// <summary>
        /// Combines the various configuration options into the AnalysisConfig file
        /// used by the build and post-processor. Saves the file and returns the config instance.
        /// </summary>
        /// <param name="localSettings">Processed local settings, including command line arguments supplied the user</param>
        /// <param name="buildSettings">Build environment settings</param>
        /// <param name="serverProperties">Analysis properties downloaded from the SonarQube server</param>
        /// <param name="analyzerSettings">Specifies the Roslyn analyzers to use. Can be empty</param>
        public static AnalysisConfig GenerateFile(ProcessedArgs localSettings,
                                                  TeamBuildSettings buildSettings,
                                                  IDictionary <string, string> serverProperties,
                                                  List <AnalyzerSettings> analyzersSettings,
                                                  ISonarQubeServer sonarQubeServer,
                                                  ILogger logger)
        {
            if (localSettings == null)
            {
                throw new ArgumentNullException(nameof(localSettings));
            }
            if (buildSettings == null)
            {
                throw new ArgumentNullException(nameof(buildSettings));
            }
            if (serverProperties == null)
            {
                throw new ArgumentNullException(nameof(serverProperties));
            }
            if (sonarQubeServer == null)
            {
                throw new ArgumentNullException(nameof(sonarQubeServer));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            var config = new AnalysisConfig
            {
                SonarProjectKey     = localSettings.ProjectKey,
                SonarProjectName    = localSettings.ProjectName,
                SonarProjectVersion = localSettings.ProjectVersion,
                SonarQubeHostUrl    = localSettings.SonarQubeUrl,
                HasBeginStepCommandLineCredentials = localSettings.CmdLineProperties.HasProperty(SonarProperties.SonarUserName),
                SonarQubeVersion = sonarQubeServer.GetServerVersion().Result.ToString()
            };

            config.SetBuildUri(buildSettings.BuildUri);
            config.SetTfsUri(buildSettings.TfsUri);
            config.SetVsCoverageConverterToolPath(buildSettings.CoverageToolUserSuppliedPath);

            config.SonarConfigDir = buildSettings.SonarConfigDirectory;
            config.SonarOutputDir = buildSettings.SonarOutputDirectory;
            config.SonarBinDir    = buildSettings.SonarBinDirectory;
            config.SonarScannerWorkingDirectory = buildSettings.SonarScannerWorkingDirectory;
            config.SourcesDirectory             = buildSettings.SourcesDirectory;

            // Add the server properties to the config
            config.ServerSettings = new AnalysisProperties();

            foreach (var property in serverProperties)
            {
                if (!Utilities.IsSecuredServerProperty(property.Key))
                {
                    AddSetting(config.ServerSettings, property.Key, property.Value);
                }
            }

            config.LocalSettings = new AnalysisProperties();
            // From the local settings, we only write the ones coming from the cmd line
            foreach (var property in localSettings.CmdLineProperties.GetAllProperties())
            {
                AddSetting(config.LocalSettings, property.Id, property.Value);
            }

            if (!string.IsNullOrEmpty(localSettings.Organization))
            {
                AddSetting(config.LocalSettings, SonarProperties.Organization, localSettings.Organization);
            }

            // Set the pointer to the properties file
            if (localSettings.PropertiesFileName != null)
            {
                config.SetSettingsFilePath(localSettings.PropertiesFileName);
            }

            config.AnalyzersSettings = analyzersSettings ?? throw new ArgumentNullException(nameof(analyzersSettings));
            config.Save(buildSettings.AnalysisConfigFilePath);

            return(config);
        }
        private string CreateProjectFile(AnalysisConfig analysisConfig, string testSpecificProjectXml, string sonarQubeOutputPath)
        {
            var projectDirectory = TestUtils.CreateTestSpecificFolder(TestContext);

            if (analysisConfig != null)
            {
                var configFilePath = Path.Combine(projectDirectory, FileConstants.ConfigFileName);
                analysisConfig.Save(configFilePath);
            }

            var sqTargetFile = TestUtils.EnsureAnalysisTargetsExists(TestContext);

            File.Exists(sqTargetFile).Should().BeTrue("Test error: the SonarQube analysis targets file could not be found. Full path: {0}", sqTargetFile);
            TestContext.AddResultFile(sqTargetFile);


            var template    = @"<?xml version='1.0' encoding='utf-8'?>
<Project ToolsVersion='15.0' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>

  <!-- Boilerplate -->
  <!-- All of these boilerplate properties can be overridden by setting the value again in the test-specific XML snippet -->
  <PropertyGroup>
    <ImportByWildcardBeforeMicrosoftCommonTargets>false</ImportByWildcardBeforeMicrosoftCommonTargets>
    <ImportByWildcardAfterMicrosoftCommonTargets>false</ImportByWildcardAfterMicrosoftCommonTargets>
    <ImportUserLocationsByWildcardBeforeMicrosoftCommonTargets>false</ImportUserLocationsByWildcardBeforeMicrosoftCommonTargets>
    <ImportUserLocationsByWildcardAfterMicrosoftCommonTargets>false</ImportUserLocationsByWildcardAfterMicrosoftCommonTargets>
    <OutputPath>bin\</OutputPath>
    <OutputType>library</OutputType>
    <ProjectGuid>ffdb93c0-2880-44c7-89a6-bbd4ddab034a</ProjectGuid>
    <Language>C#</Language>
  </PropertyGroup>

  <PropertyGroup>
    <!-- Standard values that need to be set for each/most tests -->
    <SonarQubeBuildTasksAssemblyFile>SONARSCANNER_MSBUILD_TASKS_DLL</SonarQubeBuildTasksAssemblyFile>
    <SonarQubeConfigPath>PROJECT_DIRECTORY_PATH</SonarQubeConfigPath>
    <SonarQubeTempPath>PROJECT_DIRECTORY_PATH</SonarQubeTempPath>
    <SonarQubeOutputPath>SQ_OUTPUT_PATH</SonarQubeOutputPath>

    <!-- Ensure the project is isolated from environment variables that could be picked up when running on a TeamBuild build agent-->
    <TF_BUILD_BUILDDIRECTORY />
    <AGENT_BUILDDIRECTORY />
  </PropertyGroup>

  <!-- Test-specific data -->
  TEST_SPECIFIC_XML

  <!-- Standard boilerplate closing imports -->
  <Import Project='$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), SonarQube.Integration.targets))SonarQube.Integration.targets' />
  <Import Project='$(MSBuildToolsPath)\Microsoft.CSharp.targets' />
</Project>
";
            var projectData = template.Replace("PROJECT_DIRECTORY_PATH", projectDirectory)
                              .Replace("SONARSCANNER_MSBUILD_TASKS_DLL", typeof(WriteProjectInfoFile).Assembly.Location)
                              .Replace("TEST_SPECIFIC_XML", testSpecificProjectXml ?? "<!-- none -->")
                              .Replace("SQ_OUTPUT_PATH", sonarQubeOutputPath);

            var projectFilePath = Path.Combine(projectDirectory, TestContext.TestName + ".proj.txt");

            File.WriteAllText(projectFilePath, projectData);
            TestContext.AddResultFile(projectFilePath);

            return(projectFilePath);
        }
예제 #7
0
        /// <summary>
        /// Combines the various configuration options into the AnalysisConfig file
        /// used by the build and post-processor. Saves the file and returns the config instance.
        /// </summary>
        /// <param name="args">Processed command line arguments supplied the user</param>
        /// <param name="buildSettings">Build environment settings</param>
        /// <param name="serverProperties">Analysis properties downloaded from the SonarQube server</param>
        /// <param name="analyzerSettings">Specifies the Roslyn analyzers to use</param>
        public static AnalysisConfig GenerateFile(ProcessedArgs args,
                                                  TeamBuildSettings buildSettings,
                                                  IDictionary <string, string> serverProperties,
                                                  List <AnalyzerSettings> analyzersSettings,
                                                  ILogger logger)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }
            if (buildSettings == null)
            {
                throw new ArgumentNullException(nameof(buildSettings));
            }
            if (serverProperties == null)
            {
                throw new ArgumentNullException(nameof(serverProperties));
            }
            if (analyzersSettings == null)
            {
                throw new ArgumentNullException(nameof(analyzersSettings));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            AnalysisConfig config = new AnalysisConfig();

            config.SonarProjectKey     = args.ProjectKey;
            config.SonarProjectName    = args.ProjectName;
            config.SonarProjectVersion = args.ProjectVersion;
            config.SonarQubeHostUrl    = args.GetSetting(SonarProperties.HostUrl);

            config.SetBuildUri(buildSettings.BuildUri);
            config.SetTfsUri(buildSettings.TfsUri);

            config.SonarConfigDir = buildSettings.SonarConfigDirectory;
            config.SonarOutputDir = buildSettings.SonarOutputDirectory;
            config.SonarBinDir    = buildSettings.SonarBinDirectory;
            config.SonarScannerWorkingDirectory = buildSettings.SonarScannerWorkingDirectory;
            config.SourcesDirectory             = buildSettings.SourcesDirectory;

            // Add the server properties to the config
            config.ServerSettings = new AnalysisProperties();

            foreach (var property in serverProperties)
            {
                if (!Utilities.IsSecuredServerProperty(property.Key))
                {
                    AddSetting(config.ServerSettings, property.Key, property.Value);
                }
            }

            config.LocalSettings = new AnalysisProperties();
            foreach (var property in args.LocalProperties.GetAllProperties())
            {
                AddSetting(config.LocalSettings, property.Id, property.Value);
            }

            // Set the pointer to the properties file
            if (args.PropertiesFileName != null)
            {
                config.SetSettingsFilePath(args.PropertiesFileName);
            }

            config.AnalyzersSettings = analyzersSettings;

            config.Save(buildSettings.AnalysisConfigFilePath);

            return(config);
        }
        public bool Execute(ILogger logger, string projectKey, string projectName, string projectVersion, string propertiesPath)
        {
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }
            if (string.IsNullOrWhiteSpace(projectKey))
            {
                throw new ArgumentNullException("projectKey");
            }
            if (string.IsNullOrWhiteSpace(projectName))
            {
                throw new ArgumentNullException("projectName");
            }
            if (string.IsNullOrWhiteSpace(projectVersion))
            {
                throw new ArgumentNullException("projectVersion");
            }
            if (string.IsNullOrWhiteSpace(propertiesPath))
            {
                throw new ArgumentNullException("propertiesPath");
            }

            AnalysisConfig config = new AnalysisConfig();

            config.SonarProjectKey           = projectKey;
            config.SonarProjectName          = projectName;
            config.SonarProjectVersion       = projectVersion;
            config.SonarRunnerPropertiesPath = propertiesPath;

            TeamBuildSettings teamBuildSettings = TeamBuildSettings.GetSettingsFromEnvironment(logger);

            // We're checking the args and environment variables so we can report all
            // config errors to the user at once
            if (teamBuildSettings == null)
            {
                logger.LogError(Resources.ERROR_CannotPerformProcessing);
                return(false);
            }

            config.SetBuildUri(teamBuildSettings.BuildUri);
            config.SetTfsUri(teamBuildSettings.TfsUri);
            config.SonarConfigDir = teamBuildSettings.SonarConfigDirectory;
            config.SonarOutputDir = teamBuildSettings.SonarOutputDirectory;

            // Create the directories
            logger.LogMessage(Resources.DIAG_CreatingFolders);
            EnsureEmptyDirectory(logger, config.SonarConfigDir);
            EnsureEmptyDirectory(logger, config.SonarOutputDir);

            using (SonarWebService ws = GetSonarWebService(config))
            {
                // Fetch the SonarQube project properties
                FetchSonarQubeProperties(config, ws);

                // Generate the FxCop ruleset
                GenerateFxCopRuleset(config, ws, logger);
            }

            // Save the config file
            logger.LogMessage(Resources.DIAG_SavingConfigFile, teamBuildSettings.AnalysisConfigFilePath);
            config.Save(teamBuildSettings.AnalysisConfigFilePath);

            return(true);
        }
예제 #9
0
        public void Roslyn_Settings_ValidSetup()
        {
            // Arrange
            BuildLogger logger = new BuildLogger();

            // Set the config directory so the targets know where to look for the analysis config file
            string confDir = TestUtils.CreateTestSpecificFolder(this.TestContext, "config");

            // Create a valid config file containing analyzer settings
            string[] expectedAssemblies      = new string[] { "c:\\data\\config.analyzer1.dll", "c:\\config2.dll" };
            string[] analyzerAdditionalFiles = new string[] { "c:\\config.1.txt", "c:\\config.2.txt" };

            AnalysisConfig config = new AnalysisConfig();

            AnalyzerSettings analyzerSettings = new AnalyzerSettings();

            analyzerSettings.Language              = "cs";
            analyzerSettings.RuleSetFilePath       = "d:\\my.ruleset";
            analyzerSettings.AnalyzerAssemblyPaths = expectedAssemblies.ToList();
            analyzerSettings.AdditionalFilePaths   = analyzerAdditionalFiles.ToList();
            config.AnalyzersSettings = new List <AnalyzerSettings>();
            config.AnalyzersSettings.Add(analyzerSettings);

            string configFilePath = Path.Combine(confDir, FileConstants.ConfigFileName);

            config.Save(configFilePath);

            // Create the project
            WellKnownProjectProperties properties = new WellKnownProjectProperties();

            properties.SonarQubeConfigPath         = confDir;
            properties.ResolvedCodeAnalysisRuleset = "c:\\should.be.overridden.ruleset";

            ProjectRootElement projectRoot = CreateValidProjectSetup(properties);

            projectRoot.AddItem(TargetProperties.AnalyzerItemType, "should.be.removed.analyzer1.dll");
            projectRoot.AddItem(TargetProperties.AnalyzerItemType, "c:\\should.be.removed.analyzer2.dll");

            string[] notRemovedAdditionalFiles = new string[] { "should.not.be.removed.additional1.txt", "should.not.be.removed.additional2.txt" };

            foreach (var notRemovedAdditionalFile in notRemovedAdditionalFiles)
            {
                projectRoot.AddItem(TargetProperties.AdditionalFilesItemType, notRemovedAdditionalFile);
            }

            // Act
            BuildResult result = BuildUtilities.BuildTargets(projectRoot, logger, TargetConstants.OverrideRoslynAnalysisTarget);

            string projectSpecificConfFilePath = result.ProjectStateAfterBuild.GetPropertyValue(TargetProperties.ProjectConfFilePath);

            string[] expectedRoslynAdditionalFiles = new string[] { projectSpecificConfFilePath }
            .Concat(analyzerAdditionalFiles)
            .Concat(notRemovedAdditionalFiles)
            .ToArray();

            // Assert
            logger.AssertTargetExecuted(TargetConstants.OverrideRoslynAnalysisTarget);
            logger.AssertTargetExecuted(TargetConstants.SetRoslynAnalysisPropertiesTarget);
            BuildAssertions.AssertTargetSucceeded(result, TargetConstants.OverrideRoslynAnalysisTarget);

            // Check the error log and ruleset properties are set
            AssertErrorLogIsSetBySonarQubeTargets(result);
            AssertExpectedResolvedRuleset(result, "d:\\my.ruleset");
            AssertExpectedItemValuesExists(result, TargetProperties.AdditionalFilesItemType, expectedRoslynAdditionalFiles);
            AssertExpectedItemValuesExists(result, TargetProperties.AnalyzerItemType, expectedAssemblies);

            BuildAssertions.AssertWarningsAreNotTreatedAsErrorsNorIgnored(result);
        }
        public void E2E_FxCop_TestProject_TestProjectByName()
        {
            // Arrange
            string rootInputFolder  = TestUtils.CreateTestSpecificFolder(this.TestContext, "Inputs");
            string rootOutputFolder = TestUtils.CreateTestSpecificFolder(this.TestContext, "Outputs");

            string fxCopLogFile = Path.Combine(rootInputFolder, "FxCopResults.xml");
            WellKnownProjectProperties preImportProperties = new WellKnownProjectProperties();

            preImportProperties.SonarQubeTempPath   = rootOutputFolder; // FIXME
            preImportProperties.SonarQubeOutputPath = rootOutputFolder;
            preImportProperties.CodeAnalysisLogFile = fxCopLogFile;
            preImportProperties.CodeAnalysisRuleset = "specifiedInProject.ruleset";

            preImportProperties.SonarQubeConfigPath = rootInputFolder;

            preImportProperties[TargetProperties.SonarQubeConfigPath] = rootInputFolder;
            CreateValidFxCopRuleset(rootInputFolder, string.Format(TargetProperties.SonarQubeRulesetFormat, "cs"));

            // Create a config file in the config folder containing a reg ex to identify tests projects
            AnalysisConfig config = new AnalysisConfig();

            config.LocalSettings = new AnalysisProperties();
            config.LocalSettings.Add(new Property()
            {
                Id = IsTestFileByName.TestRegExSettingId, Value = ".testp."
            });

            string configFullPath = Path.Combine(rootInputFolder, FileConstants.ConfigFileName);

            config.Save(configFullPath);

            // Create a project with a file name that will match the reg ex
            ProjectDescriptor  descriptor  = BuildUtilities.CreateValidProjectDescriptor(rootInputFolder, "MyTestProject.proj");
            ProjectRootElement projectRoot = BuildUtilities.CreateInitializedProjectRoot(this.TestContext, descriptor, preImportProperties);


            // Add a file to the project
            string itemPath = TestUtils.CreateTextFile(rootInputFolder, "code1.cs", "class myclassXXX{}");

            projectRoot.AddItem(TargetProperties.ItemType_Compile, itemPath);
            projectRoot.Save();

            BuildLogger logger = new BuildLogger();

            // Act
            BuildResult result = BuildUtilities.BuildTargets(projectRoot, logger);

            // Assert
            BuildAssertions.AssertTargetSucceeded(result, TargetConstants.DefaultBuildTarget);

            logger.AssertExpectedTargetOrdering(
                TargetConstants.CategoriseProjectTarget,
                TargetConstants.OverrideFxCopSettingsTarget,
                TargetConstants.FxCopTarget,
                TargetConstants.DefaultBuildTarget,
                TargetConstants.CalculateFilesToAnalyzeTarget,
                TargetConstants.WriteProjectDataTarget);

            // We expect the FxCop target to be executed...
            logger.AssertTargetExecuted(TargetConstants.FxCopTarget);
            // ... but we don't expect the FxCop *task* to have executed
            logger.AssertTaskNotExecuted(TargetConstants.FxCopTask);

            logger.AssertTargetNotExecuted(TargetConstants.SetFxCopResultsTarget);

            ProjectInfo projectInfo = ProjectInfoAssertions.AssertProjectInfoExists(rootOutputFolder, projectRoot.FullPath);

            ProjectInfoAssertions.AssertAnalysisResultDoesNotExists(projectInfo, AnalysisType.FxCop.ToString());
        }