Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
7f182a8
Init
janfaracik Jan 10, 2025
2c6f66e
Update _branding.scss
janfaracik Jan 10, 2025
3c7625b
Merge branch 'oklch' into consistent-branding
janfaracik Jan 10, 2025
6634164
Merge branch 'master' into consistent-branding
janfaracik Mar 11, 2026
f17fec6
Update index.jelly
janfaracik Mar 11, 2026
7a960f8
Fixes
janfaracik Mar 11, 2026
b73423b
Update _about.scss
janfaracik Mar 11, 2026
7828700
Update _sign-in-register.scss
janfaracik Mar 11, 2026
bc680a9
Refine
janfaracik Mar 11, 2026
84d5673
Push
janfaracik Mar 11, 2026
d2a4ae8
Update _branding.scss
janfaracik Mar 11, 2026
ef06499
Merge branch 'master' into consistent-branding
janfaracik Apr 19, 2026
ff55414
Update _sign-in-register.scss
janfaracik Apr 19, 2026
bd4f7b1
Update _branding.scss
janfaracik Apr 20, 2026
004d446
Merge branch 'master' into consistent-branding
janfaracik Apr 26, 2026
09dd991
Merge branch 'master' into consistent-branding
janfaracik May 25, 2026
757a0e8
Merge branch 'master' into consistent-branding
janfaracik Jun 27, 2026
c9dca23
Tidy
janfaracik Jun 27, 2026
53ba1d7
Update _sign-in-register.scss
janfaracik Jun 28, 2026
55d6352
Update _sign-in-register.scss
janfaracik Jun 28, 2026
67488d9
Update _sign-in-register.scss
janfaracik Jun 28, 2026
10a7fc0
Push
janfaracik Jun 28, 2026
0418099
Update _sign-in-register.scss
janfaracik Jun 28, 2026
9e6703d
Update _sign-in-register.scss
janfaracik Jun 28, 2026
1632955
Merge branch 'master' into consistent-branding
janfaracik Jul 1, 2026
3bfe040
Fix sortable date column ordering for 12 AM (midnight) times
thswlsqls Jun 16, 2026
e645420
Merge branch 'master' into consistent-branding
janfaracik Jul 8, 2026
e4bda21
Trigger Build
janfaracik Jul 8, 2026
de3dee3
perf: parallelize user directory scanning and XML unmarshaling at sta…
rajat315315 Jul 9, 2026
871700c
[JENKINS-75310] Fix log recorder level updates
U-S-jun Jul 10, 2026
f781924
test: add regression test for parallel User scanning with malformed c…
rajat315315 Jul 10, 2026
81fa77d
Add a password visibility toggle and a Caps Lock indicator to the sig…
BobDu Jul 10, 2026
9364f26
perf: introduce configurable ForkJoinPool for user directory scanning…
rajat315315 Jul 10, 2026
081907f
Merge branch 'master' into fix/jenkins-75310-log-recorder-level
U-S-jun Jul 10, 2026
7718e21
[JENKINS-75310] Handle removed log recorder targets
U-S-jun Jul 10, 2026
68a1903
Merge branch 'master' into consistent-branding
janfaracik Jul 11, 2026
025dddb
refactor: remove trailing whitespace from UserTest.java
rajat315315 Jul 11, 2026
972f752
Merge branch 'master' into consistent-branding
janfaracik Jul 12, 2026
a2d7ed7
[JENKINS-27993] Return useful plugin data from /pluginManager/api/json
umbertocicciaa Jul 12, 2026
bdca7a6
Update dependency org.bouncycastle:bcprov-jdk18on to v1.85
renovate[bot] Jul 13, 2026
1af75ae
refactor: use SystemProperties for scanConcurrency and enable Java nu…
rajat315315 Jul 13, 2026
b9762a3
Update softprops/action-gh-release action to v3.0.2
renovate[bot] Jul 14, 2026
7a953d8
Refactor.
rajat315315 Jul 14, 2026
7f839b7
Limit job RSS changelog feed size by default
Siddhartha-singh01 Jul 13, 2026
e776ef4
Update dependency postcss to v8.5.19
renovate[bot] Jul 14, 2026
01578bc
Update dependency org.jenkins-ci.plugins:matrix-auth to v3.3
renovate[bot] Jul 14, 2026
506602c
Fix NPE when Upstreamcause is a pipeline job after Jenkins restart
mawinter69 Jul 14, 2026
0ea4fce
Remove special characters that Jelly fails to parse
MarkEWaite Jul 14, 2026
f46496e
Merge branches 'consistent-branding', 'fix/14784-limit-rss-changelog'…
MarkEWaite Jul 14, 2026
1839570
Fast incremental build
MarkEWaite Apr 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/publish-release-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
wget -q https://get.jenkins.io/${REPO}/${PROJECT_VERSION}/${FILE_NAME}
- name: Upload Release Asset
id: upload-war
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -109,7 +109,7 @@ jobs:
- name: Upload Release Asset
id: upload-deb
if: always()
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
- name: Upload Release Asset
id: upload-rpm
if: always()
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down Expand Up @@ -182,7 +182,7 @@ jobs:
- name: Upload Release Asset
id: upload-msi
if: always()
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
Expand Down
44 changes: 7 additions & 37 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ properties([
])

