fetch_milestone.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #!/usr/bin/env python3
  2. import argparse
  3. import re
  4. import sys
  5. from typing import Dict, List
  6. import requests
  7. BASE_URL = 'https://api.github.com/repos/zauberzeug/nicegui'
  8. parser = argparse.ArgumentParser(description='Fetch the content of a milestone from a GitHub repo.')
  9. parser.add_argument('milestone_title', help='Title of the milestone to fetch.')
  10. args = parser.parse_args()
  11. milestone_title: str = args.milestone_title
  12. page = 0
  13. while True:
  14. page += 1
  15. response = requests.get(f'{BASE_URL}/milestones?state=all&page={page}&per_page=100', timeout=5)
  16. milestones = response.json()
  17. if not milestones:
  18. print(f'Milestone "{milestone_title}" not found!')
  19. sys.exit(1)
  20. matching = [m for m in milestones if m['title'] == milestone_title]
  21. if matching:
  22. milestone_number = matching[0]['number']
  23. break
  24. def link(number: int) -> str:
  25. # https://stackoverflow.com/a/71309268/3419103
  26. escape_mask = '\033]8;{};{}\033\\{}\033]8;;\033\\'
  27. return escape_mask.format('', f'https://github.com/zauberzeug/nicegui/issues/{number}', f'#{number}')
  28. issues = requests.get(f'{BASE_URL}/issues?milestone={milestone_number}&state=all', timeout=5).json()
  29. notes: Dict[str, List[str]] = {
  30. 'New features and enhancements': [],
  31. 'Bugfixes': [],
  32. 'Documentation': [],
  33. 'Testing': [],
  34. 'Dependencies': [],
  35. 'Others': [],
  36. }
  37. for issue in issues:
  38. title: str = issue['title']
  39. user: str = issue['user']['login'].replace('[bot]', '')
  40. body: str = issue['body'] or ''
  41. labels: List[str] = [label['name'] for label in issue['labels']]
  42. if user == 'dependabot':
  43. number_patterns = []
  44. else:
  45. number_patterns = [r'#(\d+)', r'https://github.com/zauberzeug/nicegui/(?:issues|discussions|pulls)/(\d+)']
  46. numbers = [issue['number']] + [int(match) for pattern in number_patterns for match in re.findall(pattern, body)]
  47. numbers_str = ', '.join(link(number) for number in sorted(numbers))
  48. note = f'{title.strip()} ({numbers_str} by @{user})'
  49. if 'bug' in labels:
  50. notes['Bugfixes'].append(note)
  51. elif 'feature' in labels:
  52. notes['New features and enhancements'].append(note)
  53. elif 'documentation' in labels:
  54. notes['Documentation'].append(note)
  55. elif 'testing' in labels:
  56. notes['Testing'].append(note)
  57. elif 'dependencies' in labels:
  58. notes['Dependencies'].append(note)
  59. else:
  60. notes['Others'].append(note)
  61. for title, lines in notes.items():
  62. if not lines:
  63. continue
  64. print(f'### {title}')
  65. print()
  66. for line in lines:
  67. print(f'- {line}')
  68. print()