Jenkins : Static Analysis in Pipelines

Attention

Please note that this wiki page sometimes does not show the changed content. In order to see the latest results you may need to add the ?cache attribute to the URL.

Up to now the static analysis plug-ins are optimized for freestyle builds:

  1. Configuration is done using a user interface, i.e. all possible options are visible and could be easily selected or edited using UI controls.
  2. Reporting of the static analysis results has been provided as a black box, i.e. users need not to hassle about intermediate steps, they just see the final result.

A user friendly approach for editing pipelines is not yet available, at least not for complex use cases: So pipelines with static analysis steps suffer from the same problems. This is something the Jenkins core team needs to fix, hopefully there will be some progress in the future. I don't think that a plug-in can provide a solution here.

The second point, however, can be addressed by the plug-in. Rather than providing all steps in a black box, these steps should be made accessible for pipelines. In the following sections these steps are described in detail. Moreover, all relevant issues are listed, so all requirements should be visible from here. If you have additional requirements, or if you need something different, please use this wiki page as discussion platform.

Structure of static analysis steps

In the following sections, the current structure is explained. Then, a first sketch of the new implementation for pipelines is given.

Current implementation 

All static analysis plug-ins basically are composed of several similar steps. In a freestyle job you can configure these steps using one configuration object. In a freestyle build this configuration is the input for a post build publisher. This publisher parses a set of files (or the console log) for warnings and attaches the recorded warnings as an action to the build of the job. This action is visualized afterwards from Jenkins' UI. There you can view the warnings or the trend report. Additionally, you can also set the build status and health depending on the set of recorded warnings.

Pipeline friendly implementation

For pipelines, this approach has several drawbacks, see the issues below. In order to provide a better experience for pipelines, the plugin needs to divide the big step into two sub-steps. In the next sections, a sketch of the planned functionality is given. In these sections, the word issue is used as placeholder for warnings, bugs, open tasks, duplications, etc. 

Note: if not described otherwise all steps can be called several times.

scanForIssues

Scans a set of files or the console log for issues. All parsers from the warnings plugin as well as all parsers or scanners from the other static analysis plugin can be used in this step. The result is an unfiltered set of issues. Depending on the selected parsers, the associated filenames might be still relative.

Input:

Output

  • a report that contains a set of unique issues

TODO (After Release 2):

  • JENKINS-44450: How to handle scanning the console log for only a subset of the pipeline (including just one branch of a parallel pipeline)? Either this step needs to support block-scoped usage (taking a closure that specifies the steps to include in the console log scan), or pipeline should provide a separate (possibly more generic) step to capture the console log for a group of steps that could then be passed to this step.
publishIssues

Makes the issues visible in a run: creates an associated action that will be persisted by Jenkins. Responsible for detail views and trend graphs and so on. Merges all issues of the provided parsers into a single result. Copies all conflicting files from a build agent to the master so that these files are available for rendering of the warnings details.

Input: 

  • 1, ..., n sets of issues: each set contains the issues from one scanForIssues calls.
  • strategy to pick the reference build (that is used as a baseline to compute the new issues): currently the freestyle options usePreviousBuildAsReference and useStableBuildAsReference are available. I'm not sure if it must be possible to provide the reference build as parameter or if additional strategies must be provided or implemented.
  • defaultEncoding: Encoding to use when reading input files.
  • thresholds for health reporting: healthy, unhealthy, minimumPriority (see freestyle project).
  • thresholds for run status evaluation: unstableAll, etc. (see freestyle project).
  • include or exclude filters (filename, type, package, etc.) to specify the set of issues that should be stored  
  • id: the ID of the result. If not provided, then the ID of the parser in the scanForIssues step is used. This ID is used as URL to the results and to get the correct labels for the user interface.
  • name: the name of the result. If not provided, then the name of the parser in the scanForIssues step is used. This name is used in all labels for the user interface.
  • See implementation PublishIssuesStep

Output

  • the created action object (which contains a reference to the created result)
  • side effect: current run has a new action attached.

TODO (After Release 2): 

  • Hierarchy of results: Would it make sense to have hierarchy in the warnings container object so that the necessary warnings can all be added to the same container, but different groups are distinguishable from each other? Then only a few steps would need to be aware of this hierarchy, others could just go through all items. Or could this publishing step create such a hierarchy in the web UI?
  • Blame: Compute the authors and commits for a set of issues (this works for freestyle jobs, it is not clear yet if the required information is available in pipelines).

