关于CI中PVS Studio的简短说明(以及缺少的内容)

我认为再也没有必要宣传一个出色的静态分析工具-PVS Studio。 Habr上已经有很多关于它的文章,但是我想谈谈另一个方面-在持续集成系统中使用此工具。


因此,有一个组织,其中有一个简单易用的CI:Jenkins在推入Git后收到一个钩子,然后启动了一些管道。 由于使用了工具,因此可以对在C#(msbuild)和C ++(msbuild,CMake)中创建的项目进行组装。 在完成阶段之一中,将开始生成报告,包括使用PVS Studio(cppcheck等,但这对于进一步的叙述而言并不重要)。


PVS Studio具有从命令行启动的控制台分析工具: PVS-Studio_Cmd.exe --target "${projectFile}" --output report.plog --progress


在输入处-项目名称(.sln),在输出处-报告。


报告-扩展名为.plog的文件,是常规XML文件。 文档方案是内置的,因此输出格式不会令人惊讶。 至少在开发人员更改方案之前,但我们不会考虑此选项。


该报告由一组记录组成,每条记录都指向一个文件和其中的一行,错误类别,错误级别,描述和其他不太有趣的内容。


但是,用眼睛阅读XML是您自己的荣幸,因此您需要某种方式来查看和导航。


最简单,最有效的方法是Visual Studio的PVS Studio插件,可以浏览代码。 但是每次都强迫技术经理或其他有兴趣的人将项目加载到VS中是个坏主意,而且该项目的开发历史也不可见。


因此,让我们走另一条路,看看可以做什么。 有一种相当标准的方法可以让您将XML转换为其他格式: XSLT 。 现在,可能是一位读者歪曲了,但尽管如此,我还是建议继续阅读。


XSLT是一种用于将XML文档转换为其他内容的语言。 它只是将转换规则与输入模板进行比较,但是我们已经为自己完成了到HTML报告的转换。


我希望没有人会判断我是否制作表格,因为数据本质上是表格形式的。 报表中的每条记录将对应一个表行,该行包含以下列:


  1. 表中的行号。
  2. 文件名
  3. 行号。
  4. 错误代码。
  5. 错误消息。

行号只是为了方便讨论中的口头参考。


文件名和行名一起使您可以创建到存储库的链接。 但是稍后会更多。


该错误代码由指向PVS-Studio开发人员网站的链接构成: http//viva64.com/en/ { ErrorCode }(或根据您的喜好,或/ ru /)。


错误消息没有评论。


有一些要处理的要点。


首先,我希望按重要性级别对邮件进行排序,并希望每种类型的邮件总数相同。 第一个任务使用xsl:sort表达式解决,第二个任务是count([])


第二:完整显示文件名,并且需要相对名称来创建指向版本控制系统的链接。 您只需要剪去与克隆了存储库的项目的目录名称相对应的前缀(我们有Git,但是很容易适应)。 但是要使此路径出现,我们需要使用xsl:param构造参数化XSL转换。 其余的相对简单:从文件名所在的行中删除带有克隆存储库的目录名称的公共前缀。 我必须说,在XSLT中,这个问题已经非常复杂地解决了。


第三:验证指的是存储库中的特定修订,这也需要牢记。 通过使用带有提交标识符的参数来解决。 分支机构也是如此。
第四:如果您将第三方库与源代码一起使用,请勿将它们中的警告与我们项目中的警告混合使用。 该问题的解决方法如下:我们将所有外部项目都放入某个目录中,该目录中没有该项目的名称。 现在,如果文件名包含此子目录(实际上只是一个子字符串),则plog中的条目不会进入报告,而是在报告标题中被视为“隐藏”。 为了获得更大的灵活性,您可以参数化转换并为该目录分配默认名称: <xsl:param name="external" select="'External'" />


好,还有一个小任务:收集到存储库的链接。 我们使用Redmine + Gitolite。 再次,适应性强。


