aboutsummaryrefslogtreecommitdiff
path: root/lib/python
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2021-11-19 04:05:08 +1100
committerGitHub <noreply@github.com>2021-11-18 17:05:08 +0000
commitb9148eb1bd00d4cf2fded05d18add3e5198a706d (patch)
tree946cd868a5d22771402cbf0e1f6c1a7e0101cbe1 /lib/python
parent88eaf78628056d722734392be56e0624dae779e3 (diff)
downloadqmk_firmware-b9148eb1bd00d4cf2fded05d18add3e5198a706d.tar.gz
qmk_firmware-b9148eb1bd00d4cf2fded05d18add3e5198a706d.zip
[cli] Export list of `develop` PRs to be merged into `master` (#13944)
* Add developer-only command for exporting the list of PRs associated with a merge to `develop`. * qmk pytest * Imports. * Remove dependencies from requirements file, manually handle. * Reduce complexity, qmk generate-api taking too long so relying on CI
Diffstat (limited to 'lib/python')
-rw-r--r--lib/python/qmk/cli/__init__.py1
-rwxr-xr-xlib/python/qmk/cli/generate/develop_pr_list.py119
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index edf351d62..c51eece95 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -47,6 +47,7 @@ subcommands = [
47 'qmk.cli.generate.api', 47 'qmk.cli.generate.api',
48 'qmk.cli.generate.compilation_database', 48 'qmk.cli.generate.compilation_database',
49 'qmk.cli.generate.config_h', 49 'qmk.cli.generate.config_h',
50 'qmk.cli.generate.develop_pr_list',
50 'qmk.cli.generate.dfu_header', 51 'qmk.cli.generate.dfu_header',
51 'qmk.cli.generate.docs', 52 'qmk.cli.generate.docs',
52 'qmk.cli.generate.info_json', 53 'qmk.cli.generate.info_json',
diff --git a/lib/python/qmk/cli/generate/develop_pr_list.py b/lib/python/qmk/cli/generate/develop_pr_list.py
new file mode 100755
index 000000000..de4eaa7d8
--- /dev/null
+++ b/lib/python/qmk/cli/generate/develop_pr_list.py
@@ -0,0 +1,119 @@
1"""Export the initial list of PRs associated with a `develop` merge to `master`.
2"""
3import os
4import re
5from pathlib import Path
6from subprocess import DEVNULL
7
8from milc import cli
9
10cache_timeout = 7 * 86400
11fix_expr = re.compile(r'fix', flags=re.IGNORECASE)
12clean1_expr = re.compile(r'\[(develop|keyboard|keymap|core|cli|bug|docs|feature)\]', flags=re.IGNORECASE)
13clean2_expr = re.compile(r'^(develop|keyboard|keymap|core|cli|bug|docs|feature):', flags=re.IGNORECASE)
14
15
16def _get_pr_info(cache, gh, pr_num):
17 pull = cache.get(f'pull:{pr_num}')
18 if pull is None:
19 print(f'Retrieving info for PR #{pr_num}')
20 pull = gh.pulls.get(owner='qmk', repo='qmk_firmware', pull_number=pr_num)
21 cache.set(f'pull:{pr_num}', pull, cache_timeout)
22 return pull
23
24
25def _try_open_cache(cli):
26 # These dependencies are manually handled because people complain. Fun.
27 try:
28 from sqlite_cache.sqlite_cache import SqliteCache
29 except ImportError:
30 return None
31
32 cache_loc = Path(cli.config_file).parent
33 return SqliteCache(cache_loc)
34
35
36def _get_github():
37 try:
38 from ghapi.all import GhApi
39 except ImportError:
40 return None
41
42 return GhApi()
43
44
45@cli.argument('-f', '--from-ref', default='0.11.0', help='Git revision/tag/reference/branch to begin search')
46@cli.argument('-b', '--branch', default='upstream/develop', help='Git branch to iterate (default: "upstream/develop")')
47@cli.subcommand('Creates the develop PR list.', hidden=False if cli.config.user.developer else True)
48def generate_develop_pr_list(cli):
49 """Retrieves information from GitHub regarding the list of PRs associated
50 with a merge of `develop` branch into `master`.
51
52 Requires environment variable GITHUB_TOKEN to be set.
53 """
54
55 if 'GITHUB_TOKEN' not in os.environ or os.environ['GITHUB_TOKEN'] == '':
56 cli.log.error('Environment variable "GITHUB_TOKEN" is not set.')
57 return 1
58
59 cache = _try_open_cache(cli)
60 gh = _get_github()
61
62 git_args = ['git', 'rev-list', '--oneline', '--no-merges', '--reverse', f'{cli.args.from_ref}...{cli.args.branch}', '^upstream/master']
63 commit_list = cli.run(git_args, capture_output=True, stdin=DEVNULL)
64
65 if cache is None or gh is None:
66 cli.log.error('Missing one or more dependent python packages: "ghapi", "python-sqlite-cache"')
67 return 1
68
69 pr_list_bugs = []
70 pr_list_dependencies = []
71 pr_list_core = []
72 pr_list_keyboards = []
73 pr_list_keyboard_fixes = []
74 pr_list_cli = []
75 pr_list_others = []
76
77 def _categorise_commit(commit_info):
78 def fix_or_normal(info, fixes_collection, normal_collection):
79 if "bug" in info['pr_labels'] or fix_expr.search(info['title']):
80 fixes_collection.append(info)
81 else:
82 normal_collection.append(info)
83
84 if "dependencies" in commit_info['pr_labels']:
85 fix_or_normal(commit_info, pr_list_bugs, pr_list_dependencies)
86 elif "core" in commit_info['pr_labels']:
87 fix_or_normal(commit_info, pr_list_bugs, pr_list_core)
88 elif "keyboard" in commit_info['pr_labels'] or "keymap" in commit_info['pr_labels'] or "via" in commit_info['pr_labels']:
89 fix_or_normal(commit_info, pr_list_keyboard_fixes, pr_list_keyboards)
90 elif "cli" in commit_info['pr_labels']:
91 fix_or_normal(commit_info, pr_list_bugs, pr_list_cli)
92 else:
93 fix_or_normal(commit_info, pr_list_bugs, pr_list_others)
94
95 git_expr = re.compile(r'^(?P<hash>[a-f0-9]+) (?P<title>.*) \(#(?P<pr>[0-9]+)\)$')
96 for line in commit_list.stdout.split('\n'):
97 match = git_expr.search(line)
98 if match:
99 pr_info = _get_pr_info(cache, gh, match.group("pr"))
100 commit_info = {'hash': match.group("hash"), 'title': match.group("title"), 'pr_num': int(match.group("pr")), 'pr_labels': [label.name for label in pr_info.labels.items]}
101 _categorise_commit(commit_info)
102
103 def _dump_commit_list(name, collection):
104 if len(collection) == 0:
105 return
106 print("")
107 print(f"{name}:")
108 for commit in sorted(collection, key=lambda x: x['pr_num']):
109 title = clean1_expr.sub('', clean2_expr.sub('', commit['title'])).strip()
110 pr_num = commit['pr_num']
111 print(f'* {title} ([#{pr_num}](https://github.com/qmk/qmk_firmware/pull/{pr_num}))')
112
113 _dump_commit_list("Bugs", pr_list_bugs)
114 _dump_commit_list("Core", pr_list_core)
115 _dump_commit_list("CLI", pr_list_cli)
116 _dump_commit_list("Submodule updates", pr_list_dependencies)
117 _dump_commit_list("Keyboards", pr_list_keyboards)
118 _dump_commit_list("Keyboard fixes", pr_list_keyboard_fixes)
119 _dump_commit_list("Others", pr_list_others)