DEV Community

Cover image for Setup Code Coverage for Monorepo - SonarQube
Vikas Yadav
Vikas Yadav

Posted on

Setup Code Coverage for Monorepo - SonarQube

In a Monorepo setup, generating a coverage report for each library or app separately is common.

However, tools like the Sonar scanner may encounter difficulties in combining these reports into a single comprehensive one.

This issue arises when running tests with tools like nx affected, where only affected projects generate coverage reports, leaving unaffected projects out.

Consequently, SonarQube may raise quality gate errors due to missing coverage data.

Project Structure

Propose Solution Implemented

To resolve this problem, a custom script can be added to merge coverage reports into one file.

Below is a simple JavaScript function named coveragemerger.js for this purpose:

const glob = require('glob');
const fs = require('fs').promises;
const path = require('path');
const util = require('util');

const REPORTS_DIR_NAME = 'coverage';
const GREEN = '\x1b[32m%s\x1b[0m';
const BLUE = '\x1b[34m%s\x1b[0m';
const REPORTS_DIR_PATH = path.resolve(process.cwd(), REPORTS_DIR_NAME);

const globPromise = util.promisify(glob);

/**
 * Fetches all lcov.info files from coverage directories, excluding node_modules.
 * @returns {Promise<string[]>} A promise that resolves with an array of file paths.
 */
const getLcovFiles = function () {
  return globPromise(`**/coverage/lcov.info`, { ignore: '**/node_modules/**' });
};

/**
 * Creates a temp directory for all the reports.
 * @returns {Promise<void>} A promise that resolves when the directory has been created.
 */
async function createTempDir() {
  console.log(BLUE, `Creating a temp ${REPORTS_DIR_NAME} directory...`);
  try {
    await fs.mkdir(REPORTS_DIR_PATH, { recursive: true });
    console.log(GREEN, 'Done!');
  } catch (err) {
    console.error('Error creating directory:', err);
  }
}

(async function () {
  try {
    // Fetch all lcov.info files
    const files = await getLcovFiles();
    console.log("files are", files);

    // Create temp directory
    await createTempDir();

    // Read all files and join their contents
    const mergedReport = await Promise.all(files.map(file => fs.readFile(file, 'utf-8'))).then(contents => contents.join(''));

    console.log(BLUE, `Copying the coverage report...`);

    // Write the merged report to a new lcov.info file
    await fs.writeFile(path.resolve(REPORTS_DIR_PATH, `lcov.info`), mergedReport);

    console.log('Code coverage has been saved!');
  } catch (err) {
    console.error('Error:', err);
  }
})();
Enter fullscreen mode Exit fullscreen mode

Azure Pipeline Integration

To integrate this into your pipeline, add the following command to your Azure Pipeline file:

- script: |
    node coverageMerger.js
  displayName: 'Merge Coverage Reports'
Enter fullscreen mode Exit fullscreen mode

SonarQube Analysis Report

SonarQube Analysis - Monorepo

Reference:
use this site to check coverage from LCOV https://lcov-viewer.netlify.app/

Top comments (0)