Skip to content

Commit

Permalink
Merge branch 'master' into JENKINS-70922-selectjs
Browse files Browse the repository at this point in the history
  • Loading branch information
timja authored May 16, 2023
2 parents 9bee3b1 + 7e23531 commit c450379
Show file tree
Hide file tree
Showing 71 changed files with 839 additions and 101 deletions.
7 changes: 6 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,14 @@ updates:
# Starting with 6.x, Spring Security requires Java 17 at a minimum.
- dependency-name: "org.springframework.security:spring-security-bom"
versions: [">=6.0.0"]

# Starting with 7.x, Guice switches from javax.* to jakarta.* bindings.
# See https://github.com/google/guice/wiki/Guice700
- dependency-name: "com.google.inject:guice-bom"
versions: [">=7.0.0"]
- package-ecosystem: "maven"
directory: "/"
target-branch: "stable-2.375"
target-branch: "stable-2.401"
labels:
- "into-lts"
- "needs-justification"
Expand Down
2 changes: 1 addition & 1 deletion bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ THE SOFTWARE.
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice-bom</artifactId>
<version>5.1.0</version>
<version>6.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
3 changes: 3 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,9 @@ THE SOFTWARE.
<phase>generate-sources</phase>
<configuration>
<sources>
<!-- The antlr4 sources are found automatically by the maven compiler,
but listing them explicitly avoids a missing classpath entry when importing the maven project in eclipse. -->
<source>${project.build.directory}/generated-sources/antlr4</source>
<source>${project.build.directory}/generated-sources/localizer</source>
<source>${project.build.directory}/generated-sources/taglib-interface</source>
</sources>
Expand Down
57 changes: 32 additions & 25 deletions core/src/main/java/hudson/model/Queue.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package hudson.model;

import static hudson.init.InitMilestone.JOB_CONFIG_ADAPTED;
import static hudson.model.Item.CANCEL;
import static hudson.util.Iterators.reverse;

