Getting error importing coverage file from sfdx force:source:deploy into SonarCloud

I have a Salesforce pipeline developed in Github Actions. I run the following steps in the pipeline to generate the report:

      - name: Check changes between branches into Salesforce Org
        run: |
          sfdx force:source:deploy -x ./deployFolder/package/package.xml --verbose --wait 60 --resultsdir ./tests/apex/ --coverageformatters json  --checkonly --testlevel RunSpecifiedTests --runtests AccountsTest,ApplicantAddressesTest

      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

The output in the tests folder is as follows:

./tests
└── apex
    └── coverage
        └── coverage.json

The contents of the coverage.json file look like the following (only the start of the file shown):

{"no-map/Accounts": {"fnMap":{},"branchMap":{},"path":"no-map/Accounts","f":{},"b":{},"s":{"111":0,"112":1,"113":1,"114":1,"115":1,"116":1,"117":1,"118":1,"119":1,"120":0,"121":0,"122":0,"123":1,"124":1,"125":1,"126":0,"127":1,"128":1,"129":1,"130":1,"131":1,"132":0,"13

The error I am seeing in the output is the following:

INFO: Sensor Apex Sensor [sonarapex]
INFO: Sensor Apex Sensor is restricted to changed files only
INFO: 31 source files to be analyzed
INFO: 31/31 source files have been analyzed
INFO: Sensor Apex Sensor [sonarapex] (done) | time=741ms
INFO: Sensor Test coverage Sensor for Apex [sonarapex]
**ERROR: Cannot read coverage report file, expecting standard SFDX test coverage result in JSON format: './tests/apex/coverage/coverage.json'**
java.lang.ClassCastException: class org.sonarsource.analyzer.commons.internal.json.simple.JSONObject cannot be cast to class org.sonarsource.analyzer.commons.internal.json.simple.JSONArray (org.sonarsource.analyzer.commons.internal.json.simple.JSONObject and org.sonarsource.analyzer.commons.internal.json.simple.JSONArray are in unnamed module of loader org.sonar.classloader.ClassRealm @6dd93a21)
	at com.A.A.D.E.execute(Unknown Source)
	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:62)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:75)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:48)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:66)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:48)
	at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:64)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:468)
	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:464)
	at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:420)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:130)
	at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:123)
	at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:109)
	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(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	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)

INFO: Sensor Test coverage Sensor for Apex [sonarapex] (done) | time=10ms

In the website for SonarCloud I have the following set:

sonar.apex.coverage.reportPath=./tests/apex/coverage/coverage.json

Can you please help me to get the correct file settings for Apex code working?

Thanks
Peter

Hey there.

SonarCloud is expecting a report like this:

[
    {
      "id": "01q3E0000007bgVQAQ",
      "name": "AccountDeletion",
      "totalLines": 4,
      "lines": {
        "4": 1,
        "6": 1,
        "7": 1,
        "8": 1
      },
      "totalCovered": 4,
      "coveredPercent": 100
    },
    {
        "id": "01p3E000001QAadQAG",
        "name": "ClassB",
        "totalLines": 12,
        "lines": {
            "1": 1,
            "2": 1,
            "3": 3,
            "4": 1,
            "5": 0,
            "6": 0,
            "10": 5,
            "11": 1,
            "14": 1,
            "15": 1,
            "16": 0,
            "18": 1
        },
        "totalCovered": 9,
        "coveredPercent": 75
    }
]

So I’m not sure… what your coverage report is made up of. As the docs mention:

sonar.apex.coverage.reportPath

Path to the test-result-codecoverage.json report file generated by the apex:test:run command of the Salesforce CLI. Note, you must have a Salesforce DX project set up and linked to your organization.

You might try this guide here (which uses sdfx force:apex:test:run rather than sfdx force:source:deploy.

Thanks for the reply.
I was aware of the output from force:apex:test:run. However, in June the sfdx team added the ability to export reports from the force:source:deploy command. I was hoping to avoid another time-consuming command and just use the output from that into SonarCloud. However, it seems that not of the files output from force:source:deploy match the format you require.

Perhaps it is an issue to raise with that team.