def axes = [
platforms: ['linux', 'windows'],
jdks: [21, 25],
platforms: ['linux'],
jdks: [21],
]
Comment on lines 16 to 19

stage('Record build') {
Expand Down Expand Up @@ -124,7 +124,12 @@ axes.values().combinations {
}
withChecks(name: 'Tests', includeStage: true) {
realtimeJUnit(healthScaleFactor: 20.0, testResults: '*/target/surefire-reports/*.xml') {
// Only use with replay, not with a commit
// sh 'curl -O https://home.markwaite.net/~mwaite/pom.patch && git apply pom.patch && rm pom.patch && git diff'
// mavenOptions.add(0, "-Dignore.dirt")
Comment on lines +127 to +129
infra.runMaven(mavenOptions, jdk)
// Only use with replay, not with a commit
// sh 'git checkout -- */pom.xml'
Comment on lines +131 to +132
if (isUnix()) {
sh 'git add . && git diff --exit-code HEAD'
}
Expand Down Expand Up @@ -212,41 +217,6 @@ axes.values().combinations {
}
}

def athAxes = [
platforms: ['linux'],
jdks: [21],
browsers: ['firefox'],
]
athAxes.values().combinations {
def (platform, jdk, browser) = it
builds["ath-${platform}-jdk${jdk}-${browser}"] = {
retry(conditions: [agent(), nonresumable()], count: 2) {
node('docker-highmem') {
// Just to be safe
deleteDir()
checkout scm

withChecks(name: 'Tests', includeStage: true) {
infra.withArtifactCachingProxy {
sh "bash ath.sh ${jdk} ${browser}"
}
junit testResults: 'target/ath-reports/TEST-*.xml', testDataPublishers: [[$class: 'AttachmentPublisher']]
}
/*
* Currently disabled, as the fact that this is a manually created subset will confuse Launchable,
* which expects this to be a full build. When we implement subsetting, this can be re-enabled using
* Launchable's subset rather than our own.
*/
/*
withCredentials([string(credentialsId: 'launchable-jenkins-acceptance-test-harness', variable: 'LAUNCHABLE_TOKEN')]) {
sh "launchable verify && launchable record tests --no-build --flavor platform=${platform} --flavor jdk=${jdk} --flavor browser=${browser} maven './target/ath-reports'"
}
*/
}
}
}
}

builds.failFast = failFast
parallel builds
infra.maybePublishIncrementals()
Comment on lines 220 to 222
4 changes: 3 additions & 1 deletion cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
<mina-sshd.version>2.19.0</mina-sshd.version>
<!-- Filled in by jacoco-maven-plugin -->
<jacocoSurefireArgs />
<!-- Intentionally run only one test to reduce cycle time -->
<test>QuotedStringTokenizerTest</test>
Comment on lines +21 to +22
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -53,7 +55,7 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.84</version>
<version>1.85</version>
<optional>true</optional>
</dependency>
<dependency>
Expand Down
2 changes: 2 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ THE SOFTWARE.
<remoting.minimum.supported.version>3176.v207ec082a_8c0</remoting.minimum.supported.version>
<!-- Filled in by jacoco-maven-plugin -->
<jacocoSurefireArgs />
<!-- Intentionally run only one test to reduce cycle time -->
<test>EnvVarsTest</test>
Comment on lines +46 to +47
</properties>

<dependencyManagement>
Expand Down
13 changes: 7 additions & 6 deletions core/src/main/java/hudson/PluginWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ public PluginWrapper(PluginManager parent, File archive, Manifest manifest, URL
this.archive = archive;
}

@Exported(visibility = 2)
@Override
public String getDisplayName() {
String displayName = getLongName();
Expand Down Expand Up @@ -595,7 +596,7 @@ public List<Dependency> getOptionalDependencies() {
/**
* Returns the short name suitable for URL.
*/
@Exported
@Exported(visibility = 2)
public String getShortName() {
return shortName;
}
Expand Down Expand Up @@ -627,7 +628,7 @@ public String getShortName() {
* null if this information is unavailable.
* @since 1.283
*/
@Exported
@Exported(visibility = 2)
public String getUrl() {
// first look in update center metadata
List<UpdateSite.Plugin> siteMetadataList = getInfoFromAllSites();
Expand Down Expand Up @@ -683,7 +684,7 @@ public YesNoMaybe supportsDynamicLoad() {
/**
* Returns the version number of this plugin
*/
@Exported
@Exported(visibility = 2)
public String getVersion() {
return getVersionOf(manifest);
}
Expand Down Expand Up @@ -894,7 +895,7 @@ private Set<String> dependentsToCheck(PluginDisableStrategy strategy) {
/**
* Returns true if this plugin is enabled for this session.
*/
@Exported
@Exported(visibility = 2)
public boolean isActive() {
return active && !hasCycleDependency();
}
Expand All @@ -921,7 +922,7 @@ public boolean isBundled() {
* If true, the plugin is going to be activated next time
* Jenkins runs.
*/
@Exported
@Exported(visibility = 2)
public boolean isEnabled() {
return !disableFile.exists();
}
Expand Down Expand Up @@ -1080,7 +1081,7 @@ private List<UpdateSite.Plugin> getInfoFromAllSites() {
* This method is conservative in the sense that if the version number is incomprehensible,
* it always returns false.
*/
@Exported
@Exported(visibility = 2)
public boolean hasUpdate() {
return getUpdateInfo() != null;
}
Expand Down
70 changes: 68 additions & 2 deletions core/src/main/java/hudson/logging/LogRecorder.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,147 +324,213 @@
* Makes sure that the logger passes through messages at the correct level to us.
*/
public void enable() {
enableLogger();
new SetLevel(name, getLevel()).broadcast();
}

private void enableLogger() {
Logger l = getLogger();
if (!l.isLoggable(getLevel()))
l.setLevel(getLevel());
new SetLevel(name, getLevel()).broadcast();
}

public void disable() {
getLogger().setLevel(null);
new SetLevel(name, null).broadcast();
}

}

private static class TargetComparator implements Comparator<Target>, Serializable {

private static final long serialVersionUID = 9285340752515798L;

@Override
public int compare(Target left, Target right) {
return right.getName().length() - left.getName().length();
}
}

private static final class SetLevel extends MasterToSlaveCallable<Void, Error> {
/** known loggers (kept per agent), to avoid GC */
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private static final Set<Logger> loggers = new HashSet<>();
private final String name;
private final Level level;

SetLevel(String name, Level level) {
this.name = name;
this.level = level;
}

@Override public Void call() throws Error {
Logger logger = Logger.getLogger(name);
loggers.add(logger);
logger.setLevel(level);
return null;
}

void broadcast() {
for (Computer c : Jenkins.get().getComputers()) {
if (!c.getName().isEmpty()) { // i.e. not master
VirtualChannel ch = c.getChannel();
if (ch != null) {
try {
ch.call(this);
} catch (Exception x) {
Logger.getLogger(LogRecorder.class.getName()).log(Level.WARNING, "could not set up logging on " + c, x);
}
}
}
}
}
}

@Extension @Restricted(NoExternalUse.class) public static final class ComputerLogInitializer extends ComputerListener {
@Override public void preOnline(Computer c, Channel channel, FilePath root, TaskListener listener) throws IOException, InterruptedException {
for (LogRecorder recorder : Jenkins.get().getLog().getRecorders()) {
for (Target t : recorder.getLoggers()) {
channel.call(new SetLevel(t.name, t.getLevel()));
}
}
}
}

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

@Override
public String getSearchUrl() {
return Util.rawEncode(name);
}

public String getName() {
return name;
}

public LogRecorderManager getParent() {
return Jenkins.get().getLog();
}

/**
* Updates controller logger levels after existing targets are reconfigured or removed. {@link Target#enable()}
* only makes a logger more verbose, so it cannot otherwise apply a change such as {@code FINEST} to {@code INFO}.
*/
private void updateLogLevels(List<Target> previousTargets) {
List<LogRecorder> recorders = getParent().getRecorders();
Set<String> changedTargetNames = new LinkedHashSet<>();
for (Target previousTarget : previousTargets) {
Target target = getTarget(previousTarget.name, loggers);
if (target != null && target.getLevel().intValue() <= previousTarget.getLevel().intValue()) {
continue;
}
changedTargetNames.add(previousTarget.name);
if (sameLevel(previousTarget.getLogger().getLevel(), previousTarget.getLevel())) {
previousTarget.getLogger().setLevel(null);
}
}

for (LogRecorder recorder : recorders) {
for (Target target : recorder.loggers) {
if (changedTargetNames.contains(target.name)) {
target.enableLogger();
}
}
}

List<Target> descendantTargets = new ArrayList<>();
for (LogRecorder recorder : recorders) {
for (Target target : recorder.loggers) {
if (changedTargetNames.stream().anyMatch(name -> isDescendant(name, target.name))) {
descendantTargets.add(target);
}
}
}
descendantTargets.sort(Comparator.comparingInt(target -> target.name.length()));
descendantTargets.forEach(Target::enableLogger);
}

private static Target getTarget(String loggerName, List<Target> targets) {
return targets.stream().filter(target -> target.name.equals(loggerName)).findFirst().orElse(null);
}

private static boolean isDescendant(String loggerName, String candidate) {
return loggerName.isEmpty()
? !candidate.isEmpty()
: candidate.startsWith(loggerName)
&& candidate.length() > loggerName.length()
&& candidate.charAt(loggerName.length()) == '.';
}

private static boolean sameLevel(Level first, Level second) {
return first == null ? second == null : second != null && first.intValue() == second.intValue();
}

/**
* Accepts submission from the configuration page.
*/
@POST
public synchronized void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);

JSONObject src = req.getSubmittedForm();

String newName = src.getString("name"), redirect = ".";
XmlFile oldFile = null;
if (!name.equals(newName)) {
Jenkins.checkGoodName(newName);
oldFile = getConfigFile();
// rename
List<LogRecorder> recorders = getParent().getRecorders();
recorders.remove(new LogRecorder(name));
this.name = newName;
recorders.add(this);
redirect = "../" + Util.rawEncode(newName) + '/';
}

List<Target> previousTargets = List.copyOf(loggers);
List<Target> newTargets = req.bindJSONToList(Target.class, src.get("loggers"));
setLoggers(newTargets);

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

@RequirePOST
public HttpResponse doClear() throws IOException {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);

handler.clear();
return HttpResponses.redirectToDot();
}

/**
* Loads the settings from a file.
*/
@Override
public synchronized void load() throws IOException {
getConfigFile().unmarshal(this);
loggers.forEach(Target::enable);
}

/**
* Save the settings to a file.
*/
@Override
public synchronized void save() throws IOException {
save(null);
}

private synchronized void save(List<Target> previousTargets) throws IOException {
if (BulkChange.contains(this)) return;

getConfigFile().write(this);
loggers.forEach(Target::enable);
if (previousTargets != null) {
updateLogLevels(previousTargets);

Check warning on line 532 in core/src/main/java/hudson/logging/LogRecorder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 327-532 are not covered by tests
}

SaveableListener.fireOnChange(this, getConfigFile());
}
Expand Down
16 changes: 5 additions & 11 deletions core/src/main/java/hudson/model/Cause.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,23 @@
}
upstreamCauses.add(trim(c, MAX_DEPTH, traversed));
}
fillCauseBag();
}

private UpstreamCause(String upstreamProject, int upstreamBuild, String upstreamUrl, @NonNull List<Cause> upstreamCauses) {
this.upstreamProject = upstreamProject;
this.upstreamBuild = upstreamBuild;
this.upstreamUrl = upstreamUrl;
this.upstreamCauses = upstreamCauses;
fillCauseBag();
}

private void fillCauseBag() {
@Restricted(DoNotUse.class) // used from Jelly
public Map<Cause, Integer> getCauseCounts() {
if (causeBag == null) {
causeBag = new LinkedHashMap<>();
for (Cause c : upstreamCauses) {
causeBag.compute(c, (unused, cnt) -> cnt == null ? 1 : cnt + 1);
}

Check warning on line 212 in core/src/main/java/hudson/model/Cause.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 208-212 are not covered by tests
}
for (Cause c : upstreamCauses) {
causeBag.compute(c, (unused, cnt) -> cnt == null ? 1 : cnt + 1);
}
}

@Restricted(DoNotUse.class) // used from Jelly
public Map<Cause, Integer> getCauseCounts() {
return Collections.unmodifiableMap(causeBag);
}

Expand Down Expand Up @@ -371,7 +366,6 @@
uc.upstreamCause = null;
OldDataMonitor.report(context, "1.288");
}
uc.fillCauseBag();
}
}

Expand Down
17 changes: 17 additions & 0 deletions core/src/main/java/hudson/model/Job.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
import jenkins.security.HexStringConfidentialKey;
import jenkins.security.stapler.StaplerNotDispatchable;
import jenkins.triggers.SCMTriggerItem;
import jenkins.util.SystemProperties;
import jenkins.widgets.HasWidgets;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
Expand Down Expand Up @@ -1155,21 +1156,37 @@
}
}

