forked from Lesin/reposync
258 lines
9.3 KiB
Python
258 lines
9.3 KiB
Python
from src.dto.sync import Project
|
|
from .repo import Repo
|
|
from .crawler import Fetch
|
|
from src.base import config
|
|
from src.dao.pull_request import PullRequestDAO
|
|
import shlex
|
|
import subprocess
|
|
from sqlalchemy import text
|
|
from src.utils.logger import logger
|
|
|
|
|
|
class Github(Repo):
|
|
|
|
organization: str
|
|
name: str
|
|
project: str
|
|
pull_request_list = []
|
|
token = config.ACCOUNT['github_token']
|
|
|
|
def __init__(self, project, organization, name: str):
|
|
super().__init__(project, organization, name)
|
|
|
|
def fetch_pull_request(self):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/pulls"
|
|
token = self.token
|
|
header = {
|
|
'Authorization': 'token ' + token}
|
|
data = Fetch(url, header=header, way='Get')
|
|
|
|
if data is None or len(data) == 0:
|
|
logger.info(
|
|
f"the github repo {self.organization}/{self.name} has no pull request")
|
|
else:
|
|
for pull in data:
|
|
pr = PullRequest(self.organization, self.name, pull['number'])
|
|
pr.project = self.project
|
|
pr.state = 'open'
|
|
pr.commit_url = pull['commits_url']
|
|
pr.inline = False
|
|
pr.comment_url = pull['comments_url']
|
|
pr.title = pull['title']
|
|
pr.html_url = pull['html_url']
|
|
pr.target_branch = pull['base']['ref']
|
|
self.pull_request_list.append(pr)
|
|
logger.info(f"fetch the pull request {pr.id} successfully")
|
|
|
|
async def save_pull_request(self):
|
|
if len(self.pull_request_list) == 0:
|
|
logger.info("no pull request need to save")
|
|
return
|
|
for pr in self.pull_request_list:
|
|
await pr.save()
|
|
|
|
|
|
class PullRequest(Github):
|
|
|
|
id: int
|
|
url: str
|
|
project: str
|
|
html_url: str
|
|
author: str
|
|
review_url: str
|
|
state: str
|
|
commit_url: str
|
|
inline: bool
|
|
comment_url: str
|
|
title: str
|
|
target_branch: str
|
|
latest_commit: str
|
|
token = config.ACCOUNT['github_token']
|
|
|
|
def __init__(self, organization: str, name: str, id: int):
|
|
self.url = f"{config.GITHUB_ENV['github_api_address']}/{organization}/{name}/pulls/{id}"
|
|
self.id = id
|
|
self.type = 'GitHub'
|
|
self.organization = organization
|
|
self.name = name
|
|
self._pull_request_dao = PullRequestDAO()
|
|
|
|
def fetch_commit(self):
|
|
logger.info(self.id)
|
|
header = {
|
|
'Authorization': 'token ' + self.token}
|
|
resp = Fetch(self.commit_url, header=header, way='Get')
|
|
self.author = resp[0]['commit']['author']['name']
|
|
self.email = resp[0]['commit']['author']['email']
|
|
|
|
def fetch_comment_url(self):
|
|
header = {
|
|
'Authorization': 'token ' + self.token}
|
|
resp = Fetch(self.url, header=header, way='Get')
|
|
self.comment_url = resp['comments_url']
|
|
|
|
def fetch_comment(self):
|
|
self.fetch_comment_url()
|
|
header = {
|
|
'Authorization': 'token ' + self.token}
|
|
resp = Fetch(self.comment_url, header=header, way='Get')
|
|
comments = []
|
|
for item in resp:
|
|
comments.append(item['body'])
|
|
return comments
|
|
|
|
def _clone(self):
|
|
dir = "/tmp/" + self.name + "_pr" + str(self.id)
|
|
address = f"git@github.com:{self.organization}/{self.name}.git"
|
|
subprocess.run(shlex.split('mkdir ' + dir), cwd='.')
|
|
subprocess.run(shlex.split('git clone ' + address), cwd=dir)
|
|
return dir
|
|
|
|
def _apply_diff(self, dir, branch: str):
|
|
subprocess.run(shlex.split('git checkout ' + branch), cwd=dir)
|
|
new_branch = 'pr' + str(self.id)
|
|
subprocess.run(shlex.split('git checkout -b ' + branch), cwd=dir)
|
|
subprocess.run(shlex.split('git apply ' + dir), cwd=dir)
|
|
subprocess.run(shlex.split('git add .'), cwd=dir)
|
|
subprocess.run(shlex.split(
|
|
"git commit -m '" + self.title + "'"), cwd=dir)
|
|
subprocess.run(shlex.split(
|
|
'git push -uv origin' + new_branch), cwd=dir)
|
|
|
|
def _get_diff(self):
|
|
filename = "/tmp/github_pr" + str(self.id) + "_diff"
|
|
baseUrl = f"{config.GITHUB_ENV['github_api_diff_address']}/{self.organization}/{self.name}/pull/"
|
|
diffUrl = baseUrl + str(self.id) + ".diff"
|
|
|
|
cmd = "curl -X GET " + diffUrl + \
|
|
" -H 'Accept: application/vnd.github.v3.diff'"
|
|
with open(filename, 'w') as outfile:
|
|
subprocess.call(shlex.split(cmd), stdout=outfile)
|
|
return filename
|
|
|
|
def _send_merge_request(self):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/issues/{self.id}/merge"
|
|
header = {
|
|
'Authorization': 'token ' + self.token,
|
|
'Content-Type': 'application/json'}
|
|
data = {
|
|
"merge_method": "squash"
|
|
}
|
|
resp = Fetch(url, header=header, data=data, way='Put')
|
|
if resp is None:
|
|
logger.error("send merge request failed")
|
|
return False
|
|
return True
|
|
|
|
def comment(self, comment: str):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/issues/{self.id}/comments"
|
|
header = {
|
|
'Authorization': 'token ' + self.token,
|
|
'Content-Type': 'application/json'}
|
|
data = {"body": comment}
|
|
resp = Fetch(url, header=header, data=data, way='Post')
|
|
if resp is None:
|
|
logger.error("send comment request failed")
|
|
return False
|
|
return True
|
|
|
|
def approve(self):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/issues/{self.id}/reviews"
|
|
header = {
|
|
'Authorization': 'token ' + self.token,
|
|
'Content-Type': 'application/json'}
|
|
data = {"body": "LGTM",
|
|
"event": "APPROVE"}
|
|
resp = Fetch(url, header=header, data=data, way='Post')
|
|
if resp is None:
|
|
logger.error("send approve request failed")
|
|
return False
|
|
return True
|
|
|
|
def close(self):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/pulls/{self.id}"
|
|
header = {
|
|
'Authorization': 'token ' + self.token,
|
|
'Accept': 'application/vnd.github.v3+json'}
|
|
data = {"state": "closed"}
|
|
resp = Fetch(url, header=header, data=data, way='Patch')
|
|
if resp is None:
|
|
logger.error("send close pull request failed")
|
|
return False
|
|
return True
|
|
|
|
def get_latest_commit(self):
|
|
url = f"{config.GITHUB_ENV['github_api_address']}/{self.organization}/{self.name}/pulls/{self.id}/commits"
|
|
header = {
|
|
'Authorization': 'token ' + self.token}
|
|
data = Fetch(url, header=header, way='Get')
|
|
|
|
if data is None or len(data) == 0:
|
|
logger.info(
|
|
f"the pull request {self.id} of github repo {self.organization}/{self.name} has no commits")
|
|
else:
|
|
self.latest_commit = data[0]['sha']
|
|
|
|
async def save(self):
|
|
self.fetch_commit()
|
|
pr = await self._pull_request_dao.fetch(text(f"pull_request_id = {self.id} and project = '{self.project}'"))
|
|
if not pr:
|
|
# insert pull request repo
|
|
resp = await self._pull_request_dao.insert_pull_request(
|
|
self.id, self.title, self.project, self.type, self.html_url,
|
|
self.author, self.email, self.target_branch, "NULL")
|
|
if not resp:
|
|
logger.error(f"save the pull request {self.id} failed")
|
|
else:
|
|
logger.info(f"save the pull request {self.id} successfully")
|
|
else:
|
|
# update pull request repo
|
|
resp = await self._pull_request_dao.update_pull_request(
|
|
self.id, self.title, self.project, self.type, self.html_url,
|
|
self.author, self.email, self.target_branch)
|
|
if not resp:
|
|
logger.error(f"update the pull request {self.id} failed")
|
|
else:
|
|
logger.info(f"update the pull request {self.id} successfully")
|
|
return
|
|
|
|
async def sync(self):
|
|
comments = self.fetch_comment()
|
|
if len(comments) == 0:
|
|
logger.info(f"the github pull request #{self.id} has no comment")
|
|
return
|
|
merge = False
|
|
cicd = False
|
|
for comment in comments:
|
|
if comment == '/merge':
|
|
logger.info(
|
|
f"the github pull request #{self.id} need to merge")
|
|
merge = True
|
|
if comment == '/cicd':
|
|
logger.info(f"the github pull request #{self.id} need to cicd")
|
|
cicd = True
|
|
if cicd:
|
|
pass
|
|
if merge:
|
|
self.merge_to_inter()
|
|
return
|
|
|
|
async def check_if_merge(self):
|
|
comments = self.fetch_comment()
|
|
if len(comments) == 0:
|
|
logger.info(f"the github pull request {self.id} has no comment")
|
|
return
|
|
merge = False
|
|
for comment in comments:
|
|
if comment == '/merge':
|
|
logger.info(f"the github pull request {self.id} need to merge")
|
|
merge = True
|
|
return merge
|
|
|
|
async def check_if_new_commit(self, origin_latest_commit: str):
|
|
latest_commit = self.get_latest_commit()
|
|
if latest_commit == origin_latest_commit:
|
|
return True
|
|
else:
|
|
return False
|