Skip to content

Commit

Permalink
Merge branch 'master' into new-build-history-2
Browse files Browse the repository at this point in the history
  • Loading branch information
janfaracik committed Jan 14, 2024
2 parents 61b0a87 + 1eb29a8 commit 855bf13
Show file tree
Hide file tree
Showing 118 changed files with 1,549 additions and 766 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/changelog.yml
Expand Up @@ -35,7 +35,7 @@ jobs:
env:
GITHUB_AUTH: github-actions:${{ secrets.GITHUB_TOKEN }}
- name: Upload Changelog YAML
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: changelog.yaml
path: changelog.yaml
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-release-artifact.yml
Expand Up @@ -16,11 +16,11 @@ jobs:
is-rc: ${{ steps.set-version.outputs.is-rc }}
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: 11
java-version: 17
cache: "maven"
- name: Set version
id: set-version
Expand Down
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
@@ -1,4 +1,4 @@
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 https://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extension>
<groupId>io.jenkins.tools.incrementals</groupId>
<artifactId>git-changelist-maven-extension</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Expand Up @@ -9,7 +9,7 @@ This page provides information about contributing code to the Jenkins core codeb
1. Fork the repository on GitHub
2. Clone the forked repository to your machine
3. Install the necessary development tools. In order to develop Jenkins, you need the following:
- Java Development Kit (JDK) 11 or 17.
- Java Development Kit (JDK) 11, 17 or 21.
In the Jenkins project we usually use [Eclipse Temurin](https://adoptium.net/) or [OpenJDK](https://openjdk.java.net/), but you can use other JDKs as well.
- Apache Maven 3.8.1 or above. You can [download Maven here](https://maven.apache.org/download.cgi).
In the Jenkins project we usually use the most recent Maven release.
Expand Down
2 changes: 1 addition & 1 deletion ath.sh
Expand Up @@ -6,7 +6,7 @@ set -o xtrace
cd "$(dirname "$0")"

# https://github.com/jenkinsci/acceptance-test-harness/releases
export ATH_VERSION=5740.vd30f30408987
export ATH_VERSION=5770.v81b_784f28b_d7

if [[ $# -eq 0 ]]; then
export JDK=17
Expand Down
12 changes: 6 additions & 6 deletions bom/pom.xml
Expand Up @@ -22,7 +22,7 @@ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand All @@ -39,7 +39,7 @@ THE SOFTWARE.

<properties>
<asm.version>9.6</asm.version>
<slf4jVersion>2.0.9</slf4jVersion>
<slf4jVersion>2.0.10</slf4jVersion>
<stapler.version>1822.v120278426e1c</stapler.version>
<groovy.version>2.4.21</groovy.version>
</properties>
Expand All @@ -64,7 +64,7 @@ THE SOFTWARE.
<!-- https://docs.spring.io/spring-security/site/docs/5.5.4/reference/html5/#getting-maven-no-boot -->
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>5.8.8</version>
<version>5.8.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand All @@ -82,7 +82,7 @@ THE SOFTWARE.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
<version>33.0.0-jre</version>
</dependency>
<dependency>
<!-- Overriding Stapler’s 1.1.3 version to diagnose JENKINS-20618: -->
Expand Down Expand Up @@ -196,9 +196,9 @@ THE SOFTWARE.
<version>${groovy.version}</version>
</dependency>
<dependency>
<groupId>org.connectbot.jbcrypt</groupId>
<groupId>org.connectbot</groupId>
<artifactId>jbcrypt</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
</dependency>
<dependency>
<!-- Groovy shell uses this, but it doesn't declare the dependency -->
Expand Down
2 changes: 1 addition & 1 deletion cli/pom.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down
4 changes: 2 additions & 2 deletions core/pom.xml
Expand Up @@ -23,7 +23,7 @@ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down Expand Up @@ -282,7 +282,7 @@ THE SOFTWARE.
<artifactId>groovy-all</artifactId>
</dependency>
<dependency>
<groupId>org.connectbot.jbcrypt</groupId>
<groupId>org.connectbot</groupId>
<artifactId>jbcrypt</artifactId>
</dependency>
<dependency>
Expand Down
17 changes: 2 additions & 15 deletions core/src/main/java/hudson/ClassicPluginStrategy.java
Expand Up @@ -86,11 +86,6 @@ public class ClassicPluginStrategy implements PluginStrategy {

private final PluginManager pluginManager;

/**
* All the plugins eventually delegate this classloader to load core, servlet APIs, and SE runtime.
*/
private final MaskingClassLoader coreClassLoader = new MaskingClassLoader(getClass().getClassLoader());

public ClassicPluginStrategy(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
Expand Down Expand Up @@ -235,16 +230,8 @@ private static Manifest loadLinkedManifest(File archive) throws IOException {

fix(atts, optionalDependencies);

// Register global classpath mask. This is useful for hiding JavaEE APIs that you might see from the container,
// such as database plugin for JPA support. The Mask-Classes attribute is insufficient because those classes
// also need to be masked by all the other plugins that depend on the database plugin.
String masked = atts.getValue("Global-Mask-Classes");
if (masked != null) {
for (String pkg : masked.trim().split("[ \t\r\n]+"))
coreClassLoader.add(pkg);
}

ClassLoader dependencyLoader = new DependencyClassLoader(coreClassLoader, archive, Util.join(dependencies, optionalDependencies), pluginManager);
ClassLoader dependencyLoader = new DependencyClassLoader(
getClass().getClassLoader(), archive, Util.join(dependencies, optionalDependencies), pluginManager);
dependencyLoader = getBaseClassLoader(atts, dependencyLoader);

return new PluginWrapper(pluginManager, archive, manifest, baseResourceURL,
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/ExtensionList.java
Expand Up @@ -468,7 +468,7 @@ public static <T> ExtensionList<T> create(Jenkins jenkins, Class<T> type) {
* @return the singleton instance of the given type in its list.
* @throws IllegalStateException if there are no instances
*
* @since TODO
* @since 2.435
*/
public static @NonNull <U> U lookupFirst(Class<U> type) {
var all = lookup(type);
Expand Down
42 changes: 40 additions & 2 deletions core/src/main/java/hudson/FilePath.java
Expand Up @@ -28,6 +28,7 @@

import static hudson.Util.fileToPath;
import static hudson.Util.fixEmpty;
import static hudson.Util.fixEmptyAndTrim;

import com.google.common.annotations.VisibleForTesting;
import com.jcraft.jzlib.GZIPInputStream;
Expand Down Expand Up @@ -962,7 +963,7 @@ public Void invoke(File dir, VirtualChannel channel) throws IOException {
* </ul>
*
* @param archive
* The resource that represents the tgz/zip file. This URL must support the {@code Last-Modified} header.
* The resource that represents the tgz/zip file. This URL must support the {@code Last-Modified} header or the {@code ETag} header.
* (For example, you could use {@link ClassLoader#getResource}.)
* @param listener
* If non-null, a message will be printed to this listener once this method decides to
Expand All @@ -984,12 +985,18 @@ private boolean installIfNecessaryFrom(@NonNull URL archive, @NonNull TaskListen
try {
FilePath timestamp = this.child(".timestamp");
long lastModified = timestamp.lastModified();
// https://httpwg.org/specs/rfc9110.html#field.etag is the ETag specification
// Read previously stored ETag if timestamp is available
String etag = timestamp.exists() ? fixEmptyAndTrim(timestamp.readToString()) : null;
URLConnection con;
try {
con = ProxyConfiguration.open(archive);
if (lastModified != 0) {
con.setIfModifiedSince(lastModified);
}
if (etag != null) {
con.setRequestProperty("If-None-Match", etag);
}
con.connect();
} catch (IOException x) {
if (this.exists()) {
Expand All @@ -1016,7 +1023,7 @@ private boolean installIfNecessaryFrom(@NonNull URL archive, @NonNull TaskListen
return false;
}
}
if (lastModified != 0) {
if (lastModified != 0 || etag != null) {
if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
return false;
} else if (responseCode != HttpURLConnection.HTTP_OK) {
Expand All @@ -1027,8 +1034,12 @@ private boolean installIfNecessaryFrom(@NonNull URL archive, @NonNull TaskListen
}

long sourceTimestamp = con.getLastModified();
String resultEtag = fixEmptyAndTrim(con.getHeaderField("ETag"));

if (this.exists()) {
if (equalETags(etag, resultEtag)) {
return false; // already up to date
}
if (lastModified != 0 && sourceTimestamp == lastModified)
return false; // already up to date
this.deleteContents();
Expand All @@ -1042,6 +1053,10 @@ private boolean installIfNecessaryFrom(@NonNull URL archive, @NonNull TaskListen
// First try to download from the agent machine.
try {
act(new Unpack(archive));
if (resultEtag != null && !equalETags(etag, resultEtag)) {
/* Store the ETag value in the timestamp file for later use */
timestamp.write(resultEtag, "UTF-8");
}
timestamp.touch(sourceTimestamp);
return true;
} catch (IOException x) {
Expand All @@ -1061,13 +1076,36 @@ private boolean installIfNecessaryFrom(@NonNull URL archive, @NonNull TaskListen
throw new IOException(String.format("Failed to unpack %s (%d bytes read of total %d)",
archive, cis.getByteCount(), con.getContentLength()), e);
}
if (resultEtag != null && !equalETags(etag, resultEtag)) {
/* Store the ETag value in the timestamp file for later use */
timestamp.write(resultEtag, "UTF-8");
}
timestamp.touch(sourceTimestamp);
return true;
} catch (IOException e) {
throw new IOException("Failed to install " + archive + " to " + remote, e);
}
}

/* Return true if etag1 equals etag2 as defined by the etag specification
https://httpwg.org/specs/rfc9110.html#field.etag
*/
private boolean equalETags(String etag1, String etag2) {
if (etag1 == null || etag2 == null) {
return false;
}
if (etag1.equals(etag2)) {
return true;
}
/* Weak tags are identified by leading characters "W/" as a marker */
/* Weak tag marker must not be considered in tag comparison.
This implements the weak comparison in the specification at
https://httpwg.org/specs/rfc9110.html#field.etag */
String opaqueTag1 = etag1.startsWith("W/") ? etag1.substring(2) : etag1;
String opaqueTag2 = etag2.startsWith("W/") ? etag2.substring(2) : etag2;
return opaqueTag1.equals(opaqueTag2);
}

// this reads from arbitrary URL
private static final class Unpack extends MasterToSlaveFileCallable<Void> {
private final URL archive;
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/hudson/Functions.java
Expand Up @@ -692,13 +692,13 @@ public static String getUserTimeZone() {
}

@Restricted(NoExternalUse.class)
public static String getUserTimeZonePostfix() {
public static String getUserTimeZonePostfix(Date date) {
if (!isUserTimeZoneOverride()) {
return "";
}

TimeZone tz = TimeZone.getTimeZone(getUserTimeZone());
return tz.getDisplayName(tz.observesDaylightTime(), TimeZone.SHORT);
return tz.getDisplayName(tz.inDaylightTime(date), TimeZone.SHORT, getCurrentLocale());
}

@Restricted(NoExternalUse.class)
Expand Down Expand Up @@ -1909,7 +1909,7 @@ public static String joinPath(String... components) {
* Computes the link to the console for the run for the specified executable, taking {@link ConsoleUrlProvider} into account.
* @param executable the executable (normally a {@link Run})
* @return the absolute URL for accessing the build console for the executable, or null if there is no build associated with the executable
* @since TODO
* @since 2.433
*/
public static @CheckForNull String getConsoleUrl(Queue.Executable executable) {
if (executable == null) {
Expand Down
26 changes: 25 additions & 1 deletion core/src/main/java/hudson/WebAppMain.java
Expand Up @@ -48,6 +48,7 @@
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -261,13 +262,36 @@ public void run() {
new HudsonFailedToLoad(e).publish(context, _home);
throw e;
} catch (Exception e) {
new HudsonFailedToLoad(e).publish(context, _home);
// Allow plugins to override error page on boot with custom BootFailure subclass thrown
Throwable error = unwrapException(e);
if (error instanceof InvocationTargetException) {
Throwable targetException = ((InvocationTargetException) error).getTargetException();

if (targetException instanceof BootFailure) {
((BootFailure) targetException).publish(context, _home);
} else {
new HudsonFailedToLoad(e).publish(context, _home);
}
} else {
new HudsonFailedToLoad(e).publish(context, _home);
}
} finally {
Jenkins instance = Jenkins.getInstanceOrNull();
if (!success && instance != null)
instance.cleanUp();
}
}

private Throwable unwrapException(Exception e) {
Throwable error = e;
while (error.getCause() != null) {
if (error.getCause() instanceof InvocationTargetException) {
return error.getCause();
}
error = error.getCause();
}
return error;
}
};
initThread.start();
} catch (BootFailure e) {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/cli/declarative/CLIMethod.java
Expand Up @@ -28,12 +28,12 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import hudson.cli.CLICommand;
import hudson.util.ListBoxModel.Option;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.jvnet.hudson.annotation_indexer.Indexed;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;

/**
* Annotates methods on model objects to expose them as CLI commands.
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/hudson/model/BuildTimelineWidget.java
Expand Up @@ -40,9 +40,9 @@
*
* @author Kohsuke Kawaguchi
* @since 1.372
* @deprecated since TODO
* @deprecated since 2.431
*/
@Deprecated
@Deprecated(since = "2.431")
public class BuildTimelineWidget {
protected final RunList<?> builds;

Expand Down
24 changes: 21 additions & 3 deletions core/src/main/java/hudson/model/ComputerSet.java
Expand Up @@ -352,15 +352,33 @@ public synchronized HttpResponse doConfigSubmit(StaplerRequest req) throws IOExc
BulkChange bc = new BulkChange(MONITORS_OWNER);
try {
Jenkins.get().checkPermission(Jenkins.MANAGE);
monitors.rebuild(req, req.getSubmittedForm(), getNodeMonitorDescriptors());
JSONObject json = req.getSubmittedForm();
monitors.rebuild(req, json, getNodeMonitorDescriptors());

// add in the rest of instances are ignored instances
for (Descriptor<NodeMonitor> d : NodeMonitor.all())
if (monitors.get(d) == null) {
for (Descriptor<NodeMonitor> d : NodeMonitor.all()) {
NodeMonitor monitor = monitors.get(d);
if (monitor == null) {
NodeMonitor i = createDefaultInstance(d, true);
if (i != null)
monitors.add(i);
} else {
/*
* Some monitors in plugins do not have a DataBoundConstructor
* but a Descriptor that overrides newInstance. For those the ignored
* field is not set, so we have to explicitly set it.
*/
String name = d.getJsonSafeClassName();
JSONObject o = json.optJSONObject(name);
boolean ignored = true;
if (o != null) {
if (o.containsKey("ignored")) {
ignored = o.getBoolean("ignored");
}
}
monitor.setIgnored(ignored);
}
}

// recompute the data
for (NodeMonitor nm : monitors) {
Expand Down

0 comments on commit 855bf13

Please sign in to comment.