DevOps-8:需求开发生命周期与DevOps系统能力

近期梳理了一下,之前的整个需求开发过程的完整流程,以及二次开发的DevOps系统,在该流程中覆盖的点,主要是从接收到需求,到需求完成上线的整个过程。
整个过程如图:
在这里插入图片描述


关键点说明:

1、代码与需求/任务/Bug关联

当时使用的是腾讯的TAPD作为项目管理和敏捷开发平台,该平台有个特点是支持关联gitlab提交:
在开发过程中的代码提交,按TAPD的格式填写comment(包含需求ID、BugID等),并通过Webhook提交给TAPD的API。
注:可以在Gitlab配置提交规则,强制要求每次提交,都必须符合该格式,即在每个项目的git地址下,配置 custom_hooks/pre-receive 钩子,pre-receive钩子文件内容参考文章最后。

2、生成发布申请

根据1,我们有了需求和代码的提交关系,那么我们在DevOps系统里,选择要发布的需求或Bug,就能自动关联得出,涉及哪几个Git项目,需要发布,就可以:

  • 自动生成发布申请单,包含所有关联的Git项目
    • 避免发布时遗漏了某个项目,或某个特性分支
  • 自动生成每个Git项目的MR申请
  • 自动推送MR通知消息给这些GIt项目的代码评审人,进行评审
  • 自动推送待发布消息给这些Git项目的开发责任人,进行关注
    • 自动生成每个Git项目的测试与预上的配置差异清单
    • 自动生成每个Git项目对应数据库的表结构差异清单,及刷库SQL
    • 开发负责人确认上述2项,是否需要推送给运维责任人处理
  • 自动推送待发布消息给需求对应的QA、产品经理,进行关注

3、每日代码质量扫描

因为代码扫描时长很久,我们从一开始的发布时代码扫描,优化为每天凌晨对有变动的项目扫描一次,只对test、prod这2个分支进行扫描,扫描不通过下,对应项目下一次禁止发布,并发钉钉通知给负责人要求整改。
使用的代码扫描工具为Sonarqube,对应的质量指标说明参考:https://docs.sonarqube.org/latest/user-guide/metric-definitions/

相关脚本参考

pre-receive文件内容参考

#!/bin/bash

while read oldVersion newVersion branch; do
#  read oldVersion newVersion branch
  echo "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 $commitList
  do
    # 获取每次提交的log,正常情况下,log格式如下:
    # $ git cat-file commit 51ffa547167535fffb0f4b87d09022938f8d404b
    # tree ffd5876a90a555eedd605b0e2df606c83840437f
    # parent b78c620aa64b75e6f312a0541e59df3ad8bfca57
    # author youbl <[email protected]> 1557478996 +0800
    # committer youbl <[email protected]> 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; fi
    match=`echo "$msg" | egrep 'Merge remote-tracking branch ' `
    if [ -n "$match" ];then continue; fi
    match=`echo "$msg" | egrep '合并分支 ' `  # gitlab上发起的合并请求,会以“合并分支”开头
    if [ -n "$match" ];then continue; fi

    # 验证log是否匹配规则
    match=`echo "$msg" | egrep '\-\-story=[0-9]{7,}' `
    if [ -n "$match" ];then continue; fi
    match=`echo "$msg" | egrep '\-\-bug=[0-9]{7,}' `
    if [ -n "$match" ];then continue; fi
    match=`echo "$msg" | egrep '\-\-task=[0-9]{7,}' `
    if [ -n "$match" ];then continue; fi

    echo "!!! Your submit msg: $msg !!!($commitSha1)"
    echo !!! This submit must be related to tapd with id !!!
    exit 1
  done


