Unable to calculate coverage for Pull Request in Apex

Hey team
I am creating a follow-up to this topic, since noone replied then and I have exactly same case: https://community.sonarsource.com/t/getting-error-importing-coverage-file-from-sfdx-forcedeploy-into-sonarcloud/75855/2

Depending on which Salesforce CLI command we use, either sf apex get tests, or sf project deploy start we will recieve as an outcome a diffrently formatted JSON with coverage report.
First command is used for static code analysis and is working fine, second has to be used in order to run validation of Pull Request changes versus Salesforce instance, but second JSON is not accepted by SonarQube, so we are not able to include Code Coverage in our Quality Gate.
Has anyone figured out how to convert one JSON to another format, or is there a chance for improvement on SonarQube to accept this JSON format as well?
On Salesforce end unfortunately this is working as expected, so no chance for changing it

KR
Bartek

1 Like

Hey @Lysander

Can you share an example of what this JSON looks like? For example, the format SonarQube is expecting looks like this:

[
    {
        "id": "01p3E000001QAacQAG",
        "name": "ClassB",
        "totalLines": 8,
        "lines": {
            "2": 5,
            "3": 1,
            "4": 1,
            "5": 1,
            "6": 1,
            "7": 1,
            "11": 1,
            "12": 1
        },
        "totalCovered": 8,
        "coveredPercent": 100
    },
    {
        "id": "01p3E000001QAadQAG",
        "name": "ClassC",
        "totalLines": 12,
        "lines": {
            "2": 1,
            "3": 1,
            "4": 1,
            "5": 1,
            "6": 1,
            "7": 1,
            "11": 1,
            "12": 1,
            "15": 1,
            "16": 1,
            "17": 0,
            "19": 1
        },
        "totalCovered": 11,
        "coveredPercent": 92
    }
]

Hey @Colin

Thank you for checking on my topic.
The JSON you shared is a result of Salesforce CLI command sf apex run test
However, for Pull Request, to validate code against target enviroment we have to use another command: sf project deploy start
And for that one, JSON with code coverage report looks completly diffrent, like the one I am pasting below.

