Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

maintainers.html: Add list of maintainers #141

Merged
merged 11 commits into from
Dec 9, 2024
2 changes: 1 addition & 1 deletion .github/workflows/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Update RIOT data
run: make update_riot_data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RIOT_CI_ACCESS_TOKEN }}

# Use GitHub Actions' cache to shorten build times and decrease load on servers
- uses: actions/cache@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/receive_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Update RIOT data
run: make update_riot_data
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RIOT_CI_ACCESS_TOKEN }}

# Use GitHub Actions' cache to shorten build times and decrease load on servers
- uses: actions/cache@v4
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RIOT_DATA_FILES += $(DATA_DIR)/riot_contributors.yml
RIOT_DATA_FILES += $(DATA_DIR)/riot_drivers.yml
RIOT_DATA_FILES += $(DATA_DIR)/riot_drivers_cats.yml
RIOT_DATA_FILES += $(DATA_DIR)/riot_cpus.yml
RIOT_DATA_FILES += $(DATA_DIR)/riot_maintainers.yml

WATCH ?= 0

Expand All @@ -40,6 +41,8 @@ ifeq ($(RIOTBASE),$(_DEFAULT_RIOTBASE))
@git -C $(RIOTBASE) pull
endif

$(DATA_DIR)/riot_maintainers.yml: $(RIOTBASE)/CODEOWNERS

$(RIOT_DATA_FILES):
@$(RIOT_FETCH_DATA_CMD)

Expand Down
1 change: 1 addition & 0 deletions _includes/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<li class="dropdown"><a href="{% link community.html %}"><span>Community</span> <i class="bi bi-chevron-down"></i></a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a href="{% link community.html %}">Overview</a></li>
<li><a href="{% link maintainers.html %}">Maintainers</a></li>
<li><a href="https://forum.riot-os.org" target="_blank">Forum <i class="bi bi-box-arrow-up-right align-text-bottom"></i></a></li>
<li><a href="https://github.com/topics/riot-os" target="_blank">GitHub <i class="bi bi-box-arrow-up-right align-text-bottom"></i></a></li>
<li><a class="scrollto" href="{% link community.html %}#socialmedia">Social Media</a></li>
Expand Down
8 changes: 8 additions & 0 deletions _sass/pages/about.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@
margin: 5px 5px 5px 5px;
}
}

