Skip to content

Commit

Permalink
Merge pull request #50 from stephenc/jenkins-40906
Browse files Browse the repository at this point in the history
[JENKINS-40906] The missing configuration UI
  • Loading branch information
jglick committed Jan 22, 2017
2 parents 068add4 + cf5969d commit b59ddd2
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 27 deletions.
18 changes: 17 additions & 1 deletion pom.xml
Expand Up @@ -66,8 +66,24 @@ THE SOFTWARE.
<jenkins.version>1.642.3</jenkins.version>
<scm-api.version>2.0.1</scm-api.version>
<no-test-jar>false</no-test-jar>
<workflow-step-api.version>2.7</workflow-step-api.version>
</properties>
<dependencyManagement>
<!-- TODO figure out why the version is being forced down to 2.5 without this -->
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>${workflow-step-api.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>${workflow-step-api.version}</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
Expand Down Expand Up @@ -142,7 +158,7 @@ THE SOFTWARE.
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.5</version>
<version>${workflow-step-api.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down
Expand Up @@ -27,34 +27,46 @@

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.AbortException;
import hudson.Extension;
import hudson.model.Descriptor;
import hudson.model.Executor;
import hudson.model.TaskListener;
import hudson.scm.SCM;
import hudson.util.FormValidation;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jenkins.model.CauseOfInterruption;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.SCMHeadObserver;
import jenkins.scm.api.SCMRevision;
import jenkins.scm.api.SCMSource;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.StepExecution;
import org.jenkinsci.plugins.workflow.steps.SynchronousStepExecution;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import static hudson.model.Result.ABORTED;

/**
* Resolves an {@link SCM} from a {@link SCMSource} using a priority list of target branch names.
*
* @since FIXME
* @since 2.10
*/
public class ResolveScmStep extends Step {

Expand Down Expand Up @@ -150,14 +162,15 @@ public String toString() {
/**
* Our {@link Descriptor}.
*/
@Extension(optional = true)
public static class DescriptorImpl extends AbstractStepDescriptorImpl {
@Extension
public static class DescriptorImpl extends StepDescriptor {

/**
* Default constructor.
* {@inheritDoc}
*/
public DescriptorImpl() {
super(Execution.class);
@Override
public Set<Class<?>> getRequiredContext() {
return Collections.<Class<?>>singleton(TaskListener.class);
}

/**
Expand All @@ -175,49 +188,97 @@ public String getFunctionName() {
public String getDisplayName() {
return "Resolves an SCM from an SCM Source and a list of candidate target branch names";
}

@Override
public Step newInstance(@CheckForNull StaplerRequest req, @NonNull JSONObject formData)
throws FormException {
assert req != null : "see contract for method, it's never null but has to claim it could be";
// roll our own because we want the groovy api to be easier than the jelly form binding would have us
JSONObject src = formData.getJSONObject("source");
src.put("id", "_");
SCMSource source = req.bindJSON(SCMSource.class, src);
List<String> targets = new ArrayList<>();
// TODO JENKINS-27901 use standard control when available
Object t = formData.get("targets");
if (t instanceof JSONObject) {
JSONObject o = (JSONObject) t;
targets.add(o.getString("target"));
} else if (t instanceof JSONArray) {
JSONArray a = (JSONArray) t;
for (int i = 0; i < a.size(); i++) {
JSONObject o = a.getJSONObject(i);
targets.add(o.getString("target"));
}
}
ResolveScmStep step = new ResolveScmStep(source, targets);
if (formData.optBoolean("ignoreErrors", false)) {
step.setIgnoreErrors(true);
}
return step;
}

public FormValidation doCheckTarget(@QueryParameter String value) {
if (StringUtils.isNotBlank(value)) {
return FormValidation.ok();
}
return FormValidation.error("You must supply a target branch name to resolve");
}
}

/**
* Our {@link StepExecution}.
*/
public static class Execution extends AbstractSynchronousStepExecution<SCM> {
public static class Execution extends SynchronousStepExecution<SCM> {

/**
* Ensure consistent serialization.
*/
private static final long serialVersionUID = 1L;

/**
* The step.
* The {@link SCMSource}
*/
private transient final ResolveScmStep step;
@NonNull
private transient final SCMSource source;

/**
* Our constructor (avoiding Guice injection).
* The {@link SCMSource}
*/
@NonNull
private final List<String> targets;

/**
* If {@code true} then {@code null} will be returned in the event that none of the target branch names can be
* resolved.
*/
private boolean ignoreErrors;

/**
* Our constructor.
*
* @param context the context.
* @param step the step.
*/
Execution(StepContext context, ResolveScmStep step) {
super(context);
this.step = step;
this.source = step.getSource();
this.targets = new ArrayList<>(step.getTargets());
this.ignoreErrors = step.isIgnoreErrors();
}

/**
* {@inheritDoc}
*/
@Override
protected SCM run() throws Exception {
StepContext context = getContext();
TaskListener listener = context.get(TaskListener.class);
assert listener != null;
PrintStream out = listener.getLogger();
SCMSource source = step.source;
out.printf("Checking for first existing branch from %s...%n", step.getTargets());
SCMRevision fetch = source.fetch(new ObserverImpl(step.getTargets()), listener).result();
out.printf("Checking for first existing branch from %s...%n", targets);
SCMRevision fetch = source.fetch(new ObserverImpl(targets), listener).result();
if (fetch == null) {
out.println("Could not find any matching branch%n");
if (step.isIgnoreErrors()) {
if (ignoreErrors) {
return null;
}
throw new AbortException("Could not find any matching branch");
Expand All @@ -226,13 +287,6 @@ protected SCM run() throws Exception {
return source.build(fetch.getHead(), fetch);
}

/**
* {@inheritDoc}
*/
@Override
public void onResume() {
// Do not re-inject with Guice
}
}

/**
Expand Down Expand Up @@ -293,5 +347,4 @@ public boolean isObserving() {
}

}

}
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright 2017 CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:dropdownDescriptorSelector field="source" title="${%Source}"/>
<f:entry field="targets" title="${%Targets}">
<f:repeatable name="${targets}" var="targets"
items="${instance.targets}" minimum="1" add="${%Add target}">
<table width="100%">
<tr>
<td width="80%">
<f:textbox name="target"/>
</td>
<td width="auto">
<f:repeatableDeleteButton/>
</td>
</tr>
</table>
</f:repeatable>
</f:entry>
<f:entry field="ignoreErrors" title="${%Ignore Errors}">
<f:checkbox />
</f:entry>
</j:jelly>
@@ -0,0 +1,26 @@
<!--
The MIT License
Copyright 2017 CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<div>
When selected, the step will return <code>null</code> in the event that no matching branch can be resolved.
</div>
@@ -0,0 +1,26 @@
<!--
The MIT License
Copyright 2017 CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<div>
The source repository from which to resolve the target branches.
</div>
@@ -0,0 +1,26 @@
<!--
The MIT License
Copyright 2017 CloudBees, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<div>
The branch names to try and resolve from the source, in order of preference.
</div>

0 comments on commit b59ddd2

Please sign in to comment.