SonarQube Tutorial – Part II: How to Use SonarScanner?

In the previous tutorial we set up our environment and ran our first analysis, but what is this tutorial about? While SonarQube is a server that keeps our process analysis and project data, it also requires something that will provide its necessary data. That’s why we need SonarScanner and in this article you will get to know what it is and how to use it!

Keep in mind this article is part of our series on SonarQube!

  1. SonarQube tutorial – how to get started?
  2. SonarScanner tutorial (you’re here!)
  3. SonarScanner for MSBuild tutorial (coming soon)
  4. Rules, quality profiles and quality gates (coming soon)
  5. Gitlab integration tutorial (coming soon)

 

What is SonarScanner and why do we need it?

SonarScanner is a separate client type application that in connection with the SonarQube server will run project analysis and then send the results to the SonarQube server to process it. SonarScanner can handle most programming languages supported by SonarQube except C# and VB. It is usually located on continuous integration agents (workers) or in separate docker images depending on your project flow.

 

Requirements

During this tutorial, I assume that you have finished the SonarQube introduction and you have your SonarQube server, sonar scanner and example projects set and ready to play with. If not please check the tutorial for “SonarScanner tutorial” for instructions.

 

Add project name

Let’s begin our tutorial by editing our dockerfile by adding a project name property.

FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN ls -list

# sonar.projectName property used for providing human-friendly project name in addition 
# for projectKey
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME"

 

Run docker build --network=host --no-cache. to execute code analysis. You will be running this command multiple times during the next examples. Remember to execute them in the project root directory!

Enter http://localhost:9000/dashboard?id=SONAR_PROJECT_KEY

It looks better, doesn’t it?

 

Add duplication exclusion

Let’s assume that our current duplication metric is false and we need to add some exclusion for duplications. Let’s exclude the passport.js file using official analysis parameters documentation and using this document (example patterns are at the bottom).

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN ls -list

# sonar.cpd is group of settings for duplication area
# sonar.cpd.exclusions adding exclusions setting to area name is common pattern
# in Sonarqube.
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js"

 

Add exclusion from analysis

For this example, let’s assume that we don’t want to analyse any login files in the src/routes/login data and routes folder.

http://localhost:9000/code?id=SONAR_PROJECT_KEY&selected=SONAR_PROJECT_KEY%3Asrc%2Froutes%2Flogin

Using official analysis parameters documentation and using this document (example patterns are at the bottom) try to achieve it.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN ls -list

# sonar.exclusions it is global exclusion from the whole analysis.
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*"

 

Add code coverage to analysis

We are still missing some pieces in our analysis to be as efficient as possible – code coverage is the key missing part. Firstly modify our dockerfile to look like this:

FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

# In order to run tests we need to install dependencies
RUN npm install
# To have nicely generated code coverage report lets run test with the following parameters.
RUN npm run test -- --ci --coverage

RUN ls -list

RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    ...

 

Then using official SonarJS documentation try to achieve it.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# In Sonarqube support multiple formats of test coverage.
# For this case we will use javascript since its default 
# format generated by the testing framework in the example project. 
# sonar.javascript.lcov.reportPaths path to lcov.info file with code coverage
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info"

 

Add code coverage file exclusions from the analysis

It looks better now, but it makes no sense for us to count coverage for everything. Let’s assume that we don’t want to calculate coverage for data and routes folders and files containing the word Utils.

Using the official SonarJS documentation try to achieve it.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# sonar.coverage.exclusions is another example of how exclusions work.
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" \
    -Dsonar.coverage.exclusions="src/data/**,src/routes/**,**/*Utils*"

 

Add unit test results to analysis

Firstly we need to add a new package to our project. Run npm i -D jest-sonar-reporter. If you don’t have npm on your computer then add this to dockerfile as RUN npm i -D jest-sonar-reporter after COPY . . command.

Then we need to add some configuration to jest.config.js:

testResultsProcessor: "jest-sonar-reporter",

 

