Swift code coverage with SonarCloud

Hello, as I understand with automatic analysis we cannot get test coverage for Swift projects.

So I’m trying to setup the sonar scanner on our CI but it fails. We’re using Bitrise.

INFO: Sensor SonarSwift [swift]
INFO: 16 source files to be analyzed
INFO: Load project repositories
INFO: Load project repositories (done) | time=119ms
INFO: 16/16 source files have been analyzed
INFO: ------------------------------------------------------------------------
INFO: EXECUTION FAILURE
INFO: ------------------------------------------------------------------------
INFO: Total time: 42.024s
INFO: Final Memory: 33M/191M
INFO: ------------------------------------------------------------------------
ERROR: Error during SonarQube Scanner execution
ERROR: java.io.IOException: Is a directory
ERROR: Caused by: Is a directory

I did read https://github.com/SonarSource/sonar-scanning-examples/tree/master/swift-coverage and the only step that I’m missing is to install the plugin. Is that what’s going on?

Thanks for your help!

Hello @Antoine4011,

There’s no extra plugin to install when running the scanner from your own CI. The scanner will download on the fly from SonarCloud all necessary plugins.
So that’s not your problem.

Could you provide more details on your CI job to understand the problem:

  • How you generate the Swift coverage report
  • What properties you pass the the scanner (either from sonar.properties file or from scanner command line)
  • Please also attach the full log of your scanner execution in debug mode ie with sonar-scanner ... -X option

Regards

1 Like

Hello @OlivierK,

I’m generating the test report that way:

#!/usr/bin/env bash
bash xccov-to-sonarqube-generic.sh $BITRISE_XCRESULT_PATH > sonarqube-generic-coverage.xml

But I’m having that error:
Requested but did not find extension point with identifier Xcode.IDEFoundation.IDEResultKitSerializationConverter Error: Error Domain=XCCovErrorDomain Code=0 "No coverage data in result bundle" UserInfo={NSLocalizedDescription=No coverage data in result bundle}

Here’s my sonar properties:

sonar.sources=.
sonar.projectKey=###
sonar.organization=###
sonar.host.url=https://sonarcloud.io
sonar.login=###
sonar.coverageReportPaths=sonarqube-generic-coverage.xml
sonar.cfamily.build-wrapper-output.bypass=true

Here’s my log file
17d30cee36700d05.txt (7.5 KB)

As I’m not sure the generated coverage file is okay (I tried locally and even though I’m having some warnings, the file is getting generated anyway), it’s worth noting that I also tried to run the scanner without the coverage report and I end up with the exact same error.

Thanks!

Hello @OlivierK any news regarding this? I’m still stuck with the same error.
I have the full error but that doesn’t help to debug what file the scanner is having an issue with.

14:40:42.030 ERROR: Error during SonarScanner execution
java.io.UncheckedIOException: java.io.IOException: Is a directory
	at java.base/java.io.BufferedReader$1.hasNext(Unknown Source)
	at java.base/java.util.Iterator.forEachRemaining(Unknown Source)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
	at com.sonar.swift.plugin.B.A(Unknown Source)
	at com.sonar.swift.plugin.B.A(Unknown Source)
	at com.sonar.swift.plugin.E.A(Unknown Source)
	at com.sonar.swift.plugin.E.execute(Unknown Source)
	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:34)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:78)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:51)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:69)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:51)
	at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:68)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:122)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:108)
	at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:402)
	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:398)
	at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:356)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:122)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:108)
	at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:126)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:122)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:108)
	at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:58)
	at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:52)
	at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
	at com.sun.proxy.$Proxy0.execute(Unknown Source)
	at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189)
	at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)
	at org.sonarsource.scanner.cli.Main.execute(Main.java:112)
	at org.sonarsource.scanner.cli.Main.execute(Main.java:75)
	at org.sonarsource.scanner.cli.Main.main(Main.java:61)
