Run the sonarqube analysis locally over a Java project (version 19) using a container

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.

Seguir leyendo

Jenkins – Sonarqube, Nodejs dependency to analyse CSS and Javascript

sonar logo-title

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.

$ su -
$ yum install rh-nodejs8
$ scl enable rh-nodejs8 bash
$ node --version
v8.6.0

Seguir leyendo

Jenkins – Sonarqube error for bad encoding

sonar logo-title

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.

https://github.com/SonarSource/sonar-jacoco/blob/2fa1baae841598238d02a945422b60348f75b52a/src/main/java/org/sonar/plugins/jacoco/XmlReportParser.java#L45-L47

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:

-Dproject.reporting.outputEncoding=UTF-8

Taken from jacoco docs.

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.

My step in jenkins looks like this:

clean verify -P sonar
-Dsonar.sourceEncoding=ISO-8859-1
-Dproject.reporting.outputEncoding=UTF-8

2020-04-04 15_51_26-test Config [Jenkins] - Brave

2. Improve the sonar-jacoco plugin

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:


public class XmlReportParser {
private final Path xmlReportPath;
public XmlReportParser(Path xmlReportPath) {
this.xmlReportPath = xmlReportPath;
}
public List<SourceFile> parse() {
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
try {
XMLStreamReader parser = factory.createXMLStreamReader(Files.newBufferedReader(xmlReportPath, getCharsetForEncoding()));
// …
}
private Charset getCharsetForEncoding(){
if(System.getProperty("sonar.sourceEncoding")==null){
return StandardCharsets.UTF_8;
}
else{
return Charset.forName(System.getProperty("sonar.sourceEncoding"));
}
}
}

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.

2020-04-04 15_33_22-Marketplace - Administration - Brave

See you my friends!

 

 

Sonarqube integration with Jenkins

sonar logo-title

In the official docs there are listed the steps to install and configure the Sonarqube server with Jenkins:

  1. Install the SonarScanner for Jenkins via the Jenkins Update Center.
  2. Configure your SonarQube server(s):
    1. Log into Jenkins as an administrator and go to Manage Jenkins > Configure System.
    2. Scroll down to the SonarQube configuration section, click Add SonarQube, and add the values you’re prompted for.
    3. The server authentication token should be created as a ‘Secret Text’ credential.

But to complete this I’ve been do some extra steps to it works, after the plugin installation may you need be prepared with this. Seguir leyendo

Sonarqube – enable web inspection with sonnar scanner

sonar

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:

sonar.languages=java,css
sonar.sources=src,WebContent

Then in the project overview the Quality Profiles will be listed:

2020-03-04 20_01_15-conafys - Brave

!Saludos!

Sonarqube – Enable JSP code inspection

sonar

To enable the code inspection over jsp pages you must to add the suffix in  the property sonar.web.file.suffixes, there are two ways to do that:

In the project configuration

Go to project Administration > General Settings > tab Web, edit the field File suffixes and save changes.

2020-02-04 18_52_14-General Settings - eph-sge - Brave

As parameter

Add the parameter with the suffixes separated by comma:

-Dsonar.web.file.suffixes=".html,.xhtml,.rhtml,.shtml,.jsp"

I prefer  use the parameter because my executions are controlled by Jenkins pipeline configuration.

Cheers!

Sonar Scanner inspect multi module java project (Mixed eclipse with maven style) from command line

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.

For example:

\tmp\root
├───module1
├───module2
├───mvnmodule
    └───src

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

  1. Login into sonar instance and select your profile (at the top rigth corner) then click on My profile
  2. 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.
  3. 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
    
    
  4. 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
    
  5. 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«
  6. In the dashboard, on the code cactegory, you can see the result for the three modules.
    2018-01-25 19_06_14-Code - eph-tarjeta-palacio

That’s it.

Cheers!

Code inspection with Sonar Qube and sonar-runner

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 server
sonar.host.url=http://localhost:9000

#----- Apache H2
sonar.jdbc.url=jdbc:h2:tcp://localhost:9092/sonar

#----- Global database settings
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

#----- Default source code encoding
sonar.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