{"no-map\\hln_ATLBatch": {"fnMap":{},"branchMap":{},"path":"no-map\\hln_ATLBatch","f":{},"b":{},"s":{"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":1,"27":1,"28":1,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":1,"41":1,"42":1,"43":1,"44":1,"45":1,"46":1,"47":1,"48":1,"49":1},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":0}},"2":{"start":{"line":2,"column":0},"end":{"line":2,"column":0}},"3":{"start":{"line":3,"column":0},"end":{"line":3,"column":0}},"4":{"start":{"line":4,"column":0},"end":{"line":4,"column":0}},"5":{"start":{"line":5,"column":0},"end":{"line":5,"column":0}},"6":{"start":{"line":6,"column":0},"end":{"line":6,"column":0}},"7":{"start":{"line":7,"column":0},"end":{"line":7,"column":0}},"8":{"start":{"line":8,"column":0},"end":{"line":8,"column":0}},"9":{"start":{"line":9,"column":0},"end":{"line":9,"column":0}},"10":{"start":{"line":10,"column":0},"end":{"line":10,"column":0}},"11":{"start":{"line":11,"column":0},"end":{"line":11,"column":0}},"12":{"start":{"line":12,"column":0},"end":{"line":12,"column":0}},"13":{"start":{"line":13,"column":0},"end":{"line":13,"column":0}},"14":{"start":{"line":14,"column":0},"end":{"line":14,"column":0}},"15":{"start":{"line":15,"column":0},"end":{"line":15,"column":0}},"16":{"start":{"line":16,"column":0},"end":{"line":16,"column":0}},"17":{"start":{"line":17,"column":0},"end":{"line":17,"column":0}},"18":{"start":{"line":18,"column":0},"end":{"line":18,"column":0}},"19":{"start":{"line":19,"column":0},"end":{"line":19,"column":0}},"20":{"start":{"line":20,"column":0},"end":{"line":20,"column":0}},"21":{"start":{"line":21,"column":0},"end":{"line":21,"column":0}},"22":{"start":{"line":22,"column":0},"end":{"line":22,"column":0}},"23":{"start":{"line":23,"column":0},"end":{"line":23,"column":0}},"24":{"start":{"line":24,"column":0},"end":{"line":24,"column":0}},"25":{"start":{"line":25,"column":0},"end":{"line":25,"column":0}},"26":{"start":{"line":26,"column":0},"end":{"line":26,"column":0}},"27":{"start":{"line":27,"column":0},"end":{"line":27,"column":0}},"28":{"start":{"line":28,"column":0},"end":{"line":28,"column":0}},"29":{"start":{"line":29,"column":0},"end":{"line":29,"column":0}},"30":{"start":{"line":30,"column":0},"end":{"line":30,"column":0}},"31":{"start":{"line":31,"column":0},"end":{"line":31,"column":0}},"32":{"start":{"line":32,"column":0},"end":{"line":32,"column":0}},"33":{"start":{"line":33,"column":0},"end":{"line":33,"column":0}},"34":{"start":{"line":34,"column":0},"end":{"line":34,"column":0}},"35":{"start":{"line":35,"column":0},"end":{"line":35,"column":0}},"36":{"start":{"line":36,"column":0},"end":{"line":36,"column":0}},"37":{"start":{"line":37,"column":0},"end":{"line":37,"column":0}},"38":{"start":{"line":38,"column":0},"end":{"line":38,"column":0}},"39":{"start":{"line":39,"column":0},"end":{"line":39,"column":0}},"40":{"start":{"line":40,"column":0},"end":{"line":40,"column":0}},"41":{"start":{"line":41,"column":0},"end":{"line":41,"column":0}},"42":{"start":{"line":42,"column":0},"end":{"line":42,"column":0}},"43":{"start":{"line":43,"column":0},"end":{"line":43,"column":0}},"44":{"start":{"line":44,"column":0},"end":{"line":44,"column":0}},"45":{"start":{"line":45,"column":0},"end":{"line":45,"column":0}},"46":{"start":{"line":46,"column":0},"end":{"line":46,"column":0}},"47":{"start":{"line":47,"column":0},"end":{"line":47,"column":0}},"48":{"start":{"line":48,"column":0},"end":{"line":48,"column":0}},"49":{"start":{"line":49,"column":0},"end":{"line":49,"column":0}}}}
,"no-map\\hln_DCRArchivingHelper": {"fnMap":{},"branchMap":{},"path":"no-map\\hln_DCRArchivingHelper","f":{},"b":{},"s":{"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1},"statementMap":{"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":0}},"2":{"start":{"line":2,"column":0},"end":{"line":2,"column":0}},"3":{"start":{"line":3,"column":0},"end":{"line":3,"column":0}},"4":{"start":{"line":4,"column":0},"end":{"line":4,"column":0}},"5":{"start":{"line":5,"column":0},"end":{"line":5,"column":0}},"6":{"start":{"line":6,"column":0},"end":{"line":6,"column":0}},"7":{"start":{"line":7,"column":0},"end":{"line":7,"column":0}},"8":{"start":{"line":8,"column":0},"end":{"line":8,"column":0}}}}
}

1 Like

This is a very interesting topic!

I would also like to know if SonarQube has a roadmap to support Apex code coverage results aligned with Salesforce SFDX CLI standards output, particularly when using the –coverage-formatters option flag. Specifically, I am referring to the sf project command (ref):

sf project deploy start

or

sf project deploy validate

Just to share with the community: on today’s date, to get code coverage on SonarQube from the sf project command output, I am using the SFDX plugin apex-code-coverage-transformer and specifying sonar.coverageReportPaths to upload the generic test data.

If anyone has a different workaround idea to this SonarQube limitation/gap or a better approach, I’m open to suggestions!

3 Likes

Hey Alvaro
Thank you for sharing this extension, I was not aware of it.
I will try it out soon