Inform-Software / sonar-groovy

SonarQube plugin for Groovy
GNU Lesser General Public License v3.0
58 stars 26 forks source link

CodeNarc sensor unable to resolve classes #27

Open agabrys opened 4 years ago

agabrys commented 4 years ago

CodeNarc sensor reports a lot of errors like:

Compilation failed for [CustomCompilerPhaseSourceDecorator[SourceString[import jenkins.model.Jenkins
// full source code

; org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
None: 1: unable to resolve class jenkins.model.Jenkins
 @ line 1, column 1.
   import jenkins.model.Jenkins
   ^

None: 6: unable to resolve class jenkins.model.Jenkins 
 @ line 6, column 22.
      def availableJdks = Jenkins.get().JDKs*.name
                        ^

2 errors

It looks for me that the sensor classpath is set improperly.

I created an example project which allows to reproduce the problem: https://github.com/agabrys/bugs-reports/tree/master/codenarc-CustomCompilerPhaseSourceDecorator

Environment:

frederic-valin-maif commented 2 years ago

Hi,

I have the same problem with a Shared Pipeline Library analysing with SonarQube groovy plugin

Sources are under src/ and vars/ directories (standard for this kind of project)

Library is built with a maven project and compiled with gmaven-plus plugin

And when analysing with Sonar 7.9 and sonar-groovy plugin 1.7, i have thousands lines in jenkins log like that :

[WARNING] Compilation failed for [CustomCompilerPhaseSourceDecorator[SourceString[package fr.maif.ingdev.ansible

import fr.maif.ingdev.jenkins.Pipeline
import fr.maif.ingdev.utils.Logger
import fr.maif.ingdev.utils.Snippets
import groovy.json.JsonOutput

class AnsibleTower implements Serializable {

    /**
     * Exécute un jobTemplateId avec un appel synchrone
     * @param towerServer , exemple 'awx-prod'
     * @param jobTemplateId , exemple 1446
     * @param jobType , type de job Ansible
     * @param extraVars , map des extraVars [product: 'exemple', env: 'recx',]
     * @return java.util.Properties avec clés JOB_ID, JOB_URL, JOB_RESULT
     */

...

]]]; org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
None: 6: unable to resolve class groovy.json.JsonOutput
 @ line 6, column 1.
   import groovy.json.JsonOutput
   ^

None: 4: unable to resolve class fr.maif.ingdev.utils.Logger
 @ line 4, column 1.
   import fr.maif.ingdev.utils.Logger

How and where can i add something to resolve that ?

Thank you

chess-levin commented 2 years ago

We have exactly the same issue! Did anyone find a solution for this issue?

Here are two sniplets from our jenkins console.log:

14:59:59  14:59:59.228 INFO: Loading ruleset from [file:/home/jenkins/workspace/eature_add_sonar_properties_file/.scannerwork/codenarc/profile.xml]
15:00:01  15:00:01.230 INFO: RuleSet configuration properties file [codenarc.properties] not found.
15:00:02  15:00:02.294 WARN: The Cobertura XML file [null] is not accessible; skipping this rule
15:00:03  15:00:03.355 WARN: Compilation failed for [CustomCompilerPhaseSourceDecorator[SourceString[package de.hmmh.itsqs.jsl
15:00:03  ]]]; org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
15:00:03  None: 10: unable to resolve class org.apache.commons.lang3.StringUtils
15:00:03   @ line 10, column 1.
15:00:03     import org.apache.commons.lang3.StringUtils
15:00:03     ^
15:00:03  
15:00:03  None: 11: unable to resolve class org.apache.maven.artifact.versioning.DefaultArtifactVersion
15:00:03   @ line 11, column 1.
15:00:03     import org.apache.maven.artifact.versioning.DefaultArtifactVersion
15:00:03     ^
15:00:03  
15:00:03  None: 32: unable to resolve class GString 
15:00:03   @ line 32, column 17.
15:00:03             GString p = "${mountPoint}/${projectId}"
15:00:03                     ^
agabrys commented 2 years ago

The issue is caused by the missing configuration of the CodeNarc runner's classpath when it is executed. I searched a little bit and this is how it is solve for the CodeNarc Ant target (see code):

def oldContextClassLoader = currentThread().contextClassLoader
def classLoader = classLoaderForPaths(paths, oldContextClassLoader)
try {
    currentThread().contextClassLoader = classLoader
    return codeNarcRunner.execute()
} finally {
    currentThread().contextClassLoader = oldContextClassLoader
    classLoader.close()
}

I think it should be possible to implement a similar mechanism for the SonarQube plugin. We have to define new properties:

SonarScanner generates Java properties when it is executed. One option would be to check how it is done and do the same. Another option would be to reuse the sonar.java.* properties or use them as defaults. I'll think about it.

@TobiX what do you think?

gtoison commented 2 years ago

Maybe this will help: the SpotBugs plugin also needs the libraries to analyze a project; it uses the JavaResourceLocator from the sonar-java plugin to get the classpath: https://github.com/spotbugs/sonar-findbugs/blob/b3599e2c27471cfaf1c18bf726d31ea3b305cc4f/src/main/java/org/sonar/plugins/findbugs/FindbugsConfiguration.java#L91

frederic-valin-maif commented 2 years ago

Hi, No news on this issue ? Anybody would be able to reproduce/develop the solution proposed by @gtoison ? Thanks for helping