Skip to content
Permalink
Browse files

[JENKINS-46162] Support workflow/pipeline linting (#30)

* Supporting pipeline jobs, fixed some bugs, bumped minimal version to allow the usage of the pipelines

* Supporting GroovySandbox checker only in Jenkinsfiles, aka WorkflowJobs

* [JENKINS-46162] Support Pipeline project to be linted

* Added TestCases for the Pipeline jobs

* Enable System Groovy detection

* Missing testcases

* Enabling JenkinsLint action for pipelines/workflows

Change-Id: Ideaa90900b836d2a2f115fc7eefa7c2ab5533197

* Support pipeline timer trigger check

Change-Id: I857d85210a0f95c22226798320508132cecaf9fa

* Fixed TimeoutChecker for pipeline (some false positives)

Change-Id: I2f9cdd04a73702ffa16cb7050123dc6a63fb759b

* Support pipeline PollingSCMtrigger check

Change-Id: I7ef1a3228096c2e43713495629e044bbb141d898
  • Loading branch information...
v1v committed Aug 14, 2017
1 parent 07b8bc8 commit 2b5910a98e8c5c3790eccf6b0b1638b9dd0e3ee2
Showing with 399 additions and 84 deletions.
  1. +15 −1 pom.xml
  2. +2 −3 src/main/java/org/jenkins/ci/plugins/jenkinslint/JenkinsLintAction.java
  3. +10 −0 src/main/java/org/jenkins/ci/plugins/jenkinslint/JenkinsLintGlobalConfiguration.java
  4. +18 −5 src/main/java/org/jenkins/ci/plugins/jenkinslint/JobLintAction.java
  5. +0 −17 src/main/java/org/jenkins/ci/plugins/jenkinslint/LintActionFactory.java
  6. +11 −0 src/main/java/org/jenkins/ci/plugins/jenkinslint/SlaveLintAction.java
  7. +0 −17 src/main/java/org/jenkins/ci/plugins/jenkinslint/SlaveLintActionFactory.java
  8. +50 −0 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/GroovySandboxChecker.java
  9. +24 −8 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/GroovySystemExitChecker.java
  10. +18 −2 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/JobDescriptionChecker.java
  11. +20 −2 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/PollingSCMTriggerChecker.java
  12. +6 −0 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/SlaveVersionChecker.java
  13. +9 −1 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/TimeoutChecker.java
  14. +28 −8 src/main/java/org/jenkins/ci/plugins/jenkinslint/check/TimerTriggerChecker.java
  15. +7 −1 src/main/java/org/jenkins/ci/plugins/jenkinslint/model/AbstractAction.java
  16. +3 −0 src/main/resources/org/jenkins/ci/plugins/jenkinslint/JenkinsLintGlobalConfiguration/config.jelly
  17. +6 −0 src/main/resources/org/jenkins/ci/plugins/jenkinslint/check/Messages.properties
  18. +10 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/AbstractTestCase.java
  19. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/ArtifactCheckerTestCase.java
  20. +11 −5 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/BFACheckerTestCase.java
  21. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/CleanupWorkspaceCheckerTestCase.java
  22. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GitRefCheckerTestCase.java
  23. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GitRefSubmoduleCheckerTestCase.java
  24. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GitShallowCheckerTestCase.java
  25. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GradleWrapperCheckerTestCase.java
  26. +49 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GroovySandboxCheckerTestCase.java
  27. +8 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/GroovySystemExitCheckerTestCase.java
  28. +4 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/HardcodedScriptCheckerTestCase.java
  29. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/JavadocCheckerTestCase.java
  30. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/JobAssignedLabelCheckerTestCase.java
  31. +9 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/JobDescriptionCheckerTestCase.java
  32. +10 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/JobLogRotatorCheckerTestCase.java
  33. +7 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/JobNameCheckerTestCase.java
  34. +4 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/MasterLabelCheckerTestCase.java
  35. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/MavenJobTypeCheckerTestCase.java
  36. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/MultibranchJobTypeCheckerTestCase.java
  37. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/NullSCMCheckerTestCase.java
  38. +7 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/PollingSCMTriggerCheckerTestCase.java
  39. +3 −0 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/TimeoutCheckerTestCase.java
  40. +17 −14 src/test/java/org/jenkins/ci/plugins/jenkinslint/check/TimerTriggerCheckerTestCase.java
16 pom.xml
@@ -11,10 +11,11 @@
</parent>

<properties>
<jenkins.version>1.580</jenkins.version>
<jenkins.version>1.607</jenkins.version>
<jenkins-test-harness.version>1.580</jenkins-test-harness.version>
<!--TODO: make true after the code cleanup-->
<findbugs.failOnError>false</findbugs.failOnError>
<workflow.version>1.14.2</workflow.version>
</properties>

<artifactId>jenkinslint</artifactId>
@@ -195,6 +196,19 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>${workflow.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>${workflow.version}</version>
<scope>test</scope>
</dependency>
<!-- JENKINS-29427 -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
@@ -29,14 +29,13 @@ public void getData() throws IOException {
this.reloadCheckList();
this.reloadSlaveCheckList();

for (AbstractProject item : Jenkins.getInstance().getAllItems(AbstractProject.class)) {
LOG.log(Level.FINER, "queryChecks " + item.getDisplayName());
for (hudson.model.Job item : Jenkins.getInstance().getAllItems(hudson.model.Job.class)) {
LOG.log(Level.FINER, "queryChecks " + item.getName());
Job newJob = new Job(item.getName(), item.getUrl());
for (InterfaceCheck checker : this.getCheckList()) {
LOG.log(Level.FINER, checker.getName() + " " + item.getName() + " " + checker.executeCheck(item));
// Lint is disabled when is ignored or globally disabled
newJob.addLint(new Lint(checker.getName(), checker.executeCheck(item), checker.isIgnored(item.getDescription()), checker.isEnabled()));

}
jobSet.put(item.getName(),newJob);
LOG.log(Level.FINER, newJob.toString());
@@ -44,6 +44,8 @@
private boolean timerTriggerCheckerEnabled = true;
private boolean windowsSlaveLaunchCheckerEnabled = true;

private boolean groovySandboxCheckerEnabled = true;

private int hardcodedScriptThreshold = HardcodedScriptChecker.THRESHOLD;
private boolean hardcodedScriptIgnoredComment = false;

@@ -302,6 +304,14 @@ public void setHardcodedScriptIgnoredComment(boolean hardcodedScriptIgnoredComme
this.hardcodedScriptIgnoredComment = hardcodedScriptIgnoredComment;
}

public boolean isGroovySandboxCheckerEnabled() {
return groovySandboxCheckerEnabled;
}

public void setWorkflowSandboxCheckerEnabled(boolean groovySandboxCheckerEnabled) {
this.groovySandboxCheckerEnabled = groovySandboxCheckerEnabled;
}

/**
* Performs on-the-fly validation of the form field 'name'.
*
@@ -1,7 +1,8 @@
package org.jenkins.ci.plugins.jenkinslint;

import hudson.model.AbstractProject;
import hudson.Extension;
import hudson.model.Action;
import jenkins.model.TransientActionFactory;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractAction;
import org.jenkins.ci.plugins.jenkinslint.model.InterfaceCheck;
import org.jenkins.ci.plugins.jenkinslint.model.Job;
@@ -10,25 +11,27 @@
import org.kohsuke.stapler.export.ExportedBean;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

@ExportedBean
public final class JobLintAction extends AbstractAction implements Action {

private static final Logger LOG = Logger.getLogger(JobLintAction.class.getName());
private AbstractProject<?, ?> project;
private hudson.model.Job project;
private Job job;

public static boolean isDisabled () {
return !JenkinsLintGlobalConfiguration.get().isJobActionEnabled();
}

public JobLintAction(AbstractProject<?, ?> project) {
public JobLintAction(hudson.model.Job project) {
this.project = project;
}

public AbstractProject<?, ?> getProject() {
public final hudson.model.Job<?, ?> getProject() {
return project;
}

@@ -38,7 +41,6 @@ public Job getJob() {
}

public void getData() throws IOException {

this.reloadCheckList();
this.job = new Job(this.project.getName(), this.project.getUrl());
for (InterfaceCheck checker : this.getCheckList()) {
@@ -47,5 +49,16 @@ public void getData() throws IOException {
LOG.log(Level.FINE, this.job.getLintList().toString());
}

@Extension
public static class Factory extends TransientActionFactory<hudson.model.Job> {
@Override
public Class<hudson.model.Job> type() {
return hudson.model.Job.class;
}

@Override
public Collection<? extends Action> createFor(hudson.model.Job target) {
return Collections.singleton(new JobLintAction(target));
}
}
}

This file was deleted.

@@ -1,7 +1,9 @@
package org.jenkins.ci.plugins.jenkinslint;

import hudson.Extension;
import hudson.model.Action;
import hudson.model.Computer;
import hudson.model.TransientComputerActionFactory;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractAction;
import org.jenkins.ci.plugins.jenkinslint.model.InterfaceSlaveCheck;
import org.jenkins.ci.plugins.jenkinslint.model.Lint;
@@ -10,6 +12,8 @@
import org.kohsuke.stapler.export.ExportedBean;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

@@ -43,4 +47,11 @@ public void getData() throws IOException {
}
}

@Extension
public static class Factory extends TransientComputerActionFactory {
@Override
public Collection<? extends Action> createFor(Computer target) {
return Collections.singleton(new SlaveLintAction(target));
}
}
}

This file was deleted.

@@ -0,0 +1,50 @@
package org.jenkins.ci.plugins.jenkinslint.check;

import hudson.model.Item;
import hudson.model.Job;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.util.logging.Level;

/**
* @author Victor Martinez
*/
public class GroovySandboxChecker extends AbstractCheck {

public GroovySandboxChecker(boolean enabled) {
super(enabled);
this.setDescription(Messages.GroovySandboxCheckerDesc());
this.setSeverity(Messages.GroovySandboxCheckerSeverity());
}

public boolean executeCheck(Item item) {
LOG.log(Level.FINE, "executeCheck " + item);
if (item instanceof Job) {
// Pipeline support
if (item.getClass().getSimpleName().equals("WorkflowJob")) {
try {
Object getDefinition = item.getClass().getMethod("getDefinition", null).invoke(item);
if (getDefinition.getClass().getSimpleName().equals("CpsFlowDefinition")) {
return !isSandbox(getDefinition);
}
} catch (Exception e) {
LOG.log(Level.FINE, "Exception " + e.getMessage(), e.getCause());
}
}
}
return false;
}

private boolean isSandbox(Object object) {
boolean status = true;
if (object != null) {
try {
Object isSandbox = object.getClass().getMethod("isSandbox", null).invoke(object);
return ((Boolean) isSandbox);
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
return status;
}
}
@@ -3,8 +3,7 @@
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.model.JobProperty;
import hudson.model.JobPropertyDescriptor;
import hudson.model.Job;
import hudson.model.ParameterDefinition;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Project;
@@ -14,7 +13,6 @@
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.util.List;
import java.util.Map;
import java.util.logging.Level;

/**
@@ -54,13 +52,31 @@ public boolean executeCheck(Item item) {
}
}

if (isSystemExitInPublisher(((AbstractProject) item).getPublishersList())) {
found = true;
if (item instanceof AbstractProject) {
if (isSystemExitInPublisher(((AbstractProject) item).getPublishersList())) {
found = true;
}

if (((AbstractProject) item).getProperty(ParametersDefinitionProperty.class) != null) {
if (isSystemExitInParameters(((ParametersDefinitionProperty) ((AbstractProject) item).getProperty(ParametersDefinitionProperty.class)).getParameterDefinitions())) {
found = true;
}
}
}

if (((AbstractProject) item).getProperty(ParametersDefinitionProperty.class)!=null) {
if (isSystemExitInParameters(((ParametersDefinitionProperty)((AbstractProject) item).getProperty(ParametersDefinitionProperty.class)).getParameterDefinitions())) {
found = true;
if (item instanceof Job) {
// Pipeline support
if (item.getClass().getSimpleName().equals("WorkflowJob")) {
try {
Object getDefinition = item.getClass().getMethod("getDefinition", null).invoke(item);
if (getDefinition.getClass().getSimpleName().equals("CpsFlowDefinition")) {
if (containsSystemExit(getDefinition.getClass().getMethod("getScript",null).invoke(getDefinition))) {
found = true;
}
}
} catch (Exception e) {
LOG.log(Level.FINE, "Exception " + e.getMessage(), e.getCause());
}
}
}
return found;
@@ -4,6 +4,9 @@
import hudson.model.Item;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.lang.reflect.Method;
import java.util.logging.Level;

/**
* @author Victor Martinez
*/
@@ -17,9 +20,22 @@ public JobDescriptionChecker(boolean enabled) {

public boolean executeCheck(Item item) {
if (item instanceof AbstractItem) {
return (((AbstractItem) item).getDescription() == null
|| ((AbstractItem) item).getDescription().length() == 0);
return isDescription(((AbstractItem) item).getDescription());
}
if (item.getClass().getSimpleName().equals("WorkflowJob")) {
try {
Object getDescription = item.getClass().getMethod("getDescription", null).invoke(item);
if (getDescription instanceof String) {
return isDescription((String) getDescription);
}
} catch (Exception e) {
LOG.log(Level.FINE, "Exception " + e.getMessage(), e.getCause());
}
}
return false;
}

private boolean isDescription(String description) {
return (description == null || description.length() == 0);
}
}
@@ -5,6 +5,9 @@
import hudson.triggers.SCMTrigger;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.util.Map;
import java.util.logging.Level;

/**
* @author Victor Martinez
*/
@@ -17,9 +20,24 @@ public PollingSCMTriggerChecker(boolean enabled) {
}

public boolean executeCheck(Item item) {
boolean found = false;
if (item instanceof AbstractProject) {
return (((AbstractProject) item).getTrigger(SCMTrigger.class) != null);
found = (((AbstractProject) item).getTrigger(SCMTrigger.class) != null);
}
if (item.getClass().getSimpleName().equals("WorkflowJob")) {
try {
Object getTriggers = item.getClass().getMethod("getTriggers", null).invoke(item);
if (getTriggers instanceof Map) {
for (Object value : ((Map) getTriggers).values()) {
if (value instanceof SCMTrigger) {
found = true;
}
}
}
} catch (Exception e) {
LOG.log(Level.FINE, "Exception " + e.getMessage(), e.getCause());
}
}
return false;
return found;
}
}

0 comments on commit 2b5910a

Please sign in to comment.
You can’t perform that action at this time.