Skip to content

Commit 557443f

Browse files
authored
Merge branch 'master' into un-inline-build-now
2 parents 3fc78c5 + c5fbbbe commit 557443f

File tree

164 files changed

+2260
-914
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

164 files changed

+2260
-914
lines changed

.github/workflows/changelog.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
private_key: ${{ secrets.JENKINS_CHANGELOG_UPDATER_PRIVATE_KEY }}
5252
repository: jenkins-infra/jenkins.io
5353
- name: Check out
54-
uses: actions/checkout@v3
54+
uses: actions/checkout@v4
5555
with:
5656
fetch-depth: 0
5757
- name: Publish jenkins.io changelog draft

.github/workflows/publish-release-artifact.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
project-version: ${{ steps.set-version.outputs.project-version }}
1515
is-lts: ${{ steps.set-version.outputs.is-lts }}
1616
steps:
17-
- uses: actions/checkout@v3
17+
- uses: actions/checkout@v4
1818
- name: Set up JDK 11
1919
uses: actions/setup-java@v3
2020
with:

bom/pom.xml

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ THE SOFTWARE.
3939

4040
<properties>
4141
<asm.version>9.5</asm.version>
42-
<slf4jVersion>2.0.7</slf4jVersion>
42+
<slf4jVersion>2.0.9</slf4jVersion>
4343
<stapler.version>1802.v9e2750160d01</stapler.version>
4444
<groovy.version>2.4.21</groovy.version>
4545
</properties>
@@ -64,7 +64,7 @@ THE SOFTWARE.
6464
<!-- https://docs.spring.io/spring-security/site/docs/5.5.4/reference/html5/#getting-maven-no-boot -->
6565
<groupId>org.springframework.security</groupId>
6666
<artifactId>spring-security-bom</artifactId>
67-
<version>5.8.5</version>
67+
<version>5.8.6</version>
6868
<type>pom</type>
6969
<scope>import</scope>
7070
</dependency>
@@ -189,12 +189,12 @@ THE SOFTWARE.
189189
<dependency>
190190
<groupId>org.apache.ant</groupId>
191191
<artifactId>ant</artifactId>
192-
<version>1.10.13</version>
192+
<version>1.10.14</version>
193193
</dependency>
194194
<dependency>
195195
<groupId>org.apache.commons</groupId>
196196
<artifactId>commons-compress</artifactId>
197-
<version>1.23.0</version>
197+
<version>1.24.0</version>
198198
</dependency>
199199
<dependency>
200200
<groupId>org.codehaus.groovy</groupId>

core/src/main/java/hudson/init/InitStrategy.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.ArrayList;
1010
import java.util.Arrays;
1111
import java.util.Collection;
12+
import java.util.Comparator;
1213
import java.util.Iterator;
1314
import java.util.List;
1415
import java.util.ServiceLoader;
@@ -64,7 +65,11 @@ private void listPluginFiles(PluginManager pm, String extension, Collection<File
6465
if (files == null)
6566
throw new IOException("Jenkins is unable to create " + pm.rootDir + "\nPerhaps its security privilege is insufficient");
6667

67-
all.addAll(Arrays.asList(files));
68+
List<File> pluginFiles = new ArrayList<>();
69+
pluginFiles.addAll(List.of(files));
70+
pluginFiles.sort(Comparator.comparing(File::getName));
71+
72+
all.addAll(pluginFiles);
6873
}
6974

