| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- <?xml version="1.0" encoding="utf-8"?>
- <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <!--
- This file contains targets to integrate SonarQube and MSBuild.
- The targets will produce an output folder structure containing information required by the sonar-scanner.
- A subdirectory will be created for each MSBuild project. Information about the project
- will be written to a file called "ProjectInfo.xml". Additional files may also be written
- containing information required by different analyzers. In particular, a file will be written
- containing the list of files in the project that should be analyzed by the sonar-scanner.
- The output will only be produced if the property $(SonarQubeTempPath) and is specified.
- $(SonarQubeTempPath) is the root folder under which per-analysis output should be written.
- Excluding projects and files from SonarQube analysis
- ****************************************************
- Individual projects can excluded from SonarQube analysis by setting the property $(SonarQubeExclude) e.g.
- <SonarQubeExclude>true</SonarQubeExclude>
- Individual files can be excluded from analysis by setting the <SonarQubeExclude> metadata item e.g.
- <Compile Include="Logger.cs">
- <SonarQubeExclude>true</SonarQubeExclude>
- </Compile>
- Project is also excluded if it's recognized as a Fakes or a Temp project. These projects are auto-generated.
- Test projects
- *************
- The analysis performed by SonarQube varies depending on whether a project is a test project or not.
- A project can be explicitly marked as being a test or product project by setting the property $(SonarQubeTestProject) e.g.
- <SonarQubeTestProject>true</SonarQubeTestProject>
- If $(SonarQubeTestProject) is not set explicitly then the project is categorized as a Test project if:
- * Is a Fakes or a Temp project explicitly marked as SonarQubeExclude=false
- * Has one of the expected test project GUIDs ("3AC096D0-A1C2-E12C-1390-A8335801FDAB" or legacy "82A7F48D-3B50-4B1E-B82E-3ADA8210C358").
- * Has a TestContainer project capability.
- * References a known unit test related assembly.
- * Deprecated: Project name matches "sonar.msbuild.testProjectPattern" parameter. Use SonarQubeTestProject=true instead.
- Otherwise it is a Product project.
- Supplying analysis setting in a project file
- ********************************************
- Project-level analysis settings can be specified in a project file using following
- syntax:
- <ItemGroup>
- <SonarQubeSetting Include="sonar.my.analysis.setting">
- <Value>42</Value>
- </SonarQubeSetting>
- </ItemGroup>
- Settings specified in the project file will override those specified on the SonarQube server.
- Specifying additional types of file to be analysed
- **************************************************
- The Scanner for MSBuild will automatically collect all of the common
- file types that can be analysed by the various Sonar language plugins
- (e.g. C# files, TypeScript, TSQL, C++ include and source files etc).
- The full list of item types that will be included for analysis is
- specified in $(SQAnalysisFileItemTypes) property below.
- If you have any additional item types that you want to have analyzed,
- you can specify them setting the property $(SQAdditionalAnalysisFileItemTypes)
- in the project being analysed e.g.
- <SQAdditionalAnalysisFileItemTypes>MyCustomFileType1;MyCustomFileType</SQAdditionalAnalysisFileItemTypes>
- Specific handling of Razor builds
- **************************************************
- During the compilation of an SDK-style MSBuild project with Razor, MSBuild executes 2 build targets:
- CoreCompile to compile the main code and RazorCoreCompile to compile ".cshtml" view files.
- Since it is not possible to execute one target more than once, there's a logic that prevents RazorCoreCompile
- from overriding output files from CoreCompile step:
- * CoreCompile produces output files in directory "X", where X represents project specific unique number.
- * Directory "X" with CoreCompile results is renamed to "X.tmp" before RazorCoreCompile and new empty directory "X" is prepared.
- * RazorCoreCompile produces its output to the current directory "X".
- * Directory "X" with Razor output is renamed to "X.Razor".
- * Directory "X.tmp" with original output is renamed back to "X".
- -->
- <!-- **************************************************************************** -->
- <!-- SonarQube MSBuild Integration implementation logic -->
- <!-- **************************************************************************** -->
- <!-- Note: where possible, these targets avoid taking dependencies on specific
- managed or C++- targets e.g. they use
- "AfterTargets='Build'" which is general rather than
- "AfterTargets='CoreCompile'" which is specific to managed projects.
- -->
- <!-- Safeguard against importing this .targets file multiple times -->
- <PropertyGroup>
- <SonarQubeTargetsImported>true</SonarQubeTargetsImported>
- </PropertyGroup>
- <!-- Set defaults if explicit values have not been provided -->
- <PropertyGroup Condition=" $(SonarQubeTempPath) != '' ">
- <SonarQubeConfigPath Condition=" $(SonarQubeConfigPath) == '' ">$(SonarQubeTempPath)\conf</SonarQubeConfigPath>
- <SonarQubeOutputPath Condition=" $(SonarQubeOutputPath) == '' ">$(SonarQubeTempPath)\out</SonarQubeOutputPath>
- <!-- Specify the ItemGroups to be analyzed -->
- <SQAnalysisFileItemTypes Condition=" $(SQAnalysisFileItemTypes) == '' ">AndroidEnvironment;AndroidJavaSource;AndroidResource;ApplicationDefinition;Build;ClCompile;ClInclude;Compile;Content;DeploymentExtensionConfiguration;EmbeddedResource;EntityDeploy;None;Page;PostDeploy;PRIResource;PreDeploy;RefactorLog;Resource;Script;ScriptCode;TypeScriptCompile;$(SQAdditionalAnalysisFileItemTypes)</SQAnalysisFileItemTypes>
- </PropertyGroup>
- <!-- **************************************************************************** -->
- <!-- Using tasks -->
- <!-- **************************************************************************** -->
- <PropertyGroup Condition=" $(SonarQubeTempPath) != '' AND $(SonarQubeBuildTasksAssemblyFile) == '' ">
- <!-- Assume that the tasks assembly is in the same location as this targets file
- or in a parent directory unless another location has already been specified. -->
- <SonarQubeBuildTasksAssemblyFile>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), SonarScanner.MSBuild.Tasks.dll))\SonarScanner.MSBuild.Tasks.dll</SonarQubeBuildTasksAssemblyFile>
- </PropertyGroup>
- <!-- Unescape the paths to work around the issue "MSBuild 4.0 UsingTask cannot have a path with parentheses".
- See https://connect.microsoft.com/VisualStudio/feedback/details/713690/msbuild-4-0-usingtask-cannot-have-a-path-with-parentheses -->
- <UsingTask TaskName="WriteProjectConfigFile" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="WriteProjectInfoFile" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="IsTestFileByName" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="IsTestByReference" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="GetAnalyzerSettings" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="MakeUniqueDir" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <UsingTask TaskName="WriteZeroLengthFiles" AssemblyFile="$([MSBUILD]::Unescape($(SonarQubeBuildTasksAssemblyFile)))" />
- <!-- **************************************************************************** -->
- <!-- **************************************************************************** -->
- <!-- Targets -->
- <!-- **************************************************************************** -->
- <!-- **************************************************************************** -->
- <Target Name="SkippingSonarQubeAnalysis" BeforeTargets="Build"
- Condition=" $(SonarQubeTempPath) == '' ">
- <Message Importance="high" Text="Sonar: ($(MSBuildProjectFile)) Skipping dumping compile outputs because SonarQubeTempPath has not been specified" />
- </Target>
- <Target Name="FailIfLowerThanMSBuild14"
- Condition=" $(SonarQubeTempPath) != '' AND $(MSBuildToolsVersion) != '14.0' AND $(MSBuildToolsVersion) != '15.0' AND $(MSBuildToolsVersion) != 'Current'"
- BeforeTargets="Build">
- <Message Importance="high" Text="Sonar: ($(MSBuildProjectFile)) Current MSBuildToolsVersion: $(MSBuildToolsVersion)" />
- <Message Importance="high" Text="Sonar: ($(MSBuildProjectFile)) Current MSBuildAssemblyVersion: $(MSBuildAssemblyVersion)" />
- <Error Text="SonarQube analysis is only supported with MSBuild 14 or later." />
- </Target>
- <Target Name="SonarResolveReferencesMsBuild14"
- AfterTargets="ResolveAssemblyReferences"
- Condition=" $(SonarQubeTempPath) != '' AND $(MSBuildToolsVersion) == '14.0'">
- <ItemGroup>
- <SonarResolvedReferences Include="@(%(ReferencePath.FusionName))" />
- </ItemGroup>
- </Target>
- <Target Name="SonarResolveReferences"
- AfterTargets="FindReferenceAssembliesForReferences"
- Condition=" $(SonarQubeTempPath) != '' AND $(MSBuildToolsVersion) != '14.0'">
- <ItemGroup>
- <SonarResolvedReferences Include="@(%(ReferencePathWithRefAssemblies.FusionName))" />
- </ItemGroup>
- </Target>
- <!-- **************************************************************************** -->
- <!-- Categorize as a product or test project -->
- <!-- **************************************************************************** -->
- <!-- This target is a utility target: it won't be executed unless a target that depends on it is executed. -->
- <Target Name="SonarCategoriseProject"
- DependsOnTargets="SonarResolveReferencesMsBuild14;SonarResolveReferences"
- Condition=" $(SonarQubeTempPath) != '' ">
- <Message Text="Sonar: ($(MSBuildProjectFile)) Categorizing project as test or product code..." />
- <Message Condition="$(SonarQubeTestProject) != ''" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) SonarQubeTestProject has been set explicitly to $(SonarQubeTestProject)." />
- <!-- Fakes detection -->
- <PropertyGroup>
- <IsFakesProject Condition="$(AssemblyName.EndsWith('.fakes', System.StringComparison.OrdinalIgnoreCase))">true</IsFakesProject>
- </PropertyGroup>
- <!-- Before deciding to exclude or tag as test such a project, make sure it is not a legitimate project that happens to be called something.fakes
- In this case, we require from the user to explicitely state whether the project is to be analyzed/considered a test project -->
- <PropertyGroup Condition="$(IsFakesProject) == 'true' and $(SonarQubeExclude) == ''">
- <SonarQubeExclude>true</SonarQubeExclude>
- </PropertyGroup>
- <PropertyGroup Condition="$(IsFakesProject) == 'true' and $(SonarQubeTestProject) == ''">
- <SonarQubeTestProject>true</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(IsFakesProject) == 'true' and $(SonarQubeExclude) == 'true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project is a temporary project generated by Microsoft Fakes and will be ignored." />
- <!-- Temporary project detection -->
- <!-- Some kinds of project have logic to trigger additional special builds based on the same project file
- e.g. WPF projects build a temporary assembly before the main compilation takes place.
- We only want to analyze the "normal" build of the project, so we should turn off analysis for the known cases. -->
- <PropertyGroup>
- <!-- Special case 1: WPF projects call the task Windows.GenerateTemporaryTargetAssembly in PresentationBuildTasks. -->
- <IsTempProject Condition="$(MSBuildProjectFile.EndsWith('.tmp_proj', System.StringComparison.OrdinalIgnoreCase))">true</IsTempProject>
- <IsTempProject Condition="$(MSBuildProjectFile.EndsWith('_wpftmp.csproj', System.StringComparison.OrdinalIgnoreCase))">true</IsTempProject>
- <IsTempProject Condition="$(MSBuildProjectFile.EndsWith('_wpftmp.vbproj', System.StringComparison.OrdinalIgnoreCase))">true</IsTempProject>
- </PropertyGroup>
- <PropertyGroup Condition="$(IsTempProject) == 'true' AND $(SonarQubeExclude)==''" >
- <SonarQubeExclude>true</SonarQubeExclude>
- </PropertyGroup>
- <Message Condition="$(IsTempProject) == 'true' AND $(SonarQubeExclude)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project is a temporary project and will be excluded." />
- <PropertyGroup Condition=" $(SonarQubeTestProject) == '' ">
- <!-- The MS Test project type guid -->
- <SonarQubeMsTestProjectTypeGuid>3AC096D0-A1C2-E12C-1390-A8335801FDAB</SonarQubeMsTestProjectTypeGuid>
- <tmpSonarHasMSTestProjectTypeGuid Condition=" $(ProjectTypeGuids.ToUpperInvariant().Contains('$(SonarQubeMsTestProjectTypeGuid)')) ">true</tmpSonarHasMSTestProjectTypeGuid>
- <SonarQubeTestProject Condition=" $(tmpSonarHasMSTestProjectTypeGuid)=='true' ">true</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(tmpSonarHasMSTestProjectTypeGuid)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project has the MSTest project type guid -> test project." />
- <PropertyGroup Condition=" $(SonarQubeTestProject) == '' ">
- <!-- The legacy Service tag added by the Test Explorer window -->
- <tmpSQServiceList>@(Service)</tmpSQServiceList>
- <tmpSonarHasServiceTag Condition="$(tmpSQServiceList.ToUpperInvariant().Contains('{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}')) ">true</tmpSonarHasServiceTag>
- <SonarQubeTestProject Condition="$(tmpSonarHasServiceTag)=='true'">true</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(tmpSonarHasServiceTag)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project has the legacy Test Explorer Service tag {82A7F48D-3B50-4B1E-B82E-3ADA8210C358} -> test project." />
- <PropertyGroup Condition=" $(SonarQubeTestProject) == '' ">
- <!-- The ProjectCapability for test projects -->
- <tmpSQProjectCapabilities>@(ProjectCapability)</tmpSQProjectCapabilities>
- <tmpSonarHasTestContainerCapability Condition="$(tmpSQProjectCapabilities.ToUpperInvariant().Contains('TESTCONTAINER')) ">true</tmpSonarHasTestContainerCapability>
- <SonarQubeTestProject Condition="$(tmpSonarHasTestContainerCapability)=='true'">true</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(tmpSonarHasTestContainerCapability)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project has the ProjectCapability 'TestContainer' -> test project." />
- <IsTestByReference Condition=" $(SonarQubeTestProject) == '' "
- References="@(SonarResolvedReferences)">
- <Output TaskParameter="TestReference" PropertyName="tmpSonarTestReferenceResult" />
- </IsTestByReference>
- <PropertyGroup Condition=" $(SonarQubeTestProject) == '' ">
- <SonarQubeTestProject Condition="$(tmpSonarTestReferenceResult)!=''">true</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(tmpSonarTestReferenceResult)!=''" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project is evaluated as a test project based on the '$(tmpSonarTestReferenceResult)' reference." />
- <!-- If we haven't already determined whether the project is a test project then check its path/name against the regular expression in the config file -->
- <IsTestFileByName Condition=" $(SonarQubeTestProject) == '' "
- AnalysisConfigDir="$(SonarQubeConfigPath)"
- FullFilePath="$(MSBuildProjectFullPath)">
- <Output TaskParameter="IsTest" PropertyName="tmpSonarIsTestFileByNameResult" />
- </IsTestFileByName>
- <PropertyGroup Condition=" $(SonarQubeTestProject) == '' ">
- <SonarQubeTestProject>$(tmpSonarIsTestFileByNameResult)</SonarQubeTestProject>
- </PropertyGroup>
- <Message Condition="$(tmpSonarIsTestFileByNameResult)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) project is evaluated as a test project based on the project name." />
- <Message Importance="normal" Condition="$(SonarQubeTestProject)=='false'" Text="Sonar: ($(MSBuildProjectFile)) categorized as MAIN project (production code)." />
- <Message Importance="normal" Condition="$(SonarQubeTestProject)=='true'" Text="Sonar: ($(MSBuildProjectFile)) categorized as TEST project (test code)." />
- </Target>
- <!-- **************************************************************************** -->
- <!-- Calculate the set of files to be analyzed -->
- <!-- **************************************************************************** -->
- <!-- This target is a utility target: it won't be executed unless a target that
- depends on it is executed.
- -->
- <Target Name="SonarWriteFilesToAnalyze"
- Condition=" $(SonarQubeTempPath) != '' ">
- <!-- Include all of contents of the specified item groups, but exclude
- any that have the metadata 'SonarQubeExclude' set, or that are auto-generated -->
- <ItemGroup Condition="('$(SQAnalysisFileItemTypes)' != '')">
- <SonarQubeAnalysisFileItems Include="$(SQAnalysisFileItemTypes)" />
- <SonarQubeAnalysisFiles Include="@(%(SonarQubeAnalysisFileItems.Identity))" />
- <SonarQubeAnalysisFiles Remove="@(SonarQubeAnalysisFiles)" Condition=" %(SonarQubeAnalysisFiles.SonarQubeExclude) == 'true' OR %(SonarQubeAnalysisFiles.AutoGen) == 'true' OR %(SonarQubeAnalysisFiles.FullPath) == '$(TargetFrameworkMonikerAssemblyAttributesPath)'" />
- </ItemGroup>
- <!-- Exclude items under the intermediate output folder e.g. XAML files that are auto-generated on build -->
- <PropertyGroup>
- <!-- Calculate the full path to the base intermediate folder -->
- <SQFullIntermediateOutputPath>$([System.IO.Path]::Combine($(MSBuildProjectDirectory),$(BaseIntermediateOutputPath)))</SQFullIntermediateOutputPath>
- </PropertyGroup>
- <ItemGroup>
- <!-- Remove based on absolute path -->
- <SQIntermediateFiles Include="$(SQFullIntermediateOutputPath)**\*.*" />
- <!-- Remove based on relative path -->
- <SQIntermediateFiles Include="$(BaseIntermediateOutputPath)**\*.*" />
- <SonarQubeAnalysisFiles Remove="@(SQIntermediateFiles)" />
- </ItemGroup>
- <PropertyGroup>
- <!-- Set a property indicating whether there are any files to analyze -->
- <AnalysisFilesExist Condition=" @(SonarQubeAnalysisFiles) != '' ">true</AnalysisFilesExist>
- </PropertyGroup>
- <!-- Write the list of files -->
- <PropertyGroup>
- <!-- Set the file name for the list file -->
- <AnalysisFileList>$(ProjectSpecificConfDir)\FilesToAnalyze.txt</AnalysisFileList>
- </PropertyGroup>
- <Message Condition="$(AnalysisFilesExist)!='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) No files were found to analyse" />
- <Message Condition="$(AnalysisFilesExist)=='true'" Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) Number of files to analyse: @(SonarQubeAnalysisFiles->Count()). The list of files to be analyzed is in $(AnalysisFileList)." />
- <!-- Write out a list of files to analyze that will be passed to the sonar-scanner -->
- <WriteLinesToFile Condition=" $(AnalysisFilesExist) == 'true' "
- File="$(AnalysisFileList)"
- Lines="%(SonarQubeAnalysisFiles.FullPath)"
- Overwrite="false"
- Encoding="utf-8" />
- </Target>
- <Target Name="SonarCreateProjectSpecificDirs" BeforeTargets="OverrideRoslynCodeAnalysisProperties;SonarWriteProjectData;SonarWriteFilesToAnalyze" Condition=" $(SonarQubeTempPath) != '' ">
- <!-- **************************************************************************** -->
- <!-- Create the project-specific directories for conf and out -->
- <!-- Create folder with unique name in the .sonarqube/out/ folder -->
- <MakeUniqueDir Path="$(SonarQubeOutputPath)">
- <Output TaskParameter="UniquePath" PropertyName="ProjectSpecificOutDir" />
- <Output TaskParameter="UniqueName" PropertyName="UniqueName" />
- </MakeUniqueDir>
- <!-- Create .sonarqube/conf/ sub-folder with the same unique name -->
- <PropertyGroup>
- <ProjectSpecificConfDir>$(SonarQubeConfigPath)\$(UniqueName)</ProjectSpecificConfDir>
- </PropertyGroup>
- <MakeDir Directories="$(ProjectSpecificConfDir)" />
- </Target>
- <!-- SonarWriteProjectData has to be invoked after the Build target, so it can pick up the results for C++ projects. -->
- <Target Name="InvokeSonarWriteProjectData_NonRazorProject"
- DependsOnTargets="SonarCategoriseProject;SonarWriteFilesToAnalyze;SonarCreateProjectSpecificDirs"
- AfterTargets="Build"
- Condition=" $(SonarQubeTempPath) != '' AND ('@(RazorCompile)'=='' OR ('@(RazorCompile)'!='' AND '$(UseRazorSourceGenerator)'=='true')) ">
- <CallTarget Targets="SonarWriteProjectData" />
- </Target>
- <Target Name="InvokeSonarWriteProjectData_RazorProject"
- DependsOnTargets="SonarCategoriseProject;SonarWriteFilesToAnalyze;SonarCreateProjectSpecificDirs"
- BeforeTargets="SonarPrepareRazorProjectCodeAnalysis"
- AfterTargets="CoreCompile"
- Condition=" $(SonarQubeTempPath) != '' AND '@(RazorCompile)'!='' AND ('$(UseRazorSourceGenerator)'=='' OR '$(UseRazorSourceGenerator)'=='false') ">
- <CallTarget Targets="SonarWriteProjectData" />
- </Target>
- <Target Name="SonarWriteProjectData" >
- <PropertyGroup>
- <SonarErrorLogExists Condition=" $(SonarErrorLog) != '' AND $([System.IO.File]::Exists($(SonarErrorLog))) == 'true' ">true</SonarErrorLogExists>
- </PropertyGroup>
- <ItemGroup>
- <SonarReportFilePath Condition= "$(SonarErrorLogExists) == 'true'" Include="$(SonarErrorLog)" />
- </ItemGroup>
- <ItemGroup>
- <SonarQubeSetting Include="sonar.$(SQLanguage).roslyn.reportFilePaths" Condition=" @(SonarReportFilePath) != '' ">
- <!-- Join the paths with | -->
- <!-- This delimiter needs to be the same as PropertiesFileGenerator.RoslynReportPathsDelimiter -->
- <Value>@(SonarReportFilePath->'%(identity)','|')</Value>
- </SonarQubeSetting>
- <SonarQubeSetting Include="sonar.$(SQLanguage).analyzer.projectOutPaths" Condition= "$(SonarErrorLogExists) == 'true'">
- <Value>$(ProjectSpecificOutDir)</Value>
- </SonarQubeSetting>
- </ItemGroup>
- <!-- Record the list of files as an analysis result -->
- <ItemGroup Condition=" $(AnalysisFilesExist) == 'true' ">
- <AnalysisResults Include="$(AnalysisFileList)">
- <Id>FilesToAnalyze</Id>
- </AnalysisResults>
- </ItemGroup>
- <CallTarget Targets="FixUpTestProjectOutputs" />
- <WriteProjectInfoFile ProjectName="$(MSBuildProjectName)"
- FullProjectPath="$(MSBuildProjectFullPath)"
- ProjectLanguage="$(Language)"
- ProjectGuid="$(ProjectGuid)"
- SolutionConfigurationContents="$(CurrentSolutionConfigurationContents)"
- IsTest="$(SonarQubeTestProject)"
- IsExcluded="$(SonarQubeExclude)"
- AnalysisResults="@(AnalysisResults)"
- AnalysisSettings="@(SonarQubeSetting)"
- OutputFolder="$(ProjectSpecificOutDir)"
- CodePage="$(CodePage)"
- Configuration="$(Configuration)"
- Platform="$(Platform)"
- TargetFramework="$(TargetFramework)" />
- <Message Importance="high" Text="Sonar: ($(MSBuildProjectFile)) Project processed successfully" />
- </Target>
- <!--
- Set the Razor specific error log properties.
- Move the results of the core compilation to a temporary folder to prevent RazorCoreCompilation from overriding its content.
- The contents will be moved back in SonarFinishRazorProjectCodeAnalysis target.
- -->
- <Target Name="SonarPrepareRazorProjectCodeAnalysis" BeforeTargets="RazorCoreCompile" AfterTargets="CoreCompile" Condition="'@(RazorCompile)'!='' AND ('$(UseRazorSourceGenerator)'=='' OR '$(UseRazorSourceGenerator)'=='false')" >
- <PropertyGroup Condition=" $(SonarErrorLog) != '' ">
- <!-- https://github.com/SonarSource/sonar-scanner-msbuild/issues/1015 Respect user-provided value. When set, users should provide unique path for each build (project and target framework). -->
- <RazorSonarErrorLogName Condition=" $(RazorCompilationErrorLog) == '' ">Issues$(RazorTargetNameSuffix).json</RazorSonarErrorLogName>
- <RazorCompilationErrorLog Condition=" $(RazorSonarErrorLogName) != '' ">$(ProjectSpecificOutDir)\$(RazorSonarErrorLogName)</RazorCompilationErrorLog>
- <ErrorLog>$(RazorCompilationErrorLog)</ErrorLog>
- <!-- Keep the path so that we could set SonarQubeSetting with sonar.language.roslyn.reportFilePaths -->
- <RazorSonarErrorLog>$(RazorCompilationErrorLog)</RazorSonarErrorLog>
- </PropertyGroup>
- <PropertyGroup>
- <SonarTemporaryProjectSpecificOutDir>$(ProjectSpecificOutDir).tmp</SonarTemporaryProjectSpecificOutDir>
- </PropertyGroup>
- <ItemGroup>
- <CoreCompileOutFiles Include="$(ProjectSpecificOutDir)\**\*.*"/>
- </ItemGroup>
- <Move
- SourceFiles="@(CoreCompileOutFiles)"
- DestinationFolder="$(SonarTemporaryProjectSpecificOutDir)\%(RecursiveDir)" />
- <Message Importance="high" Text="Sonar: Preparing for Razor compilation, moved files (@(CoreCompileOutFiles)) to $(SonarTemporaryProjectSpecificOutDir)." />
- </Target>
- <!-- In case of Razor compilation the output files generated during the core compilation step are already moved into a temporary folder.
- This target renames output directories to their final state and creates the ProjectInfo.xml for them.
- -->
- <Target Name="SonarFinishRazorProjectCodeAnalysis" AfterTargets="RazorCoreCompile;InvokeSonarWriteProjectData_RazorProject" Condition=" $(SonarTemporaryProjectSpecificOutDir) != '' AND '@(RazorCompile)'!='' AND ('$(UseRazorSourceGenerator)'=='' OR '$(UseRazorSourceGenerator)'=='false') ">
- <PropertyGroup>
- <RazorSonarProjectSpecificOutDir>$(ProjectSpecificOutDir).Razor</RazorSonarProjectSpecificOutDir>
- <RazorSonarProjectInfo>$(RazorSonarProjectSpecificOutDir)\ProjectInfo.xml</RazorSonarProjectInfo>
- </PropertyGroup>
- <ItemGroup>
- <RazorCompilationOutFiles Include="$(ProjectSpecificOutDir)\**\*.*"/>
- <SonarTempFiles Include="$(SonarTemporaryProjectSpecificOutDir)\**\*.*"/>
- </ItemGroup>
- <!-- Move main and Razor results to their final location. -->
- <Move
- SourceFiles="@(RazorCompilationOutFiles)"
- DestinationFolder="$(RazorSonarProjectSpecificOutDir)\%(RecursiveDir)" />
- <Message Importance="high" Text="Sonar: After Razor compilation, moved files (@(RazorCompilationOutFiles)) to $(RazorSonarProjectSpecificOutDir)." />
- <Move
- SourceFiles="@(SonarTempFiles)"
- DestinationFolder="$(ProjectSpecificOutDir)\%(RecursiveDir)" />
- <Message Importance="high" Text="Sonar: After Razor compilation, moved files (@(SonarTempFiles)) to $(ProjectSpecificOutDir) and will remove the temporary folder." />
- <RemoveDir Directories="$(SonarTemporaryProjectSpecificOutDir)" />
- <PropertyGroup>
- <!-- This overwrites the previously set 'RazorSonarErrorLog' in 'SonarPrepareRazorProjectCodeAnalysis'
- if 'RazorSonarErrorLogName' is set, which means 'RazorCompilationErrorLog' was null.
- The condition is a bit difficult to follow, it would be easier to change it or also add "$(RazorSonarErrorLog) != ''" -->
- <RazorSonarErrorLog Condition=" $(RazorSonarErrorLogName) != '' ">$(RazorSonarProjectSpecificOutDir)\$(RazorSonarErrorLogName)</RazorSonarErrorLog>
- <RazorSonarErrorLogExists Condition=" $(RazorSonarErrorLog) != '' AND $([System.IO.File]::Exists($(RazorSonarErrorLog))) == 'true' ">true</RazorSonarErrorLogExists>
- </PropertyGroup>
- <ItemGroup>
- <RazorSonarReportFilePath Condition= "$(RazorSonarErrorLogExists) == 'true'" Include="$(RazorSonarErrorLog)" />
- <RazorSonarQubeSetting Include="sonar.$(SQLanguage).roslyn.reportFilePaths" Condition=" @(RazorSonarReportFilePath) != '' ">
- <!-- Join the paths with | -->
- <!-- This delimiter needs to be the same as PropertiesFileGenerator.RoslynReportPathsDelimiter -->
- <Value>@(RazorSonarReportFilePath->'%(identity)','|')</Value>
- </RazorSonarQubeSetting>
- <RazorSonarQubeSetting Include="sonar.$(SQLanguage).analyzer.projectOutPaths" Condition= "$(RazorSonarErrorLogExists) == 'true'">
- <Value>$(RazorSonarProjectSpecificOutDir)</Value>
- </RazorSonarQubeSetting>
- </ItemGroup>
- <!-- Create the ProjectInfo.xml for the Razor part. -->
- <WriteProjectInfoFile ProjectName="$(MSBuildProjectName)"
- FullProjectPath="$(MSBuildProjectFullPath)"
- ProjectLanguage="$(Language)"
- ProjectGuid="$(ProjectGuid)"
- SolutionConfigurationContents="$(CurrentSolutionConfigurationContents)"
- IsTest="$(SonarQubeTestProject)"
- IsExcluded="$(SonarQubeExclude)"
- AnalysisResults="@(AnalysisResults)"
- AnalysisSettings="@(RazorSonarQubeSetting)"
- OutputFolder="$(RazorSonarProjectSpecificOutDir)"
- CodePage="$(CodePage)"
- Configuration="$(Configuration)"
- Platform="$(Platform)"
- TargetFramework="$(TargetFramework)" />
- </Target>
- <Target Name="FixUpTestProjectOutputs" Condition="$(SonarQubeTestProject)=='true'" >
- <Message Importance="low" Text="Sonar: ($(MSBuildProjectFile)) Fixing up test project outputs..." />
- <ItemGroup>
- <!-- Select specific metrics files that should not be uploaded for test files.
- Assumption: these files will be in a sub-folder under the project-specific output folder. -->
- <SQTestMetricFiles Include="$(ProjectSpecificOutDir)\*\metrics.pb" />
- <SQTestMetricFiles Include="$(ProjectSpecificOutDir)\*\token-cpd.pb" />
- </ItemGroup>
- <Message Importance="low" Text="Sonar: ($(MSBuildProjectFile)) Selected test metric file: @(SQTestMetricFiles)" />
- <WriteZeroLengthFiles FullFilePaths="@(SQTestMetricFiles)" />
- </Target>
- <!-- **************************************************************************** -->
- <!-- Code analysis -->
- <!-- **************************************************************************** -->
- <!-- Implementation notes:
- We want to override any code analysis-related properties that are set in the
- project file. To do this, we need to execute our targets at the correct
- point in the build.
- Note that both the FxCop and Roslyn targets use a property called "CodeAnalysisRuleSet".
- The FxCop targets use this value directly. However, the Roslyn targets use it
- as input to the "ResolveCodeAnalysisRuleSet" target, which sets the property
- "ResolvedCodeAnalysisRuleset".
- We override the property "ResolveCodeAnalysisRuleSet" with the path to our Roslyn ruleset.
- -->
- <PropertyGroup>
- <SQLanguage Condition="$(Language) == 'C#'">cs</SQLanguage>
- <SQLanguage Condition="$(Language) == 'VB'">vbnet</SQLanguage>
- </PropertyGroup>
- <!-- **************************************************************************** -->
- <!-- Roslyn analysis section -->
- <!-- **************************************************************************** -->
- <!-- Override VS2019 properties to make sure analysis runs in the scanner build.
- We need to run before BeforeCompile that executes _ComputeSkipAnalyzers target.
- We don't need to override this for excluded projects. -->
- <Target Name="SonarOverrideRunAnalyzers"
- Condition=" $(SonarQubeTempPath) != '' AND $(SonarQubeExclude) != 'true' "
- BeforeTargets="BeforeCompile">
- <PropertyGroup>
- <RunAnalyzers>true</RunAnalyzers>
- <RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
- </PropertyGroup>
- </Target>
- <!-- Set the properties required to run Roslyn analysis as part of the build.
- Analysis is controlled by the following properties:
- ResolvedCodeAnalysisRuleSet - the full path to the ruleset to use
- ErrorLog and RazorCompilationErrorLog - the file path for the error reporting file
- We want to run after the core "ResolveCodeAnalysisRuleSet" target which assigns a value to "ResolvedCodeAnalysisRuleSet".
- Conditions:
- * project is excluded -> turn off Roslyn analysis
- * project is a test project and parameter sonar.dotnet.excludeTestProjects=true -> run only metrics rules
- * otherwise, use the analyzer settings loaded from the config file (removing any existing analyzers)
- -->
- <Target Name="OverrideRoslynCodeAnalysisProperties"
- Condition=" $(SonarQubeTempPath) != '' "
- DependsOnTargets="SonarCategoriseProject;SonarWriteFilesToAnalyze"
- AfterTargets="ResolveCodeAnalysisRuleSet"
- BeforeTargets="CoreCompile">
- <PropertyGroup>
- <!-- Make sure no warnings are treated as errors -->
- <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
- <WarningsAsErrors></WarningsAsErrors>
- <!-- The Roslyn analyzers output messages with different warning levels. This is tied to the diagnostic severity and currently
- is translated as follows - error: 0, warning: 1, info: 4. To avoid issues being missed override the warning level by setting it to max tolerance.-->
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <CallTarget Targets="SetRoslynCodeAnalysisProperties" Condition="$(SonarQubeExclude) != 'true'" />
- </Target>
- <Target Name="SetRoslynCodeAnalysisProperties">
- <!-- Fetch the relevant settings from the config file -->
- <GetAnalyzerSettings AnalysisConfigDir="$(SonarQubeConfigPath)"
- Language="$(SQLanguage)"
- CurrentProjectDirectoryPath="$(MSBuildProjectDirectory)"
- OriginalAnalyzers="@(Analyzer)"
- OriginalAdditionalFiles="@(AdditionalFiles)"
- OriginalRulesetFilePath="$(ResolvedCodeAnalysisRuleset)"
- ProjectSpecificConfigDirectory="$(ProjectSpecificConfDir)"
- IsTestProject="$(SonarQubeTestProject)">
- <Output TaskParameter="RuleSetFilePath" PropertyName="SQRuleSetFilePath" />
- <Output TaskParameter="AnalyzerFilePaths" ItemName="SQAnalyzerFilePaths" />
- <Output TaskParameter="AdditionalFilePaths" ItemName="SQAdditionalFiles" />
- </GetAnalyzerSettings>
- <PropertyGroup>
- <!-- https://github.com/SonarSource/sonar-scanner-msbuild/issues/1015 Respect user-provided value. When set, users should provide unique path for each build (project and target framework). -->
- <!-- https://jira.sonarsource.com/browse/SONARMSBRU-211 - the full path should be unique per project and target framework. -->
- <ErrorLog Condition=" $(ErrorLog) == '' ">$(ProjectSpecificOutDir)\Issues.json</ErrorLog>
- <!-- Keep the path so that we could set SonarQubeSetting with sonar.language.roslyn.reportFilePaths -->
- <SonarErrorLog>$(ErrorLog)</SonarErrorLog>
- </PropertyGroup>
- <PropertyGroup>
- <ResolvedCodeAnalysisRuleSet>$(SQRuleSetFilePath)</ResolvedCodeAnalysisRuleSet>
- <SonarProjectOutFolderFilePath>$(ProjectSpecificConfDir)\ProjectOutFolderPath.txt</SonarProjectOutFolderFilePath>
- </PropertyGroup>
- <!--SonarProjectOutFolderFilePath is generated only for backward compatibility with CSharp and VBNet analyzers before 8.20 -->
- <WriteLinesToFile File="$(SonarProjectOutFolderFilePath)" Lines="$(ProjectSpecificOutDir)" Overwrite="true" />
- <WriteProjectConfigFile ConfigDir="$(ProjectSpecificConfDir)"
- AnalysisConfigPath="$(SonarQubeConfigPath)\SonarQubeAnalysisConfig.xml"
- ProjectPath="$(MSBuildProjectFullPath)"
- FilesToAnalyzePath ="$(AnalysisFileList)"
- OutPath="$(ProjectSpecificOutDir)"
- IsTest="$(SonarQubeTestProject)"
- TargetFramework="$(TargetFramework)">
- <Output TaskParameter="ProjectConfigFilePath" PropertyName="SonarProjectConfigFilePath" />
- </WriteProjectConfigFile>
- <ItemGroup>
- <!-- Clear the original set of analyzers and additional files -->
- <Analyzer Remove="@(Analyzer)" />
- <AdditionalFiles Remove="@(AdditionalFiles)" />
- <!-- Use the set of analyzers and additional files calculated by the GetAnalyzerSettings task -->
- <Analyzer Include="@(SQAnalyzerFilePaths)" />
- <AdditionalFiles Include="@(SQAdditionalFiles)" />
- <AdditionalFiles Include="$(SonarProjectConfigFilePath)" />
- <AdditionalFiles Include="$(SonarProjectOutFolderFilePath)" />
- </ItemGroup>
- <Message Importance="normal" Text="Sonar: ($(MSBuildProjectFile)) Analysis configured successfully with $(SonarProjectConfigFilePath)." />
- </Target>
- <!-- **************************************************************************** -->
- <!-- End of Roslyn analysis section-->
- <!-- **************************************************************************** -->
- </Project>
|