code-coverage-api-plugin icon indicating copy to clipboard operation
code-coverage-api-plugin copied to clipboard

Cobertura report parser doesn't copy source files due to doubled path

Open scottp-dpaw opened this issue 3 years ago • 4 comments

Jenkins and plugins versions report

Environment Jenkins: 2.346.3 OS: Linux - 5.4.0-1061-aws --- ace-editor:1.1 antisamy-markup-formatter:2.7 apache-httpcomponents-client-4-api:4.5.13-138.v4e7d9a_7b_a_e61 authentication-tokens:1.4 aws-credentials:191.vcb_f183ce58b_9 aws-java-sdk:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-cloudformation:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-codebuild:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-ec2:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-ecr:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-ecs:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-elasticbeanstalk:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-iam:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-logs:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-minimal:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-sns:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-sqs:1.12.246-349.v96b_b_f7eb_a_c3c aws-java-sdk-ssm:1.12.246-349.v96b_b_f7eb_a_c3c bitbucket-build-status-notifier:1.4.2 bitbucket-push-and-pull-request:2.8.3 bootstrap4-api:4.6.0-5 bootstrap5-api:5.2.0-1 bouncycastle-api:2.26 branch-api:2.1046.v0ca_37783ecc5 build-name-setter:2.2.0 build-timeout:1.21 caffeine-api:2.9.3-65.v6a_47d0f4d1fe checks-api:1.7.5 cloudbees-bitbucket-branch-source:785.ve724eb_44e286 cloudbees-folder:6.740.ve4f4ffa_dea_54 cobertura:1.17 code-coverage-api:3.1.0-SNAPSHOT (private-d12d10ff-scott) command-launcher:84.v4a_97f2027398 configuration-as-code:1512.vb_79d418d5fc8 credentials:1139.veb_9579fca_33b_ credentials-binding:523.vd859a_4b_122e6 data-tables-api:1.12.1-2 display-url-api:2.3.6 durable-task:500.v8927d9fd99d8 ec2-fleet:2.5.1 echarts-api:5.3.3-1 font-awesome-api:6.1.2-1 forensics-api:1.15.1 git:4.11.4 git-client:3.11.2 git-parameter:0.9.17 git-server:1.11 github:1.34.5 github-api:1.303-400.v35c2d8258028 github-branch-source:1677.v731f745ea_0cf google-login:1.6 handlebars:3.0.8 handy-uri-templates-2-api:2.1.8-22.v77d5b_75e6953 jackson2-api:2.13.3-285.vc03c0256d517 jakarta-activation-api:2.0.1-1 jakarta-mail-api:2.0.1-1 javadoc:226.v71211feb_e7e9 javax-activation-api:1.2.0-4 javax-mail-api:1.6.2-5 jaxb:2.3.6-1 jdk-tool:55.v1b_32b_6ca_f9ca jjwt-api:0.11.5-77.v646c772fddb_0 job-dsl:1.81 jquery:1.12.4-1 jquery3-api:3.6.0-4 jsch:0.1.55.61.va_e9ee26616e7 junit:1119.va_a_5e9068da_d7 lockable-resources:2.16 mailer:435.v79ef3972b_5c7 matrix-project:772.v494f19991984 maven-plugin:3.19 mercurial:2.16.2 mina-sshd-api-common:2.8.0-36.v8e25ce90d4b_1 mina-sshd-api-core:2.8.0-36.v8e25ce90d4b_1 momentjs:1.1.1 multiple-scms:0.8 okhttp-api:4.9.3-108.v0feda04578cf pipeline-build-step:2.18 pipeline-github-lib:38.v445716ea_edda_ pipeline-graph-analysis:195.v5812d95a_a_2f9 pipeline-groovy-lib:612.v84da_9c54906d pipeline-input-step:449.v77f0e8b_845c4 pipeline-milestone-step:101.vd572fef9d926 pipeline-model-api:2.2114.v2654ca_721309 pipeline-model-definition:2.2114.v2654ca_721309 pipeline-model-extensions:2.2114.v2654ca_721309 pipeline-rest-api:2.24 pipeline-stage-step:293.v200037eefcd5 pipeline-stage-tags-metadata:2.2114.v2654ca_721309 pipeline-stage-view:2.24 plain-credentials:139.ved2b_9cf7587b plugin-util-api:2.17.0 popper-api:1.16.1-3 popper2-api:2.11.5-2 powershell:1.7 prism-api:1.28.0-2 rebuild:1.34 resource-disposer:0.19 scm-api:621.vda_a_b_055e58f7 script-security:1175.v4b_d517d6db_f0 slack:616.v03b_1e98d13dd snakeyaml-api:1.30.2-76.vc104f7ce9870 ssh-agent:295.v9ca_a_1c7cc3a_a_ ssh-credentials:295.vced876c18eb_4 ssh-slaves:1.834.v622da_57f702c sshd:3.242.va_db_9da_b_26a_c3 structs:324.va_f5d6774f3a_d timestamper:1.18 token-macro:308.v4f2b_ed62b_b_16 trilead-api:1.67.vc3938a_35172f variant:59.vf075fe829ccb windows-slaves:1.8.1 workflow-aggregator:590.v6a_d052e5a_a_b_5 workflow-api:1192.v2d0deb_19d212 workflow-basic-steps:991.v43d80fea_ff66 workflow-cps:2759.v87459c4eea_ca_ workflow-cps-global-lib:588.v576c103a_ff86 workflow-durable-task-step:1199.v02b_9244f8064 workflow-job:1207.ve6191ff089f8 workflow-multibranch:716.vc692a_e52371b_ workflow-scm-step:400.v6b_89a_1317c9a_ workflow-step-api:639.v6eca_cd8c04a_a_ workflow-support:838.va_3a_087b_4055b ws-cleanup:0.42 xray-connector:2.6.1

