Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #46 from jglick/WorkflowJob.disabled-JENKINS-27299
[JENKINS-27299] WorkflowJob.disabled
  • Loading branch information
jglick committed May 12, 2017
2 parents cc4923e + c4a4f04 commit d1874be
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 3 deletions.
40 changes: 40 additions & 0 deletions pom.xml
Expand Up @@ -66,6 +66,8 @@
<jenkins-test-harness.version>2.19</jenkins-test-harness.version>
<no-test-jar>false</no-test-jar>
<workflow-support-plugin.version>2.2</workflow-support-plugin.version>
<scm-api-plugin.version>2.1.1</scm-api-plugin.version>
<git-plugin.version>3.2.0</git-plugin.version>
</properties>
<dependencies>
<dependency>
Expand Down Expand Up @@ -109,5 +111,43 @@
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>${scm-api-plugin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>${scm-api-plugin.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>${git-plugin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>${git-plugin.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>mailer</artifactId>
<version>1.18</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
100 changes: 98 additions & 2 deletions src/main/java/org/jenkinsci/plugins/workflow/job/WorkflowJob.java
Expand Up @@ -35,6 +35,8 @@
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.Action;
import hudson.model.BallColor;
import hudson.model.BuildAuthorizationToken;
import hudson.model.BuildableItem;
import hudson.model.Cause;
import hudson.model.Computer;
Expand All @@ -54,6 +56,7 @@
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import hudson.model.listeners.ItemListener;
import hudson.model.listeners.SCMListener;
import hudson.model.queue.CauseOfBlockage;
import hudson.model.queue.QueueTaskFuture;
Expand Down Expand Up @@ -99,6 +102,8 @@
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
Expand All @@ -124,6 +129,7 @@ public final class WorkflowJob extends Job<WorkflowJob,WorkflowRun> implements B
* TODO is it important to persist this? {@link hudson.model.AbstractProject#pollingBaseline} is not persisted.
*/
private transient volatile Map<String,SCMRevisionState> pollingBaselines;
private volatile boolean disabled;

public WorkflowJob(ItemGroup parent, String name) {
super(parent, name);
Expand Down Expand Up @@ -197,6 +203,8 @@ public void setDefinition(FlowDefinition definition) {
} else {
quietPeriod = null;
}

makeDisabled(json.optBoolean("disable"));
}


Expand All @@ -215,7 +223,8 @@ public void setDefinition(FlowDefinition definition) {
}
}
}
return true; // why not?
// TODO https://github.com/jenkinsci/jenkins/pull/2866: return ParameterizedJobMixIn.ParameterizedJob.super.isBuildable();
return !isDisabled() && !isHoldOffBuildUntilSave();
}

@Override protected RunMap<WorkflowRun> _getRuns() {
Expand Down Expand Up @@ -258,7 +267,11 @@ public void setDefinition(FlowDefinition definition) {
return buildMixIn.createHistoryWidget();
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
@Override public Queue.Executable createExecutable() throws IOException {
if (isDisabled()) {
return null;
}
return buildMixIn.newBuild();
}

Expand Down Expand Up @@ -304,6 +317,62 @@ public boolean isParameterized() {
return createParameterizedJobMixIn().isParameterized();
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 @Override
public boolean isDisabled() {
return disabled;
}

@Restricted(DoNotUse.class)
// TODO https://github.com/jenkinsci/jenkins/pull/2866 @Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 @Override
public boolean supportsMakeDisabled() {
return true;
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
public void makeDisabled(boolean b) throws IOException {
if (isDisabled() == b) {
return; // noop
}
if (b && !supportsMakeDisabled()) {
return; // do nothing if the disabling is unsupported
}
setDisabled(b);
if (b) {
Jenkins.getActiveInstance().getQueue().cancel(this);
}
save();
ItemListener.fireOnUpdated(this);
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
@RequirePOST
public HttpResponse doDisable() throws IOException, ServletException {
checkPermission(CONFIGURE);
makeDisabled(true);
return new HttpRedirect(".");
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
@RequirePOST
public HttpResponse doEnable() throws IOException, ServletException {
checkPermission(CONFIGURE);
makeDisabled(false);
return new HttpRedirect(".");
}

@Override public BallColor getIconColor() {
if (isDisabled()) {
return isBuilding() ? BallColor.DISABLED_ANIME : BallColor.DISABLED;
} else {
return super.getIconColor();
}
}

@SuppressWarnings("deprecation")
@Override public hudson.model.BuildAuthorizationToken getAuthToken() {
return authToken;
Expand Down Expand Up @@ -574,8 +643,34 @@ public void replaceAction(Action a) {
return typical;
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
public boolean schedulePolling() {
if (isDisabled()) {
return false;
}
SCMTrigger scmt = getSCMTrigger();
if (scmt == null) {
return false;
}
scmt.run();
return true;
}

// TODO https://github.com/jenkinsci/jenkins/pull/2866 remove override
@SuppressWarnings("deprecation")
public void doPolling(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
BuildAuthorizationToken.checkPermission((Job) this, getAuthToken(), req, rsp);
schedulePolling();
rsp.sendRedirect(".");
}

@SuppressFBWarnings(value="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification="TODO 1.653+ switch to Jenkins.getInstanceOrNull")
@Override public PollingResult poll(TaskListener listener) {
if (!isBuildable()) {
listener.getLogger().println("Build disabled");
return PollingResult.NO_CHANGES;
}
// TODO 2.11+ call SCMDecisionHandler
// TODO call SCMPollListener
WorkflowRun lastBuild = getLastBuild();
if (lastBuild == null) {
Expand Down Expand Up @@ -663,8 +758,9 @@ public void replaceAction(Action a) {
}

@Override protected void performDelete() throws IOException, InterruptedException {
super.performDelete();
makeDisabled(true);
// TODO call SCM.processWorkspaceBeforeDeletion
super.performDelete();
}

@Initializer(before=InitMilestone.EXTENSIONS_AUGMENTED)
Expand Down
Expand Up @@ -25,6 +25,7 @@
-->

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:f="/lib/form" xmlns:p="/lib/hudson/project">
<p:config-disableBuild/>
<p:config-quietPeriod/>

<!-- pseudo-trigger to configure URL to trigger builds remotely. -->
Expand Down
Expand Up @@ -24,7 +24,31 @@
~ THE SOFTWARE.
-->

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:p="/lib/hudson/project" xmlns:t="/lib/hudson">
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:p="/lib/hudson/project" xmlns:t="/lib/hudson" xmlns:l="/lib/layout" xmlns:f="/lib/form">
<j:choose> <!-- TODO https://github.com/jenkinsci/jenkins/pull/2866 <p:makeDisabled/> -->
<j:when test="${!it.supportsMakeDisabled()}">
<!-- for now, quietly omit the option -->
</j:when>
<j:when test="${it.disabled}">
<div class="warning">
<form method="post" id='enable-project' action="enable">
${%This project is currently disabled}
<l:hasPermission permission="${it.CONFIGURE}">
<f:submit value="${%Enable}" />
</l:hasPermission>
</form>
</div>
</j:when>
<j:otherwise>
<div align="right">
<form method="post" id="disable-project" action="disable">
<l:hasPermission permission="${it.CONFIGURE}">
<f:submit value="${%Disable Project}" />
</l:hasPermission>
</form>
</div>
</j:otherwise>
</j:choose>
<p:projectActionFloatingBox/>
<table style="margin-top: 1em; margin-left:1em;">
<!-- TODO display prominentActions -->
Expand Down
@@ -1,16 +1,26 @@
package org.jenkinsci.plugins.workflow.job;

import com.gargoylesoftware.htmlunit.HttpMethod;
import com.gargoylesoftware.htmlunit.WebRequest;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import hudson.model.Result;
import hudson.plugins.git.GitSCM;
import hudson.security.WhoAmI;
import hudson.triggers.SCMTrigger;
import jenkins.plugins.git.GitSampleRepoRule;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

public class WorkflowJobTest {

@Rule public JenkinsRule j = new JenkinsRule();
@Rule public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();

@Issue("JENKINS-40255")
@Test public void getSCM() throws Exception {
Expand Down Expand Up @@ -38,6 +48,26 @@ public class WorkflowJobTest {
assertEquals("Expecting zero SCMs",0, p.getSCMs().size());
}

@Issue("JENKINS-34716")
@Test public void polling() throws Exception {
sampleRepo.init();
sampleRepo.write("Jenkinsfile", "echo 'first version'");
sampleRepo.git("add", "Jenkinsfile");
sampleRepo.git("commit", "-m", "init");
WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
p.addTrigger(new SCMTrigger(""));
p.setDefinition(new CpsScmFlowDefinition(new GitSCM(sampleRepo.toString()), "Jenkinsfile"));
j.assertLogContains("first version", j.buildAndAssertSuccess(p));
sampleRepo.write("Jenkinsfile", "echo 'second version'");
sampleRepo.git("commit", "-a", "-m", "init");
j.jenkins.setQuietPeriod(0);
j.createWebClient().getPage(new WebRequest(j.createWebClient().createCrumbedUrl(p.getUrl() + "polling"), HttpMethod.POST));
j.waitUntilNoActivity();
WorkflowRun b2 = p.getLastBuild();
assertEquals(2, b2.getNumber());
j.assertLogContains("second version", b2);
}

@Test
public void addAction() throws Exception {
WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
Expand All @@ -46,4 +76,25 @@ public void addAction() throws Exception {
assertNotNull(p.getAction(WhoAmI.class));
}

@Issue("JENKINS-27299")
@Test public void disabled() throws Exception {
WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
assertFalse(p.isDisabled());
assertTrue(p.isBuildable());
JenkinsRule.WebClient wc = j.createWebClient();
j.submit(wc.getPage(p).<HtmlForm>getHtmlElementById("disable-project"));
assertTrue(p.isDisabled());
assertFalse(p.isBuildable());
HtmlForm form = wc.getPage(p, "configure").getFormByName("config");
HtmlCheckBoxInput checkbox = form.getInputByName("disable");
assertTrue(checkbox.isChecked());
checkbox.setChecked(false);
j.submit(form);
assertFalse(p.isDisabled());
wc.getPage(new WebRequest(wc.createCrumbedUrl(p.getUrl() + "disable"), HttpMethod.POST));
assertTrue(p.isDisabled());
assertNull(p.scheduleBuild2(0));
// TODO https://github.com/jenkinsci/jenkins/pull/2866 reënable by CLI
}

}
Expand Up @@ -33,6 +33,7 @@
import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.jenkinsci.plugins.workflow.steps.StepContextParameter;
import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep;
import static org.junit.Assert.*;
import org.junit.ClassRule;
import org.junit.Rule;
Expand All @@ -50,6 +51,29 @@ public class WorkflowRunRestartTest {
@ClassRule public static BuildWatcher buildWatcher = new BuildWatcher();
@Rule public RestartableJenkinsRule story = new RestartableJenkinsRule();

@Issue("JENKINS-27299")
@Test public void disabled() {
story.addStep(new Statement() {
@Override public void evaluate() throws Throwable {
WorkflowJob p = story.j.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("node {semaphore 'wait'}"));
WorkflowRun b = p.scheduleBuild2(0).waitForStart();
SemaphoreStep.waitForStart("wait/1", b);
p.makeDisabled(true);
}
});
story.addStep(new Statement() {
@Override public void evaluate() throws Throwable {
WorkflowJob p = story.j.jenkins.getItemByFullName("p", WorkflowJob.class);
assertTrue(p.isDisabled());
WorkflowRun b = p.getBuildByNumber(1);
assertTrue(b.isBuilding());
SemaphoreStep.success("wait/1", null);
story.j.assertBuildStatusSuccess(story.j.waitForCompletion(b));
}
});
}

@Issue("JENKINS-25550")
@Test public void hardKill() throws Exception {
story.addStep(new Statement() {
Expand Down

0 comments on commit d1874be

Please sign in to comment.