Prototype 

The development of this feature still is in progress. The implementation is visible in the 5.0 branch of the warnings plug-in. The base plugin analysis-core has not been changed, the latest version 1.95 will be used as a dependency (in the long term, this dependency will be removed). The other static analysis plugins (checkstyle, pmd, dry, findbugs, android-lint, ccm) are obsolete now: their parsers habe been integrated into the warnings plug-in, so these plugins can be removed if all jobs have been migrated. Support for the analysis-collector plugin will be added later on. (A CI build is already available: warnings plug-in.) 

The prototype works quite well, most of the requirements from the issues below will be satisfied. Below is an example script that shows the new feature in action.

Pipeline
node {
    stage ('Checkout') {
        git branch:'master', url: 'file:///Users/hafner/Development/git/analysis-model'
    }

    stage ('Build') {
        def mvnHome = tool 'mvn-default'

        sh "${mvnHome}/bin/mvn --batch-mode -V -U -e clean test -Dsurefire.useFile=false"

        junit testResults: '**/target/surefire-reports/TEST-*.xml'

        def java = scanForIssues tool: [$class: 'Java']
        def javadoc = scanForIssues tool: [$class: 'JavaDoc']
        
        publishIssues issues:[java]
        publishIssues issues:[javadoc]
    }

    stage ('Analysis') {
        def mvnHome = tool 'mvn-default'

        sh "${mvnHome}/bin/mvn -batch-mode -V -U -e checkstyle:checkstyle pmd:pmd pmd:cpd findbugs:findbugs spotbugs:spotbugs"

        def checkstyle = scanForIssues tool: [$class: 'CheckStyle'], pattern: '**/target/checkstyle-result.xml'
        publishIssues issues:[checkstyle]
   
        def pmd = scanForIssues tool: [$class: 'Pmd'], pattern: '**/target/pmd.xml'
        publishIssues issues:[pmd]
        
        def cpd = scanForIssues tool: [$class: 'Cpd'], pattern: '**/target/cpd.xml'
        publishIssues issues:[cpd]
        
        def findbugs = scanForIssues tool: [$class: 'FindBugs'], pattern: '**/target/findbugsXml.xml'
        publishIssues issues:[findbugs]

        def spotbugs = scanForIssues tool: [$class: 'SpotBugs'], pattern: '**/target/spotbugsXml.xml'
        publishIssues issues:[spotbugs]
    }
}

Related Issues

The following issues are related. Note that not all of them are from pipeline jobs, some will also benefit from the splitting shown above.

JENKINS-44450 - Block scoped usage Open

JENKINS-43155 - Multiple links and graphics when there are several branches Closed

JENKINS-40164 - Obtain parallel warnings results in pipeline Resolved

JENKINS-37325 - Make multiple static analysis results visible in a pipeline script Resolved

JENKINS-31812 - Set reference build explicitly Resolved

JENKINS-31633 - Only first execution is tracked Resolved

JENKINS-30551 - Make Warnings Plugin compatible with parallel Workflow Resolved

JENKINS-22526 - Health threshold rebaseline command Resolved

JENKINS-22874 - Ability to configure thresholds for each Warnings parser used Resolved

JENKINS-18708 - Make it possible to have several files as input for one parser Resolved

JENKINS-17196 - Add an action that allows to reset the reference build Resolved

JENKINS-13056 - Obtain reference build from SCM/Trigger Resolved

Non Functional API Requirements

These changes will change the API of the analysis-core plug-in. Since I do not have the time to make such big changes backward compatible, a new major release of analysis-core is required:

  • All changes will be part of analysis-core 2.0 release
  • analysis-core 2.0 API will be not backward compatible
  • analysis-core 2.0 will be based on Java 8
  • analysis-core 2.0 will not contain a dependency to the maven project
  • analysis-core 2.0 will remove all @Deprecated methods

Attachments:

taskScannerPlugin.JPG (image/jpeg)
Screenshot_2.png (image/png)
Screenshot_4.png (image/png)
Screenshot_5.png (image/png)
Screenshot_5.png (image/png)
Screenshot_6.png (image/png)