Skip to content

Commit b2f6591

Browse files
authored
Merge pull request #111 from sommersoft/hacktober_schedule
Schedule Hacktoberfest Labeling
2 parents 462006f + e6f0485 commit b2f6591

File tree

3 files changed

+138
-40
lines changed

3 files changed

+138
-40
lines changed

adabot/circuitpython_libraries.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from adabot import pypi_requests as pypi
3636
from adabot.lib import circuitpython_library_validators as cirpy_lib_vals
3737
from adabot.lib import common_funcs
38+
from adabot.lib import assign_hacktober_label as hacktober
3839

3940
# Setup ArgumentParser
4041
cmd_line_parser = argparse.ArgumentParser(
@@ -132,6 +133,8 @@ def run_library_checks(validators, bundle_submodules, latest_pylint, kw_args):
132133
"open_issues": [],
133134
"issue_authors": set(),
134135
"issue_closers": set(),
136+
"hacktober_assigned": 0,
137+
"hacktober_removed": 0,
135138
}
136139
core_insights = copy.deepcopy(lib_insights)
137140
for k in core_insights:
@@ -426,6 +429,20 @@ def print_issue_overview(*insights):
426429
.format(closed_issues, len(issue_closers),
427430
new_issues, len(issue_authors)))
428431

432+
# print Hacktoberfest labels changes if its Hacktober
433+
in_season, season_action = hacktober.is_hacktober_season()
434+
if in_season:
435+
hacktober_changes = ""
436+
if season_action == "add":
437+
hacktober_changes = "* Assigned Hacktoberfest label to {} issues.".format(
438+
sum([x["hacktober_assigned"] for x in insights])
439+
)
440+
elif season_action == "remove":
441+
hacktober_changes += "* Removed Hacktoberfest label from {} issues.".format(
442+
sum([x["hacktober_removed"] for x in insights])
443+
)
444+
output_handler(hacktober_changes)
445+
429446
if __name__ == "__main__":
430447
validator_kwarg_list = {}
431448
startup_message = [

adabot/lib/assign_hacktober_label.py

Lines changed: 102 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,48 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
# THE SOFTWARE.
2222

23+
import argparse
24+
import datetime
2325
import requests
2426

2527
from adabot import github_requests as github
2628
from adabot.lib import common_funcs
2729

30+
cli_args = argparse.ArgumentParser(description="Hacktoberfest Label Assigner")
31+
cli_args.add_argument("-r", "--remove-label", action="store_true",
32+
help="Option to remove Hacktoberfest labels, instead of adding them.",
33+
dest="remove_label")
2834

29-
def ensure_hacktober_label_exists(repo):
30-
""" Checks if the 'Hacktoberfest' label exists on the repo.
31-
If not, creates the label.
32-
"""
33-
response = github.get("/repos/" + repo["full_name"] + "/labels")
34-
if not response.ok:
35-
print("Failed to retrieve labels for '{}'".format(repo["name"]))
36-
return False
3735

38-
repo_labels = [label["name"] for label in response.json()]
36+
# Hacktoberfest Season
37+
# - lists are in [start, stop] format.
38+
# - tuples are in (month, day) format.
39+
_ADD_SEASON = [(9, 29), (10, 30)]
40+
_REMOVE_SEASON = [(11, 1), (11, 10)]
3941

40-
hacktober_exists = {"Hacktoberfest", "hacktoberfest"} & set(repo_labels)
41-
if not hacktober_exists:
42-
params = {
43-
"name": "Hacktoberfest",
44-
"color": "f2b36f",
45-
"description": "DigitalOcean's Hacktoberfest"
46-
}
47-
result = github.post("/repos/" + repo["full_name"] + "/labels", json=params)
48-
if not result.status_code == 201:
49-
print("Failed to create new Hacktoberfest label for: {}".format(repo["name"]))
50-
return False
51-
52-
return True
53-
54-
def assign_hacktoberfest(repo):
55-
""" Gathers open issues on a repo, and assigns the 'Hacktoberfest' label
56-
to each issue if its not already assigned.
42+
def is_hacktober_season():
43+
""" Checks if the current day falls within either the add range (_ADD_SEASON)
44+
or the remove range (_REMOVE_SEASON). Returns boolean if within
45+
Hacktoberfest season, and which action to take.
46+
"""
47+
today = datetime.date.today()
48+
add_range = [
49+
datetime.date(today.year, *month_day) for month_day in _ADD_SEASON
50+
]
51+
remove_range = [
52+
datetime.date(today.year, *month_day) for month_day in _REMOVE_SEASON
53+
]
54+
if add_range[0] <= today <= add_range[1]:
55+
return True, "add"
56+
elif remove_range[0] <= today <= remove_range[1]:
57+
return True, "remove"
58+
59+
return False, None
60+
61+
62+
def get_open_issues(repo):
63+
""" Retrieve all open issues for given repo.
5764
"""
58-
labels_assigned = 0
5965

6066
params = {
6167
"state": "open",
@@ -86,17 +92,64 @@ def assign_hacktoberfest(repo):
8692

8793
response = requests.get(link, timeout=30)
8894

95+
return issues
96+
97+
98+
def ensure_hacktober_label_exists(repo):
99+
""" Checks if the 'Hacktoberfest' label exists on the repo.
100+
If not, creates the label.
101+
"""
102+
response = github.get("/repos/" + repo["full_name"] + "/labels")
103+
if not response.ok:
104+
print("Failed to retrieve labels for '{}'".format(repo["name"]))
105+
return False
106+
107+
repo_labels = [label["name"] for label in response.json()]
108+
109+
hacktober_exists = {"Hacktoberfest", "hacktoberfest"} & set(repo_labels)
110+
if not hacktober_exists:
111+
params = {
112+
"name": "Hacktoberfest",
113+
"color": "f2b36f",
114+
"description": "DigitalOcean's Hacktoberfest"
115+
}
116+
result = github.post("/repos/" + repo["full_name"] + "/labels", json=params)
117+
if not result.status_code == 201:
118+
print("Failed to create new Hacktoberfest label for: {}".format(repo["name"]))
119+
return False
120+
121+
return True
122+
123+
def assign_hacktoberfest(repo, issues=None, remove_labels=False):
124+
""" Gathers open issues on a repo, and assigns the 'Hacktoberfest' label
125+
to each issue if its not already assigned.
126+
"""
127+
labels_changed = 0
128+
129+
if not issues:
130+
issues = get_open_issues(repo)
131+
89132
for issue in issues:
133+
update_issue = False
90134
label_names = [label["name"] for label in issue["labels"]]
91135
has_good_first = "good first issue" in label_names
92136
has_hacktober = {"Hacktoberfest", "hacktoberfest"} & set(label_names)
93137

94-
if has_good_first and not has_hacktober:
95-
label_exists = ensure_hacktober_label_exists(repo)
96-
if not label_exists:
97-
continue
98-
99-
label_names.append("Hacktoberfest")
138+
if remove_labels:
139+
if has_hacktober:
140+
label_names = [
141+
label for label in lable_names
142+
if label not in has_hacktober
143+
]
144+
update_issue = True
145+
else:
146+
if has_good_first and not has_hacktober:
147+
label_exists = ensure_hacktober_label_exists(repo)
148+
if not label_exists:
149+
continue
150+
update_issue = True
151+
152+
if update_issue:
100153
params = {
101154
"labels": label_names
102155
}
@@ -107,27 +160,36 @@ def assign_hacktoberfest(repo):
107160
json=params)
108161

109162
if result.ok:
110-
labels_assigned += 1
163+
labels_changed += 1
111164
else:
112165
# sadly, GitHub will only silently ignore labels that are
113166
# not added and return a 200. so this will most likely only
114167
# trigger on endpoint/connection failures.
115168
print("Failed to add Hacktoberfest label to: {}".format(issue["url"]))
116169

117-
return labels_assigned
170+
return labels_changed
118171

119-
def process_hacktoberfest(repo):
120-
result = assign_hacktoberfest(repo)
172+
def process_hacktoberfest(repo, issues=None, remove_labels=False):
173+
result = assign_hacktoberfest(repo, issues, remove_labels)
121174
return result
122175

123176

124177
if __name__ == "__main__":
125178
labels_assigned = 0
179+
args = cli_args.parse_args()
180+
181+
remove_labels = args.remove_label
126182

127-
print("Checking for open issues to assign the Hacktoberfest label to...")
183+
if not remove_labels:
184+
print("Checking for open issues to assign the Hacktoberfest label to...")
185+
else:
186+
print("Checking for open issues to remove the Hacktoberfest label from...")
128187

129188
repos = common_funcs.list_repos()
130189
for repo in repos:
131-
labels_assigned += process_hacktoberfest(repo)
190+
labels_assigned += process_hacktoberfest(repo, remove_labels)
132191

133-
print("Added the Hacktoberfest label to {} issues.".format(labels_assigned))
192+
if not remove_labels:
193+
print("Added the Hacktoberfest label to {} issues.".format(labels_assigned))
194+
else:
195+
print("Removed the Hacktoberfest label from {} issues.".format(labels_assigned))

adabot/lib/circuitpython_library_validators.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from adabot import travis_requests as travis
2929
from adabot import pypi_requests as pypi
3030
from adabot.lib import common_funcs
31+
from adabot.lib import assign_hacktober_label as hacktober
3132

3233

3334
# Define constants for error strings to make checking against them more robust:
@@ -867,6 +868,24 @@ def gather_insights(self, repo, insights, since):
867868
days_open.days)
868869
insights["open_issues"].append(issue_link)
869870

871+
# process Hacktoberfest labels if it is Hacktoberfest season
872+
in_season, season_action = hacktober.is_hacktober_season()
873+
if in_season:
874+
hacktober_issues = [
875+
issue for issue in issues if "pull_request" not in issue
876+
]
877+
if season_action == "add":
878+
insights["hacktober_assigned"] += (
879+
hacktober.assign_hacktoberfest(repo,
880+
issues=hacktober_issues)
881+
)
882+
elif season_action == "remove":
883+
insights["hacktober_removed"] += (
884+
hacktober.assign_hacktoberfest(repo,
885+
issues=hacktober_issues,
886+
remove_labels=True)
887+
)
888+
870889
# get milestones for core repo
871890
if repo["name"] == "circuitpython":
872891
params = {"state": "open"}

0 commit comments

Comments
 (0)