Using the above tips, official analysis parameters documentation and official “narrowing the focus” documentation try to achieve it.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# Adding tests to an analysis isn't as straightforward as another thins in previous examples.
# In addition to providing Sonarqube with a path to generated report we need also to specify
# test directory which in our example is the same as sources, so we need to add also
# distinction between source files and test files by adding "inclusions" to test area
# sonar.testExecutionReportPaths - path to test execution report
# sonar.tests - test directory
# sonar.test.inclusions - pattern to recognize files as tests files.
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" \
    -Dsonar.coverage.exclusions="src/data/**,src/routes/**,**/*Utils*" \
    -Dsonar.testExecutionReportPaths="test-report.xml" \
    -Dsonar.tests="src" \
    -Dsonar.test.inclusions="**test.js"

 

Add an advanced rule ignoring for patterns

Some rules are very useful and give us a lot of value, but they don’t make sense everywhere and we want to either exclude some files from it or restrict the rule only to some files.

Things like this can be done using either sonar.issue.ignore.multicriteria for ignoring the rule for certain patterns or with sonar.issue.enforce.multicriteria when we enforce usage of rules only to a certain pattern. The above properties aren’t well documented in the official documentation and the best example with a description that I could find was this bug about outdated documentation.

Let’s assume that in our project rule Default export names and file names should match and shouldn’t be applied for server.js file. What is more rule Properties of variables with "null" or "undefined" values should not be accessed as well and shouldn’t be applied to any files ending with port.js.

Try to achieve it using the above example.

Rule names can be retrieved by entering http://localhost:9000/project/issues?id=SONAR_PROJECT_KEY&resolved=false and pressing on the issues like on screens below.

Sonar - project name

sonar project name 2

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# sonar.issue.ignore.multicriteria - defines multicriteria names, comma separated like X1,js1 for which rule will be ignored
# sonar.issue.ignore.multicriteria.X1.ruleKey - used to choose on which rule this multicriteria will work like javascript:S3317
# sonar.issue.ignore.multicriteria.X1.resourceKey - pattern for which multicriteria will be applied
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" \
    -Dsonar.coverage.exclusions="src/data/**,src/routes/**,**/*Utils*" \
    -Dsonar.testExecutionReportPaths="test-report.xml" \
    -Dsonar.tests="src" \
    -Dsonar.test.inclusions="**test.js" \
    -Dsonar.issue.ignore.multicriteria="js1,js2" \
    -Dsonar.issue.ignore.multicriteria.js1.ruleKey="javascript:S3317" \
    -Dsonar.issue.ignore.multicriteria.js1.resourceKey="src/server.js" \
    -Dsonar.issue.ignore.multicriteria.js2.ruleKey="javascript:S2259" \
    -Dsonar.issue.ignore.multicriteria.js2.resourceKey="**/*port.js"

 

Finishing touches

Add links to a project

To improve our workflow and to make navigation more comfortable it is useful to add quick links to the project’s website and continuous integration executions.

Using official analysis parameters documentation try to achieve it.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# Sonarqube can also show links to another application that are connected
# with the development process. In this example, we are filling 2 links
# sonar.links.ci - link for continuous integration server
# sonar.links.homepage - link for project homepage - usually project repository URL
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" \
    -Dsonar.coverage.exclusions="src/data/**,src/routes/**,**/*Utils*" \
    -Dsonar.testExecutionReportPaths="test-report.xml" \
    -Dsonar.tests="src" \
    -Dsonar.test.inclusions="**test.js" \
    -Dsonar.issue.ignore.multicriteria="js1,js2" \
    -Dsonar.issue.ignore.multicriteria.js1.ruleKey="javascript:S3317" \
    -Dsonar.issue.ignore.multicriteria.js1.resourceKey="src/server.js" \
    -Dsonar.issue.ignore.multicriteria.js2.ruleKey="javascript:S2259" \
    -Dsonar.issue.ignore.multicriteria.js2.resourceKey="**/*port.js" \
    -Dsonar.links.ci="CI_LINK_URL" \
    -Dsonar.links.homepage="PROJECT_URL"

 

Make the project private

The last, but not least thing to do is to make the project private.

Firstly let’s allow the sonar-administrators group to execute analysis and revoke permissions from group Anyone in http://localhost:9000/admin/permissions.

permissions

Secondly, we need to change the project type to Private and allow sonar-administrators group to execute analysis since the project was created with old permission matrix in http://localhost:9000/project_roles?id=SONAR_PROJECT_KEY.

Lastly we should force authentication in the whole of SonarQube – we can achieve it by entering and following the link http://localhost:9000/admin/settings?category=security and switching Force user authentication setting to On like on the screen below.

admin

Currently you can only reach our server when you log in. Anonymous analysis will also not work anymore. Try to make it work again using official analysis parameters documentation.

Show example solution (click here to open)
FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

# sonar.login - a place for a token that will be used to authorise analysis in Sonarqube server
RUN sonar-scanner \
    -Dsonar.host.url="http://localhost:9000" \
    -Dsonar.projectKey="SONAR_PROJECT_KEY" \
    -Dsonar.sources="src" \
    -Dsonar.projectName="SONAR_PROJECT_NAME" \
    -Dsonar.cpd.exclusions="**passport.js" \
    -Dsonar.exclusions="**/login/Login.*" \
    -Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" \
    -Dsonar.coverage.exclusions="src/data/**,src/routes/**,**/*Utils*" \
    -Dsonar.testExecutionReportPaths="test-report.xml" \
    -Dsonar.tests="src" \
    -Dsonar.test.inclusions="**test.js" \
    -Dsonar.issue.ignore.multicriteria="js1,js2" \
    -Dsonar.issue.ignore.multicriteria.js1.ruleKey="javascript:S3317" \
    -Dsonar.issue.ignore.multicriteria.js1.resourceKey="src/server.js" \
    -Dsonar.issue.ignore.multicriteria.js2.ruleKey="javascript:S2259" \
    -Dsonar.issue.ignore.multicriteria.js2.resourceKey="**/*port.js" \
    -Dsonar.links.ci="CI_LINK_URL" \
    -Dsonar.links.homepage="PROJECT_URL" \
    -Dsonar.login="SONAR_LOGIN_TOKEN"

 