由于许多参数对于转换都是常量,因此您可以准备一个常量URL前缀:


 <xsl:variable name="repo"> <xsl:text>http://redmine.your-site.com/projects/</xsl:text> <xsl:value-of select="$project" /> <xsl:text>/revisions/</xsl:text> <xsl:value-of select="$revision" /> <xsl:text>/entry/</xsl:text> </xsl:variable> 

一些具有风格的美女,您可以使用它。 我们将CSS嵌入页面中,只是为了获得一个文件报告。 我们也不需要图片。


扰流板下的完整转换代码


XSLT
 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="msxsl" > <xsl:output method="html" indent="yes"/> <xsl:param name="project" /> <xsl:param name="base-path" /> <xsl:param name="branch" select="'master'" /> <xsl:param name="revision" select="'[required]'" /> <xsl:param name="external" select="'External'" /> <xsl:variable name="repo"> <xsl:text>http://redmine.your-company.com/projects/</xsl:text> <!-- # !!!attention!!! # --> <xsl:value-of select="$project" /> <xsl:text>/revisions/</xsl:text> <xsl:value-of select="$revision" /> <xsl:text>/entry/</xsl:text> </xsl:variable> <xsl:template name="min-len"> <xsl:param name="a" /> <xsl:param name="b" /> <xsl:variable name="la" select="string-length($a)" /> <xsl:variable name="lb" select="string-length($b)" /> <xsl:choose> <xsl:when test="$la &lt; $lb"> <xsl:value-of select="$la"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$lb" /> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="strdiff-impl"> <xsl:param name="mask" /> <xsl:param name="value" /> <xsl:param name="n" /> <xsl:param name="lim" /> <xsl:choose> <xsl:when test="$n = $lim"> <xsl:value-of select="substring($value, $lim + 1)" /> </xsl:when> <xsl:when test="substring($mask, 0, $n) = substring($value,0, $n)"> <xsl:call-template name="strdiff-impl"> <xsl:with-param name="lim" select="$lim" /> <xsl:with-param name="mask" select="$mask" /> <xsl:with-param name="value" select="$value" /> <xsl:with-param name="n" select="$n + 1" /> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="substring($value, $n - 1)"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="strdiff"> <xsl:param name="mask" /> <xsl:param name="value" /> <xsl:choose> <xsl:when test="not($value)" /> <xsl:when test="not($mask)"> <xsl:value-of select="$value" /> </xsl:when> <xsl:otherwise> <xsl:call-template name="strdiff-impl"> <xsl:with-param name="mask" select="$mask" /> <xsl:with-param name="value" select="$value" /> <xsl:with-param name="lim"> <xsl:call-template name="min-len"> <xsl:with-param name="a" select="$mask" /> <xsl:with-param name="b" select="$value" /> </xsl:call-template> </xsl:with-param> <xsl:with-param name="n" select="1" /> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/*"> <xsl:variable select="Solution_Path/SolutionPath" name="solution" /> <xsl:variable select="PVS-Studio_Analysis_Log [not(contains(File, $external))] [ErrorCode!='Renew'] " name="input" /> <html lang="en"> <head> <style type="text/css"> <![CDATA[ #report * {font-family: consolas, monospace, sans-serif; } #report {border-collapse: collapse; border: solid silver 1px;} #report th, #report td {padding: 6px 8px; border: solid silver 1px;} .sev-1 {background-color: #9A2617;} .sev-2 {background-color: #C2571A;} .sev-3 {background-color: #BCA136;} .sev-hidden {background-color: #999; } #report tbody * {color: white;} .fa * { color: #AAA; } a {color: #006;} .stat {padding: 20px;} .stat * {color: white; } .stat span {padding: 8px 16px; } html {background-color: #EEE;} .success {color: #3A3; } ]]> </style> </head> <body> <h1>PVS-Studio report</h1> <h2> <xsl:call-template name="strdiff"> <xsl:with-param name="value"> <xsl:value-of select="$solution" /> </xsl:with-param> <xsl:with-param name="mask"> <xsl:value-of select="$base-path" /> </xsl:with-param> </xsl:call-template> </h2> <div class="stat"> <span class="sev-1"> High: <b> <xsl:value-of select="count($input[Level=1])" /> </b> </span> <span class="sev-2"> Meduim: <b> <xsl:value-of select="count($input[Level=2])" /> </b> </span> <span class="sev-3"> Low: <b> <xsl:value-of select="count($input[Level=3])" /> </b> </span> <span class="sev-hidden" title="Externals etc"> Hidden: <b> <xsl:value-of select="count(PVS-Studio_Analysis_Log) - count($input)"/> </b> </span> </div> <xsl:choose> <xsl:when test="count($input) = 0"> <h2 class="success">No error messages.</h2> </xsl:when> <xsl:otherwise> <table id="report"> <thead> <tr> <th> # </th> <th> File </th> <th> Line </th> <th> Code </th> <th> Message </th> </tr> </thead> <tbody> <xsl:for-each select="$input"> <xsl:sort select="Level" data-type="number"/> <xsl:sort select="DefaultOrder" /> <tr> <xsl:attribute name="class"> <xsl:text>sev-</xsl:text> <xsl:value-of select="Level" /> <xsl:if test="FalseAlarm = 'true'"> <xsl:text xml:space="preserve"> fa</xsl:text> </xsl:if> </xsl:attribute> <th> <xsl:value-of select="position()" /> </th> <td> <xsl:variable name="file"> <xsl:call-template name="strdiff"> <xsl:with-param name="value" select="File" /> <xsl:with-param name="mask" select="$base-path" /> </xsl:call-template> </xsl:variable> <a href="{$repo}{translate($file, '\', '/')}#L{Line}"> <xsl:value-of select="$file" /> </a> </td> <td> <xsl:value-of select="Line"/> </td> <td> <a href="http://viva64.com/en/{ErrorCode}" target="_blank"> <xsl:value-of select="ErrorCode" /> </a> </td> <td> <xsl:value-of select="Message" /> </td> </tr> </xsl:for-each> </tbody> </table> </xsl:otherwise> </xsl:choose> </body> </html> </xsl:template> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 

