1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

Add Maven static code checks

* add static code checks for maven based projects as:
  * pmd plugin
  * spotBugs plugin
* test modules as unit-tests and integration-tests will be ignored by default. Additional modules to ignore are configurable
* for pmd: rulesets and excludes are configurable
* for spotBugs: includeFilter and excludeFilter are configurable
This commit is contained in:
Florian Geckeler 2020-03-09 08:58:59 +01:00 committed by GitHub
parent 84f3e10e3b
commit de2909e64b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 431 additions and 0 deletions

View File

@ -0,0 +1,90 @@
package cmd
import (
"strings"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/maven"
"github.com/SAP/jenkins-library/pkg/telemetry"
)
func mavenStaticCodeChecks(config mavenStaticCodeChecksOptions, telemetryData *telemetry.CustomData) {
c := command.Command{}
c.Stdout(log.Entry().Writer())
c.Stderr(log.Entry().Writer())
err := runMavenStaticCodeChecks(&config, telemetryData, &c)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runMavenStaticCodeChecks(config *mavenStaticCodeChecksOptions, telemetryData *telemetry.CustomData, command execRunner) error {
var defines []string
var goals []string
if !config.SpotBugs && !config.Pmd {
log.Entry().Fatal("Neither SpotBugs nor Pmd are configured. At least one of those tools have to be enabled")
}
if testModulesExcludes := maven.GetTestModulesExcludes(); testModulesExcludes != nil {
defines = append(defines, testModulesExcludes...)
}
if config.MavenModulesExcludes != nil {
for _, module := range config.MavenModulesExcludes {
defines = append(defines, "-pl")
defines = append(defines, "!"+module)
}
}
if config.SpotBugs {
spotBugsMavenParameters := getSpotBugsMavenParameters(config)
defines = append(defines, spotBugsMavenParameters.Defines...)
goals = append(goals, spotBugsMavenParameters.Goals...)
}
if config.Pmd {
pmdMavenParameters := getPmdMavenParameters(config)
defines = append(defines, pmdMavenParameters.Defines...)
goals = append(goals, pmdMavenParameters.Goals...)
}
finalMavenOptions := maven.ExecuteOptions{
Goals: goals,
Defines: defines,
}
_, err := maven.Execute(&finalMavenOptions, command)
return err
}
func getSpotBugsMavenParameters(config *mavenStaticCodeChecksOptions) *maven.ExecuteOptions {
var defines []string
if config.SpotBugsIncludeFilterFile != "" {
defines = append(defines, "-Dspotbugs.includeFilterFile="+config.SpotBugsIncludeFilterFile)
}
if config.SpotBugsExcludeFilterFile != "" {
defines = append(defines, "-Dspotbugs.excludeFilterFile="+config.SpotBugsExcludeFilterFile)
}
mavenOptions := maven.ExecuteOptions{
Goals: []string{"com.github.spotbugs:spotbugs-maven-plugin:3.1.12:spotbugs"},
Defines: defines,
}
return &mavenOptions
}
func getPmdMavenParameters(config *mavenStaticCodeChecksOptions) *maven.ExecuteOptions {
var defines []string
if config.PmdExcludes != nil {
defines = append(defines, "-Dpmd.excludes="+strings.Join(config.PmdExcludes, ","))
}
if config.PmdRuleSets != nil {
defines = append(defines, "-Dpmd.rulesets="+strings.Join(config.PmdRuleSets, ","))
}
mavenOptions := maven.ExecuteOptions{
Goals: []string{"org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd"},
Defines: defines,
}
return &mavenOptions
}

View File

@ -0,0 +1,143 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/spf13/cobra"
)
type mavenStaticCodeChecksOptions struct {
SpotBugs bool `json:"spotBugs,omitempty"`
Pmd bool `json:"pmd,omitempty"`
MavenModulesExcludes []string `json:"mavenModulesExcludes,omitempty"`
SpotBugsExcludeFilterFile string `json:"spotBugsExcludeFilterFile,omitempty"`
SpotBugsIncludeFilterFile string `json:"spotBugsIncludeFilterFile,omitempty"`
PmdExcludes []string `json:"pmdExcludes,omitempty"`
PmdRuleSets []string `json:"pmdRuleSets,omitempty"`
}
// MavenStaticCodeChecksCommand Execute static code checks for Maven based projects. The plugins SpotBugs and PMD are used.
func MavenStaticCodeChecksCommand() *cobra.Command {
metadata := mavenStaticCodeChecksMetadata()
var stepConfig mavenStaticCodeChecksOptions
var startTime time.Time
var createMavenStaticCodeChecksCmd = &cobra.Command{
Use: "mavenStaticCodeChecks",
Short: "Execute static code checks for Maven based projects. The plugins SpotBugs and PMD are used.",
Long: `Executes Spotbugs Maven plugin as well as Pmd Maven plugin for static code checks.
SpotBugs is a program to find bugs in Java programs. It looks for instances of bug patterns code instances that are likely to be errors.
For more information please visit https://spotbugs.readthedocs.io/en/latest/maven.html
PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex and Visualforce, PLSQL, Apache Velocity, XML, XSL.
For more information please visit https://pmd.github.io/`,
PreRunE: func(cmd *cobra.Command, args []string) error {
startTime = time.Now()
log.SetStepName("mavenStaticCodeChecks")
log.SetVerbose(GeneralConfig.Verbose)
return PrepareConfig(cmd, &metadata, "mavenStaticCodeChecks", &stepConfig, config.OpenPiperFile)
},
Run: func(cmd *cobra.Command, args []string) {
telemetryData := telemetry.CustomData{}
telemetryData.ErrorCode = "1"
handler := func() {
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
telemetry.Send(&telemetryData)
}
log.DeferExitHandler(handler)
defer handler()
telemetry.Initialize(GeneralConfig.NoTelemetry, "mavenStaticCodeChecks")
mavenStaticCodeChecks(stepConfig, &telemetryData)
telemetryData.ErrorCode = "0"
},
}
addMavenStaticCodeChecksFlags(createMavenStaticCodeChecksCmd, &stepConfig)
return createMavenStaticCodeChecksCmd
}
func addMavenStaticCodeChecksFlags(cmd *cobra.Command, stepConfig *mavenStaticCodeChecksOptions) {
cmd.Flags().BoolVar(&stepConfig.SpotBugs, "spotBugs", true, "Parameter to turn off SpotBugs.")
cmd.Flags().BoolVar(&stepConfig.Pmd, "pmd", true, "Parameter to turn off PMD.")
cmd.Flags().StringSliceVar(&stepConfig.MavenModulesExcludes, "mavenModulesExcludes", []string{}, "Maven modules which should be excluded by the static code checks. By default the modules 'unit-tests' and 'integration-tests' will be excluded.")
cmd.Flags().StringVar(&stepConfig.SpotBugsExcludeFilterFile, "spotBugsExcludeFilterFile", os.Getenv("PIPER_spotBugsExcludeFilterFile"), "Path to a filter file with bug definitions which should be excluded.")
cmd.Flags().StringVar(&stepConfig.SpotBugsIncludeFilterFile, "spotBugsIncludeFilterFile", os.Getenv("PIPER_spotBugsIncludeFilterFile"), "Path to a filter file with bug definitions which should be included.")
cmd.Flags().StringSliceVar(&stepConfig.PmdExcludes, "pmdExcludes", []string{}, "A comma-separated list of exclusions (.java source files) expressed as an Ant-style pattern relative to the sources root folder, i.e. application/src/main/java for maven projects.")
cmd.Flags().StringSliceVar(&stepConfig.PmdRuleSets, "pmdRuleSets", []string{}, "The PMD rulesets to use. See the Stock Java Rulesets for a list of available rules. Defaults to a custom ruleset provided by this maven plugin.")
}
// retrieve step metadata
func mavenStaticCodeChecksMetadata() config.StepData {
var theMetaData = config.StepData{
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "spotBugs",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "pmd",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "mavenModulesExcludes",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "spotBugsExcludeFilterFile",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "spotBugs/excludeFilterFile"}},
},
{
Name: "spotBugsIncludeFilterFile",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "spotBugs/includeFilterFile"}},
},
{
Name: "pmdExcludes",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{{Name: "pmd/excludes"}},
},
{
Name: "pmdRuleSets",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{{Name: "pmd/rulesSets"}},
},
},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,16 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMavenStaticCodeChecksCommand(t *testing.T) {
testCmd := MavenStaticCodeChecksCommand()
// only high level testing performed - details are tested in step generation procudure
assert.Equal(t, "mavenStaticCodeChecks", testCmd.Use, "command name incorrect")
}

