milestone_check.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. # Copyright (c) 2018 Jupyter Development Team.
  2. # Distributed under the terms of the Modified BSD License.
  3. # Generate a GitHub token at https://github.com/settings/tokens
  4. # Invoke this script using something like:
  5. # python scripts/milestone_check.py
  6. import subprocess
  7. import requests
  8. import os
  9. # Get authentication token
  10. import getpass
  11. token = getpass.getpass('GitHub token:')
  12. MILESTONE=18
  13. ranges = {
  14. 18: 'origin/master --not origin/0.34.x' #0.35.0
  15. }
  16. out = subprocess.run("git log {} --format='%H,%cE,%s'".format(ranges[MILESTONE]), shell=True, encoding='utf8', stdout=subprocess.PIPE)
  17. commits = {i[0]: (i[1], i[2]) for i in (x.split(',',2) for x in out.stdout.splitlines())}
  18. url = 'https://api.github.com/graphql'
  19. json = { 'query' : """
  20. query test($milestone: Int!) {
  21. repository(owner:"jupyterlab" name:"jupyterlab") {
  22. milestone(number:$milestone) {
  23. title
  24. pullRequests(first:100 states:[MERGED]) {
  25. nodes {
  26. title
  27. number
  28. mergeCommit {
  29. oid
  30. }
  31. commits(first:100) {
  32. nodes {
  33. commit {
  34. oid
  35. }
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }
  42. }
  43. """,
  44. 'variables': {
  45. 'milestone': MILESTONE
  46. }
  47. }
  48. api_token = os.environ['GITHUB_TOKEN']
  49. headers = {'Authorization': 'token %s' % api_token}
  50. r = requests.post(url=url, json=json, headers=headers)
  51. milestone_data = r.json()['data']['repository']['milestone']
  52. pr_list = milestone_data['pullRequests']['nodes']
  53. # construct a commit to PR dictionary
  54. prs = {}
  55. for pr in pr_list:
  56. prs[pr['number']] = {'mergeCommit': pr['mergeCommit']['oid'],
  57. 'commits': set(i['commit']['oid'] for i in pr['commits']['nodes'])}
  58. # Reverse dictionary
  59. commits_to_prs={}
  60. for key,value in prs.items():
  61. commits_to_prs[value['mergeCommit']]=key
  62. for c in value['commits']:
  63. commits_to_prs[c]=key
  64. # Check to see if commits in the repo are represented in PRs
  65. good = set()
  66. notfound = set()
  67. for c in commits:
  68. if c in commits_to_prs:
  69. good.add(commits_to_prs[c])
  70. else:
  71. notfound.add(c)
  72. prs_not_represented = set(prs.keys()) - good
  73. print("Milestone: %s, %d merged PRs"%(milestone_data['title'], len(milestone_data['pullRequests']['nodes'])))
  74. print("""
  75. PRs that are in the milestone, but have no commits in the version range.
  76. These PRs probably belong in a different milestone.
  77. """)
  78. print('\n'.join('https://github.com/jupyterlab/jupyterlab/pull/%d'%i for i in prs_not_represented))
  79. print('-'*40)
  80. print("""
  81. Commits that are not included in any PR on this milestone.
  82. This probably means the commit's PR needs to be assigned to this milestone,
  83. or the commit was pushed to master directly.
  84. """)
  85. print('\n'.join('%s %s %s'%(c, commits[c][0], commits[c][1]) for c in notfound))