Skip to content

Commit

Permalink
Merge pull request #101 from jenkinsci/build_with_parameters
Browse files Browse the repository at this point in the history
Add the ability to build with parameters
  • Loading branch information
olivierdagenais authored Aug 3, 2016
2 parents 809d1c1 + 87084ab commit 2ddb56b
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 59 deletions.
26 changes: 21 additions & 5 deletions src/main/java/hudson/plugins/tfs/TeamBuildEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import hudson.model.UnprotectedRootAction;
import hudson.plugins.tfs.model.AbstractCommand;
import hudson.plugins.tfs.model.BuildCommand;
import hudson.plugins.tfs.model.BuildWithParametersCommand;
import hudson.plugins.tfs.model.PingCommand;
import hudson.plugins.tfs.util.MediaType;
import jenkins.model.Jenkins;
Expand Down Expand Up @@ -33,6 +34,7 @@
import java.util.logging.Logger;

import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_CREATED;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
import static javax.servlet.http.HttpServletResponse.SC_OK;
Expand All @@ -47,14 +49,15 @@ public class TeamBuildEndpoint implements UnprotectedRootAction {
private static final Map<String, AbstractCommand.Factory> COMMAND_FACTORIES_BY_NAME;
public static final String URL_NAME = "team-build";
public static final String TEAM_PARAMETERS = "team-parameters";
public static final String PARAMETER = "parameter";
static final String URL_PREFIX = "/" + URL_NAME + "/";
private static final String JSON = "json";
private static final String PARAMETER = "parameter";

static {
final Map<String, AbstractCommand.Factory> map = new TreeMap<String, AbstractCommand.Factory>(String.CASE_INSENSITIVE_ORDER);
map.put("ping", new PingCommand.Factory());
map.put("build", new BuildCommand.Factory());
map.put("buildWithParameters", new BuildWithParametersCommand.Factory());
COMMAND_FACTORIES_BY_NAME = Collections.unmodifiableMap(map);
}

Expand Down Expand Up @@ -187,13 +190,18 @@ void dispatch(final StaplerRequest req, final StaplerResponse rsp, final TimeDur
final JSONObject response;
if (isStructuredForm(req.getParameter(JSON))) {
final JSONObject formData = req.getSubmittedForm();
response = command.perform(project, formData, actualDelay);
response = command.perform(project, req, formData, actualDelay);
}
else {
response = command.perform(project, req, delay);
response = command.perform(project, req, actualDelay);
}

rsp.setStatus(SC_OK);
if (response.containsKey("created")) {
rsp.setStatus(SC_CREATED);
}
else {
rsp.setStatus(SC_OK);
}
rsp.setContentType(MediaType.APPLICATION_JSON_UTF_8);
final PrintWriter w = rsp.getWriter();
final String responseJsonString = response.toString();
Expand All @@ -218,7 +226,7 @@ static boolean isStructuredForm(final String jsonParameter) {
if (jsonParameter != null) {
try {
final JSONObject jsonObject = JSONObject.fromObject(jsonParameter);
if (jsonObject.containsKey(PARAMETER) && jsonObject.containsKey(TEAM_PARAMETERS)) {
if (jsonObject.containsKey(TEAM_PARAMETERS)) {
return true;
}
}
Expand All @@ -245,4 +253,12 @@ public void doBuild(
dispatch(request, response, delay);
}

public void doBuildWithParameters(
final StaplerRequest request,
final StaplerResponse response,
@QueryParameter final TimeDuration delay
) {
dispatch(request, response, delay);
}

}
3 changes: 2 additions & 1 deletion src/main/java/hudson/plugins/tfs/model/AbstractCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ public interface Factory {
* {@code requestPayload} and returning the output as a {@link JSONObject}.
*
* @param project an {@link AbstractProject to operate on}
* @param request a {@link StaplerRequest} to help build parameter values
* @param requestPayload a {@link JSONObject} representing the command's input
* @param delay how long to wait before the project starts executing
*
* @return a {@link JSONObject} representing the hook event's output
*/
public abstract JSONObject perform(final AbstractProject project, final JSONObject requestPayload, final TimeDuration delay);
public abstract JSONObject perform(final AbstractProject project, final StaplerRequest request, final JSONObject requestPayload, final TimeDuration delay);

/**
* Actually do the work of the command, using the supplied
Expand Down
126 changes: 74 additions & 52 deletions src/main/java/hudson/plugins/tfs/model/BuildCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,28 @@
import hudson.model.Action;
import hudson.model.Cause;
import hudson.model.CauseAction;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.ParameterDefinition;
import hudson.model.ParameterValue;
import hudson.model.ParametersAction;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Queue;
import hudson.model.queue.ScheduleResult;
import hudson.plugins.tfs.CommitParameterAction;
import hudson.plugins.tfs.PullRequestParameterAction;
import hudson.plugins.tfs.TeamBuildEndpoint;
import hudson.plugins.tfs.util.MediaType;
import jenkins.model.Jenkins;
import jenkins.util.TimeDuration;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.jfree.data.Values;
import org.kohsuke.stapler.StaplerRequest;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -30,6 +42,7 @@ public class BuildCommand extends AbstractCommand {
private static final String REFS_PULL_SLASH = "refs/pull/";
private static final int REFS_PULL_SLASH_LENGTH = REFS_PULL_SLASH.length();
private static final String BUILD_REPOSITORY_URI = "Build.Repository.Uri";
private static final String BUILD_REPOSITORY_NAME = "Build.Repository.Name";
private static final String SYSTEM_TEAM_PROJECT = "System.TeamProject";
private static final String BUILD_SOURCE_VERSION = "Build.SourceVersion";
private static final String BUILD_REQUESTED_FOR = "Build.RequestedFor";
Expand All @@ -43,17 +56,17 @@ public AbstractCommand create() {

@Override
public String getSampleRequestPayload() {
return "{\n" +
" \"team-parameters\":\n" +
" {\n" +
" \"collectionUri\":\"https://fabrikam-fiber-inc.visualstudio.com\",\n" +
" \"repoUri\":\"https://fabrikam-fiber-inc.visualstudio.com/Personal/_git/olivida.tfs-plugin\",\n" +
" \"projectId\":\"Personal\",\n" +
" \"repoId\":\"olivida.tfs-plugin\",\n" +
" \"commit\":\"6a23fc7afec31f0a14bade6544bed4f16492e6d2\",\n" +
" \"pushedBy\":\"olivida\"\n" +
" }\n" +
"}";
final Class<? extends Factory> me = this.getClass();
final InputStream stream = me.getResourceAsStream("BuildCommand.json");
try {
return IOUtils.toString(stream, MediaType.UTF_8);
}
catch (final IOException e) {
throw new Error(e);
}
finally {
IOUtils.closeQuietly(stream);
}
}
}

Expand All @@ -79,7 +92,7 @@ protected JSONObject innerPerform(final AbstractProject project, final TimeDurat
}

@Override
public JSONObject perform(final AbstractProject project, final JSONObject requestPayload, final TimeDuration delay) {
public JSONObject perform(final AbstractProject project, final StaplerRequest req, final JSONObject requestPayload, final TimeDuration delay) {

final List<Action> actions = new ArrayList<Action>();
if (requestPayload.containsKey(TeamBuildEndpoint.TEAM_PARAMETERS)) {
Expand All @@ -96,7 +109,32 @@ public JSONObject perform(final AbstractProject project, final JSONObject reques
}
actions.add(action);
}
// TODO: detect if a job is parameterized and react appropriately

//noinspection UnnecessaryLocalVariable
final Job<?, ?> job = project;
final ParametersDefinitionProperty pp = job.getProperty(ParametersDefinitionProperty.class);
if (pp != null && requestPayload.containsKey(TeamBuildEndpoint.PARAMETER)) {
final List<ParameterValue> values = new ArrayList<ParameterValue>();
final JSONArray a = requestPayload.getJSONArray(TeamBuildEndpoint.PARAMETER);

for (final Object o : a) {
final JSONObject jo = (JSONObject) o;
final String name = jo.getString("name");

final ParameterDefinition d = pp.getParameterDefinition(name);
if (d == null)
throw new IllegalArgumentException("No such parameter definition: " + name);
final ParameterValue parameterValue = d.createValue(req, jo);
if (parameterValue != null) {
values.add(parameterValue);
}
else {
throw new IllegalArgumentException("Cannot retrieve the parameter value: " + name);
}
}
final ParametersAction action = new ParametersAction(values);
actions.add(action);
}

return innerPerform(project, delay, actions);
}
Expand All @@ -119,9 +157,6 @@ public JSONObject perform(final AbstractProject project, final StaplerRequest re
}
teamParameters.put(teamParamName, valueArray[0]);
}
else {
// TODO: implement when we add support for parameterized builds
}
}

if (teamParameters.containsKey(BUILD_REPOSITORY_PROVIDER) && "TfGit".equalsIgnoreCase(teamParameters.get(BUILD_REPOSITORY_PROVIDER))) {
Expand All @@ -130,49 +165,36 @@ public JSONObject perform(final AbstractProject project, final StaplerRequest re
final String repoUriString = teamParameters.get(BUILD_REPOSITORY_URI);
final URI repoUri = URI.create(repoUriString);
final String projectId = teamParameters.get(SYSTEM_TEAM_PROJECT);
final String repoId = teamParameters.get(BUILD_REPOSITORY_NAME);
final String commit = teamParameters.get(BUILD_SOURCE_VERSION);
final String pushedBy = teamParameters.get(BUILD_REQUESTED_FOR);
final Integer pullRequestId = determinePullRequestId(teamParameters);
final CommitParameterAction action;
if (pullRequestId != null) {
final PullRequestMergeCommitCreatedEventArgs args = new PullRequestMergeCommitCreatedEventArgs();
args.collectionUri = collectionUri;
args.repoUri = repoUri;
args.projectId = projectId;
args.commit = commit;
args.pushedBy = pushedBy;
args.pullRequestId = pullRequestId;
args.iterationId = -1 /* TODO: the pull request iteration ID is missing! */;
action = new PullRequestParameterAction(args);
}
else {
final GitCodePushedEventArgs args = new GitCodePushedEventArgs();
args.collectionUri = collectionUri;
args.repoUri = repoUri;
args.projectId = projectId;
args.commit = commit;
args.pushedBy = pushedBy;
action = new CommitParameterAction(args);
}
final GitCodePushedEventArgs args = new GitCodePushedEventArgs();
args.collectionUri = collectionUri;
args.repoUri = repoUri;
args.projectId = projectId;
args.repoId = repoId;
args.commit = commit;
args.pushedBy = pushedBy;
final CommitParameterAction action = new CommitParameterAction(args);
actions.add(action);
}

return innerPerform(project, delay, actions);
}

static Integer determinePullRequestId(final HashMap<String, String> teamParameters) {
Integer pullRequestId = null;
if (teamParameters.containsKey(BUILD_SOURCE_BRANCH)) {
final String sourceBranch = teamParameters.get(BUILD_SOURCE_BRANCH);
if (sourceBranch.startsWith(REFS_PULL_SLASH)) {
final String idSlashMerge = sourceBranch.substring(REFS_PULL_SLASH_LENGTH);
final int nextSlash = idSlashMerge.indexOf('/');
if (nextSlash > 0) {
final String pullRequestIdString = idSlashMerge.substring(0, nextSlash);
pullRequestId = Integer.valueOf(pullRequestIdString, 10);
//noinspection UnnecessaryLocalVariable
final Job<?, ?> job = project;
final ParametersDefinitionProperty pp = job.getProperty(ParametersDefinitionProperty.class);
if (pp != null) {
final List<ParameterDefinition> parameterDefinitions = pp.getParameterDefinitions();
final List<ParameterValue> values = new ArrayList<ParameterValue>();
for (final ParameterDefinition d : parameterDefinitions) {
final ParameterValue value = d.createValue(request);
if (value != null) {
values.add(value);
}
}
final ParametersAction action = new ParametersAction(values);
actions.add(action);
}
return pullRequestId;

return innerPerform(project, delay, actions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package hudson.plugins.tfs.model;

import hudson.plugins.tfs.util.MediaType;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;

public class BuildWithParametersCommand extends BuildCommand {

public static class Factory implements AbstractCommand.Factory {

@Override
public AbstractCommand create() {
return new BuildWithParametersCommand();
}

@Override
public String getSampleRequestPayload() {
final Class<? extends Factory> me = this.getClass();
final InputStream stream = me.getResourceAsStream("BuildWithParametersCommand.json");
try {
return IOUtils.toString(stream, MediaType.UTF_8);
}
catch (final IOException e) {
throw new Error(e);
}
finally {
IOUtils.closeQuietly(stream);
}
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/hudson/plugins/tfs/model/PingCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public String getSampleRequestPayload() {
}

@Override
public JSONObject perform(final AbstractProject project, final JSONObject requestPayload, final TimeDuration delay) {
public JSONObject perform(final AbstractProject project, final StaplerRequest request, final JSONObject requestPayload, final TimeDuration delay) {
return requestPayload;
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/resources/hudson/plugins/tfs/model/BuildCommand.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"team-parameters":
{
"collectionUri":"https://fabrikam-fiber-inc.visualstudio.com",
"repoUri":"https://fabrikam-fiber-inc.visualstudio.com/Personal/_git/olivida.tfs-plugin",
"projectId":"Personal",
"repoId":"olivida.tfs-plugin",
"commit":"6a23fc7afec31f0a14bade6544bed4f16492e6d2",
"pushedBy":"olivida"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"parameter":
[
{"name":"id","value":"123"},
{"name":"verbosity","value":"high"}
],
"team-parameters":
{
"collectionUri":"https://fabrikam-fiber-inc.visualstudio.com",
"repoUri":"https://fabrikam-fiber-inc.visualstudio.com/Personal/_git/olivida.tfs-plugin",
"projectId":"Personal",
"repoId":"olivida.tfs-plugin",
"commit":"6a23fc7afec31f0a14bade6544bed4f16492e6d2",
"pushedBy":"olivida"
}
}

0 comments on commit 2ddb56b

Please sign in to comment.