What Operating System are you using (both controller, and any agents involved in the problem)?

Ubuntu 20.04 LTS

Reproduction steps

Pass in a Cobertura format coverage report from either the Python coverage tool or the JavaScript Jest tool.

Expected Results

Source files should be detected and loaded by the source code painter.

Actual Results

The leading part of the file paths are doubled up by CoverageNode.mergePath https://github.com/jenkinsci/code-coverage-api-plugin/blob/d12d10ff0e3a763c5b5b0aeb6da1c2babdf7951d/plugin/src/main/java/io/jenkins/plugins/coverage/model/CoverageNode.java#L125

Here's an excerpt from the start of a Cobertura file generated by the Python coverage tool with the default settings:

<?xml version="1.0" ?>
<coverage branch-rate="0.03698" branches-covered="407" branches-valid="11007" complexity="0" line-rate="0.403" lines-covered="14958" lines-valid="37119" timestamp="1661146467695" version="5.3">
	<!-- Generated by coverage.py: https://coverage.readthedocs.io -->
	<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
	<sources>
		<source>/vp/dev</source>
	</sources>
	<packages>
		<package branch-rate="0.15" complexity="0" line-rate="0.5167" name="api">
			<classes>
				<class branch-rate="1" complexity="0" filename="api/__init__.py" line-rate="1" name="__init__.py">
					<methods/>
					<lines/>
				</class>

What should happen is Code Coverage API should be searching for the file api/__init__.py in the search path. We confirmed by adding log statements that it is in fact searching for api/api/__init__.py, due to CoverageNode.mergePath doubling up the file path. This includes the whole subdirectory chain, e.g. a filename of test/classes/example.py would double to test/classes/test/classes/example.py.

Anything else?

For now we have worked around this problem by hacking up a build of the plugin with the if (hasParent()) chunk of mergePath commented out; our coverage reports now load source as expected. I'm guessing the code is there to account for some aspect of pathing in Java projects, so I'm afraid I don't know the best approach to patching this.

scottp-dpaw avatar Aug 22 '22 18:08 scottp-dpaw

I see. It seems that the Cobertura format has a litte different approach than JaCoCo when storing the file nodes. Do you have some Cobertura report files that we can use as test cases for our plugin? Since Cobertura itself is not maintained anymore we have problems in generating some valid results files that we can use in tests.

uhafner avatar Aug 22 '22 21:08 uhafner

This same issue is present when using a C project with ceedling and gcovr to generate Cobertura format output. Have been fighting this for the past few days before finding this open issue. It appears to be appending package name with file name (which makes no sense in a C application). This does not occur with the Jenkins Cobertura plugin (just expects source code in a different location), so I'm using that plugin until this is solved.