// Default 20 entries (JENKINS-18992). Overridable via system property or ?max=
int maxEntries = SystemProperties.getInteger(Job.class.getName() + ".rssChangelogMaxEntries", 20);
String maxParam = req.getParameter("max");
if (maxParam != null) {
try {
maxEntries = Math.max(1, Integer.parseInt(maxParam));
} catch (NumberFormatException e) {
// keep default
}
}

List<FeedItem> entries = new ArrayList<>();
String scmDisplayName = "";
if (this instanceof SCMTriggerItem scmItem) {
List<String> scmNames = new ArrayList<>();
for (SCM s : scmItem.getSCMs()) {
scmNames.add(s.getDescriptor().getDisplayName());
}
scmDisplayName = " " + String.join(", ", scmNames);
}

// stop once we have enough; avoids loading every build for large jobs
outer:
for (RunT r = getLastBuild(); r != null; r = r.getPreviousBuild()) {
int idx = 0;
if (r instanceof RunWithSCM) {
for (ChangeLogSet<? extends ChangeLogSet.Entry> c : ((RunWithSCM<?, ?>) r).getChangeSets()) {
for (ChangeLogSet.Entry e : c) {
if (entries.size() >= maxEntries) {
break outer;

Check warning on line 1188 in core/src/main/java/hudson/model/Job.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 1160-1188 are not covered by tests
}
entries.add(new FeedItem(e, idx++));
}
}
Expand Down
Loading