使用python脚本配合Jenkins自动发布软件新版本

软件需要发布一个新版本时,需要比较多的操作。其中很多操作,我们是可以使用脚本语句代替人手去完成的,这样可以减少人工操作出错的风险,也能提高效率,我们只需要准备好必要的文件就好了。本文将介绍如何使用Jenkins和python脚本帮助我们发布软件新版本,包括:”准备发布新版文的文件RPK(release package)“、”服务器端新版本的发布“、”安卓客户端发布新版本“、”回滚war包和数据库“。

1、准备发布新版文的文件RPK(release package)。

(1)准备发布新版本的sql语句。

准备好新版本需要更新的sql语句,如修改数据库表、插入新数据、修改过的存储过程等。

如果是使用svn版本控制工具,可以找出发布版本号范围的所有涉及的数据库改动,

对于修改过的数据库表,直接对比两个文件:发布范围内最大版本和最小版本的上一个版本文件,就可以知道做了那些修改,从而写出sql更新语句。

对于修改过的存储过程,准备删除存储过程和创建存储过程sql语句。

调用其它文件的sql命令:

USE nbr;
	source D:/BXERP/trunk/release/00015_v2_0_r2193_r2312/SQL/1_所有私有DB_DeleteFutureRetailTradeAggregation.sql;
	source D:/BXERP/trunk/release/00015_v2_0_r2193_r2312/SQL/2_所有私有DB_T_ConfigCacheSize_Reset.sql;
	source D:/BXERP/trunk/release/00015_v2_0_r2193_r2312/SQL/5_所有私有DB_CreateTables.sql;
	DROP PROCEDURE IF EXISTS `SP_RetailTradePromotingSyncCacheDispatcher_RetriveN`;
	DROP PROCEDURE IF EXISTS `SP_RetailTradePromotingSyncCacheDispatcher_UpdatePOSStatus`;
	DROP PROCEDURE IF EXISTS `SP_RetailTradePromotingSyncCache_DeleteAll`;
	DROP PROCEDURE IF EXISTS `SP_RetailTradePromotingSyncCache_POSUpload`;
	DROP PROCEDURE IF EXISTS `SP_RetailTradePromotingSyncCache_RetrieveN`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCacheDispatcher_RetriveN`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCacheDispatcher_UpdatePOSStatus`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCache_Delete`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCache_DeleteAll`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCache_POSUpload`;
	DROP PROCEDURE IF EXISTS `SP_VipCategorySyncCache_RetrieveN`;
DELIMITER $$
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_Vip_UpdateBonus.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_VIP_Create.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_VIP_Update.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_SmallSheetFrame_Delete.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/Function/Func_CheckPosDependency.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_VIPCategory_Delete.sql
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PrivateDB/SP_VipCardCode_Create.sql
DELIMITER ;

USE nbr_bx;
	source D:/BXERP/trunk/release/00015_v2_0_r2193_r2312/SQL/3_公有DB_T_Bxconfiggeneral.sql
DELIMITER $$
	source D:/BXERP/tags/nbr_20200515_v2.0.4/src/sql/SP/PublicDB/SP_Company_MatchVip.sql
DELIMITER ;

具体文件的sql命令如:1_所有私有DB_DeleteFutureRetailTradeAggregation.sql

DELETE FROM t_retailtradeaggregation WHERE F_WorkTimeStart > date_sub(now(),interval 1 day);
…… 

(2)编写release步骤、注意事项。

一般根据上一次发布经验编写,检查运行环境、修改Jenkins变量等信息。

release步骤、注意事项

(3)准备替换配置文件的批处理文件。

如:更新最近的PublicAccount.properties配置文件:

copy /y D:/BXERP/trunk/release/00015_v2_0_r2193_r2312/NbrConfigFile/PublicAccount.properties D:/NbrConfigFile/PublicAccount.properties

2、服务器端新版本的发布。

使用Jenkins工具创建发布war的任务,调用python脚本。

如果是第一次在Jenkins发布新版本,需要新建任务,如服务器端新版本的发布任务war_release,配置调用的python脚本语句。

war_release_preBuildSteps.py脚本做一些发布war前的工作:

查看代码
# coding=utf-8
"""
case1: release成功
case2: release失败>重新release(特别注意:如果release失败需要rollback时,sql使用此次备份成功的sql文件,war包拿上一次release成功的war包进行rollback)
case3: 之前有无成功release(目前保证每次release的文件夹都是成功的,故可略过该case)
case4: 之前有无release过(暂不考虑该case)
"""

import time
import os
import subprocess
# 引用自定义的模块
import sys
sys.path.append('D:/BXERP/trunk/src/jenkins/Common')	#引用的自定义模块不与该python文件在同一目录时,需要指定路径
from bxUtility import printInfo
from bxUtility import closeTomcat
from bxUtility import replaceLine

# 需要从jenkins的环境变量读取的参数:文件夹路径、现使用场、版本号
CURRENT_ReleaseNO = os.getenv("CURRENT_ReleaseNO")	#示例:CURRENT_ReleaseNO=00004_v1_0_r691_r691
CURRENT_Env = os.getenv("CURRENT_Env")
CURRENT_ReleaseNbrVersionNO = os.getenv("CURRENT_ReleaseNbrVersionNO")
# 此次release放置输出文件的总路径
CURRENT_ReleasePath = 'D:/Release/' + CURRENT_ReleaseNO
# DB备份的文件夹路径
CURRENT_DbBackupPath = CURRENT_ReleasePath + '/backup'
# DB的备份
CURRENT_Time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
DB_BackupFile = CURRENT_DbBackupPath + '/' + CURRENT_Time + '.sql'
# 要执行的BAT文件
PATH_BatToRelease = 'D:/BXERP/trunk/release/' + CURRENT_ReleaseNO + '/BAT/pre_steps.bat'
# 要Release的SQL文件
PATH_SqlToRelease = 'D:/BXERP/trunk/release/' + CURRENT_ReleaseNO + '/' + CURRENT_Env + '/release'
FILE_SqlToRelease = PATH_SqlToRelease + '/release.sql'
# 找不到release.sql时的特殊提示
errTag = '~~~~~~XXXXXXXX~~~~~~~~~~~~~XXXX~~~~~~~~~~XXXX~~~~~~~~~';
# 要修改的login.jsp的路径
FILE_LoginJsp = "D:/Jenkins/workspace/war_release/src/main/webapp/WEB-INF/admin/login.jsp"
# 要修改的QueenService的helper.properties的路径
FILE_HelperProperties = "D:/QueenService/Bin/helper.properties"

def dbBackup():
	"""
	备份db(sql)
	"""
	os.system('cd D:/wamp/bin/mysql/mysql5.6.17/bin')
	(errCode, errMsg) = subprocess.getstatusoutput('mysqldump --no-defaults --login-path=root --default-character-set=gb2312 -R --hex-blob -A>' + DB_BackupFile)
	print ('备份DB的错误码=' + str(errCode));
	print ('备份DB的错误信息=' + str(errMsg));
	if (errCode == 0):
		printInfo('备份DB成功!', 0)
	else:
		printInfo ('备份DB失败!' + errTag, errCode)

try:
	# 检查要执行
	if os.path.exists(PATH_BatToRelease):	
		printInfo('pre_steps.bat文件存在,正在执行...', 0)
		os.system(PATH_BatToRelease)
		printInfo('pre_steps.bat文件存在,执行完毕', 0)
	else:
		printInfo('pre_steps.bat文件不存在,将不执行此文件', 0)
	
	# 检查release.sql是否已准备好
	if os.path.exists(PATH_SqlToRelease):
		Files = os.listdir(PATH_SqlToRelease)
		if 'release.sql' in Files:
			printInfo('release.sql文件存在。', 0)
		else:
			printInfo('release.sql文件不存在,这将令Release只会更新WAR,这极可能是错误的。' + errTag, 5)
	else:
		printInfo(PATH_SqlToRelease + '路径不存在!' + errTag, 5)
	
	# 关闭tomcat
	closeTomcat(60)	#参数为等待的时间(s),每10秒会检查一次,直到超过等待的时间
	
	# 备份DB
	print ('正在建立数据库备份...');
	if os.path.exists(CURRENT_ReleasePath):
		Files = os.listdir(CURRENT_DbBackupPath)
		for i in range(len(Files)):
			suffixName = os.path.splitext(Files[i])[1]
			print('suffixName:' + suffixName);
			if '.sql' == suffixName:
				fileName = os.path.basename(Files[i]);
				print('重命名fileName:' + fileName);
				os.rename(CURRENT_DbBackupPath + '/' + fileName, CURRENT_DbBackupPath + '/' + fileName + '.BuildFailed');
		dbBackup()
	else:
		os.makedirs(CURRENT_DbBackupPath)
		dbBackup()
	
	# 执行准备的release.sql文件
	print ('顺序执行release中的所有SQL文件...');
	print ('当前登录本机的账户是:' + os.getlogin());
	(errCode, errMsg) = subprocess.getstatusoutput('mysql --login-path=root <' + FILE_SqlToRelease)
	print ('执行release.sql的错误码=' + str(errCode));
	print ('执行release.sql的错误信息=' + str(errMsg));
	if (errCode == 0):
		printInfo('执行release.sql成功!', 0)
	else:
		printInfo('执行release.sql失败!' + errTag, errCode)

	# update D:/BXERP
	(errCode, errMsg) = subprocess.getstatusoutput('svn update D:/BXERP')
	if (errCode == 0):
		printInfo('update D:/BXERP成功!', 0)
	else:
		printInfo('update D:/BXERP失败!' + errTag, errCode)

	# 修改配置文件夹中的login.jsp
	keyword = '<input type="hidden" id="CURRENT_ReleaseNbrVersionNO" value="'
	newLine = '			<input type="hidden" id="CURRENT_ReleaseNbrVersionNO" value="' + CURRENT_ReleaseNbrVersionNO + '" />' + '\n'
	replaceLine(FILE_LoginJsp, keyword, newLine, "utf-8", 1)
	
	keyword2 = '<h4 style="font-size:15px; line-height:16px; margin-bottom: 15px;">v1.0.0</h4>'
	newLine2 = '<h4 style="font-size:15px; line-height:16px; margin-bottom: 15px;">v' + CURRENT_ReleaseNbrVersionNO + '</h4>' + '\n'
	replaceLine(FILE_LoginJsp, keyword2, newLine2, "utf-8", 1)

	# 关闭QueenService
	(errCode, errMsg) = subprocess.getstatusoutput('net stop QueenService')
	if (errCode == 0):
		printInfo('关闭QueenService成功!', 0)
	else:
		printInfo('关闭QueenService失败!' + errTag, errCode)

	# 修改D:\QueenService\Bin\helper.properties中的SVN版本号  CURRENT_ReleaseNO=00004_v1_0_r691_r691
	keyword = 'SvnVersionNO='
	newLine = 'SvnVersionNO=' + CURRENT_ReleaseNO.split('_')[-1].split('r')[-1] + '\n'
	replaceLine(FILE_HelperProperties, keyword, newLine, "utf-8", 1)
	
	# 启动QueenService
	(errCode, errMsg) = subprocess.getstatusoutput('net start QueenService')
	if (errCode == 0):
		printInfo('启动QueenService成功!', 0)
	else:
		printInfo('启动QueenService失败!' + errTag, errCode)
except Exception as e:
	printInfo('出现异常:' + str(e), 1)
else:
	os._exit(0)

war_release_postBuildSteps.py负责发布war包,启动Tomcat服务:

# coding=utf-8

import shutil
import time
import os
import zipfile
import urllib.request
from bs4 import BeautifulSoup
# 引用自定义的模块
import sys
sys.path.append('D:/BXERP/trunk/src/jenkins/Common')	#引用的自定义模块不与该python文件在同一目录时,需要指定路径
from bxUtility import printInfo
from bxUtility import startTomcat

# 需要从jenkins的环境变量读取的参数:release版本号、nbr版本号、nbr登录页网址、现使用场、当前使用的TableCreate源代码文件夹目录(v1.0 or v1.1)
CURRENT_ReleaseNO = os.getenv("CURRENT_ReleaseNO")	#示例:CURRENT_ReleaseNO=00004_v1_0_r691_r691
CURRENT_ReleaseNbrVersionNO = os.getenv("CURRENT_ReleaseNbrVersionNO")
CURRENT_ReleaseNbrHomeUrl = os.getenv("CURRENT_ReleaseNbrHomeUrl")
CURRENT_Env = os.getenv("CURRENT_Env")
CURRENT_SrcDirOfTableCreate = os.getenv("CURRENT_SrcDirOfTableCreate")
# 当前时间,参与war包命名
CURRENT_Time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
# 此次release放置文件的总路径
CURRENT_ReleasePath = 'D:/Release/' + CURRENT_ReleaseNO
# war备份的文件夹路径
CURRENT_WarBackupPath = CURRENT_ReleasePath + '/backup'
# 当前release出的war包,备份到哪个目录
FILE_WarBackup = CURRENT_WarBackupPath + '/bxb_' + CURRENT_Env + '_' + CURRENT_ReleaseNbrVersionNO + '_' + CURRENT_Time + '.war'
# 相关的操作文件和路径
FILE_WarPath = 'D:/Tomcat/webapps/nbr.war'
FILE_NbrPath = 'D:/Tomcat/webapps/nbr'
FILE_RootPath = 'D:/Tomcat/webapps/ROOT'

try:
	# 备份war包,这里没有判断文件夹是否存在,是因为在war_release_preBuildSteps.py中已经判断了
	print ('正在备份war包...');
	Files = os.listdir(CURRENT_WarBackupPath)
	for i in range(len(Files)):
		suffixName = os.path.splitext(Files[i])[1]
		print('suffixName:' + suffixName);
		if '.war' == suffixName:
			fileName = os.path.basename(Files[i]);
			print('重命名fileName:' + fileName);
			os.rename(CURRENT_WarBackupPath + '/' + fileName, CURRENT_WarBackupPath + '/' + fileName + '.BuildFailed');
	shutil.copy('D:/Jenkins/workspace/war_release/target/nbr.war', FILE_WarBackup)
	printInfo('备份war包完毕。', 0)

	# 删除旧的nbr.war
	print ('正在删除Tomcat下旧的nbr.war...');
	if os.path.exists(FILE_WarPath):
		os.remove(FILE_WarPath)
		printInfo('删除Tomcat下旧的nbr.war完毕。', 0)
	else:
		printInfo('找不到旧war包:' + FILE_WarPath + '。', 0)

	# 删除旧的nbr文件夹
	print ('正在删除Tomcat下旧的nbr文件夹...');
	if os.path.exists(FILE_NbrPath):
		shutil.rmtree(FILE_NbrPath)
		printInfo('删除Tomcat下旧的nbr文件夹完毕。', 0)
	else:
		printInfo('找不到旧nbr文件夹:' + FILE_NbrPath + '。', 0)
	
	# 删除旧ROOT文件夹
	print ('正在删除旧ROOT文件夹...');
	if os.path.exists(FILE_RootPath):
		shutil.rmtree(FILE_RootPath)
		printInfo('删除Tomcat下旧的ROOT文件夹成功。', 0)
	else:
		printInfo('找不到旧ROOT文件夹:' + FILE_RootPath + '。', 0)

	# 复制并移动新构建好的war包
	print ('正在将jenkins构建后的war包复制到Tomcat下...');
	Files = os.listdir(CURRENT_WarBackupPath)
	for i in range(len(Files)):
		if os.path.splitext(Files[i])[1] == '.war':
			shutil.copy(CURRENT_WarBackupPath + '/' + os.path.splitext(Files[i])[0] + os.path.splitext(Files[i])[1], FILE_WarPath)
			printInfo('将jenkins构建后的war包复制到D:/tomcat/webapps/nbr.war成功。', 0)
	
	# 重启tomcat
	startTomcat(300, CURRENT_ReleaseNbrHomeUrl, CURRENT_SrcDirOfTableCreate)

	# 获取页面版本号进行验证
	print ('正在打开nbr网址' + CURRENT_ReleaseNbrHomeUrl + ',获取版本号进行验证...');
	html = urllib.request.urlopen(CURRENT_ReleaseNbrHomeUrl)
	response = html.read()
	response = BeautifulSoup(response, 'html.parser')
	nbrVersionNO = response.find('input', id='CURRENT_ReleaseNbrVersionNO')["value"]
	print ('当前web前端的版本号=' + nbrVersionNO);
	if nbrVersionNO == CURRENT_ReleaseNbrVersionNO:
		printInfo('网页的版本号与jenkins设置的版本号一致。', 0)
	else:
		printInfo('网页的版本号与Jenkins设置的版本号不一致。', 3)
	
	# release成功后压缩配置文件
	dirpath = "D:/NbrConfigFile"  # 要压缩的文件夹
	outFullName = CURRENT_WarBackupPath +'/NbrConfigFile.zip'  # 压缩后要放置的文件夹路径
	zip = zipfile.ZipFile(outFullName,"w",zipfile.ZIP_DEFLATED)
	for path,dirnames,filenames in os.walk(dirpath):
		# 去掉目标跟路径,只对目标文件夹下边的文件及文件夹进行压缩
		fpath = path.replace(dirpath,'')
		for filename in filenames:
			zip.write(os.path.join(path,filename),os.path.join(fpath,filename))
	zip.close()
	printInfo('D:/NbrConfigFile中的配置文件备份成功。', 0)
except Exception as e:
	printInfo('出现异常:' + str(e), 1)
else:
	printInfo('Release成功!', 0)
	os._exit(0)

3、安卓客户端发布新版本。

建好Jenkins任务,准备好RPK,主要调用以下两个脚本语句:

psb_release_preBuildSteps.py:

查看代码
# coding=utf-8
"""
case1: release成功
case2: release失败>重新release(特别注意:如果release失败需要rollback时,sql使用此次备份成功的sql文件,war包拿上一次release成功的war包进行rollback)
case3: 之前有无成功release(目前保证每次release的文件夹都是成功的,故可略过该case)
case4: 之前有无release过(暂不考虑该case)
"""

import time
import os
import subprocess
# 引用自定义的模块
import sys
sys.path.append('D:/BXERP/trunk/src/jenkins/Common')	#引用的自定义模块不与该python文件在同一目录时,需要指定路径
from bxUtility import printInfo
from bxUtility import closeTomcat
from bxUtility import replaceLine

# 需要从jenkins的环境变量读取的参数:文件夹路径、现使用场、版本号
CURRENT_PSB_ReleaseNO = os.getenv("CURRENT_PSB_ReleaseNO")	#示例:CURRENT_PSB_ReleaseNO=psb_00001_v1_0_r2544_r3002
CURRENT_Env = os.getenv("CURRENT_Env")
CURRENT_ReleasePsbVersionNO = os.getenv("CURRENT_ReleasePsbVersionNO")
# 此次release放置输出文件的总路径
CURRENT_ReleasePath = 'D:/Release/' + CURRENT_PSB_ReleaseNO
# DB备份的文件夹路径
CURRENT_DbBackupPath = CURRENT_ReleasePath + '/backup'
# DB的备份
CURRENT_Time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
DB_BackupFile = CURRENT_DbBackupPath + '/' + CURRENT_Time + '.sql'
# 要执行的BAT文件
PATH_BatToRelease = 'D:/BXERP/trunk/release/' + CURRENT_PSB_ReleaseNO + '/BAT/pre_steps.bat'
# 要Release的SQL文件
PATH_SqlToRelease = 'D:/BXERP/trunk/release/' + CURRENT_PSB_ReleaseNO + '/' + CURRENT_Env + '/release'
FILE_SqlToRelease = PATH_SqlToRelease + '/release.sql'
# 找不到release.sql时的特殊提示
errTag = '~~~~~~XXXXXXXX~~~~~~~~~~~~~XXXX~~~~~~~~~~XXXX~~~~~~~~~';
# 要修改的login.jsp的路径
# FILE_LoginJsp = "D:/Jenkins/workspace/war_release/src/main/webapp/WEB-INF/admin/login.jsp"
# 要修改的QueenService的helper.properties的路径
# FILE_HelperProperties = "D:/QueenService/Bin/helper.properties"

def psbDbBackup(): 
	"""
	备份db(sql)
	"""
	os.system('cd D:/wamp/bin/mysql/mysql5.6.17/bin')
	# --no-defaults:不读取选项文件,如果程序因为读取未知文件而失败可以使用此选项避免读取
	# --routines, -R:包括存储程序(过程和函数)的倾倒数据库输出
	# --all-databases, -A :备份所有库中的所有表,效果等同于--database 后跟随所有库名。
	# --hex-blob:包含有二进制信息的列将会由十六进制输出(比如,‘abc’,将会输出为 0x616263,受影响的数据类型:BINARY, VARBINARY, the BLOB types, and BIT
	# mysqldump  --default-character-set=charset指定导出数据时采用何种字符集,如果数据表不是采用默认的 latin1 字符集的话,那么导出时必须指定该选项,否则再次导入数据后将产生乱码问题。
	# login-path是MySQL5.6开始支持的新特性。通过借助mysql_config_editor工具将登陆MySQL服务的认证信息加密保存在.mylogin.cnf文件(默认位于用户主目录)。之后,MySQL客户端工具可通过读取该加密文件连接MySQL,避免重复输入登录信息,避免敏感信息暴露
	(errCode, errMsg) = subprocess.getstatusoutput('mysqldump --no-defaults --login-path=root --default-character-set=gb2312 -R --hex-blob psb_bx>' + DB_BackupFile) # 备份PSB DB即可
	print ('备份DB的错误码=' + str(errCode));
	print ('备份DB的错误信息=' + str(errMsg));
	if (errCode == 0):
		printInfo('备份DB成功!', 0)
	else:
		printInfo ('备份DB失败!' + errTag, errCode)

try:
	# 检查要执行
	if os.path.exists(PATH_BatToRelease):	
		printInfo('pre_steps.bat文件存在,正在执行...', 0)
		os.system(PATH_BatToRelease)
		printInfo('pre_steps.bat文件存在,执行完毕', 0)
	else:
		printInfo('pre_steps.bat文件不存在,将不执行此文件', 0)
	
	# 检查release.sql是否已准备好
	if os.path.exists(PATH_SqlToRelease):
		Files = os.listdir(PATH_SqlToRelease)
		if 'release.sql' in Files:
			printInfo('release.sql文件存在。', 0)
		else:
			printInfo('release.sql文件不存在,这将令Release只会更新WAR,这极可能是错误的。' + errTag, 5)
	else:
		printInfo(PATH_SqlToRelease + '路径不存在!' + errTag, 5)
	
	# 关闭tomcat。在非生产环境,会连NBR也关闭掉,要注意!!!!!!!!!!!!!!!
	closeTomcat(60)	#参数为等待的时间(s),每10秒会检查一次,直到超过等待的时间
	
	# 备份DB
	print ('正在建立数据库备份...');
	if os.path.exists(CURRENT_ReleasePath):
		Files = os.listdir(CURRENT_DbBackupPath)
		for i in range(len(Files)):
			suffixName = os.path.splitext(Files[i])[1]
			print('suffixName:' + suffixName);
			if '.sql' == suffixName:
				fileName = os.path.basename(Files[i]);
				print('重命名fileName:' + fileName);
				os.rename(CURRENT_DbBackupPath + '/' + fileName, CURRENT_DbBackupPath + '/' + fileName + '.BuildFailed');
		psbDbBackup()
	else:
		os.makedirs(CURRENT_DbBackupPath)
		psbDbBackup()
	
	# 执行准备的release.sql文件
	print ('顺序执行release中的所有SQL文件...');
	print ('当前登录本机的账户是:' + os.getlogin());
	(errCode, errMsg) = subprocess.getstatusoutput('mysql --login-path=root <' + FILE_SqlToRelease)
	print ('执行release.sql的错误码=' + str(errCode));
	print ('执行release.sql的错误信息=' + str(errMsg));
	if (errCode == 0):
		printInfo('执行release.sql成功!', 0)
	else:
		printInfo('执行release.sql失败!' + errTag, errCode)

	# update D:/BXERP
	(errCode, errMsg) = subprocess.getstatusoutput('svn update D:/BXERP')
	if (errCode == 0):
		printInfo('update D:/BXERP成功!', 0)
	else:
		printInfo('update D:/BXERP失败!' + errTag, errCode)
except Exception as e:
	printInfo('出现异常:' + str(e), 1)
else:
	os._exit(0)

psb_release_postBuildSteps.py:

 

查看代码
# coding=utf-8

import shutil
import time
import os
import zipfile
import urllib.request
from bs4 import BeautifulSoup
# 引用自定义的模块
import sys
sys.path.append('D:/BXERP/trunk/src/jenkins/Common')	#引用的自定义模块不与该python文件在同一目录时,需要指定路径
from bxUtility import printInfo
from bxUtility import startTomcat

# 需要从jenkins的环境变量读取的参数:release版本号、nbr版本号、nbr登录页网址、现使用场、当前使用的TableCreate源代码文件夹目录(v1.0 or v1.1)
CURRENT_PSB_ReleaseNO = os.getenv("CURRENT_PSB_ReleaseNO")	#示例:CURRENT_PSB_ReleaseNO=psb_00001_v1_0_r2544_r3002
CURRENT_ReleasePsbVersionNO = os.getenv("CURRENT_ReleasePsbVersionNO")
CURRENT_ReleasePsbHomeUrl = os.getenv("CURRENT_ReleasePsbHomeUrl")
CURRENT_Env = os.getenv("CURRENT_Env")
CURRENT_PsbSrcDirOfTableCreate = os.getenv("CURRENT_PsbSrcDirOfTableCreate")
# 当前时间,参与war包命名
CURRENT_Time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
# 此次release放置文件的总路径
CURRENT_ReleasePath = 'D:/Release/' + CURRENT_PSB_ReleaseNO
# war备份的文件夹路径
CURRENT_WarBackupPath = CURRENT_ReleasePath + '/backup'
# 当前release出的war包,备份到哪个目录
FILE_WarBackup = CURRENT_WarBackupPath + '/bxb_' + CURRENT_Env + '_' + CURRENT_ReleasePsbVersionNO + '_' + CURRENT_Time + '.war'
# 相关的操作文件和路径
FILE_PsbWarPath = 'D:/Tomcat/webapps1/psb.war'
FILE_PsbPath = 'D:/Tomcat/webapps1/psb'
FILE_RootPath = 'D:/Tomcat/webapps1/ROOT'

try:
	# 备份war包,这里没有判断文件夹是否存在,是因为在psb_release_preBuildSteps.py中已经判断了
	print ('正在备份war包...');
	Files = os.listdir(CURRENT_WarBackupPath)
	for i in range(len(Files)):
		suffixName = os.path.splitext(Files[i])[1]
		print('suffixName:' + suffixName);
		if '.war' == suffixName:
			fileName = os.path.basename(Files[i]);
			print('重命名fileName:' + fileName);
			os.rename(CURRENT_WarBackupPath + '/' + fileName, CURRENT_WarBackupPath + '/' + fileName + '.BuildFailed');
	shutil.copy('D:/Jenkins/workspace/psb_release/target/psb.war', FILE_WarBackup)
	printInfo('备份war包完毕。', 0)

	# 删除旧的psb.war
	print ('正在删除Tomcat下旧的psb.war...');
	if os.path.exists(FILE_PsbWarPath):
		os.remove(FILE_PsbWarPath)
		printInfo('删除Tomcat下旧的psb.war完毕。', 0)
	else:
		printInfo('找不到旧psb war包:' + FILE_PsbWarPath + '。', 0)

	# 删除旧的nbr文件夹
	print ('正在删除Tomcat下旧的psb文件夹...');
	if os.path.exists(FILE_PsbPath):
		shutil.rmtree(FILE_PsbPath)
		printInfo('删除Tomcat下旧的psb文件夹完毕。', 0)
	else:
		printInfo('找不到旧psb文件夹:' + FILE_PsbPath + '。', 0)
	
	# 删除旧ROOT文件夹
	print ('正在删除旧ROOT文件夹...');
	if os.path.exists(FILE_RootPath):
		shutil.rmtree(FILE_RootPath)
		printInfo('删除Tomcat下旧的ROOT文件夹成功。', 0)
	else:
		printInfo('找不到旧ROOT文件夹:' + FILE_RootPath + '。', 0)

	# 复制并移动新构建好的war包
	print ('正在将jenkins构建后的war包复制到Tomcat下...');
	Files = os.listdir(CURRENT_WarBackupPath)
	for i in range(len(Files)):
		if os.path.splitext(Files[i])[1] == '.war':
			shutil.copy(CURRENT_WarBackupPath + '/' + os.path.splitext(Files[i])[0] + os.path.splitext(Files[i])[1], FILE_PsbWarPath)
			printInfo('将jenkins构建后的war包复制到D:/tomcat/webapps1/psb.war成功。', 0)
	
	printInfo("CURRENT_ReleasePsbHomeUrl:" + CURRENT_ReleasePsbHomeUrl, 0);
	# 重启tomcat。在测试场会影响NBR的运行
	startTomcat(300, CURRENT_ReleasePsbHomeUrl, CURRENT_PsbSrcDirOfTableCreate)

except Exception as e:
	printInfo('出现异常:' + str(e), 1)
else:
	printInfo('Release成功!', 0)
	os._exit(0)

4、回滚war包和数据库。

查看代码
# coding=utf-8

import os
import shutil
import time
import urllib.request
import subprocess
from bs4 import BeautifulSoup
# 引用自定义的模块
import sys
sys.path.append('D:/BXERP/trunk/src/jenkins/Common')	#引用的自定义模块不与该python文件在同一目录时,需要指定路径
from bxUtility import printInfo
from bxUtility import closeTomcat
from bxUtility import startTomcat

# 需要从jenkins的环境变量读取的参数:release版本号、nbr版本号、nbr登录页网址、当前使用的TableCreate源代码文件夹目录(v1.0 or v1.1)
CURRENT_ReleaseNO = os.getenv("CURRENT_ReleaseNO")	#示例:CURRENT_ReleaseNO=00004_v1_0_r691_r691
CURRENT_ReleaseNbrVersionNO = os.getenv("CURRENT_ReleaseNbrVersionNO")
CURRENT_ReleaseNbrHomeUrl = os.getenv("CURRENT_ReleaseNbrHomeUrl")
CURRENT_SrcDirOfTableCreate = os.getenv("CURRENT_SrcDirOfTableCreate")
# 放置备份的sql文件的路径
FILE_SqlBackupPath = 'D:/Release/' + CURRENT_ReleaseNO + '/backup'
# Mysql bin directory
PATH_Mysql_bin_dir = 'D:/wamp/bin/mysql/mysql5.6.17/bin'
# 相关的操作文件和路径
FILE_WarPath = 'D:/Tomcat/webapps/nbr.war'
FILE_NbrPath = 'D:/Tomcat/webapps/nbr'
FILE_RootPath = 'D:/Tomcat/webapps/ROOT'

try:
	# 关闭tomcat
	closeTomcat(60)	#参数为等待的时间(s),每10秒会检查一次,直到超过等待的时间

	# 删除旧的nbr.war
	print ('正在删除Tomcat下旧的nbr.war...');
	if os.path.exists(FILE_WarPath):
		os.remove(FILE_WarPath)
		printInfo('删除Tomcat下旧的nbr.war完毕。', 0)
	else:
		printInfo('找不到旧war包:' + FILE_WarPath + '。', 0)

	# 删除旧的nbr文件夹
	print ('正在删除Tomcat下旧的nbr文件夹...');
	if os.path.exists(FILE_NbrPath):
		shutil.rmtree(FILE_NbrPath)
		printInfo('删除Tomcat下旧的nbr文件夹完毕。', 0)
	else:
		printInfo('找不到旧nbr文件夹:' + FILE_NbrPath + '。', 0)
	
	# 删除旧ROOT文件夹
	print ('正在删除旧ROOT文件夹...');
	if os.path.exists(FILE_RootPath):
		shutil.rmtree(FILE_RootPath)
		printInfo('删除Tomcat下旧的ROOT文件夹成功。', 0)
	else:
		printInfo('找不到旧ROOT文件夹:' + FILE_RootPath + '。', 0)

	# rollback war包
	print ('Rolling back nbr.war ....');
	# 先找到上次release文件夹的关键字,这里有个问题,当release次数大于等于100000时,该代码需修改
	keyword = int(CURRENT_ReleaseNO[0:5])
	if keyword < 10:
		keyword = '0000' + str(keyword-1)
	elif keyword < 100:
		keyword = '000' + str(keyword-1)
	elif keyword < 1000:
		keyword = '00' + str(keyword-1)
	elif keyword < 10000:
		keyword = '0' + str(keyword-1)
	else:
		keyword = str(keyword-1)
	#获取上次release文件夹命名
	lastTimeReleaseFolder = []
	for i in range(len(os.listdir('D:/Release'))):
		if keyword in os.listdir('D:/Release')[i]:
			lastTimeReleaseFolder.append(os.listdir('D:/Release')[i])
		else:
			continue	#未找到含有关键字的文件或文件夹
	#获取上次release文件夹中以.war结尾的文件
	if len(lastTimeReleaseFolder) == 1:
		lastTimeWarFiles = os.listdir('D:/Release/' + lastTimeReleaseFolder[0] + '/backup')
		for i in range(len(lastTimeWarFiles)):
			if os.path.splitext(lastTimeWarFiles[i])[1] == '.war':
				shutil.copy('D:/Release/' + lastTimeReleaseFolder[0] + '/backup' + '/' + os.path.splitext(lastTimeWarFiles[i])[0] + os.path.splitext(lastTimeWarFiles[i])[1], 'D:/tomcat/webapps/nbr.war')
				printInfo('Rollback WAR done.', 0)
	else:
		printInfo('含有关键字的文件夹不唯一。', 2)

	# rollback DB
	print ('Rolling back DB Data...');
	sqlFiles = os.listdir(FILE_SqlBackupPath)
	# 暂不需要先判断有多少个sql文件,正常情况下是不存在多个sql的情况
	for i in range(len(sqlFiles)):
		if os.path.splitext(sqlFiles[i])[1] == '.sql':
			rollbackScript = FILE_SqlBackupPath + '/' + os.path.splitext(sqlFiles[i])[0] + os.path.splitext(sqlFiles[i])[1]
			print ('Rolling back ' + rollbackScript + '...');
			(errCode, errMsg) = subprocess.getstatusoutput(PATH_Mysql_bin_dir + '/mysql --login-path=root <' + rollbackScript)
			print ('Rollback DB的错误码=' + str(errCode))
			print ('Rollback DB的错误信息=' + str(errMsg))
			if (errCode == 0):
				printInfo('Rollback DB成功!', 0)
			else:
				printInfo('Rollback DB失败!' + errTag, errCode)

	# 重启tomcat
	startTomcat(300, CURRENT_ReleaseNbrHomeUrl, CURRENT_SrcDirOfTableCreate)

	# 获取页面版本号进行验证
	print ('正在打开nbr网址' + CURRENT_ReleaseNbrHomeUrl + ',获取版本号进行验证...');
	html = urllib.request.urlopen(CURRENT_ReleaseNbrHomeUrl)
	response = html.read()
	response = BeautifulSoup(response,'html.parser')
	nbrVersionNO = response.find('input', id='CURRENT_ReleaseNbrVersionNO')["value"]
	print ('当前web前端的版本号=' + nbrVersionNO);
	if nbrVersionNO == CURRENT_ReleaseNbrVersionNO:
		printInfo('网页的版本号与jenkins设置的版本号一致。', 0)
	else:
		printInfo('网页的版本号与Jenkins设置的版本号不一致。', 3)
except Exception as e:
	printInfo('出现异常:' + str(e), 1)
else:
	printInfo('Rollback成功!', 0)
	os._exit(0)

posted @ 2021-12-22 17:46  Boxin-kim  阅读(197)  评论(0编辑  收藏  举报
Web Analytics
Guang Zhou Boxin