提交 e0bccdde 编写于 作者: K Kohsuke Kawaguchi

Merge branch 'pull-301'

......@@ -55,7 +55,9 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=rfe>
Added an extension point to sort matrix configuration builds when executing them sequentially
(<a href="https://github.com/jenkinsci/jenkins/pull/301">pull #301</a>)
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -29,15 +29,16 @@ import hudson.matrix.listeners.MatrixBuildListener;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Cause.UpstreamCause;
import hudson.model.Executor;
import hudson.model.Fingerprint;
import jenkins.model.Jenkins;
import hudson.model.JobProperty;
import hudson.model.ParametersAction;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Cause.UpstreamCause;
import hudson.tasks.Publisher;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import java.io.File;
import java.io.IOException;
......@@ -45,12 +46,10 @@ import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import java.util.TreeSet;
/**
* Build of {@link MatrixProject}.
......@@ -261,6 +260,12 @@ public class MatrixBuild extends AbstractBuild<MatrixProject,MatrixBuild> {
if(!a.startBuild())
return Result.FAILURE;
MatrixConfigurationSorter sorter = p.getSorter();
if (sorter != null) {
touchStoneConfigurations = createTreeSet(touchStoneConfigurations, sorter);
delayedConfigurations = createTreeSet(delayedConfigurations,sorter);
}
try {
if(!p.isRunSequentially())
for(MatrixConfiguration c : touchStoneConfigurations)
......@@ -394,6 +399,12 @@ public class MatrixBuild extends AbstractBuild<MatrixProject,MatrixBuild> {
}
}
private <T> TreeSet<T> createTreeSet(Collection<T> items, Comparator<T> sorter) {
TreeSet<T> r = new TreeSet<T>(sorter);
r.addAll(items);
return r;
}
/**
* A private exception to help maintain the correct control flow after extracting the 'waitForCompletion' method
*/
......
package hudson.matrix;
import hudson.ExtensionPoint;
import hudson.model.AbstractDescribableImpl;
import hudson.util.FormValidation;
import java.util.Comparator;
/**
* Add sorting for configurations {@link MatrixConfiguration}s of matrix job {@link MatrixProject}
*
* @since 1.439
* @author Lucie Votypkova
* @see MatrixConfigurationSorterDescriptor
*/
public abstract class MatrixConfigurationSorter extends AbstractDescribableImpl<MatrixConfigurationSorter> implements ExtensionPoint, Comparator<MatrixConfiguration> {
/**
* Checks if this sorter is properly configured and applicable for the given project.
*
* <p>
* This method is invoked when the configuration is submitted to ensure that the sorter is compatible
* with the current project configuration (most probably with its {@link Axis}.)
*
* @param p
* Project for which this sorter is being used for.
* @throws FormValidation
* If you need to report an error to the user and reject the form submission.
*/
public abstract void validate(MatrixProject p) throws FormValidation;
@Override
public MatrixConfigurationSorterDescriptor getDescriptor() {
return (MatrixConfigurationSorterDescriptor)super.getDescriptor();
}
}
package hudson.matrix;
import hudson.DescriptorExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
/**
* Descriptor for {@link MatrixConfigurationSorter}.
*
* @author Kohsuke Kawaguchi
* @since 1.439
*/
public abstract class MatrixConfigurationSorterDescriptor extends Descriptor<MatrixConfigurationSorter> {
protected MatrixConfigurationSorterDescriptor(Class<? extends MatrixConfigurationSorter> clazz) {
super(clazz);
}
protected MatrixConfigurationSorterDescriptor() {
}
/**
* Returns all the registered {@link AxisDescriptor}s.
*/
public static DescriptorExtensionList<MatrixConfigurationSorter,MatrixConfigurationSorterDescriptor> all() {
return Jenkins.getInstance().<MatrixConfigurationSorter,MatrixConfigurationSorterDescriptor>getDescriptorList(MatrixConfigurationSorter.class);
}
}
......@@ -143,6 +143,8 @@ public class MatrixProject extends AbstractProject<MatrixProject,MatrixBuild> im
* continue with the rest
*/
private Result touchStoneResultCondition;
private MatrixConfigurationSorter sorter;
public MatrixProject(String name) {
this(Jenkins.getInstance(), name);
......@@ -152,6 +154,18 @@ public class MatrixProject extends AbstractProject<MatrixProject,MatrixBuild> im
super(parent, name);
}
/**
* @return can be null (to indicate that the configurations should be left to their natural order.)
*/
public MatrixConfigurationSorter getSorter() {
return sorter;
}
public void setSorter(MatrixConfigurationSorter sorter) throws IOException {
this.sorter = sorter;
save();
}
public AxisList getAxes() {
return axes;
}
......@@ -574,8 +588,19 @@ public class MatrixProject extends AbstractProject<MatrixProject,MatrixBuild> im
newAxes.rebuildHetero(req, json, Axis.all(),"axis");
checkAxisNames(newAxes);
this.axes = new AxisList(newAxes.toList());
runSequentially = json.optBoolean("runSequentially");
// set sorter if any sorter is chosen
if (runSequentially) {
MatrixConfigurationSorter s = req.bindJSON(MatrixConfigurationSorter.class,json.optJSONObject("sorter"));
if (s!=null) s.validate(this);
if (s instanceof NoopMatrixConfigurationSorter) s=null;
setSorter(s);
} else {
setSorter(null);
}
runSequentially = json.has("runSequentially");
buildWrappers.rebuild(req, json, BuildWrappers.getFor(this));
builders.rebuildHetero(req, json, Builder.all(), "builder");
......@@ -639,6 +664,10 @@ public class MatrixProject extends AbstractProject<MatrixProject,MatrixBuild> im
}
return r;
}
public List<MatrixConfigurationSorterDescriptor> getSorterDescriptors() {
return MatrixConfigurationSorterDescriptor.all();
}
}
private static final Logger LOGGER = Logger.getLogger(MatrixProject.class.getName());
......
package hudson.matrix;
import hudson.Extension;
import hudson.util.FormValidation;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* Place holder for default "do not sort" {@link MatrixConfigurationSorter}.
*
* @author Kohsuke Kawaguchi
*/
public class NoopMatrixConfigurationSorter extends MatrixConfigurationSorter {
@DataBoundConstructor
public NoopMatrixConfigurationSorter() {
}
@Override
public void validate(MatrixProject p) throws FormValidation {
// nothing
}
public int compare(MatrixConfiguration o1, MatrixConfiguration o2) {
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
@Extension(ordinal=100) // this is the default
public static class DescriptorImpl extends MatrixConfigurationSorterDescriptor {
@Override
public String getDisplayName() {
return "Doesn't care";
}
}
}
......@@ -59,7 +59,11 @@ THE SOFTWARE.
addCaption="${%Add axis}"/>
</f:block>
<f:optionalBlock field="runSequentially" title="${%Run each configuration sequentially}"/>
<f:optionalBlock field="runSequentially" title="${%Run each configuration sequentially}" inline="true">
<j:if test="${descriptor.sorterDescriptors.size() gt 1}">
<f:dropdownDescriptorSelector title="${%Execution order of builds}" field="sorter"/>
</j:if>
</f:optionalBlock>
<f:optionalBlock name="hasCombinationFilter" title="${%Combination Filter}" checked="${!empty(it.combinationFilter)}"
help="/help/matrix/combinationfilter.html">
......
......@@ -55,7 +55,9 @@ public class TestExtensionLoader extends AbstractGuiceFinder<TestExtension> {
protected boolean isActive(AnnotatedElement e) {
TestEnvironment env = TestEnvironment.get();
String testName = e.getAnnotation(TestExtension.class).value();
TestExtension a = e.getAnnotation(TestExtension.class);
if (a==null) return false; // stale index
String testName = a.value();
if (testName.length()>0 && !env.testCase.getName().equals(testName))
return false; // doesn't apply to this test
......
package hudson.matrix;
import hudson.util.FormValidation;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.TestExtension;
import org.kohsuke.stapler.DataBoundConstructor;
/**
* @author Kohsuke Kawaguchi
*/
public class MatrixConfigurationSorterTest extends HudsonTestCase {
public void testConfigRoundtrip() throws Exception {
MatrixProject p = createMatrixProject();
configRoundtrip(p);
assertNull(p.getSorter());
SorterImpl before = new SorterImpl();
p.setSorter(before);
p.setRunSequentially(true);
configRoundtrip(p);
Object after = p.getSorter();
assertNotSame(before,after);
assertSame(before.getClass(),after.getClass());
}
public static class SorterImpl extends MatrixConfigurationSorter {
@DataBoundConstructor
public SorterImpl() {}
@Override
public void validate(MatrixProject p) throws FormValidation {
}
public int compare(MatrixConfiguration o1, MatrixConfiguration o2) {
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
@TestExtension
public static class DescriptorImpl extends MatrixConfigurationSorterDescriptor {
@Override
public String getDisplayName() {
return "Test Sorter";
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册