近期梳理了一下,之前的整个需求开发过程的完整流程,以及二次开发的DevOps系统,在该流程中覆盖的点,主要是从接收到需求,到需求完成上线的整个过程。
整个过程如图:
图中,蓝色节点是团队负责人或项管人员跟进的流程,绿色节点是DevOps系统上操作的节点,
白色的椭圆是普通备注说明,黄色的椭圆是跟DevOps系统关联的节点备注。
关键点说明:
当时使用的是腾讯的TAPD作为项目管理和敏捷开发平台,该平台有个特点是支持关联gitlab提交:
在开发过程中的代码提交,按TAPD的格式填写comment(包含需求ID、BugID等),并通过Webhook提交给TAPD的API。
注:可以在Gitlab配置提交规则,强制要求每次提交,都必须符合该格式,即在每个项目的git地址下,配置 custom_hooks/pre-receive
钩子,pre-receive
钩子文件内容参考文章最后。
根据1,我们有了需求和代码的提交关系,那么我们在DevOps系统里,选择要发布的需求或Bug,就能自动关联得出,涉及哪几个Git项目,需要发布,就可以:
pre-receive
文件内容参考#!/bin/bashwhile read oldVersion newVersion branch; do
# read oldVersion newVersion branchecho "do pre-recievt: ${oldVersion} ${newVersion} ${branch}"# oldrev=`git rev-parse $oldVersion` # 获取该版本的sha1值,貌似多余,传入的参数就是sha1# newrev=`git rev-parse $newVersion`commitList=`git rev-list $oldVersion..$newVersion` # 获取新旧版本之间,提交了几个版本echo $commitList# 按空格分割字符串,并遍历for commitSha1 in $commitListdo# 获取每次提交的log,正常情况下,log格式如下:# $ git cat-file commit 51ffa547167535fffb0f4b87d09022938f8d404b# tree ffd5876a90a555eedd605b0e2df606c83840437f# parent b78c620aa64b75e6f312a0541e59df3ad8bfca57# author youbl 1557478996 +0800# committer youbl 1557478996 +0800# # 删除验证# sed '1,/^$/d'表示从第1行删除到第一个空行为止,剩下的就是log了msg=`git cat-file commit $commitSha1 | sed '1,/^$/d'`# 分支Merge,跳过match=`echo "$msg" | egrep 'Merge branch ' `if [ -n "$match" ];then continue; fimatch=`echo "$msg" | egrep 'Merge remote-tracking branch ' `if [ -n "$match" ];then continue; fimatch=`echo "$msg" | egrep '合并分支 ' ` # gitlab上发起的合并请求,会以“合并分支”开头if [ -n "$match" ];then continue; fi# 验证log是否匹配规则match=`echo "$msg" | egrep '\-\-story=[0-9]{7,}' `if [ -n "$match" ];then continue; fimatch=`echo "$msg" | egrep '\-\-bug=[0-9]{7,}' `if [ -n "$match" ];then continue; fimatch=`echo "$msg" | egrep '\-\-task=[0-9]{7,}' `if [ -n "$match" ];then continue; fiecho "!!! Your submit msg: $msg !!!($commitSha1)"echo !!! This submit must be related to tapd with id !!!exit 1done# ===========================================================
# 如果要遍历提交的文件,用下面的代码
function eachFiles () {diff=`git diff --name-status $oldVersion $newVersion` # 获取2个版本之间,所有版本的差异文件列表,格式: M README.md D db/20181018.sql M db/full.sql A test.mdecho $diffisDel=false# 按空格分割字符串,并遍历for file in $diffdoif [ "$file" = "D" ];thenisDel=true # 删除的文件,要置标志位,忽略下一个遍历fi# echo ${#file} # 输出字符串长度if [ "${#file}" -lt "2" ];then # 字符串长度小于1时跳过continuefiif [ "$isDel" = "true" ];then # 当前文件前面的标志是D,表示删除,不操作isDel=falsecontinuefiecho $file# fileDiff=`git show $newVersion:$file` # 获取当前文件的内容# echo $fileDiffdone
}done# echo !!!test prevent push!!!
exit 0
因为每个git项目,都必须添加上面的钩子文件,那么用户新建git项目时,是不会有这个钩子的,因此需要一个脚本,去遍历新项目,并添加钩子,
在linux的crontab里,指定每小时执行一次下面这个脚本即可。
#!/bin/bashfunction eachGitDir(){for ele in `ls $1`dosubdir="$1/$ele"if [ ! -d $subdir ];then continue; fi # 不是目录,跳过if [[ $subdir == "/data/gitlab/data/git-data/repositories/Frontend" ]]; then continue; fi # 跳过前端内部项目if [[ $ele == "boot" ]]; then continue; fi # 跳过boot项目if [[ $ele == "ops" ]]; then continue; fiif [[ $ele == "tests" ]]; then continue; fiif [[ $ele == *".wiki.git" ]]; then continue; fiif [[ $ele == "ToolsProject.git" ]]; then continue; fi # 跳过Tools项目if [[ $ele != *".git" ]]; then eachGitDir $subdircontinuefi # 不是git目录,递归hookdir=$subdir/custom_hooksif [ ! -d $hookdir ];then mkdir $hookdir; fihookfile=$hookdir/pre-receiveif [ -e $hookfile ];then continue; fi # 文件存在,不处理`/usr/bin/cp /root/hooks/pre-receive $hookfile`echo $hookdirdone
}# repository="/root/tmp"
repository="/data/gitlab/data/git-data/repositories"
eachGitDir $repository
有时,需要清理所有项目钩子,重新配置,可以使用这个脚本:
#!/bin/bashfunction eachGitDir(){for ele in `ls $1`dosubdir="$1/$ele"if [ ! -d $subdir ];then continue; fi # 不是目录,跳过if [[ $ele != *".git" ]]; then eachGitDir $subdircontinuefi # 不是git目录,递归hookdir=$subdir/custom_hooksif [ ! -d $hookdir ];then continue; fihookfile=$hookdir/pre-receiveif [ ! -e $hookfile ];then `rmdir $hookdir`continuefi # 文件不存在,不处理`rm -f $hookfile``rmdir $hookdir`echo "deleted $hookfile"done
}# repository="/root/tmp"
repository="/data/gitlab/data/git-data/repositories"
eachGitDir $repository
有时,需要清理指定项目的钩子,又懒得去查找目录和删除,可以使用这个脚本:
#!/bin/bashfunction eachGitDir(){for ele in `ls $1`dosubdir="$1/$ele"if [ ! -d $subdir ];then continue; fi # 不是目录,跳过if [[ $ele != *".git" ]]; theneachGitDir $subdircontinuefi # 不是git目录,递归processHook $subdirdone
}function processHook(){subdir=$1hookdir=$subdir/custom_hooksif [ ! -d $hookdir ];then continue; fihookfile=$hookdir/pre-receiveif [ ! -e $hookfile ];then`rmdir $hookdir`echo "rmdir $hookdir"else`rm -f $hookfile``rmdir $hookdir`echo "deleted $hookfile"fi
}ele=$1
if [ "${#ele}" -lt "1" ];then # 字符串长度小于1时跳过echo 参数不能为空exit 1
fi# 移除前面的http协议和域名
if [[ $ele = http* ]]; thenele=`echo $ele | cut -d/ -f4-`
fiele="/data/gitlab/data/git-data/repositories/$ele"
if [ ! -d $ele ];thenele=$ele".git";if [ ! -d $ele ];thenecho "目录不存在: $ele"exit 1fi
fi# echo $ele
if [[ $ele != *".git" ]]; theneachGitDir $ele
elseprocessHook $ele
fi