So I’ve been going through the core module for the past few days as part of my GSoC prep, and I wanted to write down what I’ve figured out — partly for anyone else prepping for GSoC with Jenkins, partly just so future-me remembers this.
Honestly when I first opened the repo, I assumed core was just… one folder among many. Like, how important can a folder named “core” really be, right? Turns out that was a pretty dumb assumption. Once I started tracing how a request actually moves through Jenkins, I realized this is basically the whole application. Jobs, users, permissions, the UI, scheduling — it’s all in here.
Here’s the rough layout I’m working with:
core/
├── src/
│ ├── main/
│ │ ├── java/
│ │ ├── resources/
│ │ ├── js/
│ │ ├── scss/
│ │ └── webapp/
│ └── test/
Breaking down what I found in each piece:
java/ — this is where the actual logic lives
Anything to do with creating jobs, scheduling builds, authenticating users, saving config, managing nodes, handling permissions — it’s in here somewhere. This is also where I ran into something that confused me for longer than I’d like to admit: there’s a whole package called hudson. I kept thinking, wait, isn’t this Jenkins? Why is there Hudson code everywhere?
Turns out Jenkins was literally forked from Hudson years ago, and a lot of the old package names just stuck around. So you’ll see stuff like hudson.model.Job, hudson.model.Run, hudson.model.Node, hudson.model.Queue — all still actively used. Then there’s the newer jenkins package sitting alongside it, with jenkins.model.Jenkins being probably the single most important class in the whole codebase — it represents the running instance itself.
resources/ — this is the UI, but not how I expected
I was expecting HTML here and instead found Jelly templates everywhere. Config Jenkins, manage Jenkins, job config pages — all Jelly. Files like config.jelly, index.jelly, and a bunch of Messages.properties for labels and localization. So if you ever see an issue like “the Save button text is wrong” or “this form field looks broken,” this is probably where the fix lives.
js/ — where I’ve spent most of my time honestly
This is the folder I keep coming back to because a lot of the beginner-friendly issues live here — notifications, dropdowns, form validation, AJAX calls, that kind of thing. One issue I actually traced through: a notification would get created but then disappear because the page redirected right after, before the user ever saw it. The fix was to hang onto the notification across the redirect and show it once the next page loaded. Small bug, but tracing it taught me more about how the request flow actually works than I expected.
scss/ — styling
Spacing, colors, layout, dark mode stuff. Pretty self explanatory once you’re in there.
webapp/ — icons, fonts, images, favicons
Doesn’t get touched as much but it’s there.
test/ — the tests
Obviously important so nothing quietly breaks when someone (me) touches something they probably shouldn’t have.
Putting it together, if you click Save on some config page, roughly what happens is: JS validates and fires the request → it hits the Java backend → business logic runs → config gets saved → a Jelly page renders → JS updates the UI and shows you feedback. Seeing that whole loop connected in my head was honestly the biggest “oh, THAT’S how this works” moment for me this week.
Biggest thing I’m taking away from this: I used to assume a bug report = one file to fix. Not even close. A tiny UI issue can touch Java, JS, Jelly, resource files, and tests all at once. Still very early in this GSoC prep journey, but every issue I poke at teaches me something new about how a codebase this size actually holds together.
One thing I’m still not fully clear on: how Stapler decides which class/method actually handles a given URL when there’s no explicit route defined — I get the gist of the convention-based dispatch, but the exact resolution order when multiple candidates could match is still fuzzy to me. If any maintainers or long-time contributors have a mental model (or a doc/PR I should read) for how that resolution actually works, I’d really appreciate a pointer.