Skip to content

Commit

Permalink
[FIXED JENKINS-26693] Support triggering workflows.
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Mar 5, 2015
1 parent d5b9c22 commit e859e2f
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 24 deletions.
23 changes: 23 additions & 0 deletions pom.xml
Expand Up @@ -24,6 +24,29 @@
<email>jglick@cloudbees.com</email>
</developer>
</developers>
<properties>
<workflow.version>1.3</workflow.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</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>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>${workflow.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
Expand Down
Expand Up @@ -25,15 +25,16 @@
package org.jenkinsci.plugins.build_token_root;

import hudson.Extension;
import hudson.model.AbstractProject;
import hudson.model.Cause;
import hudson.model.CauseAction;
import hudson.model.Job;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterValue;
import hudson.model.ParametersAction;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.UnprotectedRootAction;
import hudson.security.ACL;
import hudson.triggers.SCMTrigger;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
Expand All @@ -43,6 +44,9 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
import jenkins.triggers.SCMTriggerItem;
import jenkins.util.TimeDuration;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
Expand All @@ -68,22 +72,28 @@ public class BuildRootAction implements UnprotectedRootAction {
return null;
}

public void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job) throws IOException, ServletException {
public void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job, @QueryParameter TimeDuration delay) throws IOException, ServletException {
LOGGER.log(Level.FINE, "build on {0}", job);
AbstractProject<?,?> p = project(job, req, rsp);
ParametersDefinitionProperty pp = p.getProperty(ParametersDefinitionProperty.class);
ParameterizedJobMixIn.ParameterizedJob p = project(job, req, rsp);
if (delay == null) {
delay = new TimeDuration(p.getQuietPeriod());
}
ParametersDefinitionProperty pp = ((Job<?,?>) p).getProperty(ParametersDefinitionProperty.class);
if (pp != null) {
LOGGER.fine("wrong kind");
throw HttpResponses.error(HttpServletResponse.SC_BAD_REQUEST, "use buildWithParameters for this build");
}
Jenkins.getInstance().getQueue().schedule(p, p.getDelay(req), getBuildCause(req));
Jenkins.getInstance().getQueue().schedule(p, delay.getTime(), getBuildCause(req));
ok(rsp);
}

public void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job) throws IOException, ServletException {
public void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job, @QueryParameter TimeDuration delay) throws IOException, ServletException {
LOGGER.log(Level.FINE, "buildWithParameters on {0}", job);
AbstractProject<?,?> p = project(job, req, rsp);
ParametersDefinitionProperty pp = p.getProperty(ParametersDefinitionProperty.class);
ParameterizedJobMixIn.ParameterizedJob p = project(job, req, rsp);
if (delay == null) {
delay = new TimeDuration(p.getQuietPeriod());
}
ParametersDefinitionProperty pp = ((Job<?,?>) p).getProperty(ParametersDefinitionProperty.class);
if (pp == null) {
LOGGER.fine("wrong kind");
throw HttpResponses.error(HttpServletResponse.SC_BAD_REQUEST, "use build for this build");
Expand All @@ -95,29 +105,46 @@ public void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @Quer
values.add(value);
}
}
Jenkins.getInstance().getQueue().schedule(p, p.getDelay(req), new ParametersAction(values), getBuildCause(req));
Jenkins.getInstance().getQueue().schedule(p, delay.getTime(), new ParametersAction(values), getBuildCause(req));
ok(rsp);
}

public void doPolling(StaplerRequest req, StaplerResponse rsp, @QueryParameter String job) throws IOException, ServletException {
LOGGER.log(Level.FINE, "polling on {0}", job);
project(job, req, rsp).schedulePolling();
ParameterizedJobMixIn.ParameterizedJob p = project(job, req, rsp);
// AbstractProject.schedulePolling only adds one thing here: check for isDisabled. But in that case, !isBuildable, so we would not have gotten here anyway.
SCMTriggerItem scmp = SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(p);
if (scmp == null) {
LOGGER.log(Level.FINE, "{0} is not a SCMTriggerItem", p);
throw HttpResponses.error(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, new IOException(job + " is not a SCMTriggerItem"));
}
SCMTrigger trigger = scmp.getSCMTrigger();
if (trigger == null) {
LOGGER.log(Level.FINE, "{0} is not configured to poll", p);
throw HttpResponses.error(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, new IOException(job + " is not configured to poll"));
}
trigger.run();
ok(rsp);
}

@SuppressWarnings("deprecation")
private AbstractProject<?,?> project(String job, StaplerRequest req, StaplerResponse rsp) throws IOException, HttpResponses.HttpResponseException {
AbstractProject<?,?> p;
private ParameterizedJobMixIn.ParameterizedJob project(String job, StaplerRequest req, StaplerResponse rsp) throws IOException, HttpResponses.HttpResponseException {
Job<?,?> j;
SecurityContext orig = ACL.impersonate(ACL.SYSTEM);
try {
p = Jenkins.getInstance().getItemByFullName(job, AbstractProject.class);
j = Jenkins.getInstance().getItemByFullName(job, Job.class);
} finally {
SecurityContextHolder.setContext(orig);
}
if (p == null) {
LOGGER.log(Level.FINE, "no such job {0}", job);
if (j == null) {
LOGGER.log(Level.FINE, "no such job {0}", j);
throw HttpResponses.notFound();
}
if (!(j instanceof ParameterizedJobMixIn.ParameterizedJob)) {
LOGGER.log(Level.FINE, "{0} is not a ParameterizedJob", j);
throw HttpResponses.notFound();
}
ParameterizedJobMixIn.ParameterizedJob p = (ParameterizedJobMixIn.ParameterizedJob) j;
hudson.model.BuildAuthorizationToken authToken = p.getAuthToken();
if (authToken == null || authToken.getToken() == null) {
// For jobs without tokens, prefer not to leak information about their existence.
Expand All @@ -126,13 +153,13 @@ private AbstractProject<?,?> project(String job, StaplerRequest req, StaplerResp
throw HttpResponses.notFound();
}
try {
hudson.model.BuildAuthorizationToken.checkPermission(p, authToken, req, rsp);
hudson.model.BuildAuthorizationToken.checkPermission((Job) p, authToken, req, rsp);
} catch (AccessDeniedException x) {
LOGGER.log(Level.FINE, "on {0} was denied: {1}", new Object[] {job, x.getMessage()});
throw x;
}
if (!p.isBuildable()) {
LOGGER.log(Level.FINE, "{0} is not buildable (disabled={1}", new Object[] {job, p.isDisabled()});
if (!j.isBuildable()) {
LOGGER.log(Level.FINE, "{0} is not buildable", job);
throw HttpResponses.error(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, new IOException(job + " is not buildable"));
}
LOGGER.log(Level.FINE, "found {0}", p);
Expand Down
Expand Up @@ -25,19 +25,25 @@
package org.jenkinsci.plugins.build_token_root;

import com.gargoylesoftware.htmlunit.html.HtmlForm;
import hudson.model.FreeStyleProject;
import hudson.model.Job;
import hudson.model.Run;
import java.net.HttpURLConnection;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.ParameterizedJobMixIn;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.recipes.PresetData;

@SuppressWarnings("deprecation") // RunList.size, BuildAuthorizationToken
public class BuildRootActionTest {

private static final Logger logger = Logger.getLogger(BuildRootAction.class.getName());
Expand All @@ -50,10 +56,13 @@ public class BuildRootActionTest {

@Rule public JenkinsRule j = new JenkinsRule();

@SuppressWarnings("deprecation") // RunList.size, BuildAuthorizationToken
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS)
@Test public void build() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("stuff");
testBuild(j.createFreeStyleProject("p"));
}

@SuppressWarnings("unchecked") // AbstractItem.getParent snafu
private <JobT extends Job<JobT, RunT> & ParameterizedJobMixIn.ParameterizedJob, RunT extends Run<JobT, RunT>> void testBuild(JobT p) throws Exception {
JenkinsRule.WebClient wc = j.createWebClient();
wc.login("alice", "alice");
HtmlForm form = wc.getPage(p, "configure").getFormByName("config");
Expand All @@ -67,17 +76,26 @@ public class BuildRootActionTest {
wc.assertFails(p.getUrl() + "build?token=secret", HttpURLConnection.HTTP_FORBIDDEN);
j.waitUntilNoActivity();
assertEquals(0, p.getBuilds().size());
wc.goTo("buildByToken/build?job=stuff&token=secret&delay=0sec");
wc.goTo("buildByToken/build?job=" + p.getFullName() + "&token=secret&delay=0sec");
j.waitUntilNoActivity();
assertEquals(1, p.getBuilds().size());
wc.goTo("buildByToken/build?job=stuff&token=secret&delay=0sec");
wc.goTo("buildByToken/build?job=" + p.getFullName() + "&token=secret&delay=0sec");
j.waitUntilNoActivity();
assertEquals(2, p.getBuilds().size());
wc.assertFails("buildByToken/build?job=stuff&token=socket&delay=0sec", HttpURLConnection.HTTP_FORBIDDEN);
wc.assertFails("buildByToken/build?job=" + p.getFullName() + "&token=socket&delay=0sec", HttpURLConnection.HTTP_FORBIDDEN);
j.waitUntilNoActivity();
assertEquals(2, p.getBuilds().size());
}

// TODO test buildWithParameters, polling
// TODO test projects in folders

@Issue("JENKINS-26693")
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS)
@Test public void buildWorkflow() throws Exception {
WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("", true));
testBuild(p);
}

}

0 comments on commit e859e2f

Please sign in to comment.