#maintainers {
.maintainers-img {
width: 22px;
border-radius: 50%;
margin: 1px;
}
}
69 changes: 69 additions & 0 deletions _tools/default_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,75 @@
"avatar_url": "https://avatars.githubusercontent.com/u/5160052?v=4",
},
]
DEFAULT_MAINTAINERS = [
{
"login": "miri64",
"avatar_url": "https://avatars.githubusercontent.com/u/675644?v=4",
"name": "Martine Lenders",
"html_url": "https://github.com/miri64",
"admin": True,
"owner": False,
"areas": [
"sys/net",
"tests/*/tests/*.py",
],
},
{
"login": "aabadie",
"avatar_url": "https://avatars.githubusercontent.com/u/1375137?v=4",
"name": "Alexandre Abadie",
"html_url": "https://github.com/aabadie",
"admin": False,
"owner": False,
"areas": [
"pkg/semtech-loramac/",
"doc/",
],
},
{
"login": "OlegHahm",
"name": "Oleg Hahm",
"avatar_url": "https://avatars.githubusercontent.com/u/1590423?v=4",
"html_url": "https://github.com/OlegHahm",
"admin": False,
"owner": True,
"areas": [],
},
{
"login": "kaspar030",
"avatar_url": "https://avatars.githubusercontent.com/u/4679640?v=4",
"name": "Kaspar Schleiser",
"html_url": "https://github.com/kaspar030",
"admin": False,
"owner": True,
"areas": [
"sys/include/ztimer.h",
"pm.c",
],
},
{
"login": "benpicco",
"avatar_url": "https://avatars.githubusercontent.com/u/1301112?v=4",
"html_url": "https://github.com/benpicco",
"name": "",
"admin": True,
"owner": False,
"areas": [
"drivers/at86rf215/",
],
},
{
"login": "biboc",
"avatar_url": "https://avatars.githubusercontent.com/u/4921425?v=4",
"html_url": "https://github.com/biboc",
"name": "biboc",
"admin": False,
"owner": False,
"areas": [
"cpu/samd21/",
],
},
]
DEFAULT_STATS = {
"boards": len(DEFAULT_BOARDS),
"cpus": len(DEFAULT_BOARDS),
Expand Down
109 changes: 107 additions & 2 deletions _tools/fetch_riot_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

from default_data import (
DEFAULT_BOARDS, DEFAULT_CPUS, DEFAULT_DRIVERS,
DEFAULT_DRIVER_CATEGORIES, DEFAULT_CONTRIBUTORS, DEFAULT_STATS
DEFAULT_DRIVER_CATEGORIES, DEFAULT_CONTRIBUTORS, DEFAULT_STATS,
DEFAULT_MAINTAINERS,
)

DATA_DIR = os.getenv("DATA_DIR", os.path.join(os.path.abspath(__file__)))
Expand Down Expand Up @@ -57,13 +58,23 @@
commits: ${commits}
"""

MAINTAINERS_TEMPLATE = """- login: ${login}
avatar_url: ${avatar_url}
html_url: https://github.com/${login}
name: ${name}
admin: ${admin}
owner: ${owner}
areas: ${areas}
"""

TEMPLATES = {
"boards": BOARDS_TEMPLATE,
"cpus": CPU_TEMPLATE,
"drivers": DRIVERS_TEMPLATE,
"drivers_cats": DRIVER_CATEGORIES_TEMPLATE,
"contributors": CONTRIBUTORS_TEMPLATE,
"stats": STATS_TEMPLATE,
"maintainers": MAINTAINERS_TEMPLATE,
}


Expand Down Expand Up @@ -117,6 +128,51 @@ def fetch_contributors_data():
]


def fetch_maintainer_data():
if requests is None:
print(
"Warning: 'requests' package is missing, default contributors "
"will be returned (only 10 contributors).\nYou can install "
"'requests' using 'make install_python_requirements'."
)
return DEFAULT_MAINTAINERS
if not os.getenv("GITHUB_TOKEN"):
print(
"Warning: no GitHub token provided via GITHUB_TOKEN environment "
"variable, default maintainers will be returned (only 6 "
"maintainers).\nYou need a GitHub personal access token with "
"admin:org > read:org scope."
)
return DEFAULT_MAINTAINERS
maintainers = get_team_members("maintainers")
admins = get_team_members("admin")
owners = get_team_members("owners")
maintainers = maintainers.union(admins)
maintainers = maintainers.union(owners)
maintainer_areas = get_maintainer_codeowner_patterns(maintainers)
res = []
for maintainer in maintainer_areas:
github_profile = get_github_user(maintainer)
if "login" not in github_profile or github_profile["login"] != maintainer:
print(
"Warning: error on fetching GitHub profile. Make sure "
"the GITHUB_TOKEN has appropriate rights"
)
return DEFAULT_MAINTAINERS
res.append(
{
"login": maintainer,
"name": github_profile["name"],
"avatar_url": github_profile["avatar_url"],
"html_url": github_profile["html_url"],
"admin": maintainer in admins,
"owner": maintainer in owners,
"areas": list(sorted(maintainer_areas[maintainer])),
}
)
return res


def search_data(file_paths, regexp, parent_regexp=None, multi=False):
"""Search doxygen data in a list of files/dirs using regexps."""
results = []
Expand Down Expand Up @@ -273,6 +329,54 @@ def fetch_stats_data():
}


def get_team_members(team):
token = os.getenv("GITHUB_TOKEN")
assert token is not None
members = requests.get(
f"https://api.github.com/orgs/RIOT-OS/teams/{team}/members",
headers={
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"X-GitHub-Api-Version": "2022-11-28",
},
)
try:
return set(m["login"] for m in members.json())
except Exception as exc:
print(f"Error fetching team {team}: {exc}", file=sys.stderr)
raise


def get_github_user(username):
token = os.getenv("GITHUB_TOKEN")
assert token is not None
user = requests.get(
f"https://api.github.com/users/{username}",
headers={
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"X-GitHub-Api-Version": "2022-11-28",
},
)
return user.json()


def get_maintainer_codeowner_patterns(maintainers):
maintainer_patterns = {m: set() for m in maintainers}

with open(os.path.join(RIOTBASE, "CODEOWNERS")) as codeowners_file:
for line in codeowners_file:
if re.search(r"^\s*#", line) or re.match(r"^\s*$", line):
# skip comments and empty lines
continue
pattern, *owners = re.split(r"\s+", line.strip())
for owner in owners:
owner = owner.lstrip("@")
if owner in maintainer_patterns:
maintainer_patterns[owner].add(pattern.lstrip("/"))
return maintainer_patterns


def main():
"""Main function."""
if not os.path.exists(RIOTBASE):
Expand All @@ -290,11 +394,12 @@ def main():
drivers = fetch_drivers_data()
driver_categories = fetch_driver_categories_data()
contributors = fetch_contributors_data()
maintainers = fetch_maintainer_data()
stats = fetch_stats_data()
for name, data in (
("boards", boards), ("cpus", cpus), ("drivers", drivers),
("drivers_cats", driver_categories), ("contributors", contributors),
("stats", [stats])
("stats", [stats]), ("maintainers", maintainers)
):
render_data_to_file(name, data)
if os.path.exists(RIOTBASE):
Expand Down
70 changes: 70 additions & 0 deletions maintainers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
layout: simple-page
title: RIOT Maintainers
subtitle: RIOT is nurtured by a strong community of maintainers.
miri64 marked this conversation as resolved.
Show resolved Hide resolved
---
<main>
<!-- ======= Maintainers Section ======= -->
<section id="maintainers">
<div class="container">
<p>
This is the current list of maintainers within the RIOT community with there area of
miri64 marked this conversation as resolved.
Show resolved Hide resolved
expertise within the
<a href="https://github.com/RIOT-OS/RIOT/" target="_blank">RIOT codebase</a>.

If a maintainer is marked with <q>Has no chosen area of expertise</q>, they did not add any
ownership within
<a href="https://github.com/RIOT-OS/RIOT/blob/master/CODEOWNERS" target="_blank">
<tt>CODEOWNERS</tt>
</a>. This does not mean that they do not feel responsible for any part
of the code base, they just did not declare it.
</p>

<p id="maintainer-list">
miri64 marked this conversation as resolved.
Show resolved Hide resolved
<div class="row row-cols-1 g-4">
{% assign maintainer_by_login = site.data.riot_maintainers | sort_natural: "login" %}
{% for maintainer in maintainer_by_login %}
<div class="col">
<div class="card shadow rounded">
<div class="card-body">
<h5 class="card-title">
<a href="{{ maintainer.html_url }}" target="_blank"><img class="maintainers-img" src="{{ maintainer.avatar_url }}" alt="{{ maintainer.login }} avatar" /></a>
<a href="{{ maintainer.html_url }}" target="_blank">
@{{ maintainer.login }}
{% if maintainer.name or maintainer.name != maintainer.login %}<small>({{ maintainer.name }})</small>{% endif %}
</a>
</h5>
<ul>
{% if maintainer.owner %}
<li><strong>Is one of the GitHub owners of RIOT</strong></li>
{% endif %}
{% if maintainer.admin %}
<li><strong>Is one of the GitHub admins of RIOT</strong></li>
{% endif %}
{% for area in maintainer.areas %}
<li><tt>{{ area }}</tt></li>
{% else %}
<li>Has no chosen area of expertise</li>
miri64 marked this conversation as resolved.
Show resolved Hide resolved
{% endfor %}</ul>
</div>
</div>
</div>
{% endfor %}
</div>
</p>
<p>
This list is generated by combining the information from the maintainers, owners and
miri64 marked this conversation as resolved.
Show resolved Hide resolved
admin teams from the RIOT-OS GitHub organization and the
miri64 marked this conversation as resolved.
Show resolved Hide resolved
<a href="https://github.com/RIOT-OS/RIOT/blob/master/CODEOWNERS" target="_blank">
<tt>CODEOWNERS</tt>
</a> file within the RIOT repository.
</p>

<p>
If you are a maintainer and want to declare ownership for a part of a code base (and
receive notifications on pull requests against it), please add yourself and the path to
miri64 marked this conversation as resolved.
Show resolved Hide resolved
the part of the code base you want to be responsible for to CODEOWNERS via pull request to
the RIOT repository.
</p>
</section><!-- End Board Section -->
</main><!-- End #main -->
Loading