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!
- SonarQube tutorial – how to get started?
- SonarScanner tutorial (you’re here!)
- SonarScanner for MSBuild tutorial
- Rules, quality profiles and quality gates
- Gitlab integration tutorial
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.
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.
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.
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.
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