-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapply-labels.py
145 lines (117 loc) · 4.36 KB
/
apply-labels.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""
Usage:
python -m apply_label.py
Requires:
GITHUB_AUTH token in local environment
Description:
Applies a specified label, with color and description, to every
repo in a given github org
Future Work:
Remove asserts and do inscript retry &/or dump the failed repos
"""
import logging
import os
import sys
import argparse
import requests
from github_helpers import (
get_github_headers,
get_repos_plus_keys
)
# Switch to DEBUG for additional debugging info
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
LOG = logging.getLogger(__name__)
def main(org, name, color, description, exclude_private=False):
"""
Script entrypoint
"""
gh_headers = get_github_headers()
count = 0
for repo in get_repos_plus_keys(gh_headers, org, exclude_private):
# for some reason, need to fix, get_repos_plus_keys returns each repo
# in its own list so extract that.
repo = repo[0]
LOG.info(f"\n\n******* CHECKING REPO: {repo} ({count}) ************\n")
create_or_update_label(gh_headers, org, repo, name, color, description)
count = count + 1
LOG.info(f"Successfully standardised label '{name}' across {count} repos")
def create_or_update_label(gh_headers, org, repo, name, color, description):
"""
Looks for the label; if it's present, updates it with the specified color &
description.
If it's not present, creates it with specified color & description.
"""
# URL for creating a new label
create_label_url = "https://api.github.com/repos/{0}/{1}/labels".format(org, repo)
# URL for fetching a label (to check existence or to patch for update)
fetch_label_url = "https://api.github.com/repos/{0}/{1}/labels/{2}".format(org, repo, name)
action = None
# If label is present, 200; if not, 404
label_present_r = requests.get(fetch_label_url, headers=gh_headers)
if label_present_r.status_code == 200:
LOG.info("Label {0} present on repo {1}, updating label".format(name, repo))
r = requests.patch(
fetch_label_url,
headers=gh_headers,
json={"name": name, "color": color, "description": description}
)
assert r.status_code == 200, "Updating label failed with {}".format(r.status_code)
validate(r.json(), color, description)
action = "updated"
else:
# Add the label
LOG.info("didn't find the label")
LOG.info(f"URL: {create_label_url}")
r = requests.post(
create_label_url,
headers=gh_headers,
json={"name": name, "color": color, "description": description}
)
assert r.status_code == 201, "Adding label failed with {} {}".format(r.status_code, r.json())
validate(r.json(), color, description, name)
action = "added"
LOG.info("Success: {} label".format(action))
def validate(rjson, color, description, name=None):
fail = False
if name is not None and rjson['name'] != name:
fail = True
if rjson['color'] != color:
fail = True
if rjson['description'] != description:
fail = True
assert not fail, "Creation or update failed, got: {}".format(rjson)
if __name__ == "__main__":
try:
os.environ["GITHUB_TOKEN"]
except KeyError:
sys.exit("*** ERROR ***\nGITHUB_TOKEN must be defined in this environment")
parser = argparse.ArgumentParser(
description="Applies a specified label, with short description and\
color, to all repos in the specified organization - either adding\
the label if it's not already there, or updating it to match the\
specification if it is."
)
parser.add_argument(
"org",
help="Name of the organization"
)
parser.add_argument(
"name",
help="What's the case-sensitive name of the label to add/update?"
)
parser.add_argument(
"color",
help="What's 6-character hex code (no #) corresponding to label color?"
)
parser.add_argument(
"description",
help="Description of label (< 100 characters)"
)
parser.add_argument(
"-P", "--exclude-private",
help="Exclude private repos from this org",
action="store_true"
)
args = parser.parse_args()
main(args.org, args.name, args.color, args.description, args.exclude_private)