diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 50c115a850b443e51a41e46369acbc33bc1b2174..8c9e72edd9c6ba6f5c8ff2c6bab0da4d8668f109 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -150,6 +150,7 @@ import org.kohsuke.stapler.jelly.InternationalizedStringExpression.RawHtmlArgume import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import hudson.util.RunList; import java.util.concurrent.atomic.AtomicLong; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -1431,7 +1432,8 @@ public class Functions { } /** - * Returns a sub-list if the given list is bigger than the specified 'maxSize' + * Returns a sub-list if the given list is bigger than the specified {@code maxSize}. + * Warning: do not call this with a {@link RunList}, or you will break lazy loading! */ public static List subList(List base, int maxSize) { if(maxSize builds; public BuildTimelineWidget(RunList builds) { - this.builds = builds; + this.builds = builds.limit(20); // TODO instead render lazily } + @Deprecated public Run getFirstBuild() { return builds.getFirstBuild(); } + @Deprecated public Run getLastBuild() { return builds.getLastBuild(); } diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index aef474184ac66d21114e69e82c51c22bac4a1069..29a7cd9425672c4daf644cc22c404efb67f6efc6 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -1269,7 +1269,7 @@ public abstract class Job, RunT extends Run data = new DataSetBuilder(); - for (Run r : getBuilds()) { + for (Run r : getNewBuilds()) { if (r.isBuilding()) continue; data.add(((double) r.getDuration()) / (1000 * 60), "min", diff --git a/core/src/main/java/hudson/model/User.java b/core/src/main/java/hudson/model/User.java index 90e6f472f0fc996871152124b48a8e44416028b2..e0b3cd5e877b1e4b923571089ce6176a415c495d 100644 --- a/core/src/main/java/hudson/model/User.java +++ b/core/src/main/java/hudson/model/User.java @@ -24,6 +24,7 @@ */ package hudson.model; +import com.google.common.base.Predicate; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; import hudson.*; import hudson.model.Descriptor.FormException; @@ -451,19 +452,14 @@ public class User extends AbstractModelObject implements AccessControlled, Descr /** * Gets the list of {@link Build}s that include changes by this user, * by the timestamp order. - * - * TODO: do we need some index for this? */ @WithBridgeMethods(List.class) public RunList getBuilds() { - List r = new ArrayList(); - for (AbstractProject p : Jenkins.getInstance().getAllItems(AbstractProject.class)) - for (AbstractBuild b : p.getBuilds().newBuilds()){ - if (relatedTo(b)) { - r.add(b); - } + return new RunList>(Jenkins.getInstance().getAllItems(Job.class)).filter(new Predicate>() { + @Override public boolean apply(Run r) { + return r instanceof AbstractBuild && relatedTo((AbstractBuild) r); } - return RunList.fromRuns(r); + }); } /** diff --git a/core/src/main/java/hudson/util/RunList.java b/core/src/main/java/hudson/util/RunList.java index 891e4ff8b58e0aa6890abf4aa9c9d7da8733231f..add82eb8907d87486793c5b1fc6ac661be86b1d2 100644 --- a/core/src/main/java/hudson/util/RunList.java +++ b/core/src/main/java/hudson/util/RunList.java @@ -186,9 +186,10 @@ public class RunList extends AbstractList { /** * Returns elements that satisfy the given predicate. + * Warning: this method mutates the original list and then returns it. + * @since TODO */ - // for compatibility reasons, this method doesn't create a new list but updates the current one - private RunList filter(Predicate predicate) { + public RunList filter(Predicate predicate) { size = null; first = null; base = Iterables.filter(base,predicate); diff --git a/core/src/main/java/jenkins/widgets/BuildListTable.java b/core/src/main/java/jenkins/widgets/BuildListTable.java new file mode 100644 index 0000000000000000000000000000000000000000..ec8e60e368373ad98619d354729f8a6a33770984 --- /dev/null +++ b/core/src/main/java/jenkins/widgets/BuildListTable.java @@ -0,0 +1,53 @@ +/* + * The MIT License + * + * Copyright 2013 Jesse Glick. + * + * 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. + */ + +package jenkins.widgets; + +import hudson.Functions; +import hudson.model.BallColor; +import hudson.model.Run; +import net.sf.json.JSONObject; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; + +@Restricted(DoNotUse.class) // only for buildListTable.jelly +public class BuildListTable extends RunListProgressiveRendering { + + @Override protected void calculate(Run build, JSONObject element) { + BallColor iconColor = build.getIconColor(); + element.put("iconColorOrdinal", iconColor.ordinal()); + element.put("iconColorDescription", iconColor.getDescription()); + element.put("url", build.getUrl()); + element.put("buildStatusUrl", build.getBuildStatusUrl()); + element.put("parentUrl", build.getParent().getUrl()); + element.put("parentFullDisplayName", Functions.breakableString(Functions.escape(build.getParent().getFullDisplayName()))); + element.put("displayName", build.getDisplayName()); + element.put("timestampString", build.getTimestampString()); + element.put("timestampString2", build.getTimestampString2()); + Run.Summary buildStatusSummary = build.getBuildStatusSummary(); + element.put("buildStatusSummaryWorse", buildStatusSummary.isWorse); + element.put("buildStatusSummaryMessage", buildStatusSummary.message); + } + +} diff --git a/core/src/main/java/jenkins/widgets/BuildTimeTrend.java b/core/src/main/java/jenkins/widgets/BuildTimeTrend.java new file mode 100644 index 0000000000000000000000000000000000000000..158ec398ea29cca22c0e2829b81c2fef394ed137 --- /dev/null +++ b/core/src/main/java/jenkins/widgets/BuildTimeTrend.java @@ -0,0 +1,65 @@ +/* + * The MIT License + * + * Copyright 2013 Jesse Glick. + * + * 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. + */ + +package jenkins.widgets; + +import hudson.model.AbstractBuild; +import hudson.model.BallColor; +import hudson.model.Node; +import hudson.model.Run; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; + +@Restricted(DoNotUse.class) // only for buildTimeTrend.jelly +public class BuildTimeTrend extends RunListProgressiveRendering { + + @Override protected void calculate(Run build, JSONObject element) { + BallColor iconColor = build.getIconColor(); + element.put("iconColorOrdinal", iconColor.ordinal()); + element.put("iconColorDescription", iconColor.getDescription()); + element.put("buildStatusUrl", build.getBuildStatusUrl()); + element.put("number", build.getNumber()); + element.put("displayName", build.getDisplayName()); + element.put("duration", build.getDuration()); + element.put("durationString", build.getDurationString()); + if (build instanceof AbstractBuild) { + AbstractBuild b = (AbstractBuild) build; + Node n = b.getBuiltOn(); + if (n == null) { + String ns = b.getBuiltOnStr(); + if (ns != null && !ns.isEmpty()) { + element.put("builtOnStr", ns); + } + } else if (n != Jenkins.getInstance()) { + element.put("builtOn", n.getNodeName()); + element.put("builtOnStr", n.getDisplayName()); + } else { + element.put("builtOnStr", hudson.model.Messages.Hudson_Computer_DisplayName()); + } + } + } + +} diff --git a/core/src/main/java/jenkins/widgets/RunListProgressiveRendering.java b/core/src/main/java/jenkins/widgets/RunListProgressiveRendering.java new file mode 100644 index 0000000000000000000000000000000000000000..5ab72a8a38eb2af4d3001058e443dcbdc1cd5972 --- /dev/null +++ b/core/src/main/java/jenkins/widgets/RunListProgressiveRendering.java @@ -0,0 +1,81 @@ +/* + * The MIT License + * + * Copyright 2013 Jesse Glick. + * + * 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. + */ + +package jenkins.widgets; + +import hudson.model.Run; +import hudson.util.RunList; +import java.util.ArrayList; +import java.util.List; +import jenkins.util.ProgressiveRendering; +import net.sf.json.JSON; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Makes it possible to incrementally render some information from a {@link RunList}. + */ +@Restricted(NoExternalUse.class) +public abstract class RunListProgressiveRendering extends ProgressiveRendering { + + /** + * Since we cannot predict how many runs there will be, just show an ever-growing progress bar. + * The first increment will be sized as if this many runs will be in the total, + * but then like Zeno’s paradox we will never seem to finish until we actually do. + */ + private static final double MAX_LIKELY_RUNS = 20; + private final List results = new ArrayList(); + private Iterable> builds; + + /** Jelly cannot call a constructor with arguments. */ + public void setBuilds(Iterable> builds) { + this.builds = builds; + } + + @Override protected void compute() throws Exception { + double decay = 1; + for (Run build : builds) { + if (canceled()) { + return; + } + JSONObject element = new JSONObject(); + calculate(build, element); + synchronized (results) { + results.add(element); + } + decay *= (1 - 1 / MAX_LIKELY_RUNS); + progress(1 - decay); + } + } + + @Override protected synchronized JSON data() { + JSONArray d = JSONArray.fromObject(results); + results.clear(); + return d; + } + + protected abstract void calculate(Run build, JSONObject element); +} diff --git a/core/src/main/resources/hudson/model/BuildTimelineWidget/control.jelly b/core/src/main/resources/hudson/model/BuildTimelineWidget/control.jelly index 394192552612be10400215b2cee2a83f289adb08..f695275f06656ae91e35c41097263479810c7a56 100644 --- a/core/src/main/resources/hudson/model/BuildTimelineWidget/control.jelly +++ b/core/src/main/resources/hudson/model/BuildTimelineWidget/control.jelly @@ -77,10 +77,7 @@ THE SOFTWARE. // theme1.autoWidth = true; // Set the Timeline's "width" automatically. // Set autoWidth on the Timeline's first band's theme, // will affect all bands. - theme1.timeline_start = new Date(${it.firstBuild.timeInMillis-24*60*60*1000}); - theme1.timeline_stop = new Date(${it.lastBuild.timeInMillis+24*60*60*1000}); - var d = new Date(${it.lastBuild.timeInMillis}); var bandInfos = [ // the bar that shows outline Timeline.createBandInfo({ diff --git a/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly b/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly index ec41aca7154d6c43bcc4ca890c331d62193aed1f..e389beed31b9ee2b53af2ed68460f43303d481f5 100644 --- a/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly +++ b/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly @@ -34,15 +34,39 @@ THE SOFTWARE.

${%Build Time Trend}

- -
[Build time graph]
- + + + ${handler.setBuilds(it.builds)} + +
@@ -51,33 +75,8 @@ THE SOFTWARE. - - - - - - - - - -
${%Build}${%Slave}
- ${r.iconColor.description} - - - ${r.displayName} - - - ${r.durationString} - - -
-
- - ${%More than 1 builds are needed for the trend report.} - -
diff --git a/core/src/main/resources/hudson/model/User/builds.jelly b/core/src/main/resources/hudson/model/User/builds.jelly index 7b7b63834f491d740960140cb9cf9bbda31cb946..cc4a6f28dc1aecaef19be227ca55f13d113c2548 100644 --- a/core/src/main/resources/hudson/model/User/builds.jelly +++ b/core/src/main/resources/hudson/model/User/builds.jelly @@ -30,6 +30,7 @@ THE SOFTWARE. ${%title(it)} + diff --git a/core/src/main/resources/lib/hudson/buildListTable.jelly b/core/src/main/resources/lib/hudson/buildListTable.jelly index cf2b131db24ba0ce844830fc3011623f3abf8a86..17d59a4bef4c4941b362e8eec37142c6681bc44e 100644 --- a/core/src/main/resources/lib/hudson/buildListTable.jelly +++ b/core/src/main/resources/lib/hudson/buildListTable.jelly @@ -35,6 +35,37 @@ THE SOFTWARE. + + + ${handler.setBuilds(attrs.builds)} + @@ -43,33 +74,6 @@ THE SOFTWARE. - - - - - - - - - -
${%Status}
- - ${b.iconColor.description} - - - - - ${b.displayName} - - ${b.timestampString} - - - - - ${%Console output} - -