forcedotcom / salesforcedx-apex

Salesforce Apex Node Library
BSD 3-Clause "New" or "Revised" License
18 stars 25 forks source link

Add cobertura report format for force:apex:test:report command #281

Closed tprouvot closed 2 years ago

tprouvot commented 2 years ago

Is your feature request related to a problem? Please describe. On gitlab CI/CD if you want to visualize code coverage , you have to provide a cobertura report

What are you trying to do Visualize code coverage on gitlab CI/CD or Azure DevOps

Describe the solution you'd like It would be great if we could choose cobertura format in command force:apex:test:report ie: sfdx force:apex:test:report -i <test run id> -r cobertura

Describe alternatives you've considered Develop a sfdx plugin to convert existing report output (human, junit or json) into cobertura format

Additional context I tried to use this plugin but never managed to install it.

github-actions[bot] commented 2 years ago

Thank you for filing this feature request. We appreciate your feedback and will review the feature at our next grooming or sprint planning session. We prioritize feature requests with more upvotes and comments.

noerremark commented 2 years ago

I'd really appreciate this for the Azure DevOps project I'm on! For reference I found the Cobertura DTD, along with an example. The formats supports more than we get back from SFDX, for instance also coverage per method/branch/conditional is supported. Snippet below.

<?xml version="1.0"?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">

<coverage line-rate="0.21974657217686028" branch-rate="0.14609273761902078" lines-covered="11411" lines-valid="51928" branches-covered="2593" branches-valid="17749" complexity="2.054109364767518" version="2.0.3" timestamp="1403301904999">
    <sources>
        <source>/Users/apetro/code/github_jasig/uPortal/uportal-war/target/generated-sources/annotations</source>
        <source>/Users/apetro/code/github_jasig/uPortal/uportal-war/target/generated-sources/xjc</source>
        <source>--source</source>
        <source>/Users/apetro/code/github_jasig/uPortal/uportal-war/src/main/java</source>
    </sources>
    <packages>
        <package name="org.apache.commons.math3.stat.descriptive.moment" line-rate="0.0" branch-rate="1.0" complexity="0.0">
            <classes>
                <class name="org.jasig.portal.EntityIdentifier" filename="org/jasig/portal/EntityIdentifier.java" line-rate="0.2857142857142857" branch-rate="0.0" complexity="1.6666666666666667">
                    <methods>
                        <method name="&lt;init&gt;" signature="(Ljava/lang/String;Ljava/lang/Class;)V" line-rate="1.0" branch-rate="1.0">
                            <lines>
                                <line number="43" hits="71" branch="false"/>
                                <line number="44" hits="71" branch="false"/>
                                <line number="45" hits="71" branch="false"/>
                                <line number="46" hits="71" branch="false"/>
                            </lines>
                        </method>
                        <method name="equals" signature="(Ljava/lang/Object;)Z" line-rate="0.0" branch-rate="0.0">
                            <lines>
                                <line number="67" hits="0" branch="true" condition-coverage="0% (0/2)">
                                    <conditions>
                                        <condition number="0" type="jump" coverage="0%"/>
                                    </conditions>
                                </line>
                                <line number="68" hits="0" branch="false"/>
                                <line number="70" hits="0" branch="true" condition-coverage="0% (0/2)">
                                    <conditions>
                                        <condition number="0" type="jump" coverage="0%"/>
                                    </conditions>
                                </line>
                                <line number="71" hits="0" branch="false"/>
                                <line number="73" hits="0" branch="false"/>
                                <line number="74" hits="0" branch="false"/>
                            </lines>
                        </method>
                        <method name="getKey" signature="()Ljava/lang/String;" line-rate="0.0" branch-rate="1.0">
                            <lines>
                                <line number="52" hits="0" branch="false"/>
                            </lines>
                        </method>
                        <method name="getType" signature="()Ljava/lang/Class;" line-rate="0.0" branch-rate="1.0">
                            <lines>
                                <line number="59" hits="0" branch="false"/>
                            </lines>
                        </method>
                        <method name="hashCode" signature="()I" line-rate="0.0" branch-rate="1.0">
                            <lines>
                                <line number="85" hits="0" branch="false"/>
                            </lines>
                        </method>
                        <method name="toString" signature="()Ljava/lang/String;" line-rate="0.0" branch-rate="1.0">
                            <lines>
                                <line number="96" hits="0" branch="false"/>
                            </lines>
                        </method>
                    </methods>
                    <lines>
                        <line number="43" hits="71" branch="false"/>
                        <line number="44" hits="71" branch="false"/>
                        <line number="45" hits="71" branch="false"/>
                        <line number="46" hits="71" branch="false"/>
                        <line number="52" hits="0" branch="false"/>
                        <line number="59" hits="0" branch="false"/>
                        <line number="67" hits="0" branch="true" condition-coverage="0% (0/2)">
                            <conditions>
                                <condition number="0" type="jump" coverage="0%"/>
                            </conditions>
                        </line>
                        <line number="68" hits="0" branch="false"/>
                        <line number="70" hits="0" branch="true" condition-coverage="0% (0/2)">
                            <conditions>
                                <condition number="0" type="jump" coverage="0%"/>
                            </conditions>
                        </line>
                        <line number="71" hits="0" branch="false"/>
                        <line number="73" hits="0" branch="false"/>
                        <line number="74" hits="0" branch="false"/>
                        <line number="85" hits="0" branch="false"/>
                        <line number="96" hits="0" branch="false"/>
                    </lines>
                </class>
            </class>
        </package>
    </packages>
</coverage>

I think we can skip everything in <methods> because it's simply not there. As for <line>, is there a way to calculate ?hits? If not, we can just live with 1. For branch we should just put false because we'll never get branched coverage.

tprouvot commented 2 years ago

Hi guys !

Looks like the new sfdx version (7.153.0) is about to make our wish come true !

image