From cb5bff9daa30a1834220259e67da3095520e1fd7 Mon Sep 17 00:00:00 2001
From: dongjie110 <17621827400@163.com>
Date: Wed, 28 Sep 2022 10:14:46 +0800
Subject: [PATCH] add jenkins api comment api and rewrite pr comment content
---
common/common.py | 172 +++++++++++++++++++++++++++++--
core/check_release_management.py | 95 ++++++++++++++++-
openeuler_obs.py | 8 +-
3 files changed, 263 insertions(+), 12 deletions(-)
diff --git a/common/common.py b/common/common.py
index b85c223..c710431 100644
--- a/common/common.py
+++ b/common/common.py
@@ -18,7 +18,15 @@
function for all
"""
import os
+import re
import pexpect
+import requests
+import jenkins
+from requests.auth import HTTPBasicAuth
+try:
+ from urllib import urlencode
+except ImportError:
+ from urllib.parse import urlencode
def str_to_bool(s):
@@ -117,13 +125,159 @@ class Pexpect(object):
return msg
+class Comment(object):
+ """
+ gitee comments process
+ :param owner: 仓库属于哪个组织
+ :param repo: 仓库名
+ :param token: gitee 账户token
+ """
+
+ def __init__(self, owner, repo, token):
+ self._owner = owner
+ self._repo = repo
+ self._token = token
+
+
+ def comment_pr(self, pr, comment):
+ """
+ 评论pull request
+ :param pr: 本仓库PR id
+ :param comment: 评论内容
+ :return: 0成功,其它失败
+ """
+ comment_pr_url = "https://gitee.com/api/v5/repos/{}/{}/pulls/{}/comments".format(self._owner, self._repo, pr)
+ data = {"access_token": self._token, "body": comment}
+ rs = self.do_requests("post", comment_pr_url, body=data, timeout=10)
+ if rs == 0:
+ return True
+ else:
+ return False
+
+ def parse_comment_to_table(self, pr, results, tips, details):
+ """
+ :param pr: 仓库PR id
+ :param results: 门禁检查返回结果
+ :return: none
+ """
+ comment_state = {"success":":white_check_mark:", "warning":":bug:", "failed":":x:"}
+ comments = ["
", "Check Item | Check Result | Description | "]
+ for check_item, check_result in results.items():
+ emoji_result = comment_state[check_result]
+ word_result = check_result.upper()
+ info_str = '''
---|
{} | {}
+ {} | {} |
+ '''.format(check_item, emoji_result, word_result, details[check_item])
+ comments.append(info_str)
+ comments.append("
")
+ comments.extend(tips)
+ self.comment_pr(pr, "\n".join(comments))
+
+
+ def do_requests(self, method, url, querystring=None, body=None, auth=None, timeout=30, obj=None):
+ """
+ http request
+ :param method: http method
+ :param url: http[s] schema
+ :param querystring: dict
+ :param body: json
+ :param auth: dict, basic auth with user and password
+ :param timeout: second
+ :param obj: callback object, support list/dict/object
+ :return:
+ """
+ if method.lower() not in ["get", "post", "put", "delete"]:
+ return -1
+ if querystring:
+ url = "{}?{}".format(url, urlencode(querystring))
+ try:
+ func = getattr(requests, method.lower())
+ if body:
+ if auth:
+ rs = func(url, json=body, timeout=timeout, auth=HTTPBasicAuth(auth["user"], auth["password"]))
+ else:
+ rs = func(url, json=body, timeout=timeout)
+ else:
+ if auth:
+ rs = func(url, timeout=timeout, auth=HTTPBasicAuth(auth["user"], auth["password"]))
+ else:
+ rs = func(url, timeout=timeout)
+ if rs.status_code not in [requests.codes.ok, requests.codes.created, requests.codes.no_content]:
+ return 1
+ # return response
+ if obj is not None:
+ if isinstance(obj, list):
+ obj.extend(rs.json())
+ elif isinstance(obj, dict):
+ obj.update(rs.json())
+ elif callable(obj):
+ obj(rs)
+ elif hasattr(obj, "cb"):
+ getattr(obj, "cb")(rs.json())
+ return 0
+ except requests.exceptions.SSLError as sslerror:
+ return -2
+ except requests.exceptions.Timeout as timeouterror:
+ return 2
+ except requests.exceptions.RequestException as excepterror:
+ return 3
-if __name__ == "__main__":
- res = git_repo_src("https://gitee.com/src-openeuler/zip", "xxxxx", "xxxxx")
- print(res)
- test = Pexpect("root", "127.0.0.1", "112233") #, port=2224)
- res = test.ssh_cmd("osc getbinareis openEuler:20.03:LTS:Next ceph standard_x86_64 x86_64")
- print("..................")
- print(res)
- res = test.scp_file("./ip.txt", "~")
- print(res)
+class JenkinsProxy(object):
+ """
+ Jenkins 代理,实现jenkins一些操作
+ """
+
+ def __init__(self, base_url, username, token, timeout=10):
+ """
+
+ :param base_url:
+ :param username: 用户名
+ :param token:
+ :param timeout:
+ """
+ self._username = username
+ self._token = token
+ self._timeout = timeout
+ self._jenkins = jenkins.Jenkins(base_url, username=username, password=token, timeout=timeout)
+
+ def get_job_info(self, job_path):
+ """
+ 获取任务信息
+ :param job_path: job路径
+ :return: None if job_path not exist
+ """
+ try:
+ return self._jenkins.get_job_info(job_path)
+ except jenkins.JenkinsException as e:
+ return None
+
+ @classmethod
+ def get_job_path_from_job_url(cls, job_url):
+ """
+ 从url中解析job路径
+ :param job_url: 当前工程url, for example https://domain/job/A/job/B/job/C
+ :return: for example, A/B/C
+ :2 :代表目录层级
+ """
+ jenkins_first_level_dir_index = 2
+ jenkins_dir_interval_with_level = 2
+ job_path = re.sub(r"/$", "", job_url)
+ job_path = re.sub(r"http[s]?://", "", job_path)
+ sp = job_path.split("/")[jenkins_first_level_dir_index::
+ jenkins_dir_interval_with_level]
+ sp = [item for item in sp if item != ""]
+ job_path = "/".join(sp)
+ return job_path
+
+ @staticmethod
+ def get_job_path_build_no_from_build_url(build_url):
+ """
+ 从url中解析job路径
+ :param build_url: 当前构建url, for example https://domain/job/A/job/B/job/C/number/
+ :return: for example A/B/C/number
+ """
+ job_build_no = re.sub(r"/$", "", build_url)
+ job_url = os.path.dirname(job_build_no)
+ build_no = os.path.basename(job_build_no)
+ job_path = JenkinsProxy.get_job_path_from_job_url(job_url)
+ return job_path, build_no
diff --git a/core/check_release_management.py b/core/check_release_management.py
index 8cdff62..c040a57 100644
--- a/core/check_release_management.py
+++ b/core/check_release_management.py
@@ -17,6 +17,7 @@
check the software package for the corresponding project of thecorresponding branch of source
"""
import os
+import re
import sys
import yaml
import requests
@@ -26,6 +27,8 @@ sys.path.append(os.path.join(Now_path, ".."))
from common.log_obs import log
from collections import Counter
from common.common import git_repo_src
+from common.common import Comment
+from common.common import JenkinsProxy
class CheckReleaseManagement(object):
"""
@@ -40,11 +43,26 @@ class CheckReleaseManagement(object):
"""
self.kwargs = kwargs
self.prid = self.kwargs['pr_id']
+ self.token = self.kwargs['access_token']
self.current_path = os.getcwd()
self.meta_path = self.kwargs['obs_meta_path']
self.manage_path = self.kwargs['release_management_path']
self.giteeuser = self.kwargs['gitee_user']
self.giteeuserpwd = self.kwargs['gitee_pwd']
+ self.jenkins_user = self.kwargs['jenkins_user']
+ self.jenkins_api_token = self.kwargs['jenkins_api_token']
+ self.jenkins_build_url = self.kwargs['jenkins_build_url']
+ self.job_result = {
+ 'check_yaml_format':'success',
+ 'check_package_yaml_key':'success',
+ 'check_package_complete':'success',
+ 'check_package_requires':'success',
+ 'check_package_add':'success',
+ 'check_package_move':'success',
+ 'check_package_delete':'success',
+ 'valied_package_source':'success',
+ 'check_date':'success'
+ }
def _clean(self, pkgname):
"""
@@ -153,6 +171,7 @@ class CheckReleaseManagement(object):
return new_file_path,master_new_file_path,new_versin_file_path
else:
log.info("There are no file need to check!!!")
+ self._comment_to_pr()
sys.exit()
def _get_yaml_msg(self, yaml_path_list, manage_path, rollback=None):
@@ -213,6 +232,8 @@ class CheckReleaseManagement(object):
del error_pkg[change_file]
if error_pkg:
log.error("May be {0} should not be delete".format(error_pkg))
+ self.job_result['check_package_complete'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please check your PR")
def _check_key_in_yaml(self, all_pack_msg, change_file):
@@ -234,6 +255,8 @@ class CheckReleaseManagement(object):
error_flag = True
log.error("Please check {0}".format(msg))
if error_flag:
+ self.job_result['check_package_yaml_key'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please ensure the following key values in your yaml")
def _check_date_time(self, yaml_msg, change_file):
@@ -252,6 +275,7 @@ class CheckReleaseManagement(object):
log.error(msg)
log.error("Wrong Date: !!!".format(msg['date']))
if error_flag:
+ self.job_result['check_date'] = 'failed'
log.error("Please set your date to the same day as the commit time!!!")
return error_flag
@@ -271,6 +295,7 @@ class CheckReleaseManagement(object):
yaml_key = os.path.join(msg['branch_from'],
msg['obs_from'], msg['name'])
log.error("The {0} not exist in obs_meta".format(yaml_key))
+ self.job_result['check_package_add'] = 'failed'
error_flag = True
return error_flag
@@ -321,6 +346,7 @@ class CheckReleaseManagement(object):
return change_list
else:
log.info("The are no new msg in your yaml!!!")
+ self._comment_to_pr()
sys.exit()
def _check_yaml_format(self, yaml_path_list, manage_path):
@@ -336,6 +362,8 @@ class CheckReleaseManagement(object):
except Exception as e:
log.error("**********FORMAT ERROR***********")
log.error("%s format bad Because:%s" % (yaml_path, e))
+ self.job_result['check_yaml_format'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("May be %s has a bad format" % yaml_path)
def _check_same_pckg(self, change_file_path, yaml_msg):
@@ -355,6 +383,7 @@ class CheckReleaseManagement(object):
if all_pkg_name:
log.error("The following packages are duplicated in the YAML files")
log.error(all_pkg_name)
+ self.job_result['check_package_complete'] = 'failed'
return True
else:
return False
@@ -385,6 +414,7 @@ class CheckReleaseManagement(object):
for msg in error_msg[yaml_path]:
log.error(msg)
if error_msg:
+ self.job_result['valied_package_source'] = 'failed'
return True
else:
return False
@@ -421,6 +451,8 @@ class CheckReleaseManagement(object):
del info_dict[change]
if error_flag:
log.error("Check the delete group in the {0}!!!".format(info_dict))
+ self.job_result['check_package_delete'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR:Please check your PR")
def _get_move_and_add(self,old_msg,new_msg):
@@ -488,6 +520,7 @@ class CheckReleaseManagement(object):
else:
error_infos[c_branch] = [pkg]
if error_infos:
+ self.job_result['check_package_add'] = 'failed'
log.error("some errors in your commit,please check: {}".format(error_infos))
return error_flag
@@ -512,6 +545,7 @@ class CheckReleaseManagement(object):
add_names.remove(name)
if add_names:
error_flag = True
+ self.job_result['check_package_delete'] = 'failed'
log.error("master branch pkg name:{} you want delete not exist in obs_meta!!!".format(add_names))
return error_flag
@@ -584,6 +618,7 @@ class CheckReleaseManagement(object):
else:
error_infos[branch] = [pkg]
if error_infos:
+ self.job_result['check_package_move'] = 'failed'
log.error("some errors in your commit,please check: {}".format(error_infos))
return error_flag
@@ -610,6 +645,7 @@ class CheckReleaseManagement(object):
else:
error_infos[branch] = [pkg]
if error_infos:
+ self.job_result['check_date'] = 'failed'
log.error("some errors in your commit,please check: {}".format(error_infos))
return error_flag
@@ -631,11 +667,14 @@ class CheckReleaseManagement(object):
error_master_pkgs = list(set(old_pkgs).difference(set(pkgs)))
if error_master_pkgs:
error_flag = True
+ self.job_result['check_package_complete'] = 'failed'
log.error("The following {0} packages should not deleted in the master YAML files".format(error_master_pkgs))
if duplicated:
error_flag = True
+ self.job_result['check_package_complete'] = 'failed'
log.error("The following {0} packages are duplicated in the master YAML files".format(duplicated))
if error_flag:
+ self._comment_to_pr()
raise SystemExit("ERROR: Please check your PR")
def _check_pkg_from_new(self, meta_path, change_info):
@@ -674,6 +713,7 @@ class CheckReleaseManagement(object):
pkgs.remove(name)
if pkgs:
log.error("The {0} not exist in obs_meta dir {1}".format(pkgs,branch))
+ self.job_result['check_package_delete'] = 'failed'
error_flag = True
return error_flag
@@ -714,6 +754,7 @@ class CheckReleaseManagement(object):
break
if error_names:
error_flag =True
+ self.job_result['check_package_add'] = 'failed'
for pkg in pkgs:
if pkg['name'] in error_names:
log.error("branch:{}:The {} not exist in obs_meta from dir {}/{}".format(branch, pkg['name'], pkg['source_dir'], pkg['obs_from']))
@@ -740,6 +781,8 @@ class CheckReleaseManagement(object):
error_flag = True
log.error("Please check {0}".format(msg))
if error_flag:
+ self.job_result['check_package_yaml_key'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please ensure the following key values in your yaml")
def _check_valid_release_branch(self, change_info):
@@ -761,6 +804,8 @@ class CheckReleaseManagement(object):
error_flag = True
log.error("pkg:{} souce_dir or destination_dir valid check error".format(pkg['name']))
if error_flag:
+ self.job_result['valied_package_source'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please ensure the source_dir and destination_dir adapt rules")
def _check_pkg_date(self, change_info):
@@ -776,6 +821,7 @@ class CheckReleaseManagement(object):
yaml_date = int(pkg['date'].split('-')[2])
if today != yaml_date:
error_flag = True
+ self.job_result['check_date'] = 'failed'
log.error("Wrong Date: !!!".format(pkg['date']))
return error_flag
@@ -852,9 +898,13 @@ class CheckReleaseManagement(object):
log.info(pkg)
if error_pkg_flag:
log.error("May be {0} should not be delete".format(error_pkg))
+ self.job_result['check_package_complete'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please check your PR")
if same_pkg_flag:
log.error("The following {0} packages are duplicated in the YAML files".format(same_pkg))
+ self.job_result['check_package_complete'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please check your PR")
return change_infos
@@ -864,15 +914,16 @@ class CheckReleaseManagement(object):
'''
log.info("internal move pkgs check")
error_flag = False
+ internal_move_pkgs = {}
for branch,new_msgs in new_msg.items():
if old_msg.get(branch, []):
temp_new = {}
temp_old = {}
old_msgs = old_msg[branch]
for new_pkg in new_msgs:
- temp_new[new_pkg['name']] = {'obs_to':new_pkg['obs_to'],'obs_from':new_pkg['obs_from'],'source_dir':new_pkg['source_dir'],'destination_dir':new_pkg['destination_dir']}
+ temp_new[new_pkg['name']] = {'name':new_pkg['name'],'obs_to':new_pkg['obs_to'],'obs_from':new_pkg['obs_from'],'source_dir':new_pkg['source_dir'],'destination_dir':new_pkg['destination_dir']}
for old_pkg in old_msgs:
- temp_old[old_pkg['name']] = {'obs_to':old_pkg['obs_to'],'obs_from':old_pkg['obs_from'],'source_dir':old_pkg['source_dir'],'destination_dir':old_pkg['destination_dir']}
+ temp_old[old_pkg['name']] = {'name':old_pkg['name'],'obs_to':old_pkg['obs_to'],'obs_from':old_pkg['obs_from'],'source_dir':old_pkg['source_dir'],'destination_dir':old_pkg['destination_dir']}
for pkgname,obsinfo in temp_new.items():
if temp_old.get(pkgname,''):
old_obsto = temp_old[pkgname]['obs_to']
@@ -886,7 +937,14 @@ class CheckReleaseManagement(object):
error_flag = True
log.error("{}:{}".format(pkgname, obsinfo))
log.error("internal move pkg:{} source_dir must same with destination_dir and obs_from must same with before obs_to".format(pkgname))
+ else:
+ if internal_move_pkgs.get(branch, []):
+ internal_move_pkgs[branch].append(obsinfo)
+ else:
+ internal_move_pkgs[branch] = [obsinfo]
if error_flag:
+ self.job_result['check_package_move'] = 'failed'
+ self._comment_to_pr()
raise SystemExit("ERROR: Please check your PR")
def _get_new_version_yaml_msg(self, yaml_path_list, manage_path,vtype='master'):
@@ -958,6 +1016,35 @@ class CheckReleaseManagement(object):
all_master_pkgs = self._get_complete_yaml_pkgs('master')
return all_master_pkgs
+ def _comment_to_pr(self):
+ """
+ gitee comment and jenkins api comment check result to pr
+ """
+ comment_tips = []
+ jp = JenkinsProxy("https://openeulerjenkins.osinfra.cn/", self.jenkins_user, self.jenkins_api_token)
+ build_url = self.jenkins_build_url
+ job_name, job_id = jp.get_job_path_build_no_from_build_url(build_url)
+ comment_tips.append("1)本次构建号为{2}/{1},点击可查看构建详情: #{1}\n".format(build_url,job_id,job_name))
+ comment_tips.append("2)若有检查失败项目,请勿合入")
+ comment_tips.append("3)若您对如何创建提交PR有疑问," \
+ "可参考" \
+ "开发者提交PR指导手册")
+ details = {
+ 'check_yaml_format':"检查yaml格式是否正确",
+ 'check_package_yaml_key':"检查yaml中包key填写是否正确",
+ 'check_package_complete':"检查是否误删包或者增加不应添加的包",
+ 'check_package_requires':"检查分支内某project移动的包是否被同project内其他包所依赖",
+ 'check_package_add':"检查向project内添加包是否符合规则",
+ 'check_package_move':"检查分支内包移动是否符合规则",
+ 'check_package_delete':"检查删除包是否符合规则",
+ 'valied_package_source':"检查包引入时的引入分支是否符合规则",
+ 'check_date':"日期检查,必须与提交日期一致"
+ }
+ repo_owner = 'openeuler'
+ repo = 'release-management'
+ gm = Comment(repo_owner, repo, self.token)
+ gm.parse_comment_to_table(self.prid, self.job_result, comment_tips, details)
+
def check_pckg_yaml(self):
"""
check the obs_from branch_from in pckg-mgmt.yaml
@@ -988,6 +1075,7 @@ class CheckReleaseManagement(object):
del_flag = self._check_master_del_rules(del_old_master_yaml_msg, del_master_change_yaml_msg)
date_flag = self._check_master_date_rules(add_infos)
if add_flag or move_flag or date_flag or del_flag:
+ self._comment_to_pr()
raise SystemExit("Please check your commit")
if new_version_change_file:
log.info(new_version_change_file)
@@ -1001,6 +1089,7 @@ class CheckReleaseManagement(object):
error_flag_add = self._check_pkg_parent_from(change_infos, correct_from, error_from, add_infos)
error_flag_del = self._check_pkg_delete_new(self.meta_path, change_delete_infos)
if error_flag_add or error_flag_del or date_flag:
+ self._comment_to_pr()
raise SystemExit("Please check your commit")
if change_file:
log.info(change_file)
@@ -1013,7 +1102,9 @@ class CheckReleaseManagement(object):
error_flag3 = self._check_same_pckg(change_file, change_yaml_msg)
error_flag4 = self._check_branch_msg(change_msg_list, change_file, self.manage_path)
if error_flag1 or error_flag2 or error_flag3 or error_flag4:
+ self._comment_to_pr()
raise SystemExit("Please check your commit")
+ self._comment_to_pr()
if __name__ == "__main__":
kw = {"branch":"master",
diff --git a/openeuler_obs.py b/openeuler_obs.py
index 073e256..da38a85 100644
--- a/openeuler_obs.py
+++ b/openeuler_obs.py
@@ -117,6 +117,9 @@ par.add_argument("-ams", "--align_meta_service", default=False,
help="compare with repo obs_meta and release-management add or delete pkg", required=False)
par.add_argument("-amsb", "--align_meta_service_branch", default=None,
help="need compare with repo obs_meta and release-management pkgs branchs", required=False)
+par.add_argument("-ju", "--jenkins_user", help="jekins user name", required=False)
+par.add_argument("-jt", "--jenkins_api_token", help="jenkins api token", required=False)
+par.add_argument("-jbu", "--jenkins_build_url", help="jenkins build url", required=False)
args = par.parse_args()
#apply
@@ -164,7 +167,10 @@ kw = {
"check_pckg_mgmt": args.check_pckg_mgmt,
"compare": args.compare,
"align_meta_service": args.align_meta_service,
- "align_meta_service_branch": args.align_meta_service_branch
+ "align_meta_service_branch": args.align_meta_service_branch,
+ "jenkins_user": args.jenkins_user,
+ "jenkins_api_token": args.jenkins_api_token,
+ "jenkins_build_url": args.jenkins_build_url
}
run = Runner(**kw)
--
Gitee