Skip to content
Shenyu Zheng edited this page Aug 23, 2018 · 4 revisions

This plugin serves as API to integrate and publish multiple coverage report types. More information see https://jenkins.io/projects/gsoc/2018/code-coverage-api-plugin/.

How to Implement it

You need to do two things to implement Code Coverage API plugin:

  • convert other coverage reports to our report format.
  • implement an extension point, and return the converted report.

Report Format

If you want to implement a new plugin, you need to convert other coverage reports format to our XML format (or its equivalent java org.w3c.Document object), it is a format simplified by Cobertura report.

You can use two methods to generate a report.

Line Element Based

You can put line elements in other elements (like method, class and file), so the parent elements and the higher level elements will have coverage information calculated by those line elements.

The format of line element: <line number="{lineNumber}" hits="{hitNumber}" branch="{true|false}" (optional)condition-coverage="percentage%(coveredBranch/branchNumber)">.

If hits is set a value larger than 0, this line will be view as a covered line. If branch is set to true, it means it has branch and you need to set condition coverage to condition-coverage in a format like 50%(1/2).

We calculate line coverage by following the below rules:

  • Any element that contains line elements will have a coverage ratio value calculated by its child line elements.
  • Any element that contains other child elements will have a coverage ratio value calculated by its child elements coverage ratio.
  • If an element has both line elements and other type elements, the ratio value calculated by other child coverage elements will override the one by line elements.

report example:

<report name="jacoco">
    <group name="project">
        <package name="hudson/plugins/cobertura">
            <file name="hudson/plugins/cobertura/IOUtils.java">
                <class name="hudson/plugins/cobertura/IOUtils">
                    <method name="closeQuietly" signature="(Ljava/io/Closeable;)V">
                        <line branch="true" condition-coverage="50% (1/2)" hits="1" number="16"/>
                        <line branch="false" hits="1" number="18"/>
                        <line branch="false" hits="0" number="19"/>
                        <line branch="false" hits="1" number="20"/>
                        <line branch="false" hits="1" number="22"/>
                    </method>
                </class>
            </file>
        </package>
    </group>
</report>

Attribute Based

You can also add coverage information as attribute to element. In such case, plugin will not able to support souce code navigation due to the lacking information of line number.

report example:

<report name="jacoco">
    <group name="project">
        <package attr-mode="true" br-covered="216" br-missed="277" instruction-covered="2341" instruction-missed="2622"
                 line-covered="532" line-missed="586" name="hudson/plugins/cobertura">
            <file name="MavenCoberturaPublisher.java">
                <class attr-mode="true" br-covered="0" br-missed="2" instruction-covered="0" instruction-missed="57"
                       line-covered="0" line-missed="16"
                       name="hudson/plugins/cobertura/MavenCoberturaPublisher$MavenCoberturaActionAdder">
                    <method attr-mode="true" instruction-covered="0" instruction-missed="6" line-covered="0"
                            line-missed="3" name="&lt;init&gt;" signature="(Lhudson/model/BuildListener;)V"/>
                    <method attr-mode="true" br-covered="0" br-missed="2" instruction-covered="0"
                            instruction-missed="51" line-covered="0" line-missed="13" name="call"
                            signature="(Lhudson/maven/MavenBuild;)Ljava/lang/Boolean;"/>
                </class>
            </file>
        </package>
    </group>
</report>

You can take a look at the implementation in JacocoReportAdapter.

Other Elements

For other elements, we only need two values - element type, element name. If you use the CoverageParser implementation we provide, we will use element tag as the type and name attribute as the name. You can also implement CoverageParser to customize it.

If you use element types (like function, module) that we don't support, you need to register CoverageElements and implement a simple parser. See llvm-cov Plugin to get more details.

Extension Point

you need implement CoverageReportAdapter extension point to implement a coverage api plugin.

For example, by using the provided abstract layer, we can implement JaCoCo like this:

public final class JacocoReportAdapter extends JavaXMLCoverageReportAdapter {

    @DataBoundConstructor
    public JacocoReportAdapter(String path) {
        super(path);
    }

    @Override
    public String getXSL() {
        return "jacoco-to-standard.xsl";
    }

    @Override
    public String getXSD() {
        return null;
    }

    @Symbol("jacoco")
    @Extension
    public static final class JacocoReportAdapterDescriptor extends JavaCoverageReportAdapterDescriptor<CoverageReportAdapter> {

        public JacocoReportAdapterDescriptor() {
            super(JacocoReportAdapter.class, "jacoco");
        }
    }
}

All we need is to extend an abstract layer for XML-based Java report and provide an XSL file to convert the report to our standard format.