# ===========================================================
# 如果要遍历提交的文件,用下面的代码
function eachFiles () {
  diff=`git diff --name-status $oldVersion $newVersion` # 获取2个版本之间,所有版本的差异文件列表,格式: M README.md D db/20181018.sql M db/full.sql A test.md
  echo $diff

  isDel=false
  # 按空格分割字符串,并遍历
  for file in $diff
  do
    if [ "$file" = "D" ];then
      isDel=true  # 删除的文件,要置标志位,忽略下一个遍历
    fi

    # echo ${#file}  # 输出字符串长度
    if [ "${#file}" -lt "2" ];then # 字符串长度小于1时跳过
      continue
    fi
    
    if [ "$isDel" = "true" ];then # 当前文件前面的标志是D,表示删除,不操作
      isDel=false
      continue
    fi

    echo $file
    # fileDiff=`git show $newVersion:$file` # 获取当前文件的内容
    # echo $fileDiff
  done
}

done

# echo !!!test prevent push!!!
exit 0

定时任务:为新项目添加钩子的sh脚本参考

因为每个git项目,都必须添加上面的钩子文件,那么用户新建git项目时,是不会有这个钩子的,因此需要一个脚本,去遍历新项目,并添加钩子,
在linux的crontab里,指定每小时执行一次下面这个脚本即可。

#!/bin/bash

function eachGitDir(){
  for ele in `ls $1`
  do
    subdir="$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; fi
    if [[ $ele == "tests" ]]; then continue; fi
    if [[ $ele == *".wiki.git" ]]; then continue; fi
    if [[ $ele == "ToolsProject.git" ]]; then continue; fi # 跳过Tools项目

    if [[ $ele != *".git" ]]; then 
      eachGitDir $subdir
      continue
    fi # 不是git目录,递归
    
    hookdir=$subdir/custom_hooks
    if [ ! -d $hookdir ];then mkdir $hookdir; fi
    hookfile=$hookdir/pre-receive
    if [ -e $hookfile ];then continue; fi # 文件存在,不处理
    `/usr/bin/cp /root/hooks/pre-receive $hookfile`
    echo $hookdir

  done
}

# repository="/root/tmp"
repository="/data/gitlab/data/git-data/repositories"
eachGitDir $repository

清除所有项目的钩子

有时,需要清理所有项目钩子,重新配置,可以使用这个脚本:

#!/bin/bash

function eachGitDir(){
  for ele in `ls $1`
  do
    subdir="$1/$ele"

    if [ ! -d $subdir ];then continue; fi # 不是目录,跳过

    if [[ $ele != *".git" ]]; then 
      eachGitDir $subdir
      continue
    fi # 不是git目录,递归

    hookdir=$subdir/custom_hooks

    if [ ! -d $hookdir ];then continue; fi
    hookfile=$hookdir/pre-receive
    if [ ! -e $hookfile ];then 
      `rmdir $hookdir`
      continue
    fi # 文件不存在,不处理
    `rm -f $hookfile`
    `rmdir $hookdir`
    echo "deleted $hookfile"

  done
}

# repository="/root/tmp"
repository="/data/gitlab/data/git-data/repositories"
eachGitDir $repository

清除指定项目的钩子

有时,需要清理指定项目的钩子,又懒得去查找目录和删除,可以使用这个脚本:

#!/bin/bash

function eachGitDir(){
  for ele in `ls $1`
  do
    subdir="$1/$ele"

    if [ ! -d $subdir ];then continue; fi # 不是目录,跳过

    if [[ $ele != *".git" ]]; then
      eachGitDir $subdir
      continue
    fi # 不是git目录,递归
    
    processHook $subdir
  done
}

function processHook(){
  subdir=$1
  hookdir=$subdir/custom_hooks

  if [ ! -d $hookdir ];then continue; fi
  hookfile=$hookdir/pre-receive
  if [ ! -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* ]]; then
  ele=`echo $ele | cut -d/ -f4-`
fi

ele="/data/gitlab/data/git-data/repositories/$ele"
if [ ! -d $ele ];then
  ele=$ele".git";
  if [ ! -d $ele ];then
    echo "目录不存在: $ele"
    exit 1
  fi
fi

# echo $ele
if [[ $ele != *".git" ]]; then
  eachGitDir $ele
else
  processHook $ele
fi

猜你喜欢

转载自blog.csdn.net/youbl/article/details/129436790