Example Cobertura output:

<?xml version="1.0" ?>
<!DOCTYPE coverage
  SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-04.dtd'>
<coverage line-rate="0.625" branch-rate="0.5" lines-covered="5" lines-valid="8" branches-covered="1" branches-valid="2" complexity="0.0" timestamp="1661378033" version="gcovr 4.1">
<sources>
<source>.</source>
</sources>
<packages>
<package name="src.app" line-rate="0.625" branch-rate="0.5" complexity="0.0">
<classes>
<class name="foo_c" filename="src/app/foo.c" line-rate="0.625" branch-rate="0.5" complexity="0.0">
<methods/>
<lines>
<line number="3" hits="1" branch="false"/>
<line number="5" hits="1" branch="false"/>
<line number="8" hits="0" branch="false"/>
<line number="10" hits="0" branch="false"/>
<line number="13" hits="4" branch="false"/>
<line number="15" hits="4" branch="true" condition-coverage="50% (1/2)">
<conditions>
<condition number="0" type="jump" coverage="50%"/>
</conditions>
</line>
<line number="17" hits="4" branch="false"/>
<line number="21" hits="0" branch="false"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>

Jenkins relevant output: [Coverage] [-ERROR-] Source file 'src/app/src/app/foo.c' not found

jhcasco avatar Aug 24 '22 21:08 jhcasco

Can confirm we're also seeing this using pytest and its associated coverage plugin.

djh82 avatar Aug 25 '22 08:08 djh82

We are experiencing the same issue with a cobertura-coverage.xml generated by jest.

<?xml version="1.0" ?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<coverage lines-valid="783" lines-covered="719" line-rate="0.9181999999999999" branches-valid="688" branches-covered="584" branch-rate="0.8488" timestamp="1663223829379" complexity="0" version="0.1">
  <sources>
    <source>/home/tv/project/target</source>
  </sources>
  <packages>
    <package name="js.components.Button" line-rate="0.9687" branch-rate="0.8311">
      ...
      <classes>
        ...
        <class name="index.js" filename="classes/js/components/Button/index.js" line-rate="1" branch-rate="1">
          <methods>
            <method name="(anonymous_0)" hits="146" signature="()V">
              <lines>
                <line number="15" hits="146"/>
              </lines>
            </method>
          </methods>
          <lines>
            <line number="14" hits="10" branch="false"/>
            <line number="16" hits="146" branch="false"/>
            <line number="17" hits="146" branch="false"/>
            <line number="19" hits="146" branch="false"/>
            <line number="35" hits="10" branch="false"/>
            <line number="44" hits="10" branch="false"/>
          </lines>
        </class>
      </classes>
    </package>
  </packages>
</coverage>

Which created this log output: [Coverage] [-ERROR-] Source file 'js/components/Button/classes/js/components/Button/index.js' not found

It seems that the package name is prepended to the file name but the given filename in cobertura-coverage.xml is already pointing to the correct location.

tomvater avatar Sep 15 '22 10:09 tomvater

@uhafner Happy to submit a PR to fix this. Would you prefer to handle this in the cobertura XSL? It looks like that's how Jacoco handles it.

djh82 avatar Nov 11 '22 10:11 djh82

No, the old parsers in this coverage-api-model are deprecated and will be removed soon by the implementations in https://github.com/uhafner/coverage-model. If you want to help it would be more appropriate to fix the code in https://github.com/uhafner/coverage-model/blob/main/src/main/java/edu/hm/hafner/metric/parser/CoberturaParser.java

uhafner avatar Nov 11 '22 13:11 uhafner

It looks like everything is still under development; I'll wait until it's finished so I can prove whether the issue still exists or not. There are limited tests for the coverage parsers, so I'd have to grok both projects first before I could even begin to write a test.

djh82 avatar Nov 19 '22 20:11 djh82

It looks like everything is still under development; I'll wait until it's finished so I can prove whether the issue still exists or not. There are limited tests for the coverage parsers, so I'd have to grok both projects first before I could even begin to write a test.

Yes, indeed. I am still in the middle of the refactoring. My plan is, to have a new major release by the end of the year...

uhafner avatar Nov 19 '22 22:11 uhafner