DEV Community

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

Posted on

1

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/

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay