Skip to content

Commit

Permalink
Merge branch 'master' into new-reorderable-list
Browse files Browse the repository at this point in the history
  • Loading branch information
janfaracik committed Oct 22, 2024
2 parents e2a3c74 + b6c4415 commit ad341fb
Show file tree
Hide file tree
Showing 220 changed files with 1,221 additions and 853 deletions.
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@

# Yarn
# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
/war/.yarn/plugins/** binary
/.yarn/plugins/** binary
4 changes: 4 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ jobs:
GIT_COMMITTER_EMAIL: <86592549+jenkins-infra-changelog-generator[bot]@users.noreply.github.com>
run: |
wget --quiet https://raw.githubusercontent.com/jenkinsci/core-changelog-generator/master/generate-weekly-changelog.sh
# Create a Python virtual environment for pip install
# See https://github.com/jenkinsci/core-changelog-generator/issues/37
python3 -m venv venv
source venv/bin/activate
bash generate-weekly-changelog.sh
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ node/
.git

# libraries / external deps / generated files
war/src/main/js/plugin-setup-wizard/bootstrap-detached.js
src/main/js/plugin-setup-wizard/bootstrap-detached.js
war/src/main/webapp/scripts/yui
war/src/main/webapp/jsbundles/
war/src/main/scss/_bootstrap.scss
src/main/scss/_bootstrap.scss

# test files that we don't need formatted
test/src/test/resources
Expand Down
2 changes: 1 addition & 1 deletion .stylelintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
extends: "stylelint-config-standard",
customSyntax: "postcss-scss",
ignoreFiles: ["war/src/main/scss/_bootstrap.scss"],
ignoreFiles: ["src/main/scss/_bootstrap.scss"],
rules: {
"no-descending-specificity": null,
"selector-class-pattern": "[a-z]",
Expand Down
2 changes: 1 addition & 1 deletion ath.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -o xtrace
cd "$(dirname "$0")"

# https://github.com/jenkinsci/acceptance-test-harness/releases
export ATH_VERSION=6038.v190f938efc87
export ATH_VERSION=6040.v72ed2f5b_59f6

if [[ $# -eq 0 ]]; then
export JDK=17
Expand Down
4 changes: 2 additions & 2 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ THE SOFTWARE.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>6.1.13</version>
<version>6.1.14</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<!-- https://docs.spring.io/spring-security/reference/6.3/getting-spring-security.html#getting-maven-no-boot -->
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>6.3.3</version>
<version>6.3.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class FlightRecorderInputStream extends InputStream {
* Size (in bytes) of the flight recorder ring buffer used for debugging remoting issues.
* @since 2.41
*/
static final int BUFFER_SIZE = Integer.getInteger("hudson.remoting.FlightRecorderInputStream.BUFFER_SIZE", 1024 * 1024);
static final int BUFFER_SIZE = Integer.getInteger("hudson.remoting.FlightRecorderInputStream.BUFFER_SIZE", 1024);

private final InputStream source;
private ByteArrayRingBuffer recorder = new ByteArrayRingBuffer(BUFFER_SIZE);
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/hudson/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,10 @@ public static Number tryParseNumber(@CheckForNull String numberStr, @CheckForNul
* does not contain the specified method.
*/
public static boolean isOverridden(@NonNull Class<?> base, @NonNull Class<?> derived, @NonNull String methodName, @NonNull Class<?>... types) {
if (base == derived) {
// If base and derived are the same type, the method is not overridden by definition
return false;
}
// If derived is not a subclass or implementor of base, it can't override any method
// Technically this should also be triggered when base == derived, because it can't override its own method, but
// the unit tests explicitly test for that as working.
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/hudson/logging/LogRecorder.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import hudson.remoting.VirtualChannel;
import hudson.slaves.ComputerListener;
import hudson.util.CopyOnWriteList;
import hudson.util.FormApply;
import hudson.util.FormValidation;
import hudson.util.HttpResponses;
import hudson.util.RingBufferLogHandler;
Expand Down Expand Up @@ -463,7 +464,7 @@ public synchronized void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rs

save();
if (oldFile != null) oldFile.delete();
rsp.sendRedirect2(redirect);
FormApply.success(redirect).generateResponse(req, rsp, null);
}

@RequirePOST
Expand Down
112 changes: 64 additions & 48 deletions core/src/main/java/hudson/model/Computer.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import hudson.util.DaemonThreadFactory;
import hudson.util.EditDistance;
import hudson.util.ExceptionCatchingThreadFactory;
import hudson.util.FormApply;
import hudson.util.Futures;
import hudson.util.IOUtils;
import hudson.util.NamingThreadFactory;
Expand Down Expand Up @@ -179,11 +180,6 @@

private long connectTime = 0;

/**
* True if Jenkins shouldn't start new builds on this node.
*/
private boolean temporarilyOffline;

/**
* {@link Node} object may be created and deleted independently
* from this object.
Expand Down Expand Up @@ -360,6 +356,13 @@ public AnnotatedLargeText<Computer> getLogText() {
*/
@Exported
public OfflineCause getOfflineCause() {
var node = getNode();
if (node != null) {
var temporaryOfflineCause = node.getTemporaryOfflineCause();
if (temporaryOfflineCause != null) {
return temporaryOfflineCause;
}
}
return offlineCause;
}

Expand All @@ -371,6 +374,7 @@ public boolean hasOfflineCause() {
@Exported
@Override
public String getOfflineCauseReason() {
var offlineCause = getOfflineCause();
if (offlineCause == null) {
return "";
}
Expand Down Expand Up @@ -549,7 +553,7 @@ public void cliDisconnect(String cause) throws ExecutionException, InterruptedEx
@Deprecated
public void cliOffline(String cause) throws ExecutionException, InterruptedException {
checkPermission(DISCONNECT);
setTemporarilyOffline(true, new ByCLI(cause));
setTemporaryOfflineCause(new ByCLI(cause));
}

/**
Expand All @@ -558,7 +562,7 @@ public void cliOffline(String cause) throws ExecutionException, InterruptedExcep
@Deprecated
public void cliOnline() throws ExecutionException, InterruptedException {
checkPermission(CONNECT);
setTemporarilyOffline(false, null);
setTemporaryOfflineCause(null);
}

/**
Expand Down Expand Up @@ -620,7 +624,7 @@ public BuildTimelineWidget getTimeline() {
@Exported
@Override
public boolean isOffline() {
return temporarilyOffline || getChannel() == null;
return isTemporarilyOffline() || getChannel() == null;
}

public final boolean isOnline() {
Expand Down Expand Up @@ -669,41 +673,64 @@ public boolean isLaunchSupported() {
@Exported
@Deprecated
public boolean isTemporarilyOffline() {
return temporarilyOffline;
var node = getNode();
return node != null && node.isTemporarilyOffline();
}

/**
* @deprecated as of 1.320.
* Use {@link #setTemporarilyOffline(boolean, OfflineCause)}
* Use {@link #setTemporaryOfflineCause(OfflineCause)}
*/
@Deprecated
public void setTemporarilyOffline(boolean temporarilyOffline) {
setTemporarilyOffline(temporarilyOffline, null);
setTemporaryOfflineCause(temporarilyOffline ? new OfflineCause.LegacyOfflineCause() : null);
}

/**
* @deprecated
* Use {@link #setTemporaryOfflineCause(OfflineCause)} instead.
*/
@Deprecated(since = "TODO")
public void setTemporarilyOffline(boolean temporarilyOffline, OfflineCause cause) {
if (cause == null) {
setTemporarilyOffline(temporarilyOffline);
} else {
setTemporaryOfflineCause(temporarilyOffline ? cause : null);
}
}

/**
* Marks the computer as temporarily offline. This retains the underlying
* {@link Channel} connection, but prevent builds from executing.
*
* @param cause
* If the first argument is true, specify the reason why the node is being put
* offline.
* @param temporaryOfflineCause The reason why the node is being put offline.
* If null, this cancels the status
* @since TODO
*/
public void setTemporarilyOffline(boolean temporarilyOffline, OfflineCause cause) {
offlineCause = temporarilyOffline ? cause : null;
this.temporarilyOffline = temporarilyOffline;
Node node = getNode();
if (node != null) {
node.setTemporaryOfflineCause(offlineCause);
public void setTemporaryOfflineCause(@CheckForNull OfflineCause temporaryOfflineCause) {
var node = getNode();
if (node == null) {
throw new IllegalStateException("Can't set a temporary offline cause if the node has been removed");
}
synchronized (statusChangeLock) {
statusChangeLock.notifyAll();
node.setTemporaryOfflineCause(temporaryOfflineCause);
}

/**
* @since TODO
* @return If the node is temporarily offline, the reason why.
*/
@SuppressWarnings("unused") // used by setOfflineCause.jelly
public String getTemporaryOfflineCauseReason() {
var node = getNode();
if (node == null) {
// Node was deleted; computer still exists
return null;
}
if (temporarilyOffline) {
Listeners.notify(ComputerListener.class, false, l -> l.onTemporarilyOffline(this, cause));
} else {
Listeners.notify(ComputerListener.class, false, l -> l.onTemporarilyOnline(this));
var cause = node.getTemporaryOfflineCause();
if (cause instanceof OfflineCause.UserCause userCause) {
return userCause.getMessage();
}
return cause != null ? cause.toString() : "";
}

@Exported
Expand Down Expand Up @@ -785,16 +812,6 @@ protected void setNode(Node node) {
this.nodeName = null;

setNumExecutors(node.getNumExecutors());
if (this.temporarilyOffline) {
// When we get a new node, push our current temp offline
// status to it (as the status is not carried across
// configuration changes that recreate the node).
// Since this is also called the very first time this
// Computer is created, avoid pushing an empty status
// as that could overwrite any status that the Node
// brought along from its persisted config data.
node.setTemporaryOfflineCause(this.offlineCause);
}
}

/**
Expand Down Expand Up @@ -1396,24 +1413,23 @@ public void doRssLatest(StaplerRequest2 req, StaplerResponse2 rsp) throws IOExce

@RequirePOST
public HttpResponse doToggleOffline(@QueryParameter String offlineMessage) throws IOException, ServletException {
if (!temporarilyOffline) {
checkPermission(DISCONNECT);
offlineMessage = Util.fixEmptyAndTrim(offlineMessage);
setTemporarilyOffline(!temporarilyOffline,
new OfflineCause.UserCause(User.current(), offlineMessage));
} else {
var node = getNode();
if (node == null) {
return HttpResponses.notFound();
}
if (node.isTemporarilyOffline()) {
checkPermission(CONNECT);
setTemporarilyOffline(!temporarilyOffline, null);
setTemporaryOfflineCause(null);
return HttpResponses.redirectToDot();
} else {
return doChangeOfflineCause(offlineMessage);
}
return HttpResponses.redirectToDot();
}

@RequirePOST
public HttpResponse doChangeOfflineCause(@QueryParameter String offlineMessage) throws IOException, ServletException {
checkPermission(DISCONNECT);
offlineMessage = Util.fixEmptyAndTrim(offlineMessage);
setTemporarilyOffline(true,
new OfflineCause.UserCause(User.current(), offlineMessage));
setTemporaryOfflineCause(new OfflineCause.UserCause(User.current(), Util.fixEmptyAndTrim(offlineMessage)));
return HttpResponses.redirectToDot();
}

Expand Down Expand Up @@ -1512,7 +1528,7 @@ public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOE
}

// take the user back to the agent top page.
rsp.sendRedirect2("../" + result.getNodeName() + '/');
FormApply.success("../" + result.getNodeName() + '/').generateResponse(req, rsp, null);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/ComputerSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public static List<NodeMonitor> get_monitors() {
* @deprecated Use {@link #getComputers()} instead.
* @return All {@link Computer} instances managed by this set.
*/
@Deprecated(since = "TODO")
@Deprecated(since = "2.480")
public Computer[] get_all() {
return getComputers().stream().filter(Computer.class::isInstance).toArray(Computer[]::new);
}
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/hudson/model/Descriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package hudson.model;

import static hudson.util.QuotedStringTokenizer.quote;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;

import edu.umd.cs.findbugs.annotations.CheckForNull;
Expand Down Expand Up @@ -1306,7 +1305,7 @@ public String getFormField() {
@Override
public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
if (FormApply.isApply(req)) {
FormApply.applyResponse("notificationBar.show(" + quote(getMessage()) + ",notificationBar.ERROR)")
FormApply.showNotification(getMessage(), FormApply.NotificationType.ERROR)
.generateResponse(req, rsp, node);
} else {
// for now, we can't really use the field name that caused the problem.
Expand Down
26 changes: 10 additions & 16 deletions core/src/main/java/hudson/model/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.BulkChange;
import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.FileSystemProvisioner;
Expand Down Expand Up @@ -69,6 +68,7 @@
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import jenkins.model.Nodes;
import jenkins.util.Listeners;
import jenkins.util.SystemProperties;
import jenkins.util.io.OnMaster;
import net.sf.json.JSONObject;
Expand Down Expand Up @@ -265,24 +265,13 @@ public void onLoad(Nodes parent, String name) {
}

/**
* Let Nodes be aware of the lifecycle of their own {@link Computer}.
* @return true if this node has a temporary offline cause set.
*/
@Extension
public static class InternalComputerListener extends ComputerListener {
@Override
public void onOnline(Computer c, TaskListener listener) {
Node node = c.getNode();

// At startup, we need to restore any previously in-effect temp offline cause.
// We wait until the computer is started rather than getting the data to it sooner
// so that the normal computer start up processing works as expected.
if (node != null && node.temporaryOfflineCause != null && node.temporaryOfflineCause != c.getOfflineCause()) {
c.setTemporarilyOffline(true, node.temporaryOfflineCause);
}
}
boolean isTemporarilyOffline() {
return temporaryOfflineCause != null;
}

private OfflineCause temporaryOfflineCause;
private volatile OfflineCause temporaryOfflineCause;

/**
* Enable a {@link Computer} to inform its node when it is taken
Expand All @@ -294,6 +283,11 @@ void setTemporaryOfflineCause(OfflineCause cause) {
temporaryOfflineCause = cause;
save();
}
if (temporaryOfflineCause != null) {
Listeners.notify(ComputerListener.class, false, l -> l.onTemporarilyOffline(toComputer(), temporaryOfflineCause));
} else {
Listeners.notify(ComputerListener.class, false, l -> l.onTemporarilyOnline(toComputer()));
}
} catch (java.io.IOException e) {
LOGGER.warning("Unable to complete save, temporary offline status will not be persisted: " + e.getMessage());
}
Expand Down
Loading

0 comments on commit ad341fb

Please sign in to comment.