fetch-contributors 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/python
  2. '''
  3. A script to fetch recent contributors to borgmatic, used during documentation generation.
  4. '''
  5. import datetime
  6. import itertools
  7. import operator
  8. import subprocess
  9. import requests
  10. def list_merged_pulls(url):
  11. '''
  12. Given a Gitea or GitHub API endpoint URL for pull requests, fetch and return the corresponding
  13. JSON for all such merged pull requests.
  14. '''
  15. response = requests.get(f'{url}?state=closed', headers={'Accept': 'application/json', 'Content-Type': 'application/json'})
  16. if not response.ok:
  17. response.raise_for_status()
  18. return tuple(pull for pull in response.json() if pull.get('merged_at'))
  19. def list_contributing_issues(url):
  20. response = requests.get(url, headers={'Accept': 'application/json', 'Content-Type': 'application/json'})
  21. if not response.ok:
  22. response.raise_for_status()
  23. return tuple(response.json())
  24. PULLS_API_ENDPOINT_URLS = (
  25. 'https://projects.torsion.org/api/v1/repos/borgmatic-collective/borgmatic/pulls',
  26. 'https://api.github.com/repos/borgmatic-collective/borgmatic/pulls',
  27. )
  28. ISSUES_API_ENDPOINT_URL = 'https://projects.torsion.org/api/v1/repos/borgmatic-collective/borgmatic/issues?state=all'
  29. RECENT_CONTRIBUTORS_CUTOFF_DAYS = 365
  30. def get_item_timestamp(item):
  31. return item.get('merged_at') or item.get('created_at')
  32. def print_contributors():
  33. '''
  34. Display the recent contributors as a row of avatars in an HTML fragment.
  35. '''
  36. pulls = tuple(itertools.chain.from_iterable(list_merged_pulls(url) for url in PULLS_API_ENDPOINT_URLS))
  37. issues = list_contributing_issues(ISSUES_API_ENDPOINT_URL)
  38. seen_user_ids = set()
  39. print('<p>')
  40. for item in sorted(pulls + issues, key=get_item_timestamp, reverse=True):
  41. timestamp = get_item_timestamp(item)
  42. user = item.get('user')
  43. if not timestamp or not user:
  44. continue
  45. user_id = user.get('id')
  46. if not user_id or user_id in seen_user_ids:
  47. continue
  48. if datetime.datetime.fromisoformat(timestamp) < datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=RECENT_CONTRIBUTORS_CUTOFF_DAYS):
  49. continue
  50. seen_user_ids.add(user_id)
  51. print(
  52. f'''<a href="{user.get('html_url')}?tab=activity"><img src="{user.get('avatar_url')}" width="50" height="50" title="{user.get('full_name') or user.get('login')}" /></a>'''
  53. )
  54. print('</p>')
  55. if __name__ == '__main__':
  56. print_contributors()