Skip to content

Commit

Permalink
Merge pull request #120 from rsandell/api
Browse files Browse the repository at this point in the history
Export some data from InputAction to the HTTP API
  • Loading branch information
rsandell authored Nov 25, 2022
2 parents 0288444 + 800c893 commit 6d0a5df
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionList;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;

/**
* Records the pending inputs required.
*/
@ExportedBean
public class InputAction implements RunAction2 {

private static final Logger LOGGER = Logger.getLogger(InputAction.class.getName());
Expand Down Expand Up @@ -106,6 +109,7 @@ public String getIconFileName() {
}
}

@Exported
@Override
public String getDisplayName() {
if (ids == null || ids.isEmpty()) {
Expand Down Expand Up @@ -142,6 +146,7 @@ public synchronized InputStepExecution getExecution(String id) throws Interrupte
return null;
}

@Exported
public synchronized List<InputStepExecution> getExecutions() throws InterruptedException, TimeoutException {
loadExecutions();
if (executions == null) {
Expand All @@ -150,6 +155,11 @@ public synchronized List<InputStepExecution> getExecutions() throws InterruptedE
return new ArrayList<InputStepExecution>(executions);
}

@Exported
public boolean isWaitingForInput() throws InterruptedException, TimeoutException {
return !getExecutions().isEmpty();
}

/**
* Called when {@link InputStepExecution} is completed to remove it from the active input list.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;

/**
* {@link Step} that pauses for human input.
*
* @author Kohsuke Kawaguchi
*/
@ExportedBean(defaultVisibility = 2)
public class InputStep extends AbstractStepImpl implements Serializable {

private static final boolean ALLOW_POTENTIALLY_UNSAFE_IDS = SystemProperties.getBoolean(InputStep.class.getName() + ".ALLOW_UNSAFE_IDS");
Expand Down Expand Up @@ -95,12 +98,14 @@ public void setId(String id) {
this.id = _id;
}

@Exported
public String getId() {
if (id==null)
id = capitalize(Util.getDigestOf(message));
return id;
}

@Exported
public String getSubmitter() {
return submitter;
}
Expand All @@ -109,6 +114,7 @@ public String getSubmitter() {
this.submitter = Util.fixEmptyAndTrim(submitter);
}

@Exported
public String getSubmitterParameter() { return submitterParameter; }

@DataBoundSetter public void setSubmitterParameter(String submitterParameter) {
Expand All @@ -130,6 +136,7 @@ private String capitalize(String id) {
/**
* Caption of the OK button.
*/
@Exported
public String getOk() {
return ok!=null ? ok : Messages.proceed();
}
Expand All @@ -138,6 +145,7 @@ public String getOk() {
this.ok = Util.fixEmptyAndTrim(ok);
}

@Exported
public List<ParameterDefinition> getParameters() {
return parameters;
}
Expand All @@ -146,6 +154,7 @@ public List<ParameterDefinition> getParameters() {
this.parameters = parameters;
}

@Exported
public String getMessage() {
return message;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.interceptor.RequirePOST;

import edu.umd.cs.findbugs.annotations.CheckForNull;
Expand All @@ -61,6 +63,7 @@
/**
* @author Kohsuke Kawaguchi
*/
@ExportedBean(defaultVisibility = 2)
public class InputStepExecution extends AbstractStepExecutionImpl implements ModelObject {

private static final Logger LOGGER = Logger.getLogger(InputStepExecution.class.getName());
Expand Down Expand Up @@ -142,10 +145,12 @@ public void stop(Throwable cause) throws Exception {
});
}

@Exported
public String getId() {
return input.getId();
}

@Exported
public InputStep getInput() {
return input;
}
Expand All @@ -165,6 +170,7 @@ private TaskListener getListener() throws IOException, InterruptedException {
/**
* If this input step has been decided one way or the other.
*/
@Exported
public boolean isSettled() {
return outcome!=null;
}
Expand All @@ -180,7 +186,7 @@ private InputAction getPauseAction() throws IOException, InterruptedException {
return a;
}

@Override
@Override @Exported
public String getDisplayName() {
String message = getInput().getMessage();
if (message.length()<32) return message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@
import hudson.util.FormValidation.Kind;
import hudson.util.Secret;
import jenkins.model.IdStrategy;
import jenkins.model.InterruptedBuildAction;
import jenkins.model.Jenkins;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
Expand All @@ -78,6 +79,7 @@

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import org.jvnet.hudson.test.MockAuthorizationStrategy;
Expand All @@ -87,9 +89,8 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -611,5 +612,92 @@ public void test_unsafe_ids_generate_formValidation() throws Exception {
assertThat("> should be rejected", d.doCheckId("this-is-also>-not-ok"), JenkinsMatchers.hasKind(Kind.ERROR));
}

@Test
public void test_api_contains_waitingForInput() throws Exception {
//set up dummy security real
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
// job setup
WorkflowJob foo = j.jenkins.createProject(WorkflowJob.class, "foo");
foo.setDefinition(new CpsFlowDefinition(StringUtils.join(Arrays.asList(
"def x = input message:'Continue?';",
"echo(\"after: ${x}\");"),"\n"),true));

// get the build going, and wait until workflow pauses
QueueTaskFuture<WorkflowRun> q = foo.scheduleBuild2(0);
WorkflowRun b = q.getStartCondition().get();
j.waitForMessage("Continue?", b);

final JenkinsRule.WebClient webClient = j.createWebClient();
JenkinsRule.JSONWebResponse json = webClient.getJSON(b.getUrl() + "api/json?depth=1");
JSONArray actions = json.getJSONObject().getJSONArray("actions");
Optional<Object> obj = actions.stream().filter(oo ->
((JSONObject)oo).get("_class").equals("org.jenkinsci.plugins.workflow.support.steps.input.InputAction")
).findFirst();
assertTrue(obj.isPresent());
JSONObject o = (JSONObject)obj.get();
assertTrue(o.has("waitingForInput"));
assertTrue(o.getBoolean("waitingForInput"));

InputAction inputAction = b.getAction(InputAction.class);
InputStepExecution is = inputAction.getExecutions().get(0);
HtmlPage p = webClient.getPage(b, inputAction.getUrlName());
j.submit(p.getFormByName(is.getId()), "proceed");

json = webClient.getJSON(b.getUrl() + "api/json?depth=1");
actions = json.getJSONObject().getJSONArray("actions");
obj = actions.stream().filter(oo ->
((JSONObject)oo).get("_class").equals("org.jenkinsci.plugins.workflow.support.steps.input.InputAction")
).findFirst();
assertTrue(obj.isPresent());
o = (JSONObject)obj.get();
assertTrue(o.has("waitingForInput"));
assertFalse(o.getBoolean("waitingForInput"));
}

@Test
public void test_api_contains_details() throws Exception {
//set up dummy security real
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
// job setup
WorkflowJob foo = j.jenkins.createProject(WorkflowJob.class, "foo");
foo.setDefinition(new CpsFlowDefinition(StringUtils.join(Arrays.asList(
"def chosen = input message: 'Can we settle on this thing?', ok: 'Yep', parameters: [choice(choices: ['Apple', 'Blueberry', 'Banana'], description: 'The fruit in question.', name: 'fruit')], submitter: 'bobby', submitterParameter: 'dd'",
"echo(\"after: ${chosen}\");"),"\n"),true));

// get the build going, and wait until workflow pauses
QueueTaskFuture<WorkflowRun> q = foo.scheduleBuild2(0);
WorkflowRun b = q.getStartCondition().get();
j.waitForMessage("Input requested", b);

final JenkinsRule.WebClient webClient = j.createWebClient();
final JenkinsRule.JSONWebResponse json = webClient.getJSON(b.getUrl() + "api/json?depth=2");
final JSONArray actions = json.getJSONObject().getJSONArray("actions");
final Optional<Object> obj = actions.stream().filter(oo ->
((JSONObject)oo).get("_class").equals("org.jenkinsci.plugins.workflow.support.steps.input.InputAction")
).findFirst();
assertTrue(obj.isPresent());
final JSONObject o = (JSONObject)obj.get();
assertTrue(o.has("waitingForInput"));
assertTrue(o.getBoolean("waitingForInput"));

assertTrue(o.has("executions"));
JSONObject exs = o.getJSONArray("executions").getJSONObject(0);
assertEquals("Can we settle on this thing?", exs.getString("displayName"));
assertTrue(exs.has("input"));
JSONObject input = exs.getJSONObject("input");
assertEquals("Can we settle on this thing?", input.getString("message"));
assertEquals("Yep", input.getString("ok"));
assertEquals("bobby", input.getString("submitter"));
assertTrue(input.has("parameters"));
JSONObject param = input.getJSONArray("parameters").getJSONObject(0);
assertEquals("fruit", param.getString("name"));
assertEquals("ChoiceParameterDefinition", param.getString("type"));
assertThat(param.getJSONArray("choices").toArray(), arrayContaining("Apple", "Blueberry", "Banana"));

InputAction inputAction = b.getAction(InputAction.class);
InputStepExecution is = inputAction.getExecutions().get(0);
HtmlPage p = webClient.getPage(b, inputAction.getUrlName());
j.submit(p.getFormByName(is.getId()), "proceed");
j.assertBuildStatusSuccess(j.waitForCompletion(b));
}
}

0 comments on commit 6d0a5df

Please sign in to comment.