View File

@ -0,0 +1,110 @@
package cmd
import (
"os"
"testing"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/maven"
"github.com/stretchr/testify/assert"
)
func TestRunMavenStaticCodeChecks(t *testing.T) {
t.Run("should run spotBugs and pmd with all configured options", func(t *testing.T) {
execMockRunner := mock.ExecMockRunner{}
config := mavenStaticCodeChecksOptions{
SpotBugs: true,
Pmd: true,
PmdExcludes: []string{"*test.java", "*prod.java"},
PmdRuleSets: []string{"myRule.xml", "anotherRule.xml"},
SpotBugsExcludeFilterFile: "excludeFilter.xml",
SpotBugsIncludeFilterFile: "includeFilter.xml",
MavenModulesExcludes: []string{"testing-lib", "test-helpers"},
}
expected := mock.ExecCall{
Exec: "mvn",
Params: []string{"-pl", "!unit-tests", "-pl", "!integration-tests",
"-pl", "!testing-lib", "-pl", "!test-helpers",
"-Dspotbugs.includeFilterFile=includeFilter.xml",
"-Dspotbugs.excludeFilterFile=excludeFilter.xml",
"-Dpmd.excludes=*test.java,*prod.java",
"-Dpmd.rulesets=myRule.xml,anotherRule.xml",
"--batch-mode",
"com.github.spotbugs:spotbugs-maven-plugin:3.1.12:spotbugs",
"org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd",
},
}
currentDir, err := os.Getwd()
if err != nil {
t.Fatal("Could not get current working directory")
}
defer os.Chdir(currentDir)
os.Chdir("../test/resources/maven/")
err = runMavenStaticCodeChecks(&config, nil, &execMockRunner)
assert.Nil(t, err)
assert.Equal(t, expected, execMockRunner.Calls[0])
})
t.Run("should log fatal if all tools are turned off", func(t *testing.T) {
var hasFailed bool
log.Entry().Logger.ExitFunc = func(int) { hasFailed = true }
execMockRunner := mock.ExecMockRunner{}
config := mavenStaticCodeChecksOptions{
SpotBugs: false,
Pmd: false,
}
_ = runMavenStaticCodeChecks(&config, nil, &execMockRunner)
assert.True(t, hasFailed, "expected command to exit with fatal")
})
}
func TestGetPmdMavenParameters(t *testing.T) {
t.Run("should return maven options with excludes and rulesets", func(t *testing.T) {
config := mavenStaticCodeChecksOptions{
Pmd: true,
PmdExcludes: []string{"*test.java", "*prod.java"},
PmdRuleSets: []string{"myRule.xml", "anotherRule.xml"},
}
expected := maven.ExecuteOptions{
Goals: []string{"org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd"},
Defines: []string{"-Dpmd.excludes=*test.java,*prod.java", "-Dpmd.rulesets=myRule.xml,anotherRule.xml"},
}
assert.Equal(t, &expected, getPmdMavenParameters(&config))
})
t.Run("should return maven goal only", func(t *testing.T) {
config := mavenStaticCodeChecksOptions{}
expected := maven.ExecuteOptions{
Goals: []string{"org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd"}}
assert.Equal(t, &expected, getPmdMavenParameters(&config))
})
}
func TestGetSpotBugsMavenParameters(t *testing.T) {
t.Run("should return maven options with excludes and include filters", func(t *testing.T) {
config := mavenStaticCodeChecksOptions{
SpotBugs: true,
SpotBugsExcludeFilterFile: "excludeFilter.xml",
SpotBugsIncludeFilterFile: "includeFilter.xml",
}
expected := maven.ExecuteOptions{
Goals: []string{"com.github.spotbugs:spotbugs-maven-plugin:3.1.12:spotbugs"},
Defines: []string{"-Dspotbugs.includeFilterFile=includeFilter.xml", "-Dspotbugs.excludeFilterFile=excludeFilter.xml"},
}
assert.Equal(t, &expected, getSpotBugsMavenParameters(&config))
})
t.Run("should return maven goal only", func(t *testing.T) {
config := mavenStaticCodeChecksOptions{}
expected := maven.ExecuteOptions{
Goals: []string{"com.github.spotbugs:spotbugs-maven-plugin:3.1.12:spotbugs"}}
assert.Equal(t, &expected, getSpotBugsMavenParameters(&config))
})
}

