mirror of
https://github.com/langchain-ai/datafusion.git
synced 2026-07-19 15:24:21 -04:00
d572eeb671
* Add committers explicitly to governance page, with script * add license header * Update Wes McKinney's affiliation in governance.md * Update adriangb's affiliation * Update affiliation * Andy Grove Affiliation * Update Qi Zhu affiliation * Updatd linwei's info * Update docs/source/contributor-guide/governance.md * Update docs/source/contributor-guide/governance.md * Apply suggestions from code review Co-authored-by: Oleks V <comphead@users.noreply.github.com> Co-authored-by: Liang-Chi Hsieh <viirya@gmail.com> * Apply suggestions from code review Co-authored-by: Alex Huang <huangweijun1001@gmail.com> Co-authored-by: Yang Jiang <jiangyang381@163.com> Co-authored-by: Yongting You <2010youy01@gmail.com> * Apply suggestions from code review Co-authored-by: Yijie Shen <henry.yijieshen@gmail.com> * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Brent Gardner <bgardner@squarelabs.net> Co-authored-by: Dmitrii Blaginin <github@blaginin.me> Co-authored-by: Jax Liu <liugs963@gmail.com> Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com> * Apply suggestions from code review Co-authored-by: Will Jones <willjones127@gmail.com> * Clarify what is updated in the script * Apply suggestions from code review Co-authored-by: Paddy Horan <5733408+paddyhoran@users.noreply.github.com> Co-authored-by: Dan Harris <1327726+thinkharderdev@users.noreply.github.com> * Update docs/source/contributor-guide/governance.md * Update docs/source/contributor-guide/governance.md Co-authored-by: Parth Chandra <parthc@apache.org> * Update docs/source/contributor-guide/governance.md * prettier --------- Co-authored-by: Wes McKinney <wesm@apache.org> Co-authored-by: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Co-authored-by: Mustafa Akur <akurmustafa@gmail.com> Co-authored-by: Qi Zhu <821684824@qq.com> Co-authored-by: 张林伟 <lewiszlw520@gmail.com> Co-authored-by: xudong.w <wxd963996380@gmail.com> Co-authored-by: Oleks V <comphead@users.noreply.github.com> Co-authored-by: Liang-Chi Hsieh <viirya@gmail.com> Co-authored-by: Alex Huang <huangweijun1001@gmail.com> Co-authored-by: Yang Jiang <jiangyang381@163.com> Co-authored-by: Yongting You <2010youy01@gmail.com> Co-authored-by: Yijie Shen <henry.yijieshen@gmail.com> Co-authored-by: Brent Gardner <bgardner@squarelabs.net> Co-authored-by: Dmitrii Blaginin <github@blaginin.me> Co-authored-by: Jax Liu <liugs963@gmail.com> Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com> Co-authored-by: Will Jones <willjones127@gmail.com> Co-authored-by: Paddy Horan <5733408+paddyhoran@users.noreply.github.com> Co-authored-by: Dan Harris <1327726+thinkharderdev@users.noreply.github.com> Co-authored-by: Ruihang Xia <waynestxia@gmail.com> Co-authored-by: Parth Chandra <parthc@apache.org>
267 lines
8.5 KiB
Python
Executable File
267 lines
8.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
"""
|
|
Utility for updating the committer list in the governance documentation
|
|
by reading from the Apache DataFusion phonebook and combining with existing data.
|
|
"""
|
|
|
|
import re
|
|
import requests
|
|
import sys
|
|
import os
|
|
from typing import Dict, List, NamedTuple, Set
|
|
|
|
|
|
class Committer(NamedTuple):
|
|
name: str
|
|
apache: str
|
|
github: str
|
|
affiliation: str
|
|
role: str
|
|
|
|
|
|
# Return (pmc, committers) each a dictionary like
|
|
# key: apache id
|
|
# value: Real name
|
|
|
|
def get_asf_roster():
|
|
"""Get the current roster from Apache phonebook."""
|
|
# See https://home.apache.org/phonebook-about.html
|
|
committers_url = "https://whimsy.apache.org/public/public_ldap_projects.json"
|
|
|
|
# people https://whimsy.apache.org/public/public_ldap_people.json
|
|
people_url = "https://whimsy.apache.org/public/public_ldap_people.json"
|
|
|
|
try:
|
|
r = requests.get(committers_url)
|
|
r.raise_for_status()
|
|
j = r.json()
|
|
proj = j['projects']['datafusion']
|
|
|
|
# Get PMC members and committers
|
|
pmc_ids = set(proj['owners'])
|
|
committer_ids = set(proj['members']) - pmc_ids
|
|
|
|
except Exception as e:
|
|
print(f"Error fetching ASF roster: {e}")
|
|
return set(), set()
|
|
|
|
# Fetch people to get github handles and affiliations
|
|
#
|
|
# The data looks like this:
|
|
# {
|
|
# "lastCreateTimestamp": "20250913131506Z",
|
|
# "people_count": 9932,
|
|
# "people": {
|
|
# "a_budroni": {
|
|
# "name": "Alessandro Budroni",
|
|
# "createTimestamp": "20160720223917Z"
|
|
# },
|
|
# ...
|
|
# }
|
|
try:
|
|
r = requests.get(people_url)
|
|
r.raise_for_status()
|
|
j = r.json()
|
|
people = j['people']
|
|
|
|
# make a dictionary with each pmc_id and value their real name
|
|
pmcs = {p: people[p]['name'] for p in pmc_ids}
|
|
committers = {c: people[c]['name'] for c in committer_ids}
|
|
|
|
except Exception as e:
|
|
print(f"Error fetching ASF people: {e}")
|
|
|
|
|
|
return pmcs, committers
|
|
|
|
|
|
|
|
def parse_existing_table(content: str) -> List[Committer]:
|
|
"""Parse the existing committer table from the markdown content."""
|
|
committers = []
|
|
|
|
# Find the table between the markers
|
|
start_marker = "<!-- Begin Auto-Generated Committer List -->"
|
|
end_marker = "<!-- End Auto-Generated Committer List -->"
|
|
|
|
start_idx = content.find(start_marker)
|
|
end_idx = content.find(end_marker)
|
|
|
|
if start_idx == -1 or end_idx == -1:
|
|
return committers
|
|
|
|
table_content = content[start_idx:end_idx]
|
|
|
|
# Parse table rows (skip header and separator)
|
|
lines = table_content.split('\n')
|
|
for line in lines:
|
|
line = line.strip()
|
|
if line.startswith('|') and '---' not in line and line.count('|') >= 4:
|
|
# Split by | and clean up
|
|
parts = [part.strip() for part in line.split('|')]
|
|
if len(parts) >= 5:
|
|
name = parts[1].strip()
|
|
apache = parts[2].strip()
|
|
github = parts[3].strip()
|
|
affiliation = parts[4].strip()
|
|
role = parts[5].strip()
|
|
|
|
if name and name != 'Name' and (not '-----' in name):
|
|
committers.append(Committer(name, apache, github, affiliation, role))
|
|
|
|
return committers
|
|
|
|
|
|
def generate_table_row(committer: Committer) -> str:
|
|
"""Generate a markdown table row for a committer."""
|
|
github_link = f"[{committer.github}](https://github.com/{committer.github})"
|
|
return f"| {committer.name:<23} | {committer.apache:<39} |{committer.github:<39} | {committer.affiliation:<11} | {committer.role:<9} |"
|
|
|
|
|
|
def sort_committers(committers: List[Committer]) -> List[Committer]:
|
|
"""Sort committers by role ('PMC Chair', PMC, Committer) then by apache id."""
|
|
role_order = {'PMC Chair': 0, 'PMC': 1, 'Committer': 2}
|
|
|
|
return sorted(committers, key=lambda c: (role_order.get(c.role, 3), c.apache.lower()))
|
|
|
|
|
|
def update_governance_file(file_path: str):
|
|
"""Update the governance file with the latest committer information."""
|
|
try:
|
|
with open(file_path, 'r') as f:
|
|
content = f.read()
|
|
except FileNotFoundError:
|
|
print(f"Error: File {file_path} not found")
|
|
return False
|
|
|
|
# Parse existing committers
|
|
existing_committers = parse_existing_table(content)
|
|
print(f"Found {len(existing_committers)} existing committers")
|
|
|
|
# Get ASF roster
|
|
asf_pmcs, asf_committers = get_asf_roster()
|
|
print(f"Found {len(asf_pmcs)} PMCs and {len(asf_committers)} committers in ASF roster")
|
|
|
|
|
|
# Create a map of existing committers by apache id
|
|
existing_by_apache = {c.apache: c for c in existing_committers}
|
|
|
|
# Update the entries based on the ASF roster
|
|
updated_committers = []
|
|
for apache_id, name in {**asf_pmcs, **asf_committers}.items():
|
|
role = 'PMC' if apache_id in asf_pmcs else 'Committer'
|
|
if apache_id in existing_by_apache:
|
|
existing = existing_by_apache[apache_id]
|
|
# Preserve PMC Chair role if already set
|
|
if existing.role == 'PMC Chair':
|
|
role = 'PMC Chair'
|
|
updated_committers.append(Committer(
|
|
name=existing.name,
|
|
apache=apache_id,
|
|
github=existing.github,
|
|
affiliation=existing.affiliation,
|
|
role=role
|
|
))
|
|
# add a new entry for new committers with placeholder values
|
|
else:
|
|
print(f"New entry found: {name} ({apache_id})")
|
|
# Placeholder github and affiliation
|
|
updated_committers.append(Committer(
|
|
name=name,
|
|
apache=apache_id,
|
|
github="", # user should update
|
|
affiliation="", # User should update
|
|
role=role
|
|
))
|
|
|
|
|
|
# Sort the committers
|
|
sorted_committers = sort_committers(updated_committers)
|
|
|
|
# Generate new table
|
|
table_lines = [
|
|
"| Name | Apache ID | github | Affiliation | Role |",
|
|
"|-------------------------|-----------|----------------------------|-------------|-----------|"
|
|
]
|
|
|
|
for committer in sorted_committers:
|
|
table_lines.append(generate_table_row(committer))
|
|
|
|
new_table = '\n'.join(table_lines)
|
|
|
|
# Replace the table in the content
|
|
start_marker = "<!-- Begin Auto-Generated Committer List -->"
|
|
end_marker = "<!-- End Auto-Generated Committer List -->"
|
|
|
|
start_idx = content.find(start_marker)
|
|
end_idx = content.find(end_marker)
|
|
|
|
if start_idx == -1 or end_idx == -1:
|
|
print("Error: Could not find table markers in file")
|
|
return False
|
|
|
|
# Find the end of the start marker line
|
|
start_line_end = content.find('\n', start_idx) + 1
|
|
|
|
new_content = (
|
|
content[:start_line_end] +
|
|
new_table + '\n' +
|
|
content[end_idx:]
|
|
)
|
|
|
|
# Write back to file
|
|
try:
|
|
with open(file_path, 'w') as f:
|
|
f.write(new_content)
|
|
print(f"Successfully updated {file_path}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error writing file: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Main function."""
|
|
# Default path to governance file
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
repo_root = os.path.dirname(script_dir)
|
|
governance_file = os.path.join(repo_root, "source", "contributor-guide", "governance.md")
|
|
|
|
if len(sys.argv) > 1:
|
|
governance_file = sys.argv[1]
|
|
|
|
if not os.path.exists(governance_file):
|
|
print(f"Error: Governance file not found at {governance_file}")
|
|
sys.exit(1)
|
|
|
|
print(f"Updating committer list in {governance_file}")
|
|
|
|
if update_governance_file(governance_file):
|
|
print("Committer list updated successfully")
|
|
else:
|
|
print("Failed to update committer list")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|