import com.google.common.annotations.VisibleForTesting;
Expand Down Expand Up @@ -112,6 +113,7 @@
import jenkins.model.Jenkins;
import jenkins.model.queue.AsynchronousExecution;
import jenkins.model.queue.CompositeCauseOfBlockage;
import jenkins.model.queue.QueueItem;
import jenkins.security.QueueItemAuthenticator;
import jenkins.security.QueueItemAuthenticatorProvider;
import jenkins.security.stapler.StaplerAccessibleType;
Expand Down Expand Up @@ -1929,25 +1931,34 @@ default CauseOfBlockage getCauseOfBlockage() {
* Checks the permission to see if the current user can abort this executable.
* Returns normally from this method if it's OK.
* <p>
* NOTE: If you have implemented {@link AccessControlled} this should just be
* NOTE: If you have implemented {@link AccessControlled} this defaults to
* {@code checkPermission(hudson.model.Item.CANCEL);}
*
* @throws AccessDeniedException if the permission is not granted.
*/
void checkAbortPermission();
default void checkAbortPermission() {
if (this instanceof AccessControlled) {
((AccessControlled) this).checkPermission(CANCEL);
}
}

/**
* Works just like {@link #checkAbortPermission()} except it indicates the status by a return value,
* instead of exception.
* Also used by default for {@link hudson.model.Queue.Item#hasCancelPermission}.
* <p>
* NOTE: If you have implemented {@link AccessControlled} this should just be
* NOTE: If you have implemented {@link AccessControlled} this returns by default
* {@code return hasPermission(hudson.model.Item.CANCEL);}
*
* @return false
* if the user doesn't have the permission.
*/
boolean hasAbortPermission();
default boolean hasAbortPermission() {
if (this instanceof AccessControlled) {
return ((AccessControlled) this).hasPermission(CANCEL);
}
return true;
}

/**
* Returns the URL of this task relative to the context root of the application.
Expand Down Expand Up @@ -2117,7 +2128,7 @@ default long getEstimatedDuration() {
* Item in a queue.
*/
@ExportedBean(defaultVisibility = 999)
public abstract static class Item extends Actionable {
public abstract static class Item extends Actionable implements QueueItem {

private final long id;

Expand All @@ -2128,6 +2139,7 @@ public abstract static class Item extends Actionable {
* @since 1.601
*/
@Exported
@Override
public long getId() {
return id;
}
Expand All @@ -2147,12 +2159,19 @@ public int getIdLegacy() {
* Project to be built.
*/
@Exported
@NonNull
public final Task task;

private /*almost final*/ transient FutureImpl future;

private final long inQueueSince;

@Override
@NonNull
public Task getTask() {
return task;
}

/**
* Build is blocked because another build is in progress,
* required {@link Resource}s are not available, or otherwise blocked
Expand All @@ -2173,6 +2192,7 @@ public int getIdLegacy() {
* True if the item is starving for an executor for too long.
*/
@Exported
@Override
public boolean isStuck() { return false; }

/**
Expand All @@ -2188,6 +2208,7 @@ public long getInQueueSince() {
* Returns a human readable presentation of how long this item is already in the queue.
* E.g. something like '3 minutes 40 seconds'
*/
@Override
public String getInQueueForString() {
long duration = System.currentTimeMillis() - this.inQueueSince;
return Util.getTimeSpanString(duration);
Expand Down Expand Up @@ -2250,6 +2271,7 @@ public final List<Cause> getCauses() {
}

@Restricted(DoNotUse.class) // used from Jelly
@Override
public String getCausesDescription() {
List<Cause> causes = getCauses();
StringBuilder s = new StringBuilder();
Expand All @@ -2259,15 +2281,11 @@ public String getCausesDescription() {
return s.toString();
}

protected Item(Task task, List<Action> actions, long id, FutureImpl future) {
this.task = task;
this.id = id;
this.future = future;
this.inQueueSince = System.currentTimeMillis();
for (Action action : actions) addAction(action);
protected Item(@NonNull Task task, @NonNull List<Action> actions, long id, FutureImpl future) {
this(task, actions, id, future, System.currentTimeMillis());
}

protected Item(Task task, List<Action> actions, long id, FutureImpl future, long inQueueSince) {
protected Item(@NonNull Task task, @NonNull List<Action> actions, long id, FutureImpl future, long inQueueSince) {
this.task = task;
this.id = id;
this.future = future;
Expand Down Expand Up @@ -2297,6 +2315,7 @@ public String getUrl() {
* Gets a human-readable status message describing why it's in the queue.
*/
@Exported
@Override
public final String getWhy() {
CauseOfBlockage cob = getCauseOfBlockage();
return cob != null ? cob.getShortDescription() : null;
Expand All @@ -2312,6 +2331,7 @@ public final String getWhy() {
* @return String
*/
@Exported
@Override
public String getParams() {
StringBuilder s = new StringBuilder();
for (ParametersAction pa : getActions(ParametersAction.class)) {
Expand All @@ -2322,19 +2342,6 @@ public String getParams() {
return s.toString();
}

/**
* Checks whether a scheduled item may be canceled.
* @return by default, the same as {@link hudson.model.Queue.Task#hasAbortPermission}
*/
public boolean hasCancelPermission() {
return task.hasAbortPermission();
}

@Override
public String getDisplayName() {
return null;
}

@Override
public String getSearchUrl() {
return null;
Expand Down
47 changes: 34 additions & 13 deletions core/src/main/java/hudson/util/XStream2.java
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,18 @@ public Class realClass(String elementName) {
*/
private static final class AssociatedConverterImpl implements Converter {
private final XStream xstream;
private final ConcurrentHashMap<Class<?>, Converter> cache =
new ConcurrentHashMap<>();
private static final ClassValue<Class<? extends ConverterMatcher>> classCache = new ClassValue<Class<? extends ConverterMatcher>>() {
@Override
protected Class<? extends ConverterMatcher> computeValue(Class<?> type) {
return computeConverterClass(type);
}
};
private final ClassValue<Converter> cache = new ClassValue<Converter>() {
@Override
protected Converter computeValue(Class<?> type) {
return computeConverter(type);
}
};

private AssociatedConverterImpl(XStream xstream) {
this.xstream = xstream;
Expand All @@ -481,17 +491,33 @@ private Converter findConverter(@CheckForNull Class<?> t) {
if (t == null) {
return null;
}
return cache.get(t);
}

Converter result = cache.get(t);
if (result != null)
// ConcurrentHashMap does not allow null, so use this object to represent null
return result == this ? null : result;
@CheckForNull
private static Class<? extends ConverterMatcher> computeConverterClass(@NonNull Class<?> t) {
try {
final ClassLoader classLoader = t.getClassLoader();
if (classLoader == null) {
return null;
}
Class<?> cl = classLoader.loadClass(t.getName() + "$ConverterImpl");
String name = t.getName() + "$ConverterImpl";
if (classLoader.getResource(name.replace('.', '/') + ".class") == null) {
return null;
}
return classLoader.loadClass(name).asSubclass(ConverterMatcher.class);
} catch (ClassNotFoundException e) {
return null;
}
}

@CheckForNull
private Converter computeConverter(@NonNull Class<?> t) {
Class<? extends ConverterMatcher> cl = classCache.get(t);
if (cl == null) {
return null;
}
try {
Constructor<?> c = cl.getConstructors()[0];

Class<?>[] p = c.getParameterTypes();
Expand All @@ -506,14 +532,9 @@ else if (p[i] == Mapper.class)

}
ConverterMatcher cm = (ConverterMatcher) c.newInstance(args);
result = cm instanceof SingleValueConverter
return cm instanceof SingleValueConverter
? new SingleValueConverterWrapper((SingleValueConverter) cm)
: (Converter) cm;
cache.put(t, result);
return result;
} catch (ClassNotFoundException e) {
cache.put(t, this); // See above.. this object in cache represents null
return null;
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError();
x.initCause(e);
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/java/hudson/widgets/BuildHistoryWidget.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@

package hudson.widgets;

import hudson.model.Queue.Item;
import hudson.model.Queue.Task;
import java.util.LinkedList;
import java.util.List;
import jenkins.model.Jenkins;
import jenkins.model.queue.QueueItem;
import jenkins.widgets.HistoryPageFilter;

/**
Expand All @@ -52,17 +52,17 @@ public BuildHistoryWidget(Task owner, Iterable<T> baseList, Adapter<? super T> a
/**
* Returns the first queue item if the owner is scheduled for execution in the queue.
*/
public Item getQueuedItem() {
public QueueItem getQueuedItem() {
return Jenkins.get().getQueue().getItem(owner);
}

/**
* Returns the queue item if the owner is scheduled for execution in the queue, in REVERSE ORDER
*/
public List<Item> getQueuedItems() {
LinkedList<Item> list = new LinkedList<>();
for (Item item : Jenkins.get().getQueue().getItems()) {
if (item.task == owner) {
public List<QueueItem> getQueuedItems() {
LinkedList<QueueItem> list = new LinkedList<>();
for (QueueItem item : Jenkins.get().getQueue().getItems()) {
if (item.getTask() == owner) {
list.addFirst(item);
}
}
Expand Down
78 changes: 78 additions & 0 deletions core/src/main/java/jenkins/model/queue/QueueItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package jenkins.model.queue;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.model.Cause;
import hudson.model.ModelObject;
import hudson.model.Queue;
import hudson.model.Run;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.Beta;

/**
* Interface used by Jelly views to render a queue item through {@code <t:queue>}.
* @since TODO
*/
@Restricted(Beta.class)
public interface QueueItem extends ModelObject {
/**
* @return true if the item is starving for an executor for too long.
*/
boolean isStuck();

/**
* @return The underlying {@link Queue.Task} currently in queue.
*/
@NonNull
Queue.Task getTask();

/**
* Checks whether a scheduled item may be canceled.
* @return by default, the same as {@link Queue.Task#hasAbortPermission}
*/
default boolean hasCancelPermission() {
return getTask().hasAbortPermission();
}

/**
* Unique ID (per controller) that tracks the {@link Queue.Task} as it moves through different stages
* in the queue (each represented by different implementations of {@link QueueItem} and into any subsequent
* {@link Run} instance (see {@link Run#getQueueId()}).
*/
long getId();

/**
* Convenience method that returns a read only view of the {@link Cause}s associated with this item in the queue as a single string.
*/
@NonNull
String getCausesDescription();

/**
* Gets a human-readable status message describing why it's in the queue.
* May return null if there is no cause of blockage.
*/
@CheckForNull
String getWhy();

/**
* Gets a human-readable message about the parameters of this item
*/
@NonNull
String getParams();

/**
* Returns a human readable presentation of how long this item is already in the queue.
* E.g. something like '3 minutes 40 seconds'
*/
@NonNull
String getInQueueForString();

/**
* @return a display name for this queue item; by default, {@link Queue.Task#getFullDisplayName()}
*/
@CheckForNull
@Override
default String getDisplayName() {
return getTask().getFullDisplayName();
}
}
Loading

0 comments on commit c450379

Please sign in to comment.