Add a convenience entrypoint for maintainers.py

This will make iterating on improvements to the script and
subsequent use easier. Note that for now the script itself is still
broken, relying on systems that have changed in the decade or more
since it was last relied on.

Change-Id: If42d76e51e867f54e10191bb130d5f7590f67029
This commit is contained in:
Jeremy Stanley 2025-03-21 14:49:55 +00:00
parent 0e64d90509
commit 3242fadc59
3 changed files with 83 additions and 71 deletions

View File

@ -84,74 +84,78 @@ import sys
import requests
import yaml
gerrit_url = 'https://review.opendev.org/'
try:
gerrit_auth = requests.auth.HTTPDigestAuth(sys.argv[1], getpass.getpass())
except IndexError:
sys.stderr.write("Usage: %s USERNAME\n" % sys.argv[0])
sys.exit(1)
acl_path = 'gitweb?p=%s.git;a=blob_plain;f=project.config;hb=refs/meta/config'
group_path = 'a/groups/%s/members/?recursive&pp=0'
projects_file = ('gitweb?p=openstack/governance.git;a=blob_plain;'
'f=reference/projects.yaml;hb=%s')
ref_name = 'refs/heads/master'
aprv_pattern = r'label-Workflow = .*\.\.\+1 group (.*)'
projects = requests.get(gerrit_url + projects_file % ref_name)
projects.encoding = 'utf-8' # Workaround for Gitweb encoding
projects = yaml.safe_load(projects.text)
repos_dump = json.loads(requests.get(
gerrit_url + 'projects/?pp=0').text[4:])
all_groups = json.loads(requests.get(gerrit_url + 'a/groups/',
auth=gerrit_auth).text[4:])
repos = {}
aprv_groups = {}
for repo in repos_dump:
repos[repo.encode('utf-8')] = {'approvers': {}}
acl_ini = requests.get(gerrit_url + acl_path % repo).text
for aprv_group in [str(x) for x in re.findall(aprv_pattern, acl_ini)]:
if aprv_group not in repos[repo]['approvers']:
repos[repo]['approvers'][aprv_group] = []
if aprv_group not in aprv_groups:
aprv_groups[aprv_group] = []
for team in projects:
if 'deliverables' in projects[team]:
for deli in projects[team]['deliverables']:
if 'repos' in projects[team]['deliverables'][deli]:
drepos = projects[team]['deliverables'][deli]['repos']
for repo in drepos:
if repo in repos:
repos[repo]['team'] = team
if 'tags' in projects[team]['deliverables'][deli]:
repos[repo]['tags'] = \
projects[team]['deliverables'][deli]['tags']
for aprv_group in aprv_groups.keys():
# It's possible for built-in metagroups in recent Gerrit releases to
# appear in ACLs but not in the groups list
if aprv_group in all_groups:
aprv_groups[aprv_group] = json.loads(requests.get(
gerrit_url + group_path % all_groups[aprv_group]['id'],
auth=gerrit_auth).text[4:])
else:
sys.stderr.write('Ignoring nonexistent "%s" group.\n' % aprv_group)
for repo in repos:
for aprv_group in repos[repo]['approvers'].keys():
for approver in aprv_groups[aprv_group]:
if 'name' in approver:
approver_details = '"%s"' % approver['name']
else:
approver_details = ''
if 'email' in approver:
if approver_details:
approver_details += ' '
approver_details += '<%s>' % approver['email']
if 'username' in approver:
if approver_details:
approver_details += ' '
approver_details += '(%s)' % approver['username']
repos[repo]['approvers'][aprv_group].append(
approver_details.encode('utf-8'))
approvers_yaml = open('approvers.yaml', 'w')
yaml.dump(repos, approvers_yaml, allow_unicode=True, encoding='utf-8',
default_flow_style=False)
approvers_json = open('approvers.json', 'w')
json.dump(repos, approvers_json, indent=2)
def main():
gerrit_url = 'https://review.opendev.org/'
try:
gerrit_auth = requests.auth.HTTPDigestAuth(
sys.argv[1], getpass.getpass())
except IndexError:
sys.stderr.write("Usage: %s USERNAME\n" % sys.argv[0])
sys.exit(1)
acl_path = (
'gitweb?p=%s.git;a=blob_plain;f=project.config;hb=refs/meta/config')
group_path = 'a/groups/%s/members/?recursive&pp=0'
projects_file = ('gitweb?p=openstack/governance.git;a=blob_plain;'
'f=reference/projects.yaml;hb=%s')
ref_name = 'refs/heads/master'
aprv_pattern = r'label-Workflow = .*\.\.\+1 group (.*)'
projects = requests.get(gerrit_url + projects_file % ref_name)
projects.encoding = 'utf-8' # Workaround for Gitweb encoding
projects = yaml.safe_load(projects.text)
repos_dump = json.loads(requests.get(
gerrit_url + 'projects/?pp=0').text[4:])
all_groups = json.loads(requests.get(gerrit_url + 'a/groups/',
auth=gerrit_auth).text[4:])
repos = {}
aprv_groups = {}
for repo in repos_dump:
repos[repo.encode('utf-8')] = {'approvers': {}}
acl_ini = requests.get(gerrit_url + acl_path % repo).text
for aprv_group in [str(x) for x in re.findall(aprv_pattern, acl_ini)]:
if aprv_group not in repos[repo]['approvers']:
repos[repo]['approvers'][aprv_group] = []
if aprv_group not in aprv_groups:
aprv_groups[aprv_group] = []
for team in projects:
if 'deliverables' in projects[team]:
for deli in projects[team]['deliverables']:
if 'repos' in projects[team]['deliverables'][deli]:
drepos = projects[team]['deliverables'][deli]['repos']
for repo in drepos:
if repo in repos:
repos[repo]['team'] = team
if 'tags' in projects[team]['deliverables'][deli]:
repos[repo]['tags'] = projects[
team]['deliverables'][deli]['tags']
for aprv_group in aprv_groups.keys():
# It's possible for built-in metagroups in recent Gerrit releases to
# appear in ACLs but not in the groups list
if aprv_group in all_groups:
aprv_groups[aprv_group] = json.loads(requests.get(
gerrit_url + group_path % all_groups[aprv_group]['id'],
auth=gerrit_auth).text[4:])
else:
sys.stderr.write('Ignoring nonexistent "%s" group.\n' % aprv_group)
for repo in repos:
for aprv_group in repos[repo]['approvers'].keys():
for approver in aprv_groups[aprv_group]:
if 'name' in approver:
approver_details = '"%s"' % approver['name']
else:
approver_details = ''
if 'email' in approver:
if approver_details:
approver_details += ' '
approver_details += '<%s>' % approver['email']
if 'username' in approver:
if approver_details:
approver_details += ' '
approver_details += '(%s)' % approver['username']
repos[repo]['approvers'][aprv_group].append(
approver_details.encode('utf-8'))
approvers_yaml = open('approvers.yaml', 'w')
yaml.dump(repos, approvers_yaml, allow_unicode=True, encoding='utf-8',
default_flow_style=False)
approvers_json = open('approvers.json', 'w')
json.dump(repos, approvers_json, indent=2)

View File

@ -13,6 +13,13 @@ def stats(session):
session.run("engagement-stats", *session.posargs)
# Convenience wrapper for maintainer list querying
@nox.session(python="3")
def maintainers(session):
session.install(".")
session.run("engagement-maintainers", *session.posargs)
# Note setting python this way seems to give us a target name without
# python specific suffixes while still allowing us to force a specific
# version using --force-python.

View File

@ -71,6 +71,7 @@ test-unit = [
[project.scripts]
engagement-stats = "engagement.stats:main"
engagement-maintainers = "engagement.maintainers:main"
[project.urls]
"Browse Source" = "https://opendev.org/opendev/engagement"