【问题标题】:Why doesn't Sonar read the format of django-nose coverage results?为什么 Sonar 不读取 django-nose 覆盖结果的格式?
【发布时间】:2018-07-02 18:33:07
【问题描述】:

当我尝试使用声纳扫描仪发送 python 项目时,它会抛出异常:

Caused by: java.lang.IllegalStateException: Unknown report version: 4.4.2. 
This parser only handles version 1.". 

在尝试引入封面之前,项目运行正常,项目是python代码,报告是用django-nose创建的。

更多信息:

  • 声纳版本:6.7.1
  • 声纳扫描器命令:
    sonar-scanner -Dsonar.projectKey=nanas -Dsonar.host.url=http://192.168.0.1:9001 -Dsonar.login=F00B4Z
  • 声纳不通过代理运行

我附上了django-nose生成的声纳项目配置文件和覆盖xml文件。

例外:

12:53:31.919 ERROR: Error during SonarQube Scanner execution
Error during parsing of the generic coverage report '/home/bamboo-home/xml-data/build-dir/NAN-CI6-JOB1/xmlrunner/coverage.xml'. Look at SonarQube documentation to know the expected XML format.
Caused by: java.lang.IllegalStateException: Unknown report version: 4.4.2. This parser only handles version 1.
    at org.sonar.scanner.genericcoverage.GenericCoverageReportParser.parseRootNode(GenericCoverageReportParser.java:72)
    at org.sonar.scanner.genericcoverage.GenericCoverageReportParser.lambda$parse$0(GenericCoverageReportParser.java:64)
    at org.sonar.api.utils.StaxParser.parse(StaxParser.java:115)
    at org.sonar.api.utils.StaxParser.parse(StaxParser.java:95)
    at org.sonar.scanner.genericcoverage.GenericCoverageReportParser.parse(GenericCoverageReportParser.java:65)
    at org.sonar.scanner.genericcoverage.GenericCoverageReportParser.parse(GenericCoverageReportParser.java:54)
    at org.sonar.scanner.genericcoverage.GenericCoverageSensor.execute(GenericCoverageSensor.java:109)
    at org.sonar.scanner.sensor.SensorWrapper.analyse(SensorWrapper.java:53)
    at org.sonar.scanner.phases.SensorsExecutor.executeSensor(SensorsExecutor.java:88)
    at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:82)
    at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:68)
    at org.sonar.scanner.phases.AbstractPhaseExecutor.execute(AbstractPhaseExecutor.java:88)
    at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:180)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:135)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:121)
    at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:288)
    at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:283)
    at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:261)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:135)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:121)
    at org.sonar.scanner.task.ScanTask.execute(ScanTask.java:48)
    at org.sonar.scanner.task.TaskContainer.doAfterStart(TaskContainer.java:84)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:135)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:121)
    at org.sonar.scanner.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:121)
    at org.sonar.batch.bootstrapper.Batch.doExecuteTask(Batch.java:116)
    at org.sonar.batch.bootstrapper.Batch.executeTask(Batch.java:111)
    at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
    at com.sun.proxy.$Proxy0.execute(Unknown Source)
    at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:233)
    at org.sonarsource.scanner.api.EmbeddedScanner.runAnalysis(EmbeddedScanner.java:151)
    at org.sonarsource.scanner.cli.Main.runAnalysis(Main.java:123)
    at org.sonarsource.scanner.cli.Main.execute(Main.java:77)
    at org.sonarsource.scanner.cli.Main.main(Main.java:61)

配置:

sonar.projectKey=nanas
sonar.projectName=Nanas
sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8
sonar.sources=nucleo, app_administrador, app_cliente, app_gestor_de_citas, app_nana, app_test, django_gae_emailbackend
sonar.exclusions=**/tests/**, **/static/**/template/**, **/migrations/**, **/__pycache__/**, **/__init__.*
sonar.tests=xmlrunner/nosetests.xml
sonar.genericcoverage.reportPaths=xmlrunner/coverage.xml
sonar.python.coveragePlugin=cobertura
sonar.coverage.dtdVerification=false

Coverage.xml 标头:

