Skip to content

Commit 93159b9

Browse files
committed
Python script to update branch protection rules
1 parent 6a97f2e commit 93159b9

2 files changed

Lines changed: 139 additions & 42 deletions

File tree

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env -S uv run --script
2+
# /// script
3+
# dependencies = [
4+
# "pyyaml",
5+
# ]
6+
# ///
7+
8+
import argparse
9+
import pathlib
10+
import shlex
11+
import shutil
12+
import subprocess
13+
import sys
14+
15+
import yaml
16+
17+
18+
REPO = "mgedmin/check-manifest"
19+
BRANCH = "master"
20+
21+
22+
here = pathlib.Path(__file__).parent
23+
24+
25+
def pretty_print_command(command: list[str], width: int | None = None) -> None:
26+
terminal_width = shutil.get_terminal_size().columns - 2
27+
if not width:
28+
width = terminal_width - 2 # leave space for the \ at the end
29+
30+
words: list[str] = []
31+
can_join = False
32+
for arg in command:
33+
if arg.startswith('-'):
34+
can_join = False
35+
if can_join:
36+
words[-1] += ' ' + shlex.quote(arg)
37+
can_join = False
38+
else:
39+
words.append(shlex.quote(arg))
40+
if arg.startswith('-'):
41+
can_join = True
42+
43+
indent = ' ' * len(words[0])
44+
45+
lines: list[str] = []
46+
cur_line: list[str] = []
47+
cur_width = 0
48+
for word in words:
49+
space_len = 1 if cur_line else 0
50+
if cur_width + space_len + len(word) <= width:
51+
# word fits
52+
cur_line.append(word)
53+
cur_width += space_len + len(word)
54+
else:
55+
# word does not fit, need to wrap
56+
cur_line.append('\\')
57+
lines.append(' '.join(cur_line))
58+
cur_line = [indent, word]
59+
cur_width = len(indent) + 1 + len(word)
60+
if cur_line:
61+
lines.append(' '.join(cur_line))
62+
63+
# align the \ on the right
64+
longest_width = max(
65+
len(line) for line in lines if len(line) <= terminal_width
66+
)
67+
lines[:-1] = [
68+
line.rstrip('\\').ljust(longest_width) + '\\'
69+
for line in lines[:-1]
70+
]
71+
72+
print(*lines, sep='\n')
73+
74+
75+
def main() -> None:
76+
parser = argparse.ArgumentParser(
77+
description="Update GitHub branch protection rules"
78+
)
79+
parser.add_argument(
80+
"-n",
81+
"--dry-run",
82+
action="store_true",
83+
help="Print the gh api command without executing it",
84+
)
85+
args = parser.parse_args()
86+
87+
with open(here / "workflows" / "build.yml") as fp:
88+
workflow = yaml.safe_load(fp)
89+
test_name_template = workflow['jobs']['build']['name']
90+
lint_name_template = workflow['jobs']['lint']['name']
91+
test_matrix = workflow['jobs']['build']['strategy']['matrix']
92+
lint_matrix = workflow['jobs']['lint']['strategy']['matrix']
93+
94+
assert '${{ matrix.python-version }}' in test_name_template
95+
assert '${{ matrix.os }}' in test_name_template
96+
assert '${{ matrix.vcs }}' in test_name_template
97+
pythons = test_matrix['python-version']
98+
oses = test_matrix['os']
99+
vcses = test_matrix['vcs']
100+
test_names = [
101+
test_name_template
102+
.replace('${{ matrix.python-version }}', python_version)
103+
.replace('${{ matrix.os }}', os)
104+
.replace('${{ matrix.vcs }}', vcs)
105+
for python_version in pythons
106+
for os in oses
107+
for vcs in vcses
108+
]
109+
110+
assert lint_name_template == '${{ matrix.toxenv }}'
111+
lint_names = lint_matrix['toxenv']
112+
113+
check_names = test_names + lint_names
114+
115+
command = [
116+
'gh',
117+
'api',
118+
'-X', 'PUT',
119+
"-H", "Accept: application/vnd.github+json",
120+
"-H", "X-GitHub-Api-Version: 2022-11-28",
121+
(
122+
f"/repos/{REPO}/branches/{BRANCH}/protection/"
123+
"required_status_checks/contexts"
124+
),
125+
]
126+
for name in check_names:
127+
command += ["-f", f"contexts[]={name}"]
128+
129+
# Using a shorter width because I don't want multiple -f contexts[]=one -f
130+
# contexts[]=two args to be squished into each line near the end
131+
pretty_print_command(command, width=40)
132+
if not args.dry_run:
133+
rc = subprocess.run(command).returncode
134+
sys.exit(rc)
135+
136+
137+
if __name__ == "__main__":
138+
main()

‎Makefile‎

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,48 +47,7 @@ mypy: ##: check for type errors
4747
.PHONY: update-github-branch-protection-rules
4848

4949
update-github-branch-protection-rules: ##: update GitHub branch protection rules
50-
gh api -X PUT -H "Accept: application/vnd.github+json" \
51-
-H "X-GitHub-Api-Version: 2022-11-28" \
52-
/repos/mgedmin/check-manifest/branches/master/protection/required_status_checks/contexts \
53-
-f "contexts[]=check-manifest" \
54-
-f "contexts[]=check-python-versions" \
55-
-f "contexts[]=flake8" \
56-
-f "contexts[]=isort" \
57-
-f "contexts[]=mypy" \
58-
-f "contexts[]=Python 3.7, bzr" \
59-
-f "contexts[]=Python 3.7, git" \
60-
-f "contexts[]=Python 3.7, hg" \
61-
-f "contexts[]=Python 3.7, svn" \
62-
-f "contexts[]=Python 3.8, bzr" \
63-
-f "contexts[]=Python 3.8, git" \
64-
-f "contexts[]=Python 3.8, hg" \
65-
-f "contexts[]=Python 3.8, svn" \
66-
-f "contexts[]=Python 3.9, bzr" \
67-
-f "contexts[]=Python 3.9, git" \
68-
-f "contexts[]=Python 3.9, hg" \
69-
-f "contexts[]=Python 3.9, svn" \
70-
-f "contexts[]=Python 3.10, bzr" \
71-
-f "contexts[]=Python 3.10, git" \
72-
-f "contexts[]=Python 3.10, hg" \
73-
-f "contexts[]=Python 3.10, svn" \
74-
-f "contexts[]=Python 3.11, bzr" \
75-
-f "contexts[]=Python 3.11, git" \
76-
-f "contexts[]=Python 3.11, hg" \
77-
-f "contexts[]=Python 3.11, svn" \
78-
-f "contexts[]=Python 3.12, bzr" \
79-
-f "contexts[]=Python 3.12, git" \
80-
-f "contexts[]=Python 3.12, hg" \
81-
-f "contexts[]=Python 3.12, svn" \
82-
-f "contexts[]=Python 3.13, bzr" \
83-
-f "contexts[]=Python 3.13, git" \
84-
-f "contexts[]=Python 3.13, hg" \
85-
-f "contexts[]=Python 3.13, svn" \
86-
-f "contexts[]=Python pypy3.10, bzr" \
87-
-f "contexts[]=Python pypy3.10, git" \
88-
-f "contexts[]=Python pypy3.10, hg" \
89-
-f "contexts[]=Python pypy3.10, svn" \
90-
-f "contexts[]=continuous-integration/appveyor/branch" \
91-
-f "contexts[]=continuous-integration/appveyor/pr"
50+
uv run --script .github/update_branch_protection_rules.py
9251

9352
##: Releasing
9453

0 commit comments

Comments
 (0)