Skip to content

Commit

Permalink
feat: create backport issue in github project instead of zenhub
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Yu <[email protected]>
  • Loading branch information
Yu-Jack committed Aug 6, 2024
1 parent 92e4156 commit f0db028
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 63 deletions.
39 changes: 0 additions & 39 deletions github-bot/harvester_github_bot/action_sync_milestone.py

This file was deleted.

18 changes: 12 additions & 6 deletions github-bot/harvester_github_bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from everett.manager import ConfigManager, ConfigOSEnv
from werkzeug.security import generate_password_hash
from github import Github

from harvester_github_bot.github_graphql.manager import GitHubProjectManager
from harvester_github_bot.zenhub import Zenhub

FLASK_LOGLEVEL = ""
Expand All @@ -14,6 +14,7 @@
GITHUB_OWNER = ""
GITHUB_REPOSITORY = ""
GITHUB_REPOSITORY_TEST = ""
GITHUB_PROJECT_NUMBER = ""
ZENHUB_PIPELINE = ""
BACKPORT_LABEL_KEY = ""

Expand All @@ -22,7 +23,7 @@
zenh_api = {}
repo = {}
repo_test = {}

gtihub_project_manager = {}

class BotConfig(RequiredConfigMixin):
required_config = ConfigOptions()
Expand All @@ -36,6 +37,8 @@ class BotConfig(RequiredConfigMixin):
'GitHub repository.')
required_config.add_option('github_repository_test', parser=str, default='tests', doc='Set the name of the tests '
'GitHub repository.')
required_config.add_option('github_project_number', parser=int, doc='Set the project id of the github '
'GitHub Project ID.')
required_config.add_option('github_token', parser=str, doc='Set the token of the GitHub machine user.')
required_config.add_option('zenhub_pipeline', parser=str, default='Review,Ready For Testing,Testing',
doc='Set the target ZenHub pipeline to '
Expand All @@ -53,28 +56,31 @@ def get_config():


def settings():
global FLASK_LOGLEVEL, FLASK_PASSWORD, FLASK_USERNAME, GITHUB_OWNER, GITHUB_REPOSITORY, GITHUB_REPOSITORY_TEST, \
ZENHUB_PIPELINE, BACKPORT_LABEL_KEY, gh_api, zenh_api, repo, repo_test
global FLASK_LOGLEVEL, FLASK_PASSWORD, FLASK_USERNAME, GITHUB_OWNER, GITHUB_REPOSITORY, GITHUB_PROJECT_NUMBER, GITHUB_REPOSITORY_TEST, \
ZENHUB_PIPELINE, BACKPORT_LABEL_KEY, gh_api, zenh_api, repo, repo_test, gtihub_project_manager
config = get_config()
FLASK_LOGLEVEL = config('flask_loglevel')
FLASK_PASSWORD = generate_password_hash(config('flask_password'))
FLASK_USERNAME = generate_password_hash(config('flask_username'))
GITHUB_OWNER = config('github_owner')
GITHUB_REPOSITORY = config('github_repository')
GITHUB_REPOSITORY_TEST = config('github_repository_test')
GITHUB_PROJECT_NUMBER = config('github_project_number')
ZENHUB_PIPELINE = config('zenhub_pipeline')
BACKPORT_LABEL_KEY = config('backport_label_key', default='backport-needed')

gh_api = Github(config('github_token'))
zenh_api = Zenhub(config('zenhub_token'))

repo = gh_api.get_repo('{}/{}'.format(GITHUB_OWNER, GITHUB_REPOSITORY))
repo_test = gh_api.get_repo('{}/{}'.format(GITHUB_OWNER, GITHUB_REPOSITORY_TEST))
gtihub_project_manager = GitHubProjectManager(GITHUB_OWNER, GITHUB_REPOSITORY, GITHUB_PROJECT_NUMBER, {
'Authorization': f'Bearer {config("github_token")}',
'Content-Type': 'application/json'
})

numeric_level = getattr(logging, FLASK_LOGLEVEL.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('invalid log level: %s'.format(FLASK_LOGLEVEL))
app.logger.setLevel(level=numeric_level)


settings()
58 changes: 58 additions & 0 deletions github-bot/harvester_github_bot/github_graphql/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import requests
from harvester_github_bot.github_graphql.ql_queries import GET_ISSUE_QUERY, GET_ORGANIZATION_PROJECT_QUERY, GET_USER_PROJECT_QUERY
from harvester_github_bot.github_graphql.ql_mutation import ADD_ISSUE_TO_PROJECT_MUTATION

class GitHubProjectManager:
def __init__(self, organization, repository, project_number, headers):
self.organization = organization
self.repository = repository
self.headers = headers
self.url = "https://api.github.com/graphql"
self.__project = self.__get_orgnization_project(project_number)
# self.__project = self.__get_user_project(project_number) # used in testing

def get_issue(self, issue_number):
variables = {
'repo_owner': self.organization,
'repo_name': self.repository,
'issue_number': issue_number
}
response = requests.post(self.url, headers=self.headers, json={'query': GET_ISSUE_QUERY, 'variables': variables})
if response.status_code == 200:
return response.json()['data']['repository']['issue']
else:
raise Exception(f"Query failed to run by returning code of {response.status_code}. {response.json()}")

def add_issue_to_project(self, issue_id):
variables = {
'project_id': self.__project["id"],
'content_id': issue_id
}
response = requests.post(self.url, headers=self.headers, json={'query': ADD_ISSUE_TO_PROJECT_MUTATION, 'variables': variables})
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Mutation failed to run by returning code of {response.status_code}. {response.json()}")

def __get_orgnization_project(self, project_number):
variables = {
'organization': self.organization,
'project_number': project_number
}
response = requests.post(self.url, headers=self.headers, json={'query': GET_ORGANIZATION_PROJECT_QUERY, 'variables': variables})
if response.status_code == 200:
return response.json()['data']['organization']['projectV2']
else:
raise Exception(f"Query failed to run by returning code of {response.status_code}. {response.json()}")


def __get_user_project(self, project_number):
variables = {
'organization': self.organization,
'project_number': project_number
}
response = requests.post(self.url, headers=self.headers, json={'query': GET_USER_PROJECT_QUERY, 'variables': variables})
if response.status_code == 200:
return response.json()['data']['user']['projectV2']
else:
raise Exception(f"Query failed to run by returning code of {response.status_code}. {response.json()}")
9 changes: 9 additions & 0 deletions github-bot/harvester_github_bot/github_graphql/ql_mutation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ADD_ISSUE_TO_PROJECT_MUTATION = """
mutation($project_id: ID!, $content_id: ID!) {
addProjectV2ItemById(input: {projectId: $project_id, contentId: $content_id}) {
item {
id
}
}
}
"""
38 changes: 38 additions & 0 deletions github-bot/harvester_github_bot/github_graphql/ql_queries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
GET_ISSUE_QUERY = """
query($repo_owner: String!, $repo_name: String!, $issue_number: Int!) {
repository(owner: $repo_owner, name: $repo_name) {
issue(number: $issue_number) {
id
number
title
url
}
}
}
"""


GET_ORGANIZATION_PROJECT_QUERY = """
query($organization: String!, $project_number: Int!) {
organization(login: $organization) {
projectV2(number: $project_number) {
id
title
number
}
}
}
"""

# This is used to test
GET_USER_PROJECT_QUERY = """
query($organization: String!, $project_number: Int!) {
user(login: $organization) {
projectV2(number: $project_number) {
id
title
number
}
}
}
"""
17 changes: 3 additions & 14 deletions github-bot/harvester_github_bot/label_action/create_backport.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import re
from harvester_github_bot import app, zenh_api, repo, \
from harvester_github_bot import app, gtihub_project_manager, repo, \
BACKPORT_LABEL_KEY
from harvester_github_bot.exception import CustomException, ExistedBackportComment
from harvester_github_bot.label_action.create_gui_issue import CREATE_GUI_ISSUE_LABEL
Expand Down Expand Up @@ -132,17 +132,6 @@ def create_comment(self):

# associated zenhub releases
def related_release(self):
release_id = zenh_api.get_release_id_by_version(repo_id=repo.id, version=self.__ver)

if release_id is not None and len(release_id) > 0:
try:
zenh_api.add_release_to_issue(
repo_id=repo.id,
release_id=release_id,
issue_number=self.__issue.number
)
except Exception as e:
raise CustomException("failed to associated release(%s) with repo(%d) and issue(%d): %s" % (
release_id, repo.id, self.__issue.number, e))

issue = gtihub_project_manager.get_issue(self.__issue.number)
gtihub_project_manager.add_issue_to_project(issue['id'])
return "issue number: %d." % self.__issue.number
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from harvester_github_bot import repo
from harvester_github_bot import repo, gtihub_project_manager
from harvester_github_bot.action import LabelAction
import re

Expand Down Expand Up @@ -41,6 +41,7 @@ def action(self, request):
return "GUI issue already exist"
self.__create_gui_issue()
self.__create_comment()
self.__added_into_project()
return "create GUI issue success"

def __create_gui_issue(self):
Expand All @@ -62,4 +63,8 @@ def __is_gui_issue_exist(self):
for comment in comments:
if re.match(comment_pattern, comment.body):
return True
return False
return False

def __added_into_project(self):
issue = gtihub_project_manager.get_issue(self.gui_issue.number)
gtihub_project_manager.add_issue_to_project(issue['id'])
2 changes: 0 additions & 2 deletions github-bot/harvester_github_bot/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from harvester_github_bot.issue_transfer import issue_transfer
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 @@ -41,7 +40,6 @@ def zenhub():

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

@app.route('/github', methods=['POST'])
Expand Down

0 comments on commit f0db028

Please sign in to comment.