diff options
| author | Nick Brassel <nick@tzarc.org> | 2021-11-19 04:05:08 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-18 17:05:08 +0000 |
| commit | b9148eb1bd00d4cf2fded05d18add3e5198a706d (patch) | |
| tree | 946cd868a5d22771402cbf0e1f6c1a7e0101cbe1 /lib | |
| parent | 88eaf78628056d722734392be56e0624dae779e3 (diff) | |
| download | qmk_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')
| -rw-r--r-- | lib/python/qmk/cli/__init__.py | 1 | ||||
| -rwxr-xr-x | lib/python/qmk/cli/generate/develop_pr_list.py | 119 |
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 | """ | ||
| 3 | import os | ||
| 4 | import re | ||
| 5 | from pathlib import Path | ||
| 6 | from subprocess import DEVNULL | ||
| 7 | |||
| 8 | from milc import cli | ||
| 9 | |||
| 10 | cache_timeout = 7 * 86400 | ||
| 11 | fix_expr = re.compile(r'fix', flags=re.IGNORECASE) | ||
| 12 | clean1_expr = re.compile(r'\[(develop|keyboard|keymap|core|cli|bug|docs|feature)\]', flags=re.IGNORECASE) | ||
| 13 | clean2_expr = re.compile(r'^(develop|keyboard|keymap|core|cli|bug|docs|feature):', flags=re.IGNORECASE) | ||
| 14 | |||
| 15 | |||
| 16 | def _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 | |||
| 25 | def _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 | |||
| 36 | def _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) | ||
| 48 | def 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) | ||