7075
/**
@@ -76,15 +81,16 @@ private void listPluginFiles(PluginManager pm, String extension, Collection<File
7681
protected void getBundledPluginsFromProperty(final List<File> r) {
7782
String hplProperty = SystemProperties.getString("hudson.bundled.plugins");
7883
if (hplProperty != null) {
84+
List<File> pluginFiles = new ArrayList<>();
7985
for (String hplLocation : hplProperty.split(",")) {
8086
File hpl = new File(hplLocation.trim());
8187
if (hpl.exists()) {
82-
r.add(hpl);
88+
pluginFiles.add(hpl);
8389
} else if (hpl.getName().contains("*")) {
8490
try {
8591
new DirScanner.Glob(hpl.getName(), null).scan(hpl.getParentFile(), new FileVisitor() {
8692
@Override public void visit(File f, String relativePath) throws IOException {
87-
r.add(f);
93+
pluginFiles.add(f);
8894
}
8995
});
9096
} catch (IOException x) {
@@ -94,6 +100,8 @@ protected void getBundledPluginsFromProperty(final List<File> r) {
94100
LOGGER.warning("bundled plugin " + hplLocation + " does not exist");
95101
}
96102
}
103+
pluginFiles.sort(Comparator.comparing(File::getName));
104+
r.addAll(pluginFiles);
97105
}
98106
}
99107

core/src/main/java/hudson/model/Label.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -592,10 +592,16 @@ public static Set<LabelAtom> parse(@CheckForNull String labels) {
592592
final Set<LabelAtom> r = new TreeSet<>();
593593
labels = fixNull(labels);
594594
if (labels.length() > 0) {
595-
final QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(labels);
596-
while (tokenizer.hasMoreTokens())
597-
r.add(Jenkins.get().getLabelAtom(tokenizer.nextToken()));
595+
Jenkins j = Jenkins.get();
596+
LabelAtom labelAtom = j.tryGetLabelAtom(labels);
597+
if (labelAtom == null) {
598+
final QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(labels);
599+
while (tokenizer.hasMoreTokens())
600+
r.add(j.getLabelAtom(tokenizer.nextToken()));
601+
} else {
602+
r.add(labelAtom);
598603
}
604+
}
599605
return r;
600606
}
601607

core/src/main/java/hudson/model/Node.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import net.sf.json.JSONObject;
6969
import org.jvnet.localizer.Localizable;
7070
import org.kohsuke.accmod.Restricted;
71+
import org.kohsuke.accmod.restrictions.NoExternalUse;
7172
import org.kohsuke.accmod.restrictions.ProtectedExternally;
7273
import org.kohsuke.stapler.BindInterceptor;
7374
import org.kohsuke.stapler.Stapler;
@@ -298,20 +299,31 @@ public OfflineCause getTemporaryOfflineCause() {
298299
public TagCloud<LabelAtom> getLabelCloud() {
299300
return new TagCloud<>(getAssignedLabels(), Label::getTiedJobCount);
300301
}
302+
303+
/**
304+
* @return An immutable set of LabelAtom associated with the current node label.
305+
*/
306+
@NonNull
307+
@Restricted(NoExternalUse.class)
308+
protected Set<LabelAtom> getLabelAtomSet() {
309+
// Default implementation doesn't cache, since we can't hook on label updates.
310+
return Collections.unmodifiableSet(Label.parse(getLabelString()));
311+
}
312+
301313
/**
302314
* Returns the possibly empty set of labels that are assigned to this node,
303315
* including the automatic {@link #getSelfLabel() self label}, manually
304316
* assigned labels and dynamically assigned labels via the
305317
* {@link LabelFinder} extension point.
306318
*
307319
* This method has a side effect of updating the hudson-wide set of labels
308-
* and should be called after events that will change that - e.g. a agent
320+
* and should be called after events that will change that - e.g. an agent
309321
* connecting.
310322
*/
311323

