Recently I had to execute an static code analysis over a Maven Java project builded with the JDK 19, but I couldn’t do it because I have and old Sonarqube server (version 7.8) which don’t support that version of Java language.
In order to skip this limitation I’ve used a new version of Sonarqube executed into a container, and I want to share the steps here. Please note tha I have used Podman instead of Docker.
This is a quick entry to show how to use GitHub actions with Sonarcloud account to analyze a single maven project.
1. Install the Sonarcloud application from GiHub Marketplace, go to the market and search sonarcloud and select Configure access > Configure > Repository Access and add your repository to be analized and save it.
I’ve upgraded my Sonarqube server from the 6.4 to 7.8 version, the last than support MySQL database, according to documentation, the Nodejs > 6.0 is required to analyse Javascript code.
But I didn’t know, until my Jenkins jobs failed. The error is clear, I need to install Nodejs:
org.sonarsource.nodejs.NodeCommandException: Error when running: 'node -v'. Is Node.js available during analysis?
I’ve installed Sonarqube over Red Hat Enterprise Linux 7 (RHEL), the process to install Nodejs is very simple. If the repository is enabled only have to execute this commands in terminal and check the version.
Recently I had to upgrade my Sonarqube server from 6.4 to 7.8 and I noticed a problem in few projects when the jacoco report is loaded by Jenkins with the jacoco-maven-plugin to Sonarqube using the plugin sonar-jacoco (1.0.1.143) , the error show this message:
[INFO] Sensor JaCoCo XML Report Importer [jacoco]
[ERROR] Coverage report '/var/lib/jenkins/workspace/test/dummy/target/site/jacoco/jacoco.xml' could not be read/imported. Error: {}
java.lang.IllegalStateException: Failed to parse JaCoCo XML report: /var/lib/jenkins/workspace/test/sge-webapp/target/site/jacoco/jacoco.xml
at org.sonar.plugins.jacoco.XmlReportParser.parse(XmlReportParser.java:96)
at org.sonar.plugins.jacoco.JacocoSensor.importReport(JacocoSensor.java:73)
at org.sonar.plugins.jacoco.JacocoSensor.importReports(JacocoSensor.java:64)
at org.sonar.plugins.jacoco.JacocoSensor.execute(JacocoSensor.java:48)
at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:48)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:85)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:59)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:77)
at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:59)
at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:82)
at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:400)
at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:395)
at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:392)
at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:358)
at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:141)
at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:73)
at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:67)
at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
at com.sun.proxy.$Proxy43.execute(Unknown Source)
at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189)
at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138)
at org.sonarsource.scanner.maven.bootstrap.ScannerBootstrapper.execute(ScannerBootstrapper.java:65)
at org.sonarsource.scanner.maven.SonarQubeMojo.execute(SonarQubeMojo.java:104)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
Caused by: com.ctc.wstx.exc.WstxIOException: Input length = 1
at com.ctc.wstx.sr.StreamScanner.constructFromIOE(StreamScanner.java:633)
at com.ctc.wstx.sr.StreamScanner.loadMoreFromCurrent(StreamScanner.java:1063)
at com.ctc.wstx.sr.StreamScanner.parseFullName2(StreamScanner.java:1994)
at com.ctc.wstx.sr.StreamScanner.parseFullName(StreamScanner.java:1952)
at com.ctc.wstx.sr.BasicStreamReader.handleNonNsAttrs(BasicStreamReader.java:3117)
at com.ctc.wstx.sr.BasicStreamReader.handleStartElem(BasicStreamReader.java:2968)
at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2839)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1073)
at org.sonar.plugins.jacoco.XmlReportParser.parse(XmlReportParser.java:53)
... 55 common frames omitted
Caused by: java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.read1(BufferedReader.java:212)
at java.io.BufferedReader.read(BufferedReader.java:289)
at com.ctc.wstx.io.MergedReader.read(MergedReader.java:105)
at com.ctc.wstx.io.ReaderSource.readInto(ReaderSource.java:86)
at com.ctc.wstx.io.BranchingReaderSource.readInto(BranchingReaderSource.java:56)
at com.ctc.wstx.sr.StreamScanner.loadMoreFromCurrent(StreamScanner.java:1060)
... 62 common frames omitted
Even the job finished with success status the Sonarqube server don’t show the coverage report over the source code.
After some research I found the problem is because my jacoco.xml report has some characters in ISO-8859-1 that can’t be parsed by the sonar-jacoco plugin, this one load the xml file with charset in UTF-8 by default, you can check the source code in github.
I think the jacoco-maven-plugin is building the report in the right way because my project needs the charset encoding in ISO-8859-1 but the sonar-jacoco plugin only support UTF-8.
Then to resolve it there are two choices:
1. Change the output encoding for jacoco report
I don’t like this option but is the most rapid way, during the runtime the jacoco.xml report is built with the same charset encoding than sonar (sonar.sourceEncoding) but the output of jacoco can be modified with this property:
Then the inspection use correctly the encoding ISO-8859-1 but the output of the jacoco report is in UTF-8. The error in sonar-jacoco plugin is skipped but the impact of this change only affect the presentation in Sonarqube.
I downloaded the version release 1.0.2.475 and modified the source code to support other charset encoding, I’m not sure if is the best implementation but I’m gonna will send the pull request to the community. This is the class:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Because the jacoco use the same source encoding in maven, only if I set the parameter «sonar.sourceEncoding» the plugin will change the charset when the xml is loaded.
Even the plugin is not supported in my Sonarqube server, is working with my projects now.
A quick tip, if you have to inspect a web project using sonar scanner, be careful when configure the language parameter in your sonar-project.properties because there are two options:
sonar.language for single language sonar.languages for multiple languages
for example If your project has a web content folder and java source, you have to use the parameter for multiple languages and set both sources folders:
Well, recently I was need to review legacy project to do meassuring the code quality java.
There are a project with multi module structure based on old eclipse syle mixed with maven structure, I have 3 modules (2 in eclipse and 1 in maven) all of them are used to build the final artifact and I needed to do code inspection with sonarqube.
Fortunly sonar can manage this, let’s gets started.
Requirements
A sonarqube instance (version 6.6)
Sonar scanner tool (version 3.0.3)
Compiled classes for projects to analize
Steps
Login into sonar instance and select your profile (at the top rigth corner) then click on My profile
Create a new token on tab Security, write a name for the token and click on Generate and copy the token string, becareful but you won’t be able to see this string again.
Conigure your sonar scanner, open the instalation folder (where you uncompress it) and edit the file conf/sonar-scanner.properties, add the host and login token string:
#Configure here general information about the environment, such as SonarQube DB details for example
#No information about specific project should appear here
#----- Default SonarQube server
sonar.host.url=http://localhost:9000
#----- Default source code encoding
sonar.sourceEncoding=UTF-8
#----- Security (when 'sonar.forceAuthentication' is set to 'true')
sonar.login=57e0bf00a0af633f5c0534fc72535c16f2f0fc3b
Create a project configuration file into your source code folder, go to project folder and create a file named sonar-project.properties, set the properties to binaries (compiled classes) and the source code per module, previously you need it compile the project with their modules. I use eclipse to build each of them. The content of file is something like these:
#Required project data fron sonar
sonar.projectKey=com.abc:my-project
sonar.projectName=abc-my-project
sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8
#sonar.modules=PalacioHierro
sonar.modules=module1,module2,mvnmodule
sonar.java.source=1.7
#Lib Dir (Opcional) ej: path/library.jar,path/to/classes/dir
sonar.libraries=module2/lib
# Project Language ( by default is Java)
sonar.language=java
# Properties can obviously be overriden for
# each module - just prefix them with the module ID
module1.sonar.projectName=my-project-m1
module1.sonar.java.source=1.7
module1.sonar.sources=src,WebContent
module1.sonar.java.binaries=build/classes
module2.sonar.projectName=my-projct-m2
module2.sonar.java.source=1.7
module2.sonar.sources=src
module2.sonar.java.binaries=build/classes
mvnmodule.sonar.projectName=mvn-webapp
mvnmodule.sonar.java.source=1.7
mvnmodule.sonar.sources=src/main/java,src/main/resources,src/main/webapp
mvnmodule.sonar.java.binaries=target/classes
sonar.skipDesign=true
sonar.skipPackageDesign=true
sonar.profile=my-profile
Start the inspection, open an terminal and go to your root project folder and execute sonnar-scanner, this will start the code inspection (maybe take a long time, depend of size of their projects) at the end you must see in the log something like this «ANALYSIS SUCCESSFUL, you can browse http://loaclhost:9000/dashboard/index/com.abc«
In the dashboard, on the code cactegory, you can see the result for the three modules.
El análisis de código es fundamental para control de calidad en los desarrollos y para ello un producto muy bueno es el Sonar Qube .
Lo he utilizado para proyectos Java con maven, pero veo hay una herramienta llamada sonar runner que te permite hacer el análisis sin necesidad de maven. Puedes utilizar esta herramienta para ejecutar la inspección de código de todos los lenguajes que soporte sonar.
Instalación
Descargar Sonar Qube y Sonar Qube Runner, descomprimes ambos en una carpeta: Agregas la variable de entorno SONARQUBE_RUNNER_HOME y como valor escribes la ruta donde tienes la carpeta del Sonar Runner. Configurar Sonar Runner, editas el archivo SONARQUBE_RUNNER_HOME/conf/sonar-runner.properties agregas las siguientes líneas:
#Configure here general information about the environment, such as SonarQube DB details for example
#No information about specific project should appear here
#----- Default SonarQube serversonar.host.url=http://localhost:9000#----- Apache H2sonar.jdbc.url=jdbc:h2:tcp://localhost:9092/sonar#----- Global database settingssonar.jdbc.username=sonarsonar.jdbc.password=sonar#----- Default source code encodingsonar.sourceEncoding=UTF-8
Nota: Debes colocar los mismos datos que tienes en tu archivo SONAR_SERVER_HOME/conf/sonar.properties, si utilzas otra base como Oracle o MySQL deben conicidir los datos de conexión. Seguir leyendo →