diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 10637d666d68..2ba53d7182a0 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -90,6 +90,7 @@ import jenkins.model.BuildDiscarder; import jenkins.model.BuildDiscarderProperty; import jenkins.model.DirectlyModifiableTopLevelItemGroup; +import jenkins.model.HistoricalBuild; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import jenkins.model.ModelObjectWithChildren; @@ -636,9 +637,9 @@ protected HistoryWidget createHistoryWidget() { throw new IllegalStateException("HistoryWidget is now created via WidgetFactory implementation"); } - public static final HistoryWidget.Adapter HISTORY_ADAPTER = new Adapter<>() { + public static final HistoryWidget.Adapter HISTORY_ADAPTER = new Adapter<>() { @Override - public int compare(Run record, String key) { + public int compare(HistoricalBuild record, String key) { try { int k = Integer.parseInt(key); return record.getNumber() - k; @@ -648,12 +649,12 @@ public int compare(Run record, String key) { } @Override - public String getKey(Run record) { + public String getKey(HistoricalBuild record) { return String.valueOf(record.getNumber()); } @Override - public boolean isBuilding(Run record) { + public boolean isBuilding(HistoricalBuild record) { return record.isBuilding(); } diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index f4084bcbf254..5359634d9642 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -115,6 +115,7 @@ import jenkins.model.ArtifactManagerConfiguration; import jenkins.model.ArtifactManagerFactory; import jenkins.model.BuildDiscarder; +import jenkins.model.HistoricalBuild; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import jenkins.model.RunAction2; @@ -159,7 +160,7 @@ */ @ExportedBean public abstract class Run, RunT extends Run> - extends Actionable implements ExtensionPoint, Comparable, AccessControlled, PersistenceRoot, DescriptorByNameOwner, OnMaster, StaplerProxy, WithConsoleUrl { + extends Actionable implements ExtensionPoint, Comparable, AccessControlled, PersistenceRoot, DescriptorByNameOwner, OnMaster, StaplerProxy, HistoricalBuild, WithConsoleUrl { /** * The original {@link Queue.Item#getId()} has not yet been mapped onto the {@link Run} instance. @@ -167,15 +168,6 @@ public abstract class Run, RunT extends Run - * When a build is {@link #isBuilding() in progress}, this method - * returns an intermediate result. - * @return The status of the build, if it has completed or some build step has set a status; may be null if the build is ongoing. - */ @Exported + @Override public @CheckForNull Result getResult() { return result; } @@ -520,6 +505,7 @@ public void setResult(@NonNull Result r) { /** * Gets the subset of {@link #getActions()} that consists of {@link BuildBadgeAction}s. */ + @Override public @NonNull List getBadgeActions() { List r = getActions(BuildBadgeAction.class); if (isKeepLog()) { @@ -529,11 +515,8 @@ public void setResult(@NonNull Result r) { return r; } - /** - * Returns true if the build is not completed yet. - * This includes "not started yet" state. - */ @Exported + @Override public boolean isBuilding() { return state.compareTo(State.POST_PRODUCTION) < 0; } @@ -652,11 +635,11 @@ public final boolean isKeepLog() { } /** - * When the build is scheduled. - * + * {@inheritDoc} * @see #getStartTimeInMillis() */ @Exported + @Override public @NonNull Calendar getTimestamp() { GregorianCalendar c = new GregorianCalendar(); c.setTimeInMillis(timestamp); @@ -691,73 +674,12 @@ public final long getStartTimeInMillis() { } @Exported + @Override @CheckForNull public String getDescription() { return description; } - - /** - * Returns the length-limited description. - * The method tries to take HTML tags within the description into account, but it is a best-effort attempt. - * Also, the method will likely not work properly if a non-HTML {@link hudson.markup.MarkupFormatter} is used. - * @return The length-limited description. - * @deprecated truncated description based on the {@link #TRUNCATED_DESCRIPTION_LIMIT} setting. - */ - @Deprecated - public @CheckForNull String getTruncatedDescription() { - if (TRUNCATED_DESCRIPTION_LIMIT < 0) { // disabled - return description; - } - if (TRUNCATED_DESCRIPTION_LIMIT == 0) { // Someone wants to suppress descriptions, why not? - return ""; - } - - final int maxDescrLength = TRUNCATED_DESCRIPTION_LIMIT; - final String localDescription = description; - if (localDescription == null || localDescription.length() < maxDescrLength) { - return localDescription; - } - - final String ending = "..."; - final int sz = localDescription.length(), maxTruncLength = maxDescrLength - ending.length(); - - boolean inTag = false; - int displayChars = 0; - int lastTruncatablePoint = -1; - - for (int i = 0; i < sz; i++) { - char ch = localDescription.charAt(i); - if (ch == '<') { - inTag = true; - } else if (ch == '>') { - inTag = false; - if (displayChars <= maxTruncLength) { - lastTruncatablePoint = i + 1; - } - } - if (!inTag) { - displayChars++; - if (displayChars <= maxTruncLength && ch == ' ') { - lastTruncatablePoint = i; - } - } - } - - String truncDesc = localDescription; - - // Could not find a preferred truncatable index, force a trunc at maxTruncLength - if (lastTruncatablePoint == -1) - lastTruncatablePoint = maxTruncLength; - - if (displayChars >= maxDescrLength) { - truncDesc = truncDesc.substring(0, lastTruncatablePoint) + ending; - } - - return truncDesc; - - } - /** * Gets the string that says how long since this build has started. * @@ -776,9 +698,7 @@ public String getDescription() { return Util.XS_DATETIME_FORMATTER2.format(Instant.ofEpochMilli(timestamp)); } - /** - * Gets the string that says how long the build took to run. - */ + @Override public @NonNull String getDurationString() { if (hasntStartedYet()) { return Messages.Run_NotStartedYet(); @@ -797,9 +717,7 @@ public long getDuration() { return duration; } - /** - * Gets the icon color for display. - */ + @Override public @NonNull BallColor getIconColor() { if (!isBuilding()) { // already built @@ -834,6 +752,7 @@ public String toString() { } @Exported + @Override public String getFullDisplayName() { return project.getFullDisplayName() + ' ' + getDisplayName(); } @@ -859,6 +778,7 @@ public void setDisplayName(String value) throws IOException { } @Exported(visibility = 2) + @Override public int getNumber() { return number; } @@ -1036,14 +956,8 @@ protected void dropLinks() { return nextBuild; } - /** - * Returns the URL of this {@link Run}, relative to the context root of Hudson. - * - * @return - * String like "job/foo/32/" with trailing slash but no leading slash. - */ - // I really messed this up. I'm hoping to fix this some time - // it shouldn't have trailing '/', and instead it should have leading '/' + + @Override public @NonNull String getUrl() { // RUN may be accessed using permalinks, as "/lastSuccessful" or other, so try to retrieve this base URL @@ -1107,6 +1021,12 @@ public String getConsoleUrl() { return new File(project.getBuildDir(), Integer.toString(number)); } + @Override + public List getParameterValues() { + ParametersAction a = getAction(ParametersAction.class); + return a != null ? a.getParameters() : List.of(); + } + /** * Gets an object responsible for storing and retrieving build artifacts. * If {@link #pickArtifactManager} has previously been called on this build, @@ -2175,14 +2095,6 @@ public void doBuildStatus(StaplerRequest2 req, StaplerResponse2 rsp) throws IOEx rsp.sendRedirect2(req.getContextPath() + "/images/48x48/" + getBuildStatusUrl()); } - public @NonNull String getBuildStatusUrl() { - return getIconColor().getImage(); - } - - public String getBuildStatusIconClassName() { - return getIconColor().getIconClassName(); - } - public static class Summary { /** * Is this build worse or better, compared to the previous build? diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index 2c171b594f5a..bf75e2bf0c7a 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import jenkins.model.HistoricalBuild; import jenkins.model.Jenkins; import jenkins.model.queue.QueueItem; import jenkins.widgets.HistoryPageFilter; @@ -47,7 +48,7 @@ *

* This widget enhances {@link HistoryWidget} by groking the notion * that {@link #owner} can be in the queue toward the next build. - * + * @param typically {@link HistoricalBuild} * @author Kohsuke Kawaguchi */ public class BuildHistoryWidget extends HistoryWidget { @@ -84,7 +85,6 @@ public HistoryPageFilter getHistoryPageFilter() { final HistoryPageFilter historyPageFilter = newPageFilter(); historyPageFilter.add(baseList, getQueuedItems()); - historyPageFilter.widget = this; return updateFirstTransientBuildKey(historyPageFilter); } diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index 44f6de67ee6f..e7dcafbb5426 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -31,7 +31,6 @@ import hudson.model.Job; import hudson.model.ModelObject; import hudson.model.Queue; -import hudson.model.Run; import hudson.util.AlternativeUiTextProvider; import jakarta.servlet.ServletException; import java.io.IOException; @@ -40,6 +39,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; +import jenkins.model.HistoricalBuild; import jenkins.util.SystemProperties; import jenkins.widgets.HistoryPageEntry; import jenkins.widgets.HistoryPageFilter; @@ -53,12 +53,12 @@ import org.kohsuke.stapler.StaplerResponse2; /** - * Displays the history of records (normally {@link Run}s) on the side panel. + * Displays the history of records on the side panel. * * @param - * Owner of the widget. + * Owner of the widget, typically {@link Job} * @param - * Type individual record. + * Type individual record, typically {@link HistoricalBuild} * @author Kohsuke Kawaguchi */ public class HistoryWidget extends Widget { @@ -142,7 +142,7 @@ public String getFirstTransientBuildKey() { * @return * The history page filter that was passed in. */ - @SuppressWarnings("unchecked") + @SuppressWarnings("unchecked") // TODO actually not type-safe protected HistoryPageFilter updateFirstTransientBuildKey(HistoryPageFilter historyPageFilter) { updateFirstTransientBuildKey(historyPageFilter.runs); return historyPageFilter; @@ -195,7 +195,7 @@ private List> toPageEntries(Iterable historyItemList) { /** * Get a {@link jenkins.widgets.HistoryPageFilter} for rendering a page of queue items. */ - public HistoryPageFilter getHistoryPageFilter() { + public HistoryPageFilter getHistoryPageFilter() { HistoryPageFilter historyPageFilter = newPageFilter(); historyPageFilter.add(baseList); @@ -205,6 +205,7 @@ public HistoryPageFilter getHistoryPageFilter() { protected HistoryPageFilter newPageFilter() { HistoryPageFilter historyPageFilter = new HistoryPageFilter<>(THRESHOLD); + historyPageFilter.widget = this; if (newerThan != null) { historyPageFilter.setNewerThan(newerThan); diff --git a/core/src/main/java/jenkins/model/HistoricalBuild.java b/core/src/main/java/jenkins/model/HistoricalBuild.java new file mode 100644 index 000000000000..2f9f14aefff7 --- /dev/null +++ b/core/src/main/java/jenkins/model/HistoricalBuild.java @@ -0,0 +1,211 @@ +/* + * The MIT License + * + * Copyright 2024 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. + */ + +package jenkins.model; + +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.markup.MarkupFormatter; +import hudson.model.BallColor; +import hudson.model.BuildBadgeAction; +import hudson.model.ModelObject; +import hudson.model.ParameterValue; +import hudson.model.ParametersAction; +import hudson.model.Queue; +import hudson.model.Result; +import hudson.model.Run; +import hudson.widgets.BuildHistoryWidget; +import java.util.Calendar; +import java.util.List; +import jenkins.util.SystemProperties; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; + +/** + * A {@link Run}-like object as it might be displayed by {@link BuildHistoryWidget}. + * + * @since TODO + */ +@Restricted(Beta.class) +public interface HistoricalBuild extends ModelObject { + + /** + * @return A build number + */ + int getNumber(); + + /** + * Returns the URL of this {@link HistoricalBuild}, relative to the context root of Jenkins. + * + * @return + * String like "job/foo/32/" with trailing slash but no leading slash. + */ + @NonNull String getUrl(); + + /** + * Returns a human-readable description which is used on the main build page. + *

+ * It can also be quite long, and it may use markup in a format defined by a {@link hudson.markup.MarkupFormatter}. + * {@link #getTruncatedDescription()} may be used to retrieve a size-limited description, + * but it implies some limitations. + * @return the build description. + */ + @CheckForNull + String getDescription(); + + /** + * @return a human-readable full display name of this build. + */ + @NonNull + String getFullDisplayName(); + + /** + * Get the {@link Queue.Item#getId()} of the original queue item from where this {@link HistoricalBuild} instance + * originated. + * @return The queue item ID. + */ + long getQueueId(); + + /** + * Returns the build result. + * + *

+ * When a build is {@link #isBuilding() in progress}, this method + * returns an intermediate result. + * @return The status of the build, if it has completed or some build step has set a status; may be null if the build is ongoing. + */ + @CheckForNull + Result getResult(); + + /** @see ParametersAction#getParameters */ + @NonNull + List getParameterValues(); + + /** + * Returns true if the build is not completed yet. + * This includes "not started yet" state. + */ + boolean isBuilding(); + + /** + * Gets the icon color for display. + */ + @NonNull + BallColor getIconColor(); + + @NonNull + default String getBuildStatusIconClassName() { + return getIconColor().getIconClassName(); + } + + @NonNull + default String getBuildStatusUrl() { + return getIconColor().getImage(); + } + + /** + * When the build is scheduled. + */ + @NonNull + Calendar getTimestamp(); + + /** + * Gets the string that says how long the build took to run. + */ + @NonNull + String getDurationString(); + + /** + * Gets the list of {@link BuildBadgeAction}s applicable to this instance. + */ + @NonNull + List getBadgeActions(); + + /** + * Returns the length-limited description. + * The method tries to take HTML tags within the description into account, but it is a best-effort attempt. + * Also, the method will likely not work properly if a non-HTML {@link MarkupFormatter} is used. + * @return The length-limited description. + */ + @CheckForNull + default String getTruncatedDescription() { + String description = getDescription(); + /* + * Target size limit for truncated {@link #description}s in the Build History Widget. + * This is applied to the raw, unformatted description. Especially complex formatting + * like hyperlinks can result in much less text being shown than this might imply. + * Negative values will disable truncation, {@code 0} will enforce empty strings. + */ + int truncatedDescriptionLimit = SystemProperties.getInteger("historyWidget.descriptionLimit", 100); + if (truncatedDescriptionLimit < 0) { // disabled + return description; + } + if (truncatedDescriptionLimit == 0) { // Someone wants to suppress descriptions, why not? + return ""; + } + + if (description == null || description.length() < truncatedDescriptionLimit) { + return description; + } + + final String ending = "..."; + final int sz = description.length(), maxTruncLength = truncatedDescriptionLimit - ending.length(); + + boolean inTag = false; + int displayChars = 0; + int lastTruncatablePoint = -1; + + for (int i = 0; i < sz; i++) { + char ch = description.charAt(i); + if (ch == '<') { + inTag = true; + } else if (ch == '>') { + inTag = false; + if (displayChars <= maxTruncLength) { + lastTruncatablePoint = i + 1; + } + } + if (!inTag) { + displayChars++; + if (displayChars <= maxTruncLength && ch == ' ') { + lastTruncatablePoint = i; + } + } + } + + String truncDesc = description; + + // Could not find a preferred truncatable index, force a trunc at maxTruncLength + if (lastTruncatablePoint == -1) + lastTruncatablePoint = maxTruncLength; + + if (displayChars >= truncatedDescriptionLimit) { + truncDesc = truncDesc.substring(0, lastTruncatablePoint) + ending; + } + + return truncDesc; + + } + +} diff --git a/core/src/main/java/jenkins/widgets/HistoryPageEntry.java b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java index 98f0a7aac58e..2770fa928b02 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageEntry.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java @@ -26,16 +26,16 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.Run; +import jenkins.model.HistoricalBuild; import jenkins.model.queue.QueueItem; /** * Represents an entry used by the {@link HistoryPageFilter}. * *

- * Wraps {@link QueueItem} and {@link Run} instances from the build queue, normalizing + * Wraps {@link QueueItem} and {@link HistoricalBuild} instances from the build queue, normalizing * access to the info required for pagination. - * - * + * @param typically {@link HistoricalBuild} or {@link QueueItem} * @author tom.fennelly@gmail.com */ public class HistoryPageEntry { @@ -57,7 +57,7 @@ public long getEntryId() { protected static long getEntryId(@NonNull Object entry) { if (entry instanceof QueueItem) { return ((QueueItem) entry).getId(); - } else if (entry instanceof Run run) { + } else if (entry instanceof HistoricalBuild run) { return Long.MIN_VALUE + run.getNumber(); } else if (entry instanceof Number) { // Used for testing purposes because of JENKINS-30899 and JENKINS-30909 diff --git a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java index 6b6d9fa214cb..f51c27c22122 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -30,9 +30,6 @@ import hudson.model.AbstractBuild; import hudson.model.Job; import hudson.model.ParameterValue; -import hudson.model.ParametersAction; -import hudson.model.Queue; -import hudson.model.Run; import hudson.search.UserSearchProperty; import hudson.util.Iterators; import hudson.widgets.HistoryWidget; @@ -43,11 +40,13 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import jenkins.model.HistoricalBuild; import jenkins.model.queue.QueueItem; /** * History page filter. - * + * @param typically {@link HistoricalBuild} * @author tom.fennelly@gmail.com */ public class HistoryPageFilter { @@ -57,10 +56,10 @@ public class HistoryPageFilter { private Long olderThan; private String searchString; - // Need to use different Lists for QueueItem and Runs because + // Need to use different Lists for QueueItem and HistoricalBuilds because // we need access to them separately in the jelly files for rendering. public final List> queueItems = new ArrayList<>(); - public final List> runs = new ArrayList<>(); + public final List> runs = new ArrayList<>(); @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "read by Stapler") public boolean hasUpPage = false; // there are newer builds than on this page @@ -242,13 +241,9 @@ public int compare(Object o1, Object o2) { } private long getNextBuildNumber(@NonNull Object entry) { - if (entry instanceof QueueItem) { - Queue.Task task = ((QueueItem) entry).getTask(); - if (task instanceof Job) { - return ((Job) task).getNextBuildNumber(); - } - } else if (entry instanceof Run) { - return ((Run) entry).getParent().getNextBuildNumber(); + // TODO refactor into method on HistoryWidget + if (widget != null && widget.owner instanceof Job job) { + return job.getNextBuildNumber(); } // TODO maybe this should be an error? @@ -261,12 +256,13 @@ private void addQueueItem(QueueItem item) { updateNewestOldest(entry.getEntryId()); } - private void addRun(Run run) { - HistoryPageEntry entry = new HistoryPageEntry<>(run); + private void addRun(HistoricalBuild run) { + HistoryPageEntry entry = new HistoryPageEntry<>(run); // Assert that runs have been added in descending order if (!runs.isEmpty()) { if (entry.getEntryId() > runs.get(runs.size() - 1).getEntryId()) { - throw new IllegalStateException("Runs were out of order"); + throw new IllegalStateException("Cannot add newer " + run + " to descending-order list " + + runs.stream().map(HistoryPageEntry::getEntry).collect(Collectors.toList())); } } runs.add(entry); @@ -288,8 +284,7 @@ private boolean add(Object entry) { } addQueueItem(item); return true; - } else if (entry instanceof Run) { - Run run = (Run) entry; + } else if (entry instanceof HistoricalBuild run) { if (searchString != null && !fitsSearchParams(run)) { return false; } @@ -322,7 +317,7 @@ private boolean fitsSearchParams(@NonNull QueueItem item) { return false; } - private boolean fitsSearchParams(@NonNull Run run) { + private boolean fitsSearchParams(@NonNull HistoricalBuild run) { if (searchString == null) { return true; } @@ -340,8 +335,8 @@ private boolean fitsSearchParams(@NonNull Run run) { } else if (run instanceof AbstractBuild && fitsSearchBuildVariables((AbstractBuild) run)) { return true; } else { - ParametersAction parametersAction = run.getAction(ParametersAction.class); - if (parametersAction != null && fitsSearchBuildParameters(parametersAction)) { + List parameters = run.getParameterValues(); + if (fitsSearchBuildParameters(parameters)) { return true; } } @@ -381,8 +376,7 @@ private boolean fitsSearchBuildVariables(AbstractBuild runAsBuild) { return false; } - private boolean fitsSearchBuildParameters(ParametersAction parametersAction) { - List parameters = parametersAction.getParameters(); + private boolean fitsSearchBuildParameters(List parameters) { for (ParameterValue parameter : parameters) { if (!parameter.isSensitive() && fitsSearchString(parameter.getValue())) { return true; diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly deleted file mode 100644 index 54309319f0a3..000000000000 --- a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly index dc367464b57c..60c3bdec4aba 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly @@ -23,7 +23,7 @@ THE SOFTWARE. --> diff --git a/core/src/main/resources/lib/hudson/buildProgressBar.jelly b/core/src/main/resources/lib/hudson/buildProgressBar.jelly index 55d2a50c825b..49aac35f0909 100644 --- a/core/src/main/resources/lib/hudson/buildProgressBar.jelly +++ b/core/src/main/resources/lib/hudson/buildProgressBar.jelly @@ -26,8 +26,8 @@ THE SOFTWARE. Progress bar for a build in progress. - - Build in progress. Must have a url property. + + Build in progress. Must have a url property; may have an executor property. Executor that's carrying out the build. If null, defaults to "build.executor" @@ -37,9 +37,17 @@ THE SOFTWARE. - + + + + + + + + +