forked from apache/kafka
-
Notifications
You must be signed in to change notification settings - Fork 0
/
approve-workflows.py
116 lines (102 loc) · 4.23 KB
/
approve-workflows.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import subprocess
import shlex
import webbrowser
def prompt_user() -> str:
choices = "ynw?"
while True:
try:
user_input = input(f"Make a selection [{','.join(choices)}]: ")
except (KeyboardInterrupt, EOFError):
exit(0)
clean_input = user_input.strip().lower()
if clean_input == "?":
print("\ny: approve the run\nn: do nothing\nw: open the URL for this run")
continue
if clean_input not in choices:
print(f"\nInvalid selection '{clean_input}'. Valid choices are:")
print("y: approve the run\nn: do nothing\nw: open the URL for this run")
continue
else:
return clean_input
def run_gh_command(cmd: str) -> str:
"Run a gh CLI command and return the stdout"
p = subprocess.run(
shlex.split(cmd),
capture_output=True
)
if p.returncode == 4:
# Not auth'd
print(p.stderr.decode())
exit(1)
elif p.returncode == 0:
return p.stdout.decode()
else:
print(f"Had an error running '{cmd}'.\nSTDOUT: {p.stdout.decode()}\nSTDERR: {p.stderr.decode()}")
def list_pending_workflow_runs():
command = r"gh run list --limit 20 --repo apache/kafka --workflow CI --status action_required --json 'databaseId,headBranch'"
out = run_gh_command(command)
pending_workflows = json.loads(out)
runs_by_branch = dict()
for workflow in pending_workflows:
run_id = workflow.get("databaseId")
branch = workflow.get("headBranch")
if branch in runs_by_branch:
print(f"Ignoring run {run_id} since there is a newer one: {runs_by_branch[branch]}")
continue
runs_by_branch[branch] = run_id
return runs_by_branch.values()
def load_workflow_run(run_id: str):
command = rf"gh api --method GET -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/apache/kafka/actions/runs/{run_id}"
out = run_gh_command(command)
workflow_run = json.loads(out)
return workflow_run
def approve_workflow_run(run_id: str):
command = rf"gh api --method POST -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/apache/kafka/actions/runs/{run_id}/approve"
out = run_gh_command(command)
workflow_run = json.loads(out)
return workflow_run
if __name__ == "__main__":
"""
Interactive script to approve pending CI workflow runs. This script can only be used by committers.
Requires the GitHub CLI. See https://cli.github.com/ for installation instructions.
Once installed authenticate with: gh auth login
"""
pending_runs = list_pending_workflow_runs()
for run_id in pending_runs:
run = load_workflow_run(run_id)
branch = run.get("head_branch")
run_id = run.get("id")
title = run.get("display_title")
repo = run.get("head_repository", {}).get("full_name")
actor = run.get("actor", {}).get("login")
url = run.get("html_url")
updated = run.get("updated_at")
print("-"*80)
print(f"PR: {title}")
print(f"Actor: {actor}")
print(f"Branch: {repo} {branch}")
print(f"Updated: {updated}")
print(f"URL: {url}")
print("")
selection = prompt_user()
if selection == "y":
approve_workflow_run(run_id)
elif selection == "n":
continue
elif selection == "w":
webbrowser.open(url)