/team: Fetch contributors data from all major repos.

Also wait 2 seconds before trying again.
This commit is contained in:
Tommy Ip 2017-11-16 13:05:26 +00:00 committed by Tim Abbott
parent 84384196f2
commit 771abf4179
1 changed files with 59 additions and 49 deletions

View File

@ -9,10 +9,12 @@ from lib import sanity_check
sanity_check.check_venv(__file__) sanity_check.check_venv(__file__)
from typing import Any, Dict, List, Optional, Union, Text from typing import Any, Dict, List, Optional, Union, Text
from mypy_extensions import TypedDict
import os import os
import sys import sys
import argparse import argparse
from time import sleep
from datetime import date from datetime import date
import subprocess import subprocess
@ -25,7 +27,6 @@ from django.conf import settings
from zerver.lib.utils import split_by from zerver.lib.utils import split_by
FIXTURE_FILE = os.path.join(os.path.dirname(__file__), '../zerver/fixtures/authors.json') FIXTURE_FILE = os.path.join(os.path.dirname(__file__), '../zerver/fixtures/authors.json')
GITHUB_LINK = 'https://api.github.com/repos/zulip/zulip/stats/contributors'
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--max-retries', type=int, default=3, parser.add_argument('--max-retries', type=int, default=3,
@ -38,22 +39,18 @@ parser.add_argument('--not-required', action='store_true', default=False,
help='Consider failures to reach GitHub nonfatal') help='Consider failures to reach GitHub nonfatal')
args = parser.parse_args() args = parser.parse_args()
def fetch_data(retries, link): ContributorsJSON = TypedDict('ContributorsJSON', {
# type: (int, str) -> Optional[List[Dict[str, Any]]] 'date': str,
for _ in range(retries): 'contrib': Dict[str, Dict[str, Union[str, int]]],
try: })
r = requests.get(link) # type: requests.Response
if r.status_code == 200:
return r.json()
else:
print('Github API return non 200 status.')
except requests.exceptions.RequestException as e:
print(e)
return None
def write_to_disk(json_data, out_file): def fetch_contributors(repo_link: str) -> Optional[List[Dict[str, Dict[str, Any]]]]:
# type: (Dict[str, Any], str) -> None r = requests.get(repo_link) # type: requests.Response
return r.json() if r.status_code == 200 else None
def write_to_disk(json_data: ContributorsJSON, out_file: str) -> None:
with open(out_file, 'w') as f: with open(out_file, 'w') as f:
try: try:
f.write("{}\n".format(json.dumps(json_data))) f.write("{}\n".format(json.dumps(json_data)))
@ -61,53 +58,66 @@ def write_to_disk(json_data, out_file):
print(e) print(e)
sys.exit(1) sys.exit(1)
def run_production():
# type: () -> None def run_production() -> None:
""" """
Fetch data from Github and stored it in Get contributors data from Github and insert them into a temporaril
`static/generated/github-contributors.json` dictionary. Retry fetching each repository if responded with non HTTP
200 status.
""" """
json_data = fetch_data(args.max_retries, GITHUB_LINK) # type: Optional[List[Dict[str, Any]]] repositories = {
if json_data: 'server': 'https://api.github.com/repos/zulip/zulip/stats/contributors',
# Successfully fetch data from Github 'desktop': 'https://api.github.com/repos/zulip/zulip-electron/stats/contributors',
contribs = [] 'mobile': 'https://api.github.com/repos/zulip/zulip-mobile/stats/contributors',
for user in json_data: 'python-zulip-api': 'https://api.github.com/repos/zulip/python-zulip-api/stats/contributors',
author = user.get('author') 'zulipbot': 'https://api.github.com/repos/zulip/zulipbot/stats/contributors',
if author is None: }
print("Unable to access fields for %s" % (user,))
continue
result_user = dict(
avatar=author.get('avatar_url'),
name=author.get('login'),
commits=user.get('total')
)
contribs.append(result_user)
out_contrib_data = sorted( data = dict(date=str(date.today()), contrib={}) # type: ContributorsJSON
contribs, contribs_data = {} # type: Dict[str, Dict[str, Union[str, int]]]
key=lambda k: k.get('commits'),
reverse=True
) # type: List[Dict[str, Union[Text, int]]]
out_data = dict( for t in range(args.max_retries):
data=out_contrib_data, repo_done = []
date=str(date.today()) for k, v in repositories.items():
) # type: Dict[str, Any] contribs = fetch_contributors(v)
if contribs:
repo_done.append(k)
for contrib in contribs:
username = contrib.get('author').get('login')
contrib_data = {
'avatar': contrib.get('author').get('avatar_url'),
k: contrib.get('total'),
}
if username in contribs_data:
contribs_data[username].update(contrib_data)
else:
contribs_data[username] = contrib_data
for k in repo_done:
del repositories[k]
write_to_disk(out_data, settings.CONTRIBUTORS_DATA) if not repositories:
break
elif not args.not_required: # Wait before retrying failed requests for Github to aggregate data.
print('Fail to fetch data from Github.') sleep(2)
sys.exit(1) else:
print("ERROR: Failed fetching contributors data from Github.")
if not args.not_required:
sys.exit(1)
def copy_fixture(): data['contrib'] = contribs_data
# type: () -> None
write_to_disk(data, settings.CONTRIBUTORS_DATA)
def copy_fixture() -> None:
""" """
Copy test fixture file from zerver/fixtures. This is used to avoid Copy test fixture file from zerver/fixtures. This is used to avoid
constantly fetching data from Github during testing. constantly fetching data from Github during testing.
""" """
subprocess.check_call(['cp', FIXTURE_FILE, settings.CONTRIBUTORS_DATA]) subprocess.check_call(['cp', FIXTURE_FILE, settings.CONTRIBUTORS_DATA])
if args.use_fixture: if args.use_fixture:
copy_fixture() copy_fixture()
else: else: