This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/storm-site.git
The following commit(s) were added to refs/heads/main by this push:
new 2a5444b60c Add team page sourced from ASF roster and trim hero tagline
2a5444b60c is described below
commit 2a5444b60c8e59ed84cfda175d958784265b2f4a
Author: Richard Zowalla <[email protected]>
AuthorDate: Thu May 7 11:53:18 2026 +0200
Add team page sourced from ASF roster and trim hero tagline
Build-time Jekyll plugin pulls Storm's PMC and committer roster from
Whimsy and projects.apache.org, then overlays the active set defined
in _data/team.yml. Anyone in LDAP not flagged active is shown as
emeritus. Header "People" link is replaced with "Team" pointing at
/team/; the old contribute/People.md becomes a stub redirect.
Hero tagline no longer repeats the H2 title above it.
---
_data/team.yml | 20 +++++++
_includes/header.html | 2 +-
_plugins/team.rb | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++
contribute/People.md | 2 +-
css/style.css | 124 +++++++++++++++++++++++++++++++++++++++++-
index.html | 2 +-
team.md | 87 ++++++++++++++++++++++++++++++
7 files changed, 378 insertions(+), 4 deletions(-)
diff --git a/_data/team.yml b/_data/team.yml
new file mode 100644
index 0000000000..c108cdf45c
--- /dev/null
+++ b/_data/team.yml
@@ -0,0 +1,20 @@
+# Apache Storm team โ active members.
+#
+# Anyone listed under `active` is shown in the "Active" section of /team/.
+# Anyone in the ASF LDAP roster but NOT listed here is shown as "Emeritus".
+# `chair` overrides whatever LDAP reports (use this to fix lag in Whimsy).
+#
+# Names + GitHub usernames are resolved at build time by _plugins/team.rb
+# from Whimsy / projects.apache.org. No need to duplicate them here.
+
+chair: rzo1
+
+active:
+ - rzo1 # Richard Zowalla
+ - rabreu # Rui Abreu
+ - bipinprasad # Bipin Prasad
+ - jnioche # Julien Nioche
+ - avermeerbergen # Alexandre Vermeerbergen
+ - puru # Purshotam Shah
+ - agresch # Aaron Gresch
+ - roshannaik # Roshan Naik
diff --git a/_includes/header.html b/_includes/header.html
index 89dbe7c85e..bcd0df4a97 100644
--- a/_includes/header.html
+++ b/_includes/header.html
@@ -61,7 +61,7 @@
<ul class="dropdown-menu">
<li><a href="/getting-help.html">Getting Help</a></li>
<li><a
href="/contribute/Contributing-to-Storm.html">Contributing</a></li>
- <li><a href="/contribute/People.html">People</a></li>
+ <li><a href="/team/">Team</a></li>
<li><a href="/contribute/BYLAWS.html">ByLaws</a></li>
<li role="separator" class="divider"></li>
<li><a href="/talksAndVideos.html">Talks and
Slideshows</a></li>
diff --git a/_plugins/team.rb b/_plugins/team.rb
new file mode 100644
index 0000000000..2e8ffbf29d
--- /dev/null
+++ b/_plugins/team.rb
@@ -0,0 +1,145 @@
+require 'jekyll'
+require 'net/http'
+require 'json'
+require 'yaml'
+require 'uri'
+
+# Storm team data generator.
+#
+# Pulls the Storm PMC + committer roster from public ASF sources at build
+# time and exposes it to Liquid templates as:
+#
+# site.data.team_active # active members (chair, then PMC, then
committers)
+# site.data.team_emeritus # everyone else in the LDAP roster
+#
+# Active membership is driven by _data/team.yml (`active:` list of availids
+# plus an optional `chair:` override). Anyone in LDAP not listed in the
+# YAML is shown as emeritus.
+#
+# Network sources (no auth required):
+# * https://whimsy.apache.org/public/public_ldap_projects.json โ committee
+# * https://projects.apache.org/json/foundation/people.json โ names + GH
+#
+# Successful fetches are cached to tmp/asf_roster.yml; the cache is consulted
+# only when the live fetch fails, so the build degrades gracefully if Whimsy
+# or projects.apache.org is unreachable.
+module StormTeam
+ WHIMSY_PROJECTS_URL =
'https://whimsy.apache.org/public/public_ldap_projects.json'.freeze
+ PEOPLE_JSON_URL =
'https://projects.apache.org/json/foundation/people.json'.freeze
+ CACHE_RELATIVE_PATH = 'tmp/asf_roster.yml'.freeze
+ PROJECT_NAME = 'storm'.freeze
+ HTTP_TIMEOUT = 8
+
+ class Generator < Jekyll::Generator
+ def generate(site)
+ cache_path = File.join(site.source, CACHE_RELATIVE_PATH)
+
+ committee = fetch_committee
+ people = fetch_people
+
+ if committee.nil? || people.nil?
+ cached = load_cache(cache_path)
+ committee ||= cached && cached['committee']
+ people ||= cached && cached['people']
+ end
+
+ save_cache(cache_path, committee, people) if committee && people
+
+ yaml_team = site.data['team'] || {}
+ active_set = (yaml_team['active'] || []).map(&:to_s)
+ chair_id = (yaml_team['chair'] || (committee &&
committee['chair'])).to_s
+
+ pmc_ids = (committee && committee['owners']) || []
+ committer_ids = (committee && committee['members']) || []
+ all_ids = (pmc_ids + committer_ids + active_set + [chair_id])
+ .uniq.reject { |s| s.nil? || s.empty? }
+
+ records = all_ids.map do |aid|
+ person = people ? (people[aid] || {}) : {}
+ role =
+ if aid == chair_id then 'chair'
+ elsif pmc_ids.include?(aid) then 'pmc'
+ elsif committer_ids.include?(aid) then 'committer'
+ else 'committer'
+ end
+ {
+ 'apache_id' => aid,
+ 'name' => person['name'] || aid,
+ 'github' => person['github'] || aid,
+ 'role' => role,
+ 'active' => (aid == chair_id) || active_set.include?(aid),
+ }
+ end
+
+ site.data['team_active'] = records.select { |r| r['active'] }.sort_by
{ |r| active_sort_key(r) }
+ site.data['team_emeritus'] = records.reject { |r| r['active'] }.sort_by
{ |r| r['name'].to_s.downcase }
+
+ Jekyll.logger.info 'StormTeam:',
+ "active=#{site.data['team_active'].size}
emeritus=#{site.data['team_emeritus'].size}"
+ end
+
+ private
+
+ def active_sort_key(record)
+ rank = { 'chair' => 0, 'pmc' => 1, 'committer' => 2 }[record['role']] ||
3
+ [rank, record['name'].to_s.downcase]
+ end
+
+ def fetch_committee
+ data = fetch_json(WHIMSY_PROJECTS_URL)
+ data && data.dig('projects', PROJECT_NAME)
+ rescue StandardError => e
+ Jekyll.logger.warn 'StormTeam:', "Whimsy fetch failed: #{e.message}"
+ nil
+ end
+
+ def fetch_people
+ data = fetch_json(PEOPLE_JSON_URL)
+ return nil unless data.is_a?(Hash)
+
+ data.each_with_object({}) do |(aid, rec), out|
+ next unless rec.is_a?(Hash)
+ out[aid] = { 'name' => rec['name'] || aid, 'github' =>
extract_github(rec) }
+ end
+ rescue StandardError => e
+ Jekyll.logger.warn 'StormTeam:', "people.json fetch failed: #{e.message}"
+ nil
+ end
+
+ def extract_github(rec)
+ urls = rec['urls']
+ return nil unless urls.is_a?(Hash)
+ raw = urls['github'] || urls['GitHub'] || urls['github.com']
+ return nil unless raw.is_a?(String) && !raw.empty?
+ handle = raw.sub(%r{\Ahttps?://github\.com/}, '').sub(%r{/.*\z},
'').strip
+ handle.empty? ? nil : handle
+ end
+
+ def fetch_json(url)
+ uri = URI.parse(url)
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = (uri.scheme == 'https')
+ http.open_timeout = HTTP_TIMEOUT
+ http.read_timeout = HTTP_TIMEOUT
+ req = Net::HTTP::Get.new(uri.request_uri, 'User-Agent' =>
'storm-site-team/1.0')
+ res = http.request(req)
+ return nil unless res.is_a?(Net::HTTPSuccess)
+ JSON.parse(res.body)
+ end
+
+ def load_cache(path)
+ return nil unless File.exist?(path)
+ YAML.safe_load(File.read(path))
+ rescue StandardError => e
+ Jekyll.logger.warn 'StormTeam:', "cache read failed: #{e.message}"
+ nil
+ end
+
+ def save_cache(path, committee, people)
+ FileUtils.mkdir_p(File.dirname(path))
+ File.write(path, { 'committee' => committee, 'people' => people
}.to_yaml)
+ rescue StandardError => e
+ Jekyll.logger.warn 'StormTeam:', "cache write failed: #{e.message}"
+ end
+ end
+end
diff --git a/contribute/People.md b/contribute/People.md
index b5be3cb47b..98d22e02f7 100644
--- a/contribute/People.md
+++ b/contribute/People.md
@@ -4,4 +4,4 @@ layout: documentation
documentation: true
---
-Current list of committers and PMC members is
[here](https://projects.apache.org/committee.html?storm)
+The Apache Storm team page has moved to [/team/](/team/).
diff --git a/css/style.css b/css/style.css
index 511ae34032..b0ddd60087 100644
--- a/css/style.css
+++ b/css/style.css
@@ -830,9 +830,131 @@ footer hr {
.github-fork-ribbon { display: none; }
}
+/* /team/ page */
+.team-page { margin: 0 0 40px; }
+.team-intro {
+ font-size: 16px;
+ line-height: 1.6;
+ max-width: 780px;
+ color: #444;
+ margin: 0 0 30px;
+}
+.team-section { margin: 36px 0; }
+.team-section h2 {
+ font-size: 24px;
+ margin: 0 0 18px;
+ padding-bottom: 8px;
+ border-bottom: 2px solid #e6e6e6;
+ color: #235693;
+}
+.team-grid {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
+ gap: 16px;
+}
+.team-card {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ padding: 14px 16px;
+ background: #fff;
+ border: 1px solid #e2e6ea;
+ border-radius: 6px;
+ transition: box-shadow 0.15s ease, border-color 0.15s ease;
+}
+.team-card:hover {
+ box-shadow: 0 4px 14px rgba(35, 86, 147, 0.10);
+ border-color: #c8d3df;
+}
+.team-avatar {
+ flex: 0 0 48px;
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #328fbf, #235693);
+ color: #fff;
+ font-weight: 700;
+ font-size: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-transform: uppercase;
+}
+.team-card--active .team-avatar { background: linear-gradient(135deg, #32bf61,
#235693); }
+.team-meta { min-width: 0; flex: 1; }
+.team-name {
+ margin: 0 0 4px;
+ font-weight: 700;
+ font-size: 15px;
+ color: #222;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.team-roles { margin: 0 0 4px; line-height: 1; }
+.role-badge {
+ display: inline-block;
+ padding: 2px 7px;
+ margin-right: 4px;
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 0.4px;
+ text-transform: uppercase;
+ border-radius: 3px;
+ color: #fff;
+ vertical-align: middle;
+}
+.role-chair { background: #c75a26; }
+.role-pmc { background: #235693; }
+.role-committer { background: #4a90a4; }
+.role-badge--sm { padding: 1px 5px; font-size: 10px; }
+.team-links {
+ margin: 0;
+ font-size: 13px;
+ color: #666;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.team-links a { color: #235693; font-weight: 600; }
+.team-links a:hover { color: #328fbf; }
+.team-availid { color: #999; font-size: 12px; }
+.team-emeritus-intro {
+ color: #555;
+ max-width: 780px;
+ margin: 0 0 16px;
+}
+.team-emeritus-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 6px 18px;
+ font-size: 14px;
+}
+.team-emeritus-list li {
+ padding: 4px 0;
+ color: #444;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.team-emeritus-list a { color: #235693; }
+.team-emeritus-list a:hover { color: #328fbf; }
-
+.team-thanks {
+ padding: 14px 18px;
+ background: #f6f9fc;
+ border-left: 4px solid #32bf61;
+ border-radius: 3px;
+ margin: 16px 0;
+}
+.team-empty { color: #888; font-style: italic; }
diff --git a/index.html b/index.html
index 4853b41dcc..002a12ea07 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@ title: Apache Storm
<div class="row">
<div class="col-md-7 hero-text">
<h2 class="hero-title">Distributed real-time computation</h2>
- <p class="hero-tagline">Distributed real-time computation.
Free and open source. Process unbounded streams of data — fast,
fault-tolerant, and reliable.</p>
+ <p class="hero-tagline">Free and open source. Process
unbounded streams of data — fast, fault-tolerant, and reliable.</p>
<p class="hero-cta">
<a href="/downloads.html" class="btn-hero
btn-hero-primary">Download {{ current.name }}</a>
<a href="/releases/current/Tutorial.html" class="btn-hero
btn-hero-secondary">Get Started</a>
diff --git a/team.md b/team.md
new file mode 100644
index 0000000000..9c4c082e06
--- /dev/null
+++ b/team.md
@@ -0,0 +1,87 @@
+---
+title: Team
+layout: default
+permalink: /team/
+description: The PMC, committers, and contributors behind Apache Storm.
+---
+
+<div class="team-page">
+
+<p class="team-intro">
+ Apache Storm is developed and maintained by a community of volunteers from
+ around the world. Below are the project's active and emeritus PMC members
+ and committers, sourced from
+ <a href="https://whimsy.apache.org/roster/committee/storm">the official ASF
roster</a>
+ and overlaid with the project's currently active set.
+</p>
+
+<section class="team-section">
+ <h2 id="active">Active team</h2>
+ {% if site.data.team_active and site.data.team_active.size > 0 %}
+ <ul class="team-grid">
+ {% for m in site.data.team_active %}
+ <li class="team-card team-card--active">
+ <div class="team-avatar" aria-hidden="true">{{ m.name | slice: 0, 1 |
upcase }}</div>
+ <div class="team-meta">
+ <p class="team-name">{{ m.name }}</p>
+ <p class="team-roles">
+ {% if m.role == 'chair' %}<span class="role-badge role-chair"
title="PMC Chair">Chair</span>{% endif %}
+ {% if m.role == 'pmc' or m.role == 'chair' %}<span class="role-badge
role-pmc" title="PMC member">PMC</span>{% endif %}
+ <span class="role-badge role-committer"
title="Committer">Committer</span>
+ </p>
+ <p class="team-links">
+ <a href="https://github.com/{{ m.github }}" rel="noopener"
target="_blank">@{{ m.github }}</a>
+ <span class="team-availid">ยท {{ m.apache_id }}@apache.org</span>
+ </p>
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p class="team-empty">Active team list is currently unavailable.</p>
+ {% endif %}
+</section>
+
+{% if site.data.team_emeritus and site.data.team_emeritus.size > 0 %}
+<section class="team-section">
+ <h2 id="emeritus">Emeritus</h2>
+ <p class="team-emeritus-intro">
+ Past contributors who served as Storm PMC members or committers and are
+ no longer actively maintaining the project. Many of them shaped Storm
+ into what it is today — thank you.
+ </p>
+ <ul class="team-emeritus-list">
+ {% for m in site.data.team_emeritus %}
+ <li>
+ <a href="https://github.com/{{ m.github }}" rel="noopener"
target="_blank">{{ m.name }}</a>
+ {% if m.role == 'pmc' %}<span class="role-badge role-pmc
role-badge--sm">PMC</span>{% endif %}
+ <span class="team-availid">({{ m.apache_id }})</span>
+ </li>
+ {% endfor %}
+ </ul>
+</section>
+{% endif %}
+
+<section class="team-section">
+ <h2 id="contributors">Wall of fame</h2>
+ <p>
+ Apache Storm exists because of the many people who have contributed code,
+ reviews, documentation, and bug reports across the project's repositories
+ on GitHub. The full list is far too long to render here — please
+ have a look at the
+ <a href="https://github.com/apache/storm/graphs/contributors"
rel="noopener" target="_blank">contributors graph on GitHub</a>
+ to see them all.
+ </p>
+ <p class="team-thanks">
+ <strong>Thank you to every contributor</strong> — your patches,
+ reports, and reviews are what keep Storm moving.
+ </p>
+ <p>
+ If you would like to contribute, see the
+ <a href="/contribute/Contributing-to-Storm.html">contributing guide</a>
+ and join the conversation on the
+ <a href="/getting-help.html">developer mailing list</a>.
+ </p>
+</section>
+
+</div>