microsoft/azure-pipelines-tasks-common-packages

'Failed to enable code coverage: TypeError: Cannot read properties of undefined (reading 'split')' error when enabling JaCoCo coverage on Ant task without supplying optional input

ataverascrespo opened this issue · 0 comments

The issue was previously opened in the azure-pipelines-tasks repo, as issue #19724, but I will be re-opening the issue in this repo (the correct one).

To summarize, when creating an Azure DevOps build pipeline, and working with Ant@V1 task, enabling JaCoCo code coverage is failing, and is generating the following error:

##[warning]Failed to enable code coverage: TypeError: Cannot read properties of undefined (reading 'split')
Here is the log output:

masking file paths with (...)

##[debug]classFilter=undefined
##[debug]classFilesDirectories=build/src/
##[debug]srcDirectories=undefined
##[debug]rm -rf (...)/cobertura.ser
##[debug]rm -rf (...)/CCReport43F6D5EF
##[debug]removing directory
##[debug]rm -rf (...)/CCReportBuildA4D283EG.xml
##[debug]removing file
##[debug]rm -rf (...)/InstrumentedClasses
##[debug]Input parameters: {"buildfile":"(...)/build.xml","classfilesdirectories":"build/src/","summaryfile":"summary.xml","reportdirectory":"(...)/CCReport43F6D5EF","ccreporttask":"CodeCoverage_9064e1d0","reportbuildfile":"(...)/CCReportBuildA4D283EG.xml"}
##[debug]Extracting Azure Pipelines filter: undefined
##[debug]Applying the filter pattern:  op: 
##[debug]Applying the filter pattern:  op: 
##[debug]Reading XML file: (...)/build.xml
##[debug]Converting XML file to JSON
##[warning]Failed to enable code coverage: TypeError: Cannot read properties of undefined (reading 'split')
##[debug]Processed: ##vso[task.issue type=warning;]Failed to enable code coverage: TypeError: Cannot read properties of undefined (reading 'split')

This error was generated with the following YAML configuration for the Ant@V1 task:

codeCoverageToolOptions: 'JaCoCo'
codeCoverageClassFilesDirectories: 'build/src/'

After several days of debugging, our team found the issue was able to be resolved by adding the following optional field to the YAML configuration for the Ant@V1 task:

codeCoverageSourceDirectories: 'components/src/'

This is inconsistent with the Ant@V1 documentation, which states the codeCoverageSourceDirectories input is optional when codeCoverageToolOptions != None. I looked into the JaCoCo code coverage functions and believe I found the root cause of the issue in the enableCodeCoverage() function in the jacoco.ant.cc.enabler class.

In enableCodeCoverage(), the global sourceDirs variable is set to the value of ccProps["sourcedirectories"], which contains the value of the INPUT_SRCDIRECTORIES environment variable passed from the Ant task.

From there, addCodeCoverageData() is called, which then calls getSourceFilter().

    protected getSourceFilter(): string {
        let srcData = "";
        let srcDirs = this.sourceDirs === null ? "" : this.sourceDirs;
        srcDirs.split(",").forEach(dir => {
            if (!util.isNullOrWhitespace(dir)) {
                srcData += `<fileset dir="${dir}"/>`;
                srcData += os.EOL;
            }
        });
        if (util.isNullOrWhitespace(srcData)) {
            srcData = `<fileset dir="."/>`;
            srcData += os.EOL;
        }
        return srcData;
    }

If the codeCoverageSourceDirectories YAML input is not given a value, then INPUT_SRCDIRECTORIES is undefined, meaning the value of global var sourceDirs is set to undefined. Thus, calling split() on an undefined value generates the error and causes JaCoCo code coverage to fail on the pipeline.

I believe the issue is due to a lack of handling undefined values. At the same time, that doesn't seem to affect that classFilter variable when that value is undefined. I have reproduced this on several build pipelines, all to the same effect. This probably just needs a bare minimum change like

    if (srcDirs) {
        srcDirs.split(",").forEach(dir => {
               // continues if srcDirs != undefined
        });
    }
    else {
        // continues if srcDirs == undefined
    }

but not sure if anyone has run into this issue ever...