Caused by: java.io.IOException: Is a directory
	at java.base/sun.nio.ch.FileDispatcherImpl.read0(Native Method)
	at java.base/sun.nio.ch.FileDispatcherImpl.read(Unknown Source)
	at java.base/sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
	at java.base/sun.nio.ch.IOUtil.read(Unknown Source)
	at java.base/sun.nio.ch.FileChannelImpl.read(Unknown Source)
	at java.base/sun.nio.ch.ChannelInputStream.read(Unknown Source)
	at java.base/sun.nio.ch.ChannelInputStream.read(Unknown Source)
	at java.base/sun.nio.ch.ChannelInputStream.read(Unknown Source)
	at java.base/sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
	at java.base/sun.nio.cs.StreamDecoder.implRead(Unknown Source)
	at java.base/sun.nio.cs.StreamDecoder.read(Unknown Source)
	at java.base/java.io.InputStreamReader.read(Unknown Source)
	at java.base/java.io.BufferedReader.fill(Unknown Source)
	at java.base/java.io.BufferedReader.readLine(Unknown Source)
	at java.base/java.io.BufferedReader.readLine(Unknown Source)
	... 42 more

I ruled out anything related to the code coverage itself. The generated file is okay.

Thank you for your help.

Hello @Antoine4011,

Ok, I don’t know how bitrise works exactly. There are some hints that bitrise environment could be the root cause of the problem.
There seem to be a file with .xml extension in the workspace, but it indeed seems to be a directory, not a file. The XML analyzer detects the file (from its extension) but in then unable to analyze it (that would make sense if that’s a directory).

WARN: Unable to analyse file file:///Users/vagrant/git/sonarqube-generic-coverage.xml;
INFO: Sensor XML Sensor [xml] (done) | time=93ms
INFO: Sensor SonarSwift [swift]

So I would recommend:

  • To run your build outside of bitrise to check if it is working problem (to isolated the root cause… possibly bitrise)
  • To check the file file:///Users/vagrant/git/sonarqube-generic-coverage.xml in the bitrise build to confirm if that a correct XML (coverage) file or a directory. I highly expect it’s a directory
    You stated “I ruled out anything related to the code coverage itself. The generated file is okay.”, do yo mean you checked the file file:///Users/vagrant/git/sonarqube-generic-coverage.xml already and it was a legit XML file ?
    If yes, can you, as part of your build add a step that just cat file:///Users/vagrant/git/sonarqube-generic-coverage.xml just to see how the file looks like at the time you run the scanner.
1 Like

Hello @OlivierK, I was able to find the solution.

First, I reproduce the issue locally. So not related to Bitrise.
Like I said, even when disabling code coverage the scanner would still fail, so not related to
sonarqube-generic-coverage.xml

Since the error message was related to a folder, I started deleting folders on the project to see which one was causing an issue. And when deleting our test folder, well no more issue.
I endup renaming CoreDataKitTests to CoreDataKit Tests for sonar-scanner to work. I honestly have no idea why this could affect the outcome, yet it does.

1 Like

Hello @Antoine4011,

Great.
Looking art your logs I would like to mention a few anomalies that you may want to “improve” … or not:

  • The scanner seems to be re-downloaded from our public artifacts repository for each scan. This is highly inefficient network wise, and putting stress on our repository… not to mention that your build would fail if our web site is down for maintenance or whatever.
  • The step downloading the scanner downloads scanner 3.3, our latest version is 4.3 (available from same repository
  • The scanner is run with Java 8, this is still OK but deprecated, we’ll soon require Java 11. If you can anticipate the drop of Java 8 support, your build is more future proof
  • Finally it seems it’s a scanner step to be used for any kind of build (For instance it sets sonar.java.binaries property). This is not ideal. When building Java projects, you typically use Maven or Gradle, and you should use the scanner for Maven or Gradle. You scan will be much easier to configure (there’s almost no config) and scan results will be more accurate. See https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-maven/, https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-gradle/ (and there is also a Scanner for MSBuild/dotnet)
1 Like

Hello @OlivierK,

I had the same error with version 4.3, so I still don’t understand why it was happening, but let’s move on. :slight_smile:

I sent your recommendations to the Bitrise team. I would love to see more collaboration between Sonar and Bitrise, their repos is here btw: https://github.com/DroidsOnRoids/bitrise-step-sonarqube-scanner

Thanks,

Antoine.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.