Sonarqube 没有从 LCOV 检索我的 JavaScript 报道
Sonarqube does not retrieve my JavaScript coverage from LCOV
我有一个具有以下结构的应用程序:
my-application
+- pom.xml
+- app
| +- scripts
| | +- app.js
| | +- **/*.js
| +- 3rd-party-libs
+- build
+- node_modules
+- test
我创建了 pom.xml
仅用于 运行 SonarQube 分析。否则,所有任务都是 运行 by G运行t(测试是 运行 with Karma)。
pom.xml
内容如下:
<properties>
<sonar.language>js</sonar.language>
<sonar.sourceEncoding>UTF-8</sonar.sourceEncoding>
<sonar.javascript.coveragePlugin>lcov</sonar.javascript.coveragePlugin>
<sonar.javascript.lcov.reportPath>build/karma/coverage/lcov.info</sonar.javascript.lcov.reportPath>
<sonar.exclusions>app/3rd-party-libs/**,node_modules/**</sonar.exclusions>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
</properties>
<build>
<sourceDirectory>app/scripts</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
</build>
当我 运行 grunt test
时,它会创建一个包含以下信息的 build/karma/coverage/lcov.info
:
TN:
SF:./app/scripts/app.js
FN:16,(anonymous_1)
FN:26,(anonymous_2)
FNF:2
...
SonarQube 分析后,仪表板显示代码覆盖率为 0%。
我怀疑 SF:
中的路径是错误的来源。因此,我将 sonar.javascript.lcov.reportPath
属性 更改为使用另一个 lcov.info
来测试不同的值:app.js
、./app.js
、app/scripts/app.js
、./app/scripts/app.js
,但 none 有效,将覆盖率保持在 0%。
我错过了什么?
以防万一,我的 karma.conf.js
中有以下配置:
coverageReporter: {
reporters: [
{
type: 'lcov',
dir: 'build/karma/coverage',
subdir: '.'
}
]
},
ps: Sonar版本是3.7.2,我也试了4.3,结果一样...
编辑:我已经更新我的配置以直接使用 Sonar-运行ner,我使用的是最新版本的 Sonar (5.0.1) 和JS 插件 (2.3)。我还手动修改了 lcov.info
以具有 "good" 格式(至少一种与 Sonar repo 示例匹配的格式):
SF:./app/scripts/app.js
DA:2,1
DA:20,1
DA:29,1
DA:34,1
end_of_record
SF:./app/scripts/services/exampleService.js
DA:1,1
DA:11,1
DA:12,0
end_of_record
sonar-project.properties
看起来像:
sonar.projectKey=xxx
sonar.projectName=xxx
sonar.projectVersion=xxx
sonar.sourceEncoding=UTF-8
sonar.sources=app/scripts
sonar.tests=test
sonar.exclusions=app/3rd-party-libs/**,node_modules/**
sonar.dynamicAnalysis=reuseReports
sonar.language=js
sonar.projectBaseDir=.
sonar.javascript.coveragePlugin=lcov
sonar.javascript.lcov.reportPath=build/karma/coverage/lcov.info
而且仍然是 0% 的覆盖率:(
我一无所知,所以我决定修改 JavaScript plugin 以添加更多日志。而我终于找到了错误,这是一个...区分大小写的恶性问题!
让我解释一下。让我们考虑 CoverageSensor.java
:
的 saveMeasureFromLCOVFile
方法
protected void saveMeasureFromLCOVFile(SensorContext context) {
String providedPath = settings.getString(JavaScriptPlugin.LCOV_REPORT_PATH);
File lcovFile = getIOFile(fileSystem.baseDir(), providedPath);
...
LOG.info("Analysing {}", lcovFile);
LCOVParser parser = new LCOVParser(fileSystem.baseDir());
Map<String, CoverageMeasuresBuilder> coveredFiles = parser.parseFile(lcovFile);
for (InputFile inputFile : fileSystem.inputFiles(mainFilePredicate)) {
try {
CoverageMeasuresBuilder fileCoverage = coveredFiles.get(inputFile.file().getAbsolutePath());
org.sonar.api.resources.File resource = org.sonar.api.resources.File.create(inputFile.relativePath());
if (fileCoverage != null) {
for (Measure measure : fileCoverage.createMeasures()) {
context.saveMeasure(resource, measure);
}
} else {
// colour all lines as not executed
LOG.debug("Default value of zero will be saved for file: {}", resource.getPath());
LOG.debug("Because: either was not present in LCOV report either was not able to retrieve associated SonarQube resource");
saveZeroValueForResource(resource, context);
}
} catch (Exception e) {
LOG.error("Problem while calculating coverage for " + inputFile.absolutePath(), e);
}
}
}
首先,它读取给定的 lcov.info
文件以了解我们拥有哪些文件的覆盖率数据(通过解析文件检索,使用 LCOVParser
class 完成)。
之后,它从 coveredFiles
映射中获取相同的文件来进行指标和代码之间的匹配。如果找不到文件(if (fileCoverage != null) {
的else
部分),则代码覆盖率强制为 0。
我的项目就是这样。
为什么会这样?仅仅是因为在我的环境中,inputFile
等于 d:\dev\my-application\app\scripts\app.js
,而在 coveredFiles
映射中,我有 D:\dev\my-application\app\scripts\app.js
。请注意驱动器号中的大小写差异(d:
与 D:
)。由于 map.get(...)
区分大小写,因此 fileCoverage
为 null
,因此不计算覆盖率。
现在,我必须研究如何强制路径具有正确的大小写...
经过更多调查,我发现对插件代码的修改有效(至少对我而言,我没有考虑所有可能的影响)。在 LCOVParser
中,filePath = CoverageSensor.getIOFile(moduleBaseDir, filePath).getCanonicalPath();
可以修改为 filePath = CoverageSensor.getIOFile(moduleBaseDir, filePath).getAbsolutePath();
,因为第一个 return 的路径类似于 D:\...
,而第二个 return d:\...
.
事实上,我什至不知道在 Windows 上使用什么是 首选 案例。以下代码:
public static void main(String[] args) throws IOException {
System.out.println("PATH 1 : " + new File(".").getAbsolutePath());
System.out.println("PATH 2 : " + new File(".").getCanonicalPath());
}
将return:
PATH 1 : D:\dev\preclosing\preclosing-eme\.
PATH 2 : D:\dev\preclosing\preclosing-eme
无论如何,我暂时被卡住了,我什至不确定如何在不等待 JS 插件修复的情况下解决我的问题(因为我的 "official" Sonar 对于时刻,仅支持 v2.1 及以下的 JS 插件。
我有一个具有以下结构的应用程序:
my-application
+- pom.xml
+- app
| +- scripts
| | +- app.js
| | +- **/*.js
| +- 3rd-party-libs
+- build
+- node_modules
+- test
我创建了 pom.xml
仅用于 运行 SonarQube 分析。否则,所有任务都是 运行 by G运行t(测试是 运行 with Karma)。
pom.xml
内容如下:
<properties>
<sonar.language>js</sonar.language>
<sonar.sourceEncoding>UTF-8</sonar.sourceEncoding>
<sonar.javascript.coveragePlugin>lcov</sonar.javascript.coveragePlugin>
<sonar.javascript.lcov.reportPath>build/karma/coverage/lcov.info</sonar.javascript.lcov.reportPath>
<sonar.exclusions>app/3rd-party-libs/**,node_modules/**</sonar.exclusions>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
</properties>
<build>
<sourceDirectory>app/scripts</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
</build>
当我 运行 grunt test
时,它会创建一个包含以下信息的 build/karma/coverage/lcov.info
:
TN:
SF:./app/scripts/app.js
FN:16,(anonymous_1)
FN:26,(anonymous_2)
FNF:2
...
SonarQube 分析后,仪表板显示代码覆盖率为 0%。
我怀疑 SF:
中的路径是错误的来源。因此,我将 sonar.javascript.lcov.reportPath
属性 更改为使用另一个 lcov.info
来测试不同的值:app.js
、./app.js
、app/scripts/app.js
、./app/scripts/app.js
,但 none 有效,将覆盖率保持在 0%。
我错过了什么?
以防万一,我的 karma.conf.js
中有以下配置:
coverageReporter: {
reporters: [
{
type: 'lcov',
dir: 'build/karma/coverage',
subdir: '.'
}
]
},
ps: Sonar版本是3.7.2,我也试了4.3,结果一样...
编辑:我已经更新我的配置以直接使用 Sonar-运行ner,我使用的是最新版本的 Sonar (5.0.1) 和JS 插件 (2.3)。我还手动修改了 lcov.info
以具有 "good" 格式(至少一种与 Sonar repo 示例匹配的格式):
SF:./app/scripts/app.js
DA:2,1
DA:20,1
DA:29,1
DA:34,1
end_of_record
SF:./app/scripts/services/exampleService.js
DA:1,1
DA:11,1
DA:12,0
end_of_record
sonar-project.properties
看起来像:
sonar.projectKey=xxx
sonar.projectName=xxx
sonar.projectVersion=xxx
sonar.sourceEncoding=UTF-8
sonar.sources=app/scripts
sonar.tests=test
sonar.exclusions=app/3rd-party-libs/**,node_modules/**
sonar.dynamicAnalysis=reuseReports
sonar.language=js
sonar.projectBaseDir=.
sonar.javascript.coveragePlugin=lcov
sonar.javascript.lcov.reportPath=build/karma/coverage/lcov.info
而且仍然是 0% 的覆盖率:(
我一无所知,所以我决定修改 JavaScript plugin 以添加更多日志。而我终于找到了错误,这是一个...区分大小写的恶性问题!
让我解释一下。让我们考虑 CoverageSensor.java
:
saveMeasureFromLCOVFile
方法
protected void saveMeasureFromLCOVFile(SensorContext context) {
String providedPath = settings.getString(JavaScriptPlugin.LCOV_REPORT_PATH);
File lcovFile = getIOFile(fileSystem.baseDir(), providedPath);
...
LOG.info("Analysing {}", lcovFile);
LCOVParser parser = new LCOVParser(fileSystem.baseDir());
Map<String, CoverageMeasuresBuilder> coveredFiles = parser.parseFile(lcovFile);
for (InputFile inputFile : fileSystem.inputFiles(mainFilePredicate)) {
try {
CoverageMeasuresBuilder fileCoverage = coveredFiles.get(inputFile.file().getAbsolutePath());
org.sonar.api.resources.File resource = org.sonar.api.resources.File.create(inputFile.relativePath());
if (fileCoverage != null) {
for (Measure measure : fileCoverage.createMeasures()) {
context.saveMeasure(resource, measure);
}
} else {
// colour all lines as not executed
LOG.debug("Default value of zero will be saved for file: {}", resource.getPath());
LOG.debug("Because: either was not present in LCOV report either was not able to retrieve associated SonarQube resource");
saveZeroValueForResource(resource, context);
}
} catch (Exception e) {
LOG.error("Problem while calculating coverage for " + inputFile.absolutePath(), e);
}
}
}
首先,它读取给定的 lcov.info
文件以了解我们拥有哪些文件的覆盖率数据(通过解析文件检索,使用 LCOVParser
class 完成)。
之后,它从 coveredFiles
映射中获取相同的文件来进行指标和代码之间的匹配。如果找不到文件(if (fileCoverage != null) {
的else
部分),则代码覆盖率强制为 0。
我的项目就是这样。
为什么会这样?仅仅是因为在我的环境中,inputFile
等于 d:\dev\my-application\app\scripts\app.js
,而在 coveredFiles
映射中,我有 D:\dev\my-application\app\scripts\app.js
。请注意驱动器号中的大小写差异(d:
与 D:
)。由于 map.get(...)
区分大小写,因此 fileCoverage
为 null
,因此不计算覆盖率。
现在,我必须研究如何强制路径具有正确的大小写...
经过更多调查,我发现对插件代码的修改有效(至少对我而言,我没有考虑所有可能的影响)。在 LCOVParser
中,filePath = CoverageSensor.getIOFile(moduleBaseDir, filePath).getCanonicalPath();
可以修改为 filePath = CoverageSensor.getIOFile(moduleBaseDir, filePath).getAbsolutePath();
,因为第一个 return 的路径类似于 D:\...
,而第二个 return d:\...
.
事实上,我什至不知道在 Windows 上使用什么是 首选 案例。以下代码:
public static void main(String[] args) throws IOException {
System.out.println("PATH 1 : " + new File(".").getAbsolutePath());
System.out.println("PATH 2 : " + new File(".").getCanonicalPath());
}
将return:
PATH 1 : D:\dev\preclosing\preclosing-eme\.
PATH 2 : D:\dev\preclosing\preclosing-eme
无论如何,我暂时被卡住了,我什至不确定如何在不等待 JS 插件修复的情况下解决我的问题(因为我的 "official" Sonar 对于时刻,仅支持 v2.1 及以下的 JS 插件。