|
@@ -0,0 +1,102 @@
|
|
|
+# Copyright (c) 2018 Jupyter Development Team.
|
|
|
+# Distributed under the terms of the Modified BSD License.
|
|
|
+
|
|
|
+# Generate a GitHub token at https://github.com/settings/tokens
|
|
|
+# Invoke this script using something like:
|
|
|
+# python scripts/milestone_check.py
|
|
|
+
|
|
|
+import subprocess
|
|
|
+import requests
|
|
|
+import os
|
|
|
+
|
|
|
+# Get authentication token
|
|
|
+import getpass
|
|
|
+token = getpass.getpass('GitHub token:')
|
|
|
+
|
|
|
+MILESTONE=18
|
|
|
+
|
|
|
+ranges = {
|
|
|
+ 18: 'origin/master --not origin/0.34.x' #0.35.0
|
|
|
+}
|
|
|
+
|
|
|
+out = subprocess.run("git log {} --format='%H,%cE,%s'".format(ranges[MILESTONE]), shell=True, encoding='utf8', stdout=subprocess.PIPE)
|
|
|
+commits = {i[0]: (i[1], i[2]) for i in (x.split(',',2) for x in out.stdout.splitlines())}
|
|
|
+
|
|
|
+
|
|
|
+url = 'https://api.github.com/graphql'
|
|
|
+json = { 'query' : """
|
|
|
+query test($milestone: Int!) {
|
|
|
+ repository(owner:"jupyterlab" name:"jupyterlab") {
|
|
|
+ milestone(number:$milestone) {
|
|
|
+ title
|
|
|
+ pullRequests(first:100 states:[MERGED]) {
|
|
|
+ nodes {
|
|
|
+ title
|
|
|
+ number
|
|
|
+ mergeCommit {
|
|
|
+ oid
|
|
|
+ }
|
|
|
+ commits(first:100) {
|
|
|
+ nodes {
|
|
|
+ commit {
|
|
|
+ oid
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+""",
|
|
|
+ 'variables': {
|
|
|
+ 'milestone': MILESTONE
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+api_token = os.environ['GITHUB_TOKEN']
|
|
|
+headers = {'Authorization': 'token %s' % api_token}
|
|
|
+
|
|
|
+r = requests.post(url=url, json=json, headers=headers)
|
|
|
+milestone_data = r.json()['data']['repository']['milestone']
|
|
|
+pr_list = milestone_data['pullRequests']['nodes']
|
|
|
+
|
|
|
+# construct a commit to PR dictionary
|
|
|
+prs = {}
|
|
|
+for pr in pr_list:
|
|
|
+ prs[pr['number']] = {'mergeCommit': pr['mergeCommit']['oid'],
|
|
|
+ 'commits': set(i['commit']['oid'] for i in pr['commits']['nodes'])}
|
|
|
+
|
|
|
+# Reverse dictionary
|
|
|
+commits_to_prs={}
|
|
|
+for key,value in prs.items():
|
|
|
+ commits_to_prs[value['mergeCommit']]=key
|
|
|
+ for c in value['commits']:
|
|
|
+ commits_to_prs[c]=key
|
|
|
+
|
|
|
+# Check to see if commits in the repo are represented in PRs
|
|
|
+good = set()
|
|
|
+notfound = set()
|
|
|
+for c in commits:
|
|
|
+ if c in commits_to_prs:
|
|
|
+ good.add(commits_to_prs[c])
|
|
|
+ else:
|
|
|
+ notfound.add(c)
|
|
|
+
|
|
|
+prs_not_represented = set(prs.keys()) - good
|
|
|
+
|
|
|
+print("Milestone: %s, %d merged PRs"%(milestone_data['title'], len(milestone_data['pullRequests']['nodes'])))
|
|
|
+print("""
|
|
|
+PRs that are in the milestone, but have no commits in the version range.
|
|
|
+These PRs probably belong in a different milestone.
|
|
|
+""")
|
|
|
+print('\n'.join('https://github.com/jupyterlab/jupyterlab/pull/%d'%i for i in prs_not_represented))
|
|
|
+
|
|
|
+print('-'*40)
|
|
|
+
|
|
|
+print("""
|
|
|
+Commits that are not included in any PR on this milestone.
|
|
|
+This probably means the commit's PR needs to be assigned to this milestone,
|
|
|
+or the commit was pushed to master directly.
|
|
|
+""")
|
|
|
+print('\n'.join('%s %s %s'%(c, commits[c][0], commits[c][1]) for c in notfound))
|