Following the previous proposed technique, I wrote a PowerShell script that runs InspectCode, then performs the XSLT conversion of the output file and imports the result into TeamCity. You can run this as a PowerShell build step by passing the solution file name as the first argument to the script and the% system.teamcity.build.tempDir% variable as the second.
TransformResults.xslt:
(This should be located in the same folder as the PowerShell script)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" /> <xsl:strip-space elements="*"/> <xsl:key name="issueType" match="IssueTypes/IssueType" use="@Id" /> <!-- Template to strip out issues where the severity is HINT or SUGGESTION --> <xsl:template match="Issues//Issue"> <xsl:choose> <xsl:when test="not(contains('HINT SUGGESTION', key('issueType', @TypeId)/@Severity))" > <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:when> </xsl:choose> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
RunInspectCode.ps1:
param( [Parameter(Mandatory = $true)][string]$solutionFile, [Parameter(Mandatory = $true)][string]$buildTempDir) # Runs the Jetbrains Resharper code inspection utility (InspectCode) # - see https://confluence.jetbrains.com/display/NETCOM/Introducing+InspectCode # We don't want to use the built-in TeamCity inspection plugin because it reports # HINT and SUGGESTION issues, which we don't want to make mandatory. # Basically we run InspectCode to generate an intermediate XML report, then we # transform that report via XSLT to strip out the issues we don't want to see. $ErrorActionPreference = "Stop" # Required if Powershell < 3.0 #$PSScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path # General-purpose function to transform XML function Transform-Xml { param([string]$stylesheetPath=$(throw '$stylesheetPath is required'), [string[]]$xmlPath) begin { # Compile the stylesheet $compiledXslt = New-Object System.Xml.Xsl.XslCompiledTransform $compiledXslt.Load($stylesheetPath) function transformXmlDoc { param([xml]$xml, [System.Xml.Xsl.XslCompiledTransform]$xslt = $(throw '$xslt param is required')) $output = New-Object System.IO.MemoryStream $arglist = new-object System.Xml.Xsl.XsltArgumentList $outputReader = new-object System.IO.StreamReader($output) $xmlReader = New-Object System.Xml.XmlNodeReader($xml) $xslt.Transform($xmlReader, $arglist, $output) $output.position = 0 $transformed = [string]$outputReader.ReadToEnd() $outputReader.Close() return $transformed } function applyStylesheetToXml([xml]$xml) { $result = transformXmlDoc $xml $compiledXslt [string]::join([environment]::newline, $result) } function applyStylesheetToXmlFile($sourcePath) { $rpath = resolve-path $sourcePath [xml]$xml = Get-Content $rpath $result = transformXmlDoc $xml $compiledXslt [string]::join([environment]::newline, $result) } } process { if ($_) { if ($_ -is [xml]) { applyStylesheetToXml $_ } elseif ($_ -is [IO.FileInfo]) { applyStylesheetToXmlFile $_.FullName } elseif ($_ -is [string]) { if (test-path -type Leaf $_) { applyStylesheetToXmlFile $_ } else { applyStylesheetToXml $_ } } else { throw "Pipeline input type must be one of: [xml], [string] or [IO.FileInfo]" } } } end { if ($xmlPath) { foreach ($path in $xmlPath) { applyStylesheetToXmlFile $path } } } } $solutionPath = Resolve-Path $solutionFile $tempDir = Resolve-Path $buildTempDir # Locate inspectcode if (-Not (Test-Path Env:\RESHARPER_TOOLS_PATH)) { throw 'RESHARPER_TOOLS_PATH environment variable not set' } $inspectcode = Join-Path $env:RESHARPER_TOOLS_PATH 'inspectcode.exe' if (-Not (Test-Path -type Leaf $inspectcode)) { throw 'InpectCode executable not found' } # Path to XSLT transformation file $fullXsltPath = Resolve-Path (Join-Path $PSScriptRoot 'TransformResults.xslt') # Names of intermediate and final output files $intermediateOutput = Join-Path $tempDir 'inspectcode-intermediate.xml' $outputPath = Join-Path $tempDir 'inspectcode-final.xml' # Run InspectCode & $inspectcode "/o=$intermediateOutput" $solutionPath # Transform the inspection output to remove HINT and SUGGESTION $transformed = Transform-Xml $fullXsltPath @($intermediateOutput) # The PowerShell Out-File cmdlet always adds a UTF8 Byte Order Marker so we need to take steps to # ensure this is not emitted, as the TeamCity XML importer will choke on it $encoding = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllLines($outputPath, $transformed, $encoding) # When PowerShell is started through TeamCity Command Runner, the standard # output will be wrapped at column 80 (a default). This has a negative impact # on service messages, as TeamCity quite naturally fails parsing a wrapped # message. The solution is to set a new, much wider output width. It will # only be set if TEAMCITY_VERSION exists, ie, if started by TeamCity. $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size(8192,50) Write-Output "##teamcity[importData type='ReSharperInspectCode' path='$outputPath']"
Rich tebb
source share