python3对系统增量进行取包处理
定义引用方法:
点击查看代码
# _*_ utf-8 _*_
import os, re, zipfile
from openpyxl import load_workbook
def zip_folder(dataList, zip_full_name):
"""
压缩dataList下所有文件夹下所有子文件夹和文件
:param zip_full_name: zip文件绝对路径
dataList:路径相对路径
"""
with zipfile.ZipFile(zip_full_name, 'w') as zf:
for yunyan_num in dataList:
for dir_full_path, dir_names, file_names in os.walk(yunyan_num):
# zip压缩包内的相对路径
print('--', dir_full_path, file_names)
for dir_name in dir_names:
zf.write(os.path.join(dir_full_path, dir_name), os.path.join(dir_full_path, dir_name))
for file_name in file_names:
zf.write(os.path.join(dir_full_path, file_name), os.path.join(dir_full_path, file_name))
zf.close()
def is_onlyString(char):
'''判断是否是包含中文字符'''
checkWord = []
if type(char) == str:
for word in char:
if type(word) == str:
if b'\xb0\xa1' <= word.encode('gb2312') <= b'\xd7\xf9':
checkWord.append(1)
if len(checkWord) == 0:
return True
else:
return False
def removeQiCode(string):
'''对一个str进行成员去重'''
if string:
'''去除前后空格,去除" '等符号,去除可能存在的\字符'''
string = string.strip().replace("\"", '').replace("\'", '').replace('\\', '')
return string
else:
# 不为真的不做任何操作
return None
def removeDumplict(List):
'''对一个List进行去重'''
if List:
for item in List:
if List.count(item) == 2:
List.remove(item)
# print(List) # 测试完删除
return List
else:
return None
def checkKongGe(string):
'''检查字符中是否包含\n,返回一个列表'''
result = []
if re.findall('\n', string):
return string.split('\n')
else:
result.append(string)
return result
def dealwith_service(dataList):
'''
将给定的列表,按照字符要求去掉不需要的字符和空格等
:return: dictionary = {wen: [], haoren: []}
'''
result_dict = {'wen4sx': [], 'haoren': [], 'nginx': [], 'number': []}
if dataList:
for num, item in enumerate(dataList):
# 筛选不包含中文字符的成员
if is_onlyString(item):
# 对\n进行处理
for code_path in checkKongGe(item):
# print(str(num) + ':' + code_path) # 测试完成后删除
if code_path.startswith('/xiaoweiba-wen/'):
# 处理一个空格中有多行内容的情况
# 去除/xiaoweiba-wen/字符
result_dict['wen4sx'].append(removeQiCode(code_path[len('/xiaoweiba-wen/'):]))
elif code_path.startswith('/xiaoweiba-haoren-huairen/'):
# 去除/xiaoweiba-haoren/字符
result_dict['haoren'].append(removeQiCode(code_path[len('/xiaoweiba-haoren-huairen/'):]))
elif code_path.startswith('/xiaoweiba-haoren-basiccommon/'):
# 去除/xiaoweiba-haoren-basiccommon/字符
result_dict['haoren'].append(removeQiCode(code_path[len('/xiaoweiba-haoren-basiccommon/'):]))
elif code_path.startswith('/xiaoweiba-jadp-static/'):
# 去除/xiaoweiba-jadp-static/
result_dict['nginx'].append(removeQiCode(code_path[len('/xiaoweiba-jadp-static/'):]))
elif code_path.startswith('/xiaoweiba-haoren-static/'):
# 去除/xiaoweiba-haoren-static/
result_dict['nginx'].append(removeQiCode(code_path[len('/xiaoweiba-haoren-static/'):]))
elif code_path.startswith('xiaoweiba-Q'):
# 获取云烟但号
result_dict['number'].append(removeQiCode(code_path))
else:
# 待扩展模块
pass
if result_dict['wen4sx']:
result_dict['wen4sx'] = removeDumplict(result_dict['wen4sx'])
if result_dict['haoren']:
result_dict['haoren'] = removeDumplict(result_dict['haoren'])
if result_dict['nginx']:
result_dict['nginx'] = removeDumplict(result_dict['nginx'])
return result_dict
def dealwith_data(fileName, columnName, sheetNum=0):
'''
从一个给定的xlsx文件(绝对路径)
读取一个sheet
读取第n列
'''
RELEASE = []
def single_file(filename):
# 加载Excel文件
wb = load_workbook(filename=filename, read_only=True, data_only=True)
# 问题列表
ws1 = wb[wb.sheetnames[sheetNum]]
# 最大行数
row_max = ws1.max_row
word = ws1.rows
row_num = 0
sheet = wb.active
for num in range(1, 30):
row_value = sheet.cell(row=2, column=num).value
if row_value == columnName:
num_col = num - 1
for row in word:
# 这里可以对num_col service_col static_col判断,为true则执行,false则输出字段不存在
col_value = row[num_col].value
if col_value:
RELEASE.append(col_value)
row_num += 1
wb.close()
# 以上内容为define变量和识别目录
# print(fileName)
single_file(fileName)
if RELEASE:
return RELEASE
else:
return None
def printListInfo(str1, dataList):
print('==从表格中获取的{0}为:{1}'.format(str1, dataList))
def printInfo(txt):
print("============================={0}=============================".format(txt))
def printMember(Dict, char):
'''
按照关键字char输出dataList中有关char的成员清单
:param Dict: 字典数据
:param char: 关键字字符
:return: None
'''
# 显示增量内容
if char == 'service':
if Dict['wen4sx']:
for item in Dict['wen4sx']:
print(item)
if Dict['haoren']:
for item in Dict['haoren']:
print(item)
elif char == 'nginx':
for item in Dict[char]:
print(item)
if __name__ == '__main__':
pass
取包脚本主体如下:
点击查看代码
# _*_ utf-8 _*_
import os, sys, re, glob, time, shutil
from zipfile import ZipFile
from os.path import join, exists, dirname
from svn.remote import RemoteClient
from autoApiDeamo import zip_folder, dealwith_service
from autoApiDeamo import printInfo, printMember, dealwith_data, printListInfo
# 定义部署包路径和取包路径
APPS_HOME = '/data/aa/cc/dd/apps'
# RELEASE_HOME = '/data/aa/cc/dd/xiaoweiba-release'
RELEASE_HOME = os.getcwd()
# 获取当前时间
NOW_TIME = time.strftime("%Y%m%d%H%M") # 202306071508
# 获取xlsx清单
file_list = re.findall('小尾巴想看雪\S+.xlsx',
str(glob.glob(join(RELEASE_HOME,"/*.*"))))
XLSX_FILE = file_list[0]
# 增量版本号
RELEASE_NAME = str(XLSX_FILE)[15:][:-5]
# 镜像版本号
RELEASE_NUM = str(XLSX_FILE)[18:][:-5]
IMAGES_TARNAME = 'xiaoweiba-images-' + RELEASE_NAME + '.tar.gz'
SQL_ZIPNAME = 'xiaoweiba-sql-' + RELEASE_NAME + '.zip'
# 取包镜像备份目录
RELEASE_BAK = join(RELEASE_HOME, 'release_bak')
# 基准包备份目录(初始备份+每次增量完后备份)
PACKAGE_BASE_BAK = join(RELEASE_HOME, join('package_base_bak',RELEASE_NAME))
# 取包存放目录
PACKAGE_HOME = join(RELEASE_HOME, RELEASE_NAME)
BACKUP_IMAGES = "true" # 是否打包镜像
IMAGE_NAMES = '' # 定义镜像名,在使用时需要去重
# 脚本SVN库本地关联目录
DOC_HOME = join(RELEASE_HOME, 'releasedoc')
# 脚本SVN库地址
DOC_SVN_PATH = 'http://192.168.xx.xx/SC/xiaoweiba/aa/ee/releasedoc'
svn_username = 'xiaoweiba'
svn_password = 'xiaoweiba@522'
def autoCreateDir():
if len(file_list) != 1:
print('==当前目录下出现了{0}个xlsx文件,请确认并清理不是本次发布得xlsx文件'.format(len(file_list)))
sys.exit()
"""检查取包目录是否存在,不存在则创建"""
if exists(PACKAGE_HOME):
print('=={0}已存在'.format(PACKAGE_HOME))
else:
print('==创建目录{0}'.format(PACKAGE_HOME))
os.mkdir(PACKAGE_HOME)
def getServicePackage():
"""提取后端发布包"""
# 从excel文件获取代码路径列数据,返回数据为字典
global IMAGE_NAMES
global SERVICE_CODE_LIST
SERVICE_CODE_LIST = dealwith_service(dealwith_data(XLSX_FILE,
'代码路径', sheetNum=0))
if SERVICE_CODE_LIST['wen4sx']:
printListInfo('wen代码路径', SERVICE_CODE_LIST['wen4sx'])
if SERVICE_CODE_LIST['huairen']:
printListInfo('huairen后端代码路径', SERVICE_CODE_LIST['huairen'])
# 获取后端代码并移动到基础包目录
for key in SERVICE_CODE_LIST.keys():
if SERVICE_CODE_LIST[key]:
# 处理需要打包的镜像名
if key == 'wen4sx':
IMAGE_NAMES = IMAGE_NAMES + ' ' + 'wen:' + RELEASE_NUM
else:
IMAGE_NAMES = IMAGE_NAMES + ' ' + key + ':' + RELEASE_NUM
for item in SERVICE_CODE_LIST[key]:
apps_path = APPS_HOME + '/' + key + '/' + item
release_path = RELEASE_HOME + '/' + key + '/' + item
# 从测试环境目录移动后端代码到发布基准目录
shutil.copy(apps_path, release_path)
def getStaticPackage():
global IMAGE_NAMES
global STATIC_CODE_LIST
STATIC_CODE_LIST = dealwith_service(dealwith_data(XLSX_FILE,
'设计方案', sheetNum=0))
# 测试完成后视情况判断是否删除
printListInfo('前端路径', SERVICE_CODE_LIST['nginx'])
# # # 获取前端代码并移动到基础包目录
for key in STATIC_CODE_LIST.keys():
if STATIC_CODE_LIST[key]:
# 处理需要打包的镜像名
if key == 'nginx':
IMAGE_NAMES = IMAGE_NAMES + ' ' + key + ':' + RELEASE_NUM
for item in STATIC_CODE_LIST[key]:
apps_path = APPS_HOME + '/' + key + '/' + item
release_path = RELEASE_HOME + '/' + key + '/' + item
# 从测试环境目录移动前端代码到发布基准目录
shutil.copy(apps_path, release_path)
def getSqlPackage():
# 获取单号
global NUMBER_CODE_LIST
NUMBER_CODE_LIST = dealwith_service(dealwith_data(XLSX_FILE,
'问题编号', sheetNum=0))
if NUMBER_CODE_LIST['number']:
# 测试完成后删除
printListInfo('单号', SERVICE_CODE_LIST['number'])
patterns = ''
for item in NUMBER_CODE_LIST['number']:
if patterns:
patterns = patterns + '|' + item
else:
patterns = item
if not exists(DOC_HOME):
os.mkdir(DOC_HOME)
# checkout svn库
svnClient = RemoteClient(DOC_SVN_PATH,
username=svn_username, password=svn_password)
svnClient.checkout(DOC_HOME)
os.chdir(DOC_HOME)
num_list = []
for root, dirs, files in os.walk(DOC_HOME):
# 测试完成后删除
if not re.findall('已发现场', root):
# 测试完成后删除
# print('{0} -- {1}'.format(root, files))
if re.findall(patterns, root):
num_list.append(root.replace(DOC_HOME + '/', ''))
if num_list:
print('==本次匹配单号:{0}'.format(num_list))
# 打包zip压缩包文件
zip_folder(num_list, join(PACKAGE_HOME, SQL_ZIPNAME))
# 移动到正式已执行
svn_command_mv = 'mv'
for item in num_list:
dir_path = join(DOC_HOME, item)
target_path = join(DOC_SVN_PATH, dirname(item))
tar_path = join(target_path, join(target_path, '已发正式'))
command_args_mv = [dir_path, tar_path]
svnClient.run_command(svn_command_mv, command_args_mv)
else:
print('==svn库中未匹配到相关单号内容')
else:
print('==从excel中未获取单号')
def tarImages():
# 执行脚本
os.chdir(RELEASE_HOME)
os.system('sh build_image.sh')
# 镜像
if IMAGE_NAMES:
os.system('docker save {0} -o {1}'.format(IMAGE_NAMES,
join(PACKAGE_HOME, IMAGES_TARNAME)))
# 移动清单文件到package_home
shutil.move(XLSX_FILE, PACKAGE_HOME)
# 将增量文件名写入txt文件
with open(join(PACKAGE_HOME, RELEASE_NAME + '_增量清单.txt'), mode='w+') as file:
for item in os.listdir(PACKAGE_HOME):
file.write(item)
file.close()
# 备份增量包和备份基准包
if not exists(PACKAGE_BASE_BAK):
os.mkdir(PACKAGE_BASE_BAK)
for item in IMAGE_NAMES:
service = item.split(':')[0]
if service == 'wen':
service = 'wen4sx'
shutil.copy(service, join(PACKAGE_BASE_BAK,
service + '-' + NOW_TIME))
if not exists(RELEASE_BAK):
os.mkdir(RELEASE_BAK)
shutil.copy(PACKAGE_HOME, RELEASE_BAK)
def detailedList():
# 显示增量内容
printInfo('增量取包清单')
printInfo('前端文件清单')
printMember(STATIC_CODE_LIST, 'service')
printInfo('后端文件清单清单')
printMember(SERVICE_CODE_LIST, 'service')
printInfo('容器镜像清单')
image_list = IMAGE_NAMES.replace(' ', '\n')
print(image_list)
sql_num, doc_num = 0, 0
zip_name_path = join(PACKAGE_HOME, SQL_ZIPNAME)
if zip_name_path:
for item in ZipFile(zip_name_path).namelist():
if re.findall('\S+.sql$', item):
if sql_num == 0:
printInfo('业务脚本清单')
sql_num += 1
print(item)
for item in ZipFile(zip_name_path).namelist():
if re.findall('\S+.docx$|\S+.doc$|\S+.xlsx$|\S+.xls$|\S*.csv$', item):
if doc_num == 0:
printInfo('操作票文档')
doc_num += 1
print(item)
else:
printInfo('业务脚本清单')
printInfo('操作票文档')
if __name__ == '__main__':
autoCreateDir()
getServicePackage()
getStaticPackage()
getSqlPackage()
tarImages()
detailedList()
取包后自动下发工单:
点击查看代码
# coding: utf-8
import time,sys
import requests
import jsonpath as jp
import json
# 类的实例化
class ApiDemo():
'''
定义函数进行引用
'''
# 登录url
def do_get(self, url, params=None, **kwargs):
return requests.get(url=url, params=params, **kwargs)
# 切换项目
def do_post(self, url, data=None, json=None, **kwargs):
return requests.post(url=url, data=data, json=json, **kwargs)
# 数据读取
def get_data(self, res, keys, part=2):
'''res需要是一个字典'''
if res is not None:
try:
if part == 2:
value = jp.jsonpath(json.loads(res), '$..{0}'.format(keys))
else:
value = jp.jsonpath(json.loads(res), '$.{0}'.format(keys))
# 判断值
if value:
if len(value) == 1:
return value[0]
return value
except Exception as e:
return e
def get_data1(self, res, keys):
'''res需要是一个字典'''
if res is not None:
try:
value = jp.jsonpath(json.loads(res), keys)
if value:
if len(value) == 1:
return value[0]
return value
except Exception as e:
return e
# file_name = 'data.yaml'
# current_path = os.path.abspath("../data")
# file = os.path.join(current_path, file_name)
# def get_yaml(self, file_name, keys):
# '''
# 从yaml文件中读取参数,返回一个字典
# 将结果处理为一个json对象
# '''
# with open(file_name, 'r', encoding="utf-8") as file:
# file_read = file.read()
# file.close()
# file_read = yaml.load_all(file_read, Loader=yaml.FullLoader)
# while True:
# try:
# values = json.dumps(next(file_read)) # 这个生成器一次就可以输出来
# return self.get_data(values, keys)
# except StopIteration:
# break
api = ApiDemo()
# 定义参数
base_url = 'http://weiba.haoren.com'
login_url = base_url + '/web/login.html'
session_url = base_url + '/get/auth/session'
# 登录用户信息,未用到
params = {
'account': "hauiren_user",
'password': "xZzyjv/6zet7/7Uxq+L3ig=="
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.27',
'Cookie': 'JSESSIONID=9FA2039AE5B37CEA49B6A016DE81BC39; OWASP_CSRFTOKEN=20UR-7LDT-UD5J-SFK1-WY3R-VL8Y-AWED-9P1X; _account=%7B%22account%22%3A%22dwglscm%22%2C%22password%22%3A%22xZzyjv%2F6zet7%2F7Uxq%2BL3ig%3D%3D%22%2C%22inputPassword%22%3A%22POWER_scm%232020%22%7D; province_flag=7F079D562F9A8360BE8CA1292A27AF28; _isLogout=false; JSESSIONID=CD4115BAFBAD89CD02F4050B278632E0; access-token=eyJhbGciOiJIUzUxMiJ9.eyJhY2NvdW50IjoiZHdnbHNjbSIsInVzZXJJZCI6IkJDQTEwQkJEQTUzOTRDN0RCNTRENkE4QkNDNDFGMEYxIiwiZW1wbG95ZWVJZCI6IkJFREYwM0E5NDdBNDQ3NDk5OUI0QjNCNjQ1ODdFQjI4IiwiZW1wbG95ZWVOYW1lIjoi6YWN572u566h55CG5ZGYIiwib3JnSWQiOiJGNURDNEUzRUZFQUE0RDA4OTBCQjIzRjM0RkNBM0M5RCIsIm9yZ0NvZGUiOiIwMzExNzYiLCJvcmdOYW1lIjoi6YWN572u566h55CG57uEIiwiYmFzZU9yZ0NvZGUiOiIiLCJ0aGlyZFN5c3RlbU5hbWUiOiJKQURQIiwic2FwSHJPcmdJZCI6IiIsInN5c3RlbU5hbWUiOiJudWxsIiwiYmVsb25nUHJvdmluY2UiOiIwMyIsInN1YiI6IumFjee9rueuoeeQhuWRmCIsImlhdCI6MTY2MjYwMDUxOCwiZXhwIjoxNjYyNjAyNDA5LCJyZWZyZXNoSW50ZXJ2YWwiOjMwLCJqdGkiOiI4MTkzM2RiNS0xNzY0LTRmNmItYThiOS02ZmJhZDZkNDkxYmEiLCJyZWZyZXNoRGF0ZSI6MTY2MjYwMDYwOTAwMH0.xO78U6K55jCtnqhfhwqKucagJuZ9y3BXpkFfrZ7ZNtmkg5OJQEAMxk-onc8ikoeoXkZZu6zhd-ADMa9jSETszg'
}
payload = {
"endPlanReleaseTime": "2023-04-14",
'operatorIdList': [],
'pageNo': 1,
'pageSize': 25,
'projectId': "AAAAAAAAAAAAAAAAAAAAAAAAAAAA",
'releaseTypeList': [],
"startPlanReleaseTime": "2023-01-14",
'statusList': [5, 6]
}
if len(sys.argv) == 2:
release_name = sys.argv[1]
else:
print('请输入完整的单号')
sys.exit()
#
versionlist_id = []
def get_versionlist():
url = base_url + '/get/testcase/version/queryVersionListByPagePagination'
data = payload
# print("测试待删除data值为%s" %(data))
VersionList_res = json.loads(api.do_post(url=url, json=data, headers=headers).text)
VersionList_list = jp.jsonpath(VersionList_res, '$..list')[0]
# print(VersionList_list)
for single_version in VersionList_list:
single_id = single_version["id"]
if release_name == single_version["versionName"]:
versionlist_id.append(single_id)
print('单号为:%s'.format(versionlist_id))
def dealwith_sc():
if versionlist_id:
for value in versionlist_id:
loadById_url = base_url + '/get/testcase/version/loadById/' + value
loadById_info = requests.get(loadById_url)
# 获取工单号的operator,我们的节点为:管理员
operator_scm = jp.jsonpath(json.loads(loadById_info.text), '$..operator')[0]
id = jp.jsonpath(json.loads(loadById_info.text), '$..id')[0]
# print("测试待删除--这里的ID输出%s" % (id))
versionName = jp.jsonpath(json.loads(loadById_info.text), '$..versionName')[0]
projectId = jp.jsonpath(json.loads(loadById_info.text), '$..projectId')[0]
operatorId = jp.jsonpath(json.loads(loadById_info.text), '$..operatorId')[0]
payload_data = jp.jsonpath(json.loads(loadById_info.text), '$.data')[0]
planReleaseCount = jp.jsonpath(json.loads(loadById_info.text), '$..planReleaseCount')[0] # 工单数量
# print('测试待删除,sleep时间为%d' %(2*planReleaseCount))
if operator_scm == '管理员':
print('---- 待内部发布-->点击提交 ----')
# http://weiba.huairen.com/get/testcase/version/waitVersionRelease 重要请求
url = base_url + '/get/testcase/version/waitVersionRelease'
payload_data['releasePackageName'] = versionName
payload_data['remark'] = ''
payload_data['webSocketId'] = '9934da5e94def6357b57569b5c4a9a4a' # 目前看来所有工单都可以使用
payload = payload_data
res = requests.post(url=url, json=payload, headers=headers)
print('{0}({1})的步骤{2}处理结果为: {3}'.format(versionName, id, 'waitVersionRelease', res.text))
time.sleep(4 * planReleaseCount) # 下发工单需要时间 == 缺陷单条数*2
else:
print('---- 待内部发布-->点击提交 ----')
print('{0}({1})的状态不为待内部发布状态'.format(versionName, id))
res_data = jp.jsonpath(json.loads(requests.get(loadById_url).text), '$.data')[0]
len_num = len(jp.jsonpath(res_data, '$.versionConfirmerRecordList')[0])
operator_fz = jp.jsonpath(res_data, '$.operator')[0]
# 存在部分工单长度不一致的情况,目前处理方式为所有的工单都过一次接口,看其响应状态判断处理结果
if operator_fz == '人员名':
print('---- 环境发布-->点击提交 ----')
# 获取object_id
url = base_url + '/get/testcase/sceneReleaseTask/queryVersionReleaseRecordByVersonIdPagination'
payload = {'releaseVersionId': id, 'pageNo': 1, 'pageSize': 10}
res = requests.post(url=url, json=payload, headers=headers)
objectId = jp.jsonpath(json.loads(res.text), '$..id')[0]
# print('获取objectId为: %s' % (objectId))
# waitSimulationEnvRelease
url = base_url + '/get/testcase/sceneReleaseTask/waitSimulationEnvRelease'
payload = {'id': objectId, 'remark': ''}
# print(payload)
res = requests.post(url=url, json=payload, headers=headers)
if res.status_code == 200:
print('{0}({1})的步骤{2}处理结果为: {3}'.format(versionName,
id, 'waitSimulationEnvRelease', res.text))
elif res.status_code == 500:
print('{0}({1})的状态不为仿真环境发布状态'.format(versionName, id))
else:
# 暂时应该还无其它
print('{0}({1})的步骤{2}处理结果为: {3}'.format(versionName,
id, 'waitSimulationEnvRelease', res.text))
print('')
if __name__ == '__main__':
get_versionlist()
dealwith_sc()