Keeping SonarQube scanner configuration in a configuration file

Instead of keeping configuration as command line parameters we may also define them in the sonar-project.properties file that must be located in the project root directory. We can move all or some settings there:

sonar.host.url=http://localhost:9000
sonar.projectKey=SONAR_PROJECT_KEY 
sonar.sources=src 
sonar.projectName=SONAR_PROJECT_NAME 
sonar.cpd.exclusions=**passport.js 
sonar.exclusions=**/login/Login.* 
sonar.javascript.lcov.reportPaths=coverage/lcov.info 
sonar.coverage.exclusions=src/data/**,src/routes/**,**/*Utils* 
sonar.testExecutionReportPaths=test-report.xml 
sonar.tests=src 
sonar.test.inclusions=**test.js 
sonar.issue.ignore.multicriteria=js1,js2 
sonar.issue.ignore.multicriteria.js1.ruleKey=javascript:S3317 
sonar.issue.ignore.multicriteria.js1.resourceKey=src/server.js 
sonar.issue.ignore.multicriteria.js2.ruleKey=javascript:S2259 
sonar.issue.ignore.multicriteria.js2.resourceKey=**/*port.js
sonar.links.ci=CI_LINK_URL
sonar.links.homepage=PROJECT_URL
sonar.login=SONAR_LOGIN_TOKEN

Our new dockerfile:

FROM sonar-scanner-image:latest AS sonarqube_scan

WORKDIR /app

COPY . .

RUN npm install
RUN npm run test -- --ci --coverage

RUN ls -list

RUN sonar-scanner

 

What next?

In the next tutorial, we will take a look into SonarScanner for MSBuild and check what are the differences between it and SonarScanner and work with its unique features – SonarScanner for MSBuild tutorial.

Then we will play a little with customization of server rules and behaviors in analysis context in Rules, quality profiles and quality gates tutorial.

We will wrap things up with a Gitlab integration tutorial, which will show us how to integrate SonarQube with pull requests.

 

Cleaning up after tutorial

To stop a container running SonarQube server instance run the following command: (don’t do this if you want to continue with the next tutorials!)

docker container stop sonarqube

To remove also all docker containers run

docker container prune --force

Finally to remove all images used in this tutorial run

docker image remove sonarqube:7.5-community sonar-scanner-image

Is Code Quality important to you?
Our experts can take care of that!

Let's create
something meaningful together!

Company data
  • Setapp Sp. z o.o.
  • VAT ID: PL7781465185
  • REGON: 301183743
  • KRS: 0000334616
Address
  • ul. Wojskowa 4
  • 60-792 Poznań, Poland
Contact us
Stay connected