Streamlining Coverage Reports in SonarCloud with an NX Monorepo
Tags: webdev, javascript, devops, programming
Published: 2024-04-16 16:04:20

After setting up your nx-workspace project, including your apps and libraries, you also want to use the power of nx-affected commands and the nx cloud. Perhaps you, like me, want also to define multiple code quality gates, including coverage reports for new and existing code in your repository. To handle that goal, I’m using SonarCube or SonarCloud for all of my professional projects.

![Sonar Scan Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmlpak6rv43o7pvw8ygu.png)

[SonarCloud](https://www.sonarsource.com/products/sonarcloud/) makes it possible to auto-scan your repositories without setting up a CI pipeline. All you have to do is create a free SonarCloud account, connect your GitHub project, and commit and push the sonar config file. But with this approach, it is impossible to generate a coverage report for your repository. To handle this issue, Sonar provides a [GitHub action](https://github.com/SonarSource/sonarcloud-github-action) to upload your generated coverage report as part of your defined quality gates.

![nx project screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j58z93dm7h1nhgypzbjo.png)

# Necessary Steps to Enhance Code Quality Reporting

To solve this problem, the following steps are necessary:

1. run the test command on all nx-projects without using affected
2. add a custom script to merge coverage reports into one file
3. create a sonar-project.properties file and define the coverage report path
4. upload the coverage report to SonarCloud using the official Sonar GitHub action.

## Step 1: Running Tests Across All Projects

The first step is kind of simple. nx provides the run-many command to run a specified target on all nx-projects. In the past, I also had the best experience with Sonar using lcov reports.

```bash
npx nx run-many --all --target=test --parallel=3 --ci --code-coverage --coverageReporters=lcov
```

## Step 2: Merging Coverage Reports

The second step is also not that complicated. I wrote a simple JavaScript function to loop through the coverage folder and merge the project lcov files into one single file. The script is placed inside the tools/scripts folder.

```js
const glob = require('glob');
const fs = require('fs');
const path = require('path');

const getLcovFiles = function (src) {
  return new Promise((resolve) => {
    glob(`${src}/**/lcov.info`, (error, result) => {
      if (error) resolve([]);
      resolve(result);
    });
  });
};

(async function () {
  const files = await getLcovFiles('coverage');
  const mergedReport = files.reduce((mergedReport, currFile) => (mergedReport += fs.readFileSync(currFile)), '');
  await fs.writeFile(path.resolve('./coverage/lcov.info'), mergedReport, (err) => {
    if (err) throw err;
    console.log('The file has been saved!');
  });
})();
```

## Step 3 & 4: Configuring and Uploading the Coverage Report

I added the merge command to my nx-cloud GitHubAction file. This will add the executed command to the nx-cloud report posted by nx in all pull requests.


![report example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6a2uq7vv6ho50lfzzza.png)

I also added the coverage report as an artifact to use it later with the Sonar GitHub action. You can take a look at my configuration here.

{% gist https://gist.github.com/danielsogl/6986371d185dc145a078cdb195d8230d.js %}

Based on your Sonar configuration, your config file will differ from mine. The demo project’s related config file looks like this.

```md
sonar.projectKey=danielsogl_nx-sonar-example
sonar.organization=danielsogl
sonar.host.url=https://sonarcloud.io

# This is the name and version displayed in the SonarCloud UI.
#sonar.projectName=nx-sonar-example
#sonar.projectVersion=1.0

# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
#sonar.sources=.

# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8

sonar.test.inclusions=**/*.spec.ts
sonar.typescript.lcov.reportPaths=coverage/lcov.info
```

After all CI steps are executed, the Sonar action will download the previously created coverage report artifact and upload it.

When I now create a [new pull request](https://github.com/danielsogl/nx-sonar-example/pull/2), Sonar will not only check my code quality gates. Sonar now also checks my new checked-in code and its coverage.


![scan result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjgpwbj9rd4ey5f0au36.png)

I created a public demo repository where you can take a closer look at my solution: [https://github.com/danielsogl/nx-sonar-example](https://github.com/danielsogl/nx-sonar-example)