back to index

Wiring a JS/TS Project into Sonarqube

Sonarqube's Java docs are deep. JS/TS, less so — here's a working setup.

published Mar 07, 2019 tags #javascript #tooling #qa

~/posts/sonarqube-javascript $ cat post.md

/ LANG EN / 中文
/ THEME / /

Why

Sonarqube’s documentation skews heavily Java. If your team is Java-first, you’ll eventually feel it — the day they ask you to put a JS project on Sonarqube to track Code Smell, the docs and the blog posts you can find aren’t going to be quite enough. This post assumes you already know what Sonarqube is and what it’s for, and walks through the bits you’ll need on top of the basic guides.

Background

  • For languages other than Java, Sonarqube doesn’t run tests for you. You run them locally and upload the coverage file alongside the source.
  • The base Docker image, while primarily Java-focused, still bundles configs for several languages. The non-Java support is thinner than Java’s, but it’s something.
  • Sonarqube only accepts one coverage format — lcov.info. Not the most common one. More on generating it below.
  • Uploading the build doesn’t need a password, locally or in CI. All you need is the Sonarqube URL. That’s also a fine reason to keep it on the internal network.

Walkthrough

Once the server’s up, configure the project. The JS setup is slightly fiddly — using a small wrapper package saves time. Honestly, the “third-party” packages I found mostly just wrap sonar-scanner, same as what you’d write yourself. The Java console app pulls things like the version, declared dependencies, and test results out of maven; on the JS side those need to be wired up explicitly. Doing it by hand means maintaining the version in two places, which is silly.

You might think: “I’ll just read the version out of package.json.” That’s the same work the wrapper does, so save yourself the reimplementation.

yarn add --dev sonarqube-scanner

Usage:

import * as Sonar from "sonarqube-scanner";

Sonar({
    options: {
        // ...
    },
    serverUrl: "https://sonarqube.dev.something.com/",
}, () => done());

What goes into options:

package.json already has things like title, description, and version, but a few fields need overriding because they don’t match Java conventions. The project name in particular: JS packages, under npm’s influence, often go with @org/project, whose special characters Sonarqube won’t take. Use org-project:

options: {
    ...other,
    "sonar.projectKey": "org-project",
}

Sources and coverage next. Sonarqube doesn’t tell tests apart from source files and doesn’t run tests for you. You’re uploading the src tree plus coverage/lcov.info. The lcov file is easy to produce — whether you’re on nyc, jest, or istanbul, the lcov reporter exists, no extra deps needed.

options: {
    ...other,
    "sonar.inclusions": "src/**,coverage/lcov.info",
    "sonar.javascript.lcov.reportPaths": "coverage/lcov.info",
    "sonar.typescript.lcov.reportPaths": "coverage/lcov.info",
}

In theory inclusions is sufficient, but declaring exclusions alongside it makes the config easier to read (the same reason tsconfig.json keeps both):

options: {
    ...other,
    "sonar.exclusions": "node_modules/**,dist/**,.cache/**,infrastructure/**",
}

That’s enough to run it.

back to index