312324
@Exported
313325
public Set<LabelAtom> getAssignedLabels() {
314-
Set<LabelAtom> r = Label.parse(getLabelString());
326+
Set<LabelAtom> r = new HashSet<>(getLabelAtomSet());
315327
r.add(getSelfLabel());
316328
r.addAll(getDynamicLabels());
317329
return Collections.unmodifiableSet(r);

core/src/main/java/hudson/model/Slave.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import hudson.Util;
3737
import hudson.cli.CLI;
3838
import hudson.model.Descriptor.FormException;
39+
import hudson.model.labels.LabelAtom;
3940
import hudson.remoting.Callable;
4041
import hudson.remoting.Channel;
4142
import hudson.remoting.Which;
@@ -60,6 +61,7 @@
6061
import java.net.URLConnection;
6162
import java.util.ArrayList;
6263
import java.util.Collection;
64+
import java.util.Collections;
6365
import java.util.List;
6466
import java.util.Set;
6567
import java.util.jar.JarFile;
@@ -179,6 +181,7 @@ protected Slave(@NonNull String name, String remoteFS, ComputerLauncher launcher
179181
this.name = name;
180182
this.remoteFS = remoteFS;
181183
this.launcher = launcher;
184+
this.labelAtomSet = Collections.unmodifiableSet(Label.parse(label));
182185
}
183186

184187
/**
@@ -193,7 +196,7 @@ protected Slave(@NonNull String name, String nodeDescription, String remoteFS, i
193196
this.numExecutors = numExecutors;
194197
this.mode = mode;
195198
this.remoteFS = Util.fixNull(remoteFS).trim();
196-
this.label = Util.fixNull(labelString).trim();
199+
this.labelAtomSet = Collections.unmodifiableSet(Label.parse(labelString));
197200
this.launcher = launcher;
198201
this.retentionStrategy = retentionStrategy;
199202
getAssignedLabels(); // compute labels now
@@ -308,6 +311,10 @@ public DescribableList<NodeProperty<?>, NodePropertyDescriptor> getNodePropertie
308311

309312
@DataBoundSetter
310313
public void setNodeProperties(List<? extends NodeProperty<?>> properties) throws IOException {
314+
if (nodeProperties == null) {
315+
warnPlugin();
316+
nodeProperties = new DescribableList<>(this);
317+
}
311318
nodeProperties.replaceBy(properties);
312319
}
313320

@@ -328,11 +335,33 @@ public String getLabelString() {
328335
@Override
329336
@DataBoundSetter
330337
public void setLabelString(String labelString) throws IOException {
331-
this.label = Util.fixNull(labelString).trim();
338+
_setLabelString(labelString);
332339
// Compute labels now.
333340
getAssignedLabels();
334341
}
335342

343+
private void _setLabelString(String labelString) {
344+
this.label = Util.fixNull(labelString).trim();
345+
this.labelAtomSet = Collections.unmodifiableSet(Label.parse(label));
346+
}
347+
348+
@CheckForNull // should be @NonNull, but we've seen plugins overriding readResolve() without calling super.
349+
private transient Set<LabelAtom> labelAtomSet;
350+
351+
@Override
352+
protected Set<LabelAtom> getLabelAtomSet() {
353+
if (labelAtomSet == null) {
354+
warnPlugin();
355+
this.labelAtomSet = Collections.unmodifiableSet(Label.parse(label));
356+
}
357+
return labelAtomSet;
358+
}
359+
360+
private void warnPlugin() {
361+
LOGGER.log(Level.WARNING, () -> getClass().getName() + " or one of its superclass overrides readResolve() without calling super implementation." +
362+
"Please file an issue against the plugin implementing it: " + Jenkins.get().getPluginManager().whichPlugin(getClass()));
363+
}
364+
336365
@Override
337366
public Callable<ClockDifference, IOException> getClockDifferenceCallable() {
338367
return new GetClockDifference1();
@@ -574,6 +603,7 @@ public int hashCode() {
574603
protected Object readResolve() {
575604
if (nodeProperties == null)
576605
nodeProperties = new DescribableList<>(this);
606+
_setLabelString(label);
577607
return this;
578608
}
579609

core/src/main/java/hudson/security/SecurityRealm.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -647,15 +647,27 @@ public static String getFrom() {
647647
from = request.getParameter("from");
648648
}
649649

650+
// On the 404 error page, use the session attribute it sets
651+
if (request != null && request.getRequestURI().equals(request.getContextPath() + "/404")) {
652+
final HttpSession session = request.getSession(false);
653+
if (session != null) {
654+
final Object attribute = session.getAttribute("from");
655+
if (attribute != null) {
656+
from = attribute.toString();
657+
}
658+
}
659+
}
660+
650661
// If entry point was not found, try to deduce it from the request URI
651-
// except pages related to login process
662+
// except pages related to login process and the 404 error page
652663
if (from == null
653664
&& request != null
654665
&& request.getRequestURI() != null
655-
&& !request.getRequestURI().equals("/loginError")
656-
&& !request.getRequestURI().equals("/login")) {
657-
658-
from = request.getRequestURI();
666+
// The custom login page makes the next two lines obsolete, but safer to have them.
667+
&& !request.getRequestURI().equals(request.getContextPath() + "/loginError")
668+
&& !request.getRequestURI().equals(request.getContextPath() + "/login")
669+
&& !request.getRequestURI().equals(request.getContextPath() + "/404")) {
670+
from = request.getRequestURI();
659671
}
660672

661673
// If deduced entry point isn't deduced yet or the content is a blank value

core/src/main/java/hudson/util/ProcessTree.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import static java.util.logging.Level.FINER;
3030
import static java.util.logging.Level.FINEST;
3131

32-
import com.google.common.primitives.Ints;
3332
import com.sun.jna.LastErrorException;
3433
import com.sun.jna.Memory;
3534
import com.sun.jna.Native;
@@ -750,7 +749,7 @@ abstract static class Unix extends Local {
750749
@CheckForNull
751750
@Override
752751
public OSProcess get(@NonNull Process proc) {
753-
return get(Ints.checkedCast(proc.pid()));
752+
return get(Math.toIntExact(proc.pid()));
754753
}
755754

756755
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package jenkins;
2+
3+
import java.io.IOException;
4+
import javax.servlet.Filter;
5+
import javax.servlet.FilterChain;
6+
import javax.servlet.FilterConfig;
7+
import javax.servlet.ServletException;
8+
import javax.servlet.ServletRequest;
9+
import javax.servlet.ServletResponse;
10+
import jenkins.model.Jenkins;
11+
import org.kohsuke.accmod.Restricted;
12+
import org.kohsuke.accmod.restrictions.NoExternalUse;
13+
import org.springframework.security.core.Authentication;
14+
15+
/**
16+
* Record the current user authentication for later impersonation if the response is 404 Not Found.
17+
*
18+
* @see Jenkins#generateNotFoundResponse(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse)
19+
*/
20+
@Restricted(NoExternalUse.class)
21+
public class ErrorAttributeFilter implements Filter {
22+
23+
public static final String USER_ATTRIBUTE = "jenkins.ErrorAttributeFilter.user";
24+
25+
@Override
26+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
27+
final Authentication authentication = Jenkins.getAuthentication2();
28+
servletRequest.setAttribute(USER_ATTRIBUTE, authentication);
29+
filterChain.doFilter(servletRequest, servletResponse);
30+
}
31+
32+
@Override
33+
public void destroy() {
34+
// Otherwise the PCT fails
35+
}
36+
37+
@Override
38+
public void init(FilterConfig filterConfig) throws ServletException {
39+
// Otherwise the PCT fails
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* The MIT License
3+
*
4+
* Copyright (c) 2023, Tim Jacomb
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package jenkins.appearance;
26+
27+
import hudson.Extension;
28+
import jenkins.model.GlobalConfigurationCategory;
29+
30+
/**
31+
* <p>Global configuration of appearance configuration.</p>
32+
*
33+
* <p>This should be used for Plugins that contribute to the look and feel of Jenkins.
34+
* Theming, header and footer changes, information density are all good examples.
35+
* API plugins for UI components that are used by other plugins also fit into that, e.g. source code display.</p>
36+
*
37+
* <p>Configuration specific to a single plugin that is not related to the overall look and feel of Jenkins may not belong here.</p>
38+
*
39+
* <p>If a plugin has a single global configuration it should separate appearance and general configuration to different classes.</p>
40+
*
41+
*/
42+
@Extension
43+
public class AppearanceCategory extends GlobalConfigurationCategory {
44+
@Override
45+
public String getShortDescription() {
46+
return Messages.AppearanceCategory_DisplayName();
47+
}
48+
49+
@Override
50+
public String getDisplayName() {
51+
return Messages.AppearanceCategory_Description();
52+
}
53+
}

0 commit comments

Comments
 (0)