Skip to content

Commit

Permalink
feat: create gui issue when assign require-ui label (#27)
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Yu <[email protected]>
  • Loading branch information
Yu-Jack authored May 20, 2024
1 parent 87b2541 commit 4c1b7d3
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 44 deletions.
28 changes: 28 additions & 0 deletions github-bot/harvester_github_bot/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import abc

class ActionRequest:
def __init__(self):
pass
def setAction(self, action):
self.action = action


class Action(abc.ABC):
# isMatched returns True if the actionRequest is matched with the action from github webook
@abc.abstractmethod
def isMatched(self, actionRequest):
raise NotImplementedError

@abc.abstractmethod
def action(self, request):
raise NotImplementedError

class LabelAction(abc.ABC):
# isMatched returns True if it meets the condition to execute the action
@abc.abstractmethod
def isMatched(self, request):
raise NotImplementedError

@abc.abstractmethod
def action(self, request):
raise NotImplementedError
26 changes: 26 additions & 0 deletions github-bot/harvester_github_bot/action_label.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from harvester_github_bot.label_action.create_gui_issue import CreateGUIIssue
from harvester_github_bot.label_action.create_backport import CreateBackport
from harvester_github_bot.action import Action

ALL_LABEL_ACTIONS = [
CreateBackport,
CreateGUIIssue
]

class ActionLabel(Action):
def __init__(self):
pass

def isMatched(self, actionRequest):
if actionRequest.action not in ['labeled']:
return False
return True

def action(self, request):
for label_action in ALL_LABEL_ACTIONS:
__label_action = label_action()
if __label_action.isMatched(request):
__label_action.action(request)

return "labeled related actions succeed"

7 changes: 4 additions & 3 deletions github-bot/harvester_github_bot/action_sync_milestone.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from harvester_github_bot import app
from harvester_github_bot import zenh_api, repo
from harvester_github_bot.exception import CustomException
from harvester_github_bot.action import Action

class ActionSyncMilestone:
class ActionSyncMilestone(Action):
def __init__(self):
pass
def isMatched(self, action):
if action not in ['opened', 'milestoned', 'demilestoned']:
def isMatched(self, actionRequest):
if actionRequest.action not in ['opened', 'milestoned', 'demilestoned']:
return False
return True
def action(self, request):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,8 @@
from harvester_github_bot import app, zenh_api, repo, \
BACKPORT_LABEL_KEY
from harvester_github_bot.exception import CustomException, ExistedBackportComment

class ActionBackport:
def __init__(self):
pass
def isMatched(self, action):
if action not in ['labeled']:
return False
return True
def action(self, request):
return backport(request)
from harvester_github_bot.label_action.create_gui_issue import CREATE_GUI_ISSUE_LABEL
from harvester_github_bot.action import LabelAction

# check the issue's include backport-needed/(1.0.3|v1.0.3|v1.0.3-rc0) label
backport_label_pattern = r'^%s\/[\w0-9\.]+' % BACKPORT_LABEL_KEY
Expand All @@ -22,35 +14,47 @@ def action(self, request):
# Description: backport the issue #link-id
# Copy assignees and all labels except the backport-needed and add the not-require/test-plan label.
# Move the issue to the associated milestone and release.
def backport(request):
normal_labels = []
backport_labels = []
for label in request['issue']['labels']:
if re.match(backport_label_pattern, label['name']) is not None:
backport_labels.append(label)
else:
normal_labels.append(label)

msg = []
for backport_label in backport_labels:
try:
app.logger.debug(f"issue number {request['issue']['number']} start to create backport with labels {backport_label['name']}")

bp = Backport(request['issue']['number'], normal_labels, backport_label)
bp.verify()
bp.create_issue_if_not_exist()
bp.create_comment()
r = bp.related_release()
msg.append(r)
except ExistedBackportComment as e:
app.logger.debug(f"issue number {request['issue']['number']} had created backport with labels {backport_label['name']}")
except CustomException as e:
app.logger.exception(f"Custom exception : {str(e)}")
except Exception as e:
app.logger.exception(e)
class CreateBackport(LabelAction):
def __init__(self):
pass

return ",".join(msg)

def isMatched(self, request):
for label in request['issue']['labels']:
if re.match(backport_label_pattern, label['name']) is not None:
return True
return False

def action(self, request):
normal_labels = []
backport_labels = []
for label in request['issue']['labels']:
if re.match(backport_label_pattern, label['name']) is not None:
backport_labels.append(label)
else:
# backport should not include the 'require-ui' label
# because gui issue has its own backport
if CREATE_GUI_ISSUE_LABEL not in label['name']:
normal_labels.append(label)

msg = []
for backport_label in backport_labels:
try:
app.logger.debug(f"issue number {request['issue']['number']} start to create backport with labels {backport_label['name']}")

bp = Backport(request['issue']['number'], normal_labels, backport_label)
bp.verify()
bp.create_issue_if_not_exist()
bp.create_comment()
r = bp.related_release()
msg.append(r)
except ExistedBackportComment as e:
app.logger.debug(f"issue number {request['issue']['number']} had created backport with labels {backport_label['name']}")
except CustomException as e:
app.logger.exception(f"Custom exception : {str(e)}")
except Exception as e:
app.logger.exception(e)

return ",".join(msg)

class Backport:
def __init__(
Expand Down
63 changes: 63 additions & 0 deletions github-bot/harvester_github_bot/label_action/create_gui_issue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from harvester_github_bot import repo
from harvester_github_bot.action import LabelAction
import re

CREATE_GUI_ISSUE_LABEL = "require-ui"
AREA_UI_LABEL = "area/ui"
class CreateGUIIssue(LabelAction):
def __init__(self):
pass

def isMatched(self, request):
matched = False

# We can't expect the labels order from Github Webhook request.
# It might be ["require-ui/small", "area/ui"] or ["area/ui", "require-ui/small"]
# So we need to consider those two cases.
# "area/ui" is high priority label.
# If "area/ui" is in the labels, we can skip the rest of the labels.
for label in request['issue']['labels']:
if AREA_UI_LABEL in label['name']:
return False
if CREATE_GUI_ISSUE_LABEL in label['name']:
matched = True

return matched

def action(self, request):
self.labels = [AREA_UI_LABEL]

for label in request['issue']['labels']:
if CREATE_GUI_ISSUE_LABEL not in label['name']:
self.labels.append(label['name'])

self.issue_number = request['issue']['number']
self.original_issue = repo.get_issue(self.issue_number)

if self.__is_gui_issue_exist():
return "GUI issue already exist"
self.__create_gui_issue()
self.__create_comment()
return "create GUI issue success"

def __create_gui_issue(self):
issue_data = {
'title': f"[GUI] {self.original_issue.title}",
'body': f"GUI Issue from #{self.issue_number}",
'labels': self.labels,
'assignees': self.original_issue.assignees,
}
if self.original_issue.milestone is not None:
issue_data['milestone'] = self.original_issue.milestone
self.gui_issue = repo.create_issue(**issue_data)

def __create_comment(self):
self.original_issue.create_comment(body=f"GUI issue created #{self.gui_issue.number}.")

def __is_gui_issue_exist(self):
comment_pattern = r'GUI issue created #[\d].'
comments = self.original_issue.get_comments()
for comment in comments:
if re.match(comment_pattern, comment.body):
return True
return False
10 changes: 7 additions & 3 deletions github-bot/harvester_github_bot/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from harvester_github_bot.config import app, FLASK_USERNAME, FLASK_PASSWORD, GITHUB_OWNER, GITHUB_REPOSITORY
from harvester_github_bot.issue_transfer import issue_transfer
from harvester_github_bot.action_backport import ActionBackport
from harvester_github_bot.action import ActionRequest
from harvester_github_bot.action_label import ActionLabel
from harvester_github_bot.action_sync_milestone import ActionSyncMilestone

auth = HTTPBasicAuth()
Expand Down Expand Up @@ -39,7 +40,7 @@ def zenhub():


SUPPORTED_ACTIONS = [
ActionBackport(),
ActionLabel(),
ActionSyncMilestone(),
]

Expand All @@ -53,9 +54,12 @@ def gh():
return {
'message': msg
}, http.HTTPStatus.OK

action_request = ActionRequest()
action_request.setAction(req.get('action'))

for action in SUPPORTED_ACTIONS:
if action.isMatched(req.get('action')):
if action.isMatched(action_request):
msg = action.action(req)
break

Expand Down

0 comments on commit 4c1b7d3

Please sign in to comment.