View File

@ -59,6 +59,7 @@ func Execute() {
rootCmd.AddCommand(MtaBuildCommand())
rootCmd.AddCommand(ProtecodeExecuteScanCommand())
rootCmd.AddCommand(MavenExecuteCommand())
rootCmd.AddCommand(MavenStaticCodeChecksCommand())
addRootFlags(rootCmd)
if err := rootCmd.Execute(); err != nil {

View File

@ -0,0 +1,71 @@
metadata:
name: mavenStaticCodeChecks
description: Execute static code checks for Maven based projects. The plugins SpotBugs and PMD are used.
longDescription: |
Executes Spotbugs Maven plugin as well as Pmd Maven plugin for static code checks.
SpotBugs is a program to find bugs in Java programs. It looks for instances of “bug patterns” — code instances that are likely to be errors.
For more information please visit https://spotbugs.readthedocs.io/en/latest/maven.html
PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex and Visualforce, PLSQL, Apache Velocity, XML, XSL.
For more information please visit https://pmd.github.io/
spec:
inputs:
params:
- name: spotBugs
description: Parameter to turn off SpotBugs.
type: bool
default: true
scope:
- PARAMETERS
- STAGES
- STEPS
- name: pmd
description: Parameter to turn off PMD.
type: bool
default: true
scope:
- PARAMETERS
- STAGES
- STEPS
- name: mavenModulesExcludes
description: Maven modules which should be excluded by the static code checks. By default the modules 'unit-tests' and 'integration-tests' will be excluded.
type: '[]string'
scope:
- PARAMETERS
- STAGES
- STEPS
- name: spotBugsExcludeFilterFile
description: Path to a filter file with bug definitions which should be excluded.
type: string
scope:
- PARAMETERS
- STAGES
- STEPS
aliases:
- name: spotBugs/excludeFilterFile
- name: spotBugsIncludeFilterFile
description: Path to a filter file with bug definitions which should be included.
type: string
scope:
- PARAMETERS
- STAGES
- STEPS
aliases:
- name: spotBugs/includeFilterFile
- name: pmdExcludes
description: A comma-separated list of exclusions (.java source files) expressed as an Ant-style pattern relative to the sources root folder, i.e. application/src/main/java for maven projects.
type: '[]string'
scope:
- PARAMETERS
- STAGES
- STEPS
aliases:
- name: pmd/excludes
- name: pmdRuleSets
description: The PMD rulesets to use. See the Stock Java Rulesets for a list of available rules. Defaults to a custom ruleset provided by this maven plugin.
type: '[]string'
scope:
- PARAMETERS
- STAGES
- STEPS
aliases:
- name: pmd/rulesSets