<?xml version="1.0" ?>
<coverage branch-rate="0" branches-covered="0" branches-valid="0" complexity="0" line-rate="0.5905" lines-covered="1142" lines-valid="1934" timestamp="1516639621366" version="4.4.2">
    <!-- Generated by coverage.py: https://coverage.readthedocs.io -->
    <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
    <sources>

我已根据指示配置扫描仪,并将插件更新到 1.9 版,但现在它会生成行数错误。我已经在几个网站上搜索了解决方案,几乎所有内容都归结为添加一个空行,但这不起作用。

运行测试:

nosetests --with-coverage --cover-package=app_administrador,app_cliente,app_nana,app_test,app_gestor_de_citas,nucleo --cover-erase --cover-xml --with-xunit --xunit-file=xmlrunner/nosetests.xml --cover-xml-file=xmlrunner/coverage.xml --attr=!pendiente --verbosity=1

运行声纳:

sonar-scanner   -Dsonar.projectKey=nana   -Dsonar.host.url=http://192.168.0.15:9001   -Dsonar.login=*********

sonar-project.properties

sonar.projectKey=nanas
sonar.projectName=nanas
sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8
sonar.sources=nucleo, app_administrador, app_cliente, app_gestor_de_citas, app_nana, app_test, django_gae_emailbackend
sonar.exclusions=**/tests/**, **/static/**/template/**, **/migrations/**, **/__pycache__/**, **/admin.py
sonar.tests=xmlrunner/nosetests.xml
sonar.python.coverage.reportPath=xmlrunner/coverage.xml

错误:

ERROR: Error during SonarQube Scanner execution
java.lang.IllegalStateException: Line 21 is out of range in the file app_administrador/middleware.py (lines: 19)
        at org.sonar.api.internal.google.common.base.Preconditions.checkState(Preconditions.java:197)

Python 插件

SonarPython 1.9 (build 1989)installed

