all blogs
$ cat gsoc-2026-final-submission.md

Bootstrap 2 → 5: my GSoC '26 with Learning Unlimited

Aug 2026 · ~9 min read · Anurag Singh (Oval17)

GSoC '26Learning UnlimitedESP-WebsiteOpen Source

Learning Unlimited is a national nonprofit that empowers college students to create educational programs for younger learners — student-led events and courses spanning everything from rocket science to poetry. Multiple chapters run those programs every year on one shared codebase, ESP-Website.

My project was the layer underneath the bundled themes — the theming system that lets each chapter give its program a distinct look. It was still on Bootstrap 2.3.2, a release from 2013, hand-rolled LESS, sprite icons that break on retina displays, and enough contrast failures to fail a WCAG audit outright. GSoC '26's coding period runs May 26 through August 23 — I used it to walk that pipeline up to Bootstrap 5, migrate the three major themes (droplets, fruitsalad, and bigpicture), wire in Bootswatch so chapters get real theme choice out of the box, and not take a single live chapter site down doing it.

stats.json — zsh — 80×24
{
  "org": "learning-unlimited",
  "pull_requests": 46,
  "phases_shipped": 4,
  "bootstrap": "2.3.2 → 5.3.3",
  "pytest_suite": "756+ passing",
  "status": "still shipping"
}

01Before GSoC: earning the keys

I started sending PRs to ESP-Website in February, three months before community bonding even opened, because a proposal to rebuild someone else's theming pipeline is only as convincing as your proof you've actually read it. Those 29 pull requests before Phase 1 were a grab-bag — closing WCAG label gaps on the Custom Form Creation page, adding pytest-django and pytest-xdist so the suite could run in parallel, fixing a theme-editor crash on nested image directories, decoding a stray LaTeX byte-string bug, tightening registration form validation — and the one that mattered most for student class registration, upgrading Knockout.js 2.3.0 → 3.5.1 and Select2 3.4.3 → 4.1.0 (#4209), the two packages that power that flow. By the time my proposal was due, I wasn't guessing at the codebase anymore.

02The coding period: four phases, one migration

My mentors were clear early on: this had to be sequential. Bootstrap 2 straight to 5 in one PR would be an untestable diff, and a live chapter site needs to be able to deploy at any point in the migration — not just at the end. So the coding period split into four PRs, each one a full major-version jump, each one merged and green on the pytest suite before the next began.

Phase 01

Bootstrap 2 → 3

merged early June

The least glamorous, most necessary phase. I pulled 42 committed Bootstrap 2 LESS files out of the repo, replaced them with npm-managed Bootstrap 3.3.7 and Bootswatch 3.4.1, and ported 3 of the six bundled themes — droplets, fruitsalad, and barebones — plus every shared template to BS3 markup. .span8 became .col-md-8, .navbar-inner disappeared, .icon-* sprites gave way to a real icon font. Most of that diff is deletion, which is usually the sign a migration is going well.

117 files · +634 / −7,920#5806 ↗
Phase 02

Bootstrap 3 → 4, LESS → SCSS

merged mid-June

The single biggest change in the project, because Bootstrap 4 was the release that dropped LESS entirely in favor of SCSS. I built a dual compile pipeline into ThemeController — has_scss(), compile_scss(), uses_scss_pipeline()— so themes could move to SCSS one at a time without the ones that hadn't migrated yet breaking. A small follow-up, #5828, fixed a crash in /themes/customise for the droplets theme that this phase surfaced.

143 files · +4,868 / −674#5816 ↗
Phase 03

Bootstrap 4 → 5, Bootstrap Icons, WCAG AA

merged mid-July

Finished the version climb, replaced the last sprite-based Glyphicons with Bootstrap Icons, and — the part chapters will actually notice — added a Bootswatch theme selector to the theme editor, so an admin can pick Cerulean, Flatly, Darkly, or Lux as a real starting point instead of hand-tuning LESS variables from zero. This is also where the accessibility pass landed: contrast ratios, aria-labels on icon-only buttons, and properly associated <label> elements across registration and admin forms, all against WCAG 2.1 AA.

57 files · +1,063 / −426#5817 ↗
Phase 04

Per-variable overrides on Bootswatch

merged end of July

The phase that made Phase 3 actually usable day to day. Picking a Bootswatch theme is nice, but chapters used to be able to tune individual colors, and Bootswatch on its own is all-or-nothing. This layers per-variable customization on top of whatever Bootswatch theme is active, so a chapter can start from Flatly and still nudge just the primary color without forking the whole theme.

12 files · +950 / −171#5862 ↗

Threaded through all four phases: a pytest suite of 756+ tests that had to stay green at every merge, and — because apparently once you're in controllers.py every week, people notice — a side quest shipping recurring class scheduling for the AJAX scheduler, closing three long-open issues along the way. Beyond authoring, I also reviewed 50+ PRs across different domains of the codebase. Thanks to Katherine Brumberg and Will Gearty for mentoring through all of it.

03After the four phases: owning it

Bootstrap 5 merging doesn't mean the theming system is finished — it means the part nobody claps for starts. Past the four core phases, I've got eleven PRs open right now: ten adding unit test coverage to modules that had none — ListGenModule, GroupTextModule, TeacherModeratorModule, StudentJunctionAppModule, OnSiteCheckoutModule, DeactivationModule, OnSiteRegister, TeacherOnsite, SurveyManagement, VolunteerManage — and one, #5936, removing the legacy LESS pipeline outright, because main has been Bootstrap-5-only for weeks and the dead LESS branch was still quietly breaking manage.py update whenever theme recompilation fell through to it.

That's the plan going forward: stay on as a maintainer for the theming system, not a summer contributor to it. I want to get properly involved in how ESP-Website actually cuts and ships releases, not just merge code into it, and push on follow-ups like a live theme preview in the editor and an automated accessibility check in CI. Learning Unlimited is genuinely useful software — chapters have reached over 50,000 students since 2007. This was never meant to be a one-summer thing.

Everything above links straight to the PRs — dig in on GitHub if you want the diffs. More soon.