我们借助一个用C#编写的小型控制台实用程序开始转换,但是您可以以不同的方式进行转换(如果需要,我也将与您分享,那里没有复杂和秘密的内容)。
然后您可以由此创建仪表板,但是正如他们所说,这是一个完全不同的故事。


现在对开发人员有些哭了。 有一个错误,没有一个功能,这使得不可能完全执行上述操作,而且,这仅适用于C ++项目,在C#中没有这样的麻烦。 形成plog文件时,在<File>名称始终强制转换为小写。 而且,当Redmine(和其他Web)托管在具有区分大小写的文件名的类UNIX系统上时,在形成指向文件的链接时大小写会中断,这会使链接无效。 真悲伤


我收到了一份技术支持信的答复,该行为是由于外部API引起的,但尚不清楚为什么它如此有选择性,并且仅适用于C ++,而不适用于C#。
因此,就目前而言,正如我所承诺的,我呼吁继续保尔,并希望进行富有成果的合作。


谢谢您的关注。


更新 :根据与Paullkhandeliants代表的开发人员的通信结果,进行了深基坑挖掘,结果发布了beta版,从而解决了上述问题。 但是,为了使它起作用,至少在进行分析的驱动器上,需要支持短路径。 为此,在注册表中,沿着路径HKLM \ SYSTEM \ CurrentControlSet \ Control \ FileSystem,您需要将NtfsDisable8dot3NameCreation(DWORD)参数设置为允许保存短文件名的值。 在MSDN上查看详细信息。
需要默认禁止使用短名称,以提高NTFS的速度。
您可以将值设置为0且不打扰;如果在系统分区或系统分区的其他位置的用户配置文件中执行CI任务,则可以设置为3,或者在2中运行命令fsutil 8dot3name set Z: 0 (您的磁盘而不是Z) :),将在其中部署CI工作区(顺便说一下,也适用于RAM磁盘)。


我希望这些信息出现在viva64网站上的某个位置。


现在看来格式塔已关闭,再次感谢您的关注。

Source: https://habr.com/ru/post/zh-CN423829/


All Articles