【问题讨论】:

    标签: python django sonarqube code-coverage


    【解决方案1】:

    SonarPython 具有对 coverage.py 报告的嵌入式支持。 要启用它,您可以替换通用覆盖配置:

    sonar.genericcoverage.reportPaths=xmlrunner/coverage.xml
    sonar.python.coveragePlugin=cobertura
    sonar.coverage.dtdVerification=false
    

    通过具体的 SonarPython 配置:

    sonar.python.coverage.reportPath=xmlrunner/coverage.xml
    

    更多详情见Python Coverage Results Import

    注意:SonarPython 1.9 中已对 coverage.py(最高 4.4.2)进行了改进,如果您还不能下载 SonarPython 1.9,则候选版本是 here

    【讨论】:

      【解决方案2】:

      我终于知道发生了什么事。似乎扫描仪混淆了不同 django 应用程序中的两个同名文件,因为每个应用程序都在 django-nose 的 django 设置中配置为“cover-package”。

      显然 django-nose 将所有数据包根文件视为单个模块“./”,如果有重复文件(例如:admin.py)只读取一个,但是当您将数据传递给 python 扫描仪时,它会尝试阅读另一个,如果它们都有不同的行,则会引发冲突,我想如果它们碰巧有相同的行,声纳覆盖的代码与行的表示也会是错误的。

      django-nose 修改前生成的覆盖文件:

        <?xml version="1.0" ?>
      <coverage branch-rate="0" branches-covered="0" branches-valid="0" complexity="0" line-rate="0.5905" lines-covered="1142" lines-valid="1934" timestamp="1516895775536" version="4.4.2">
          <!-- Generated by coverage.py: https://coverage.readthedocs.io -->
          <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
          <sources>
              <source>/home/jvallina/PycharmProjects/nana_project/app_administrador</source>
              <source>/home/jvallina/PycharmProjects/nana_project/app_cliente</source>
              <source>/home/jvallina/PycharmProjects/nana_project/app_gestor_de_citas</source>
              <source>/home/jvallina/PycharmProjects/nana_project/app_nana</source>
              <source>/home/jvallina/PycharmProjects/nana_project/app_test</source>
              <source>/home/jvallina/PycharmProjects/nana_project/nucleo</source>
          </sources>
          <packages>
              <package branch-rate="0" complexity="0" line-rate="0.5668" name=".">
                  <classes>
                      <class branch-rate="0" complexity="0" filename="__init__.py" line-rate="1" name="__init__.py">
                          <methods/>
                          <lines/>
                      </class>
                      <class branch-rate="0" complexity="0" filename="admin.py" line-rate="0" name="admin.py">
                          <methods/>
                          <lines>
                              <line hits="0" number="1"/>
                              ...
                              <line hits="0" number="238"/>
                          </lines>
                      </class>
      

      那我们要替换它(django设置):

      NOSE_ARGS = [
          '--with-coverage',
          '--cover-package=app_administrador,app_cliente,app_nana,app_test,app_gestor_de_citas,nucleo',
          '--cover-erase',
          '--cover-xml',
          '--with-xunit',
          '--xunit-file=xmlrunner/nosetests.xml',
          '--cover-xml-file=xmlrunner/coverage.xml'
      ]
      

      这样:

      NOSE_ARGS = [
          '--with-coverage',
          '--cover-package=.',
          '--cover-erase',
          '--cover-xml',
          '--with-xunit',
          '--xunit-file=xmlrunner/nosetests.xml',
          '--cover-xml-file=xmlrunner/coverage.xml'
      ]
      

      变更后的覆盖文件: 我们可以看到,模块中重复的每个文件都已经通过其源应用程序进行了区分。

       <?xml version="1.0" ?>
          <coverage branch-rate="0" branches-covered="0" branches-valid="0" complexity="0" line-rate="0.6718" lines-covered="3069" lines-valid="4568" timestamp="1516896635767" version="4.4.2">
              <!-- Generated by coverage.py: https://coverage.readthedocs.io -->
              <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
              <sources>
                  <source>/home/jvallina/PycharmProjects/nana_project</source>
              </sources>
              <packages>
                  <package branch-rate="0" complexity="0" line-rate="0" name=".">
                      <classes>
                          <class branch-rate="0" complexity="0" filename="manage.py" line-rate="0" name="manage.py">
                              <methods/>
                              <lines>
                                  <line hits="0" number="2"/>
                                  <line hits="0" number="3"/>
                                  <line hits="0" number="5"/>
                                  <line hits="0" number="6"/>
                                  <line hits="0" number="7"/>
                                  <line hits="0" number="8"/>
                                  <line hits="0" number="9"/>
                                  <line hits="0" number="13"/>
                                  <line hits="0" number="14"/>
                                  <line hits="0" number="15"/>
                                  <line hits="0" number="16"/>
                                  <line hits="0" number="21"/>
                                  <line hits="0" number="22"/>
                              </lines>
                          </class>
                      </classes>
                  </package>
                  <package branch-rate="0" complexity="0" line-rate="0.4884" name="app_administrador">
          <classes>
                          <class branch-rate="0" complexity="0" filename="app_administrador/__init__.py" line-rate="1" name="__init__.py">
                              <methods/>
                              <lines/>
                          </class>
                          <class branch-rate="0" complexity="0" filename="app_administrador/admin.py" line-rate="1" name="admin.py">
                              <methods/>
                              <lines/>
                          </class>
          ...
          </package>
      <package branch-rate="0" complexity="0" line-rate="0.7931" name="app_cliente">
                  <classes>
                      <class branch-rate="0" complexity="0" filename="app_cliente/__init__.py" line-rate="1" name="__init__.py">
                          <methods/>
                          <lines/>
                      </class>
                      <class branch-rate="0" complexity="0" filename="app_cliente/admin.py" line-rate="1" name="admin.py">
                          <methods/>
                          <lines/>
                      </class>
      ...
      </package>
      

      【讨论】:

      • 您的调查强调了 SonarPython 1.9 RC 中的一个限制。它使用&lt;source&gt; 元素的第一次出现来解析coverage.xml 文件的filename 属性。相反,它应该考虑所有&lt;source&gt; 元素。这是票SONARPY-257。感谢您的反馈。
      猜你喜欢
      • 1970-01-01
      • 2012-07-10
      • 2016-11-11
      • 1970-01-01
      • 2016-06-22
      • 2013-09-09
      • 1970-01-01
      • 2019-07-02
      • 2015-01-07
      相关资源
      最近更新 更多