JB的测试之旅-使用gitlab ci获取提交记录

4,275 阅读9分钟

前言

这篇文章,很久很久之前就想写了,但实际在写的过程,发现涉及到2个玩意:

  • git命令,比如git log
  • gitlab ci的配置以及gitlab-ci.yml的基本使用

于是花费了不少时间来学习这些知识
如果你对上面这两块没了解,建议你先看下下面三篇文章,先扫盲吧:
JB的git之旅--.gitlab-ci.yml介绍
JB的git之旅-git命令行
JB的git之旅-gitlab ci介绍

继续往下读,默认是对git log跟gitlab ci都了解了,并且相关环境已经配置好了;

开篇

做为一个久经沙场的测试同学,肯定会遇到下面这种场景:

项目经理/领导:JB,这BUG怎么回事啊?(此时反馈BUG描述)
JB:我看看(同时赶紧确认BUG)
(几分钟后)
JB:这真的是有BUG,我看看怎么回事(心里描述,我去,昨天都没问题的,怎么就突然又有BUG了)
(一段时间过去了)
研发:这个BUG是因为昨晚JB2同学提交的代码导致的,现在已经修复了;
JB:???昨晚提交的代码?怎么没通知测试验收?测试都不知道这回事啊~

上面这种只是日常生活的冰山一角。。

研发:JB啊,我这有个优化,你来验证一下;
JB:这个优化做了什么,改动了什么,有什么影响面?
研发:这个就优化网页响应速度,你可以对比下响应速度是不是更快了;没什么影响的,就如果真有问题,只会影响到打开速度而已;
JB:那行,我验证下速度是否有优化跟打开网页功能是否正常;
(一段时间后)
JB:OK,没问题了,可以上线吧;
(上线后一段时间)
领导:JB,怎么这里会显示不出东西?早上还是正常的啊;
后来确认,就是早上研发说的网页速度优化导致的,但是这两者没有关系啊!尼玛!

生活中,研发偷偷上代码或者研发修改后给出的影响面不足导致出现线上问题的情况是非常比较常见的,尤其在小公司里面,常见的不得了;

那这类问题有没有解决方案?
这个原因归根到底是,个人认为是测试知道的太少了;
人都是不自觉的,如果一味依赖研发提供的信息,假如某天研发说不清楚,又或者压根没有说,然后就直接上线了,怎么破?

有同学可能会跳出来说,通过流程约束,这个方案是可行的,但是本次想介绍是利用工具来解决这问题;

因此就有了这么一个想法:

获取研发每一次提交的记录,通过钉钉/邮箱通知对应的同学~

这种做法能杜绝上面说的场景吗?

答案肯定是否定的,但做了这个,至少测试同学有更多的信息输入,而不再是一问三不知,怎么利用这些信息,就要看具体的同学了~

效果图

先贴一个效果图,样式就是:
XX推动到了项目名的XX分支
XX-提交记录sha值+提交内容信息

样式为:
jb推动到了项目名的XX分支
jb-提交记录sha值+提交内容信息

功能介绍:
点击项目名可以跳转到仓库地址,点击分支名可以跳转到仓库的分支地址;
点击sha值,可以跳转到对应提交记录

任务拆解下,分成2块:

1.获取数据
2.钉钉通知

钉钉通知

接入钉钉这块,官网有文档,点击查看即可;

链接里面有交怎么在钉钉上新建机器人,这里不介绍了;
可以看到,钉钉支持以下类型:

文本类型
link类型
markdown类型
整体跳转ActionCard类型
独立跳转ActionCard类型
FeedCard类型

根据需要的结果,选择不同类型吧,比如本文,选择的是markdown类型
根据文档,直接上代码:

import requests
import json
dingdingurl = "你的钉钉机器人webhook"
#钉钉机器人的webhook
headers = {'Content-Type': 'application/json'}
String_textMsg = {
    "msgtype": "markdown",
    "markdown": {
        "title" : "jbtest",
        "text":    "jb is here"
    }
}
requests.packages.urllib3.disable_warnings()
String_textMsg = json.dumps(String_textMsg)
requests.post(dingdingurl, data=String_textMsg, headers=headers, verify=False)

这里的dingdingurl需要修改成你的机器人webhook,至于webhook怎么获取,看下上面的官网文档,都有介绍的,这里不细说了;

上面的代码,运行后的效果就是这样的了:

title对应的就是图1钉钉显示的标题,text就是点击进去后的内容,ok,钉钉接入就是如此的简单~
代码的话,应该不需要说明了,就是根据钉钉的要求,构建请求头,然后把对应信息填入,发起post请求即可;
不过这里可能有个疑问,下面这代码是干嘛的?

requests.packages.urllib3.disable_warnings()

之前的文档有介绍过,可以试试,注释掉会怎样:

InsecureRequestWarning: Unverified HTTPS request is being made. 
Adding certificate verification is strongly advised.

会报错,但是不影响结果运行,这是一个安全警告提示,原因是我们在请求的时候,设置了, verify=False,意思是不校验https;
在这个例子吧,把这个去掉依然是可以正常运行的,但是大部分涉及到https,都会进行校验,为了调试,就会加上verify=False;
这就是这么一个由来~

git log获取提交记录

顶部git log的文章有提及到,git log里面有一个pretty可以进行定制化,最终得出这么一个命令:

git log --pretty=format:\"%an-%h-%s-%H\" -1
-1是表示最近一次提交,就是最新的提交记录

关于%an %h %s %H的含义,可以看下面,还有更多的字段信息,请移步到git log介绍吧~

选项 说明
%an 作者(author)的名字
%h 提交对象的简短哈希字串
%s 提交说明
%H 提交对象(commit)的完整哈希字串

最终的执行结果如下:

可能会有人问,为什么我们要用这些参数?因为我们显示的结果就是想要这些字段;

根据上图,我们需要以下信息:

作者名
仓库名称以及url
分支名称以及url
提交对象的简短的哈希子串及url
提交说明

上面git log已经获得了3个参数了,那还剩下5个参数,通过其他方式获取

.gitlab-ci.yml

来到这里,默认是配置了runner,如果还是弄,从顶部的gitlab ci文章进去看看,里面有介绍怎么配置runner

按照要求,在项目首页创建一个文件:

.gitlab-ci.yml

新建后,编辑这文件,不难写出下面的代码:

stages:
  - test

job_test:
  stage: test
  variables: 
      branch_url: $CI_PROJECT_URL/tree/$CI_COMMIT_REF_NAME
      commit_url: $CI_PROJECT_URL/commit/$CI_COMMIT_SHA
  script:
    - python getcommitlog.py $CI_PROJECT_URL $branch_url $CI_PROJECT_NAME $commit_url $CI_COMMIT_REF_NAME
  only:
    - master

上面的代码,是根据JB的git之旅--.gitlab-ci.yml介绍这里面的要求写出的;

这里再说明下:

 定义一个stage,里面包含一个叫test的阶段;
 然后定义个job_test任务,这个任务对应的就是一个叫test阶段的stage;
 然后创建两个变量,分别是:branch_url跟commit_url,具体的值,就是不同变量的拼接;
 创建完变量,就执行getcommitlog.py脚本,并且传一堆参数过去,最后设置只允许master分支执行;

定义变量以及执行脚本传参时,涉及到几个系统变量,含义如下:

变量 描述
CI_PROJECT_URL 访问项目的HTTP地址
CI_COMMIT_REF_NAME 构建项目的 branch 或 tag 名称
CI_COMMIT_SHA 构建项目的 commit SHA 值
CI_PROJECT_NAME 当前正在构建的项目名称(实际上是项目文件夹名)

更多的系统变量,请看移步到JB的git之旅--.gitlab-ci.yml介绍查看;

那自定义变量最终的含义是:

  • branch_url:当然分支地址,比如http://xxxx/jb/jbtest/tree/master
  • commit_url:提交记录地址,比如http://xxxx/jb/jbtest/commit/对应的SHA

其他4个传参的解释如下,简单说就是项目地址,项目名称,提交分支名称,commit 的SHA值

getcommitlog.py

介绍完.gitlab-ci.yml,那来介绍下里面调用的getcommitlog.py脚本
该脚本逻辑很简单,
1)获取git log信息以及处理传参信息,
2)钉钉post,代码如下:

import re
import os
import requests
import json
import sys


def getContent():
    #获取提交记录信息
    content = (os.popen("git log --pretty=format:\"%an-&%h-&%s\" -1 ").read()).split("-&")
    return content


def postDingDing(content):
    print(sys.argv)
    project_url = sys.argv[1]
    branch_url = sys.argv[2]
    project_name = sys.argv[3]
    commit_url = sys.argv[4]
    branch_name = sys.argv[5]
    name,shortcodenum,explain = content
    dingdingurl = ["https://oapi.dingtalk.com/robot/send?access_token=你的机器人access_token"]
headers = {'Content-Type': 'application/json'}
String_textMsg = {
    "msgtype": "markdown",
    "markdown": {
        "title" : "jbtest",
        "text":   "#### "+name+" 推送到了  ["+project_name+"]("+project_url+")"+"  的["+branch_name+"]("+branch_url+")  分支\n>"
        +name+" -["+shortcodenum+"]("+commit_url+")"+"  "+explain
    }
}
requests.packages.urllib3.disable_warnings()
String_textMsg = json.dumps(String_textMsg)
for i in dingdingurl:
    requests.post(i, data=String_textMsg, headers=headers, verify=False)
print(name,shortcodenum,explain,project_url,branch_url,project_name,commit_url,branch_name)

if __name__ == "__main__":
    content = getContent()
    postDingDing(content)

脚本很简单,
1)就是获取git log所需要的值,
2)就是获取传过来的参数,
3)字符串拼接,
4)钉钉post通知,
这部分不打算介绍了,很简单的代码;

至此,整个功能介绍完毕了,把.gitlab-ci.yml放到仓库根目录,getcommitlog.py自定义目录,只不过.gitlab-ci.yml上也要跟着改下路径,然后提交两个文件,在master分支改下代码提交,就钉钉就可以收到信息了,如果不想指定master分支,就把only master去掉;

除了钉钉可以收到通知,gitlab ci上也可以看到运行情况,在仓库-CI/CD-jobs,就能看到所有.gitlab-ci的运行情况

题外话

有同学可能会问,如果有一个脚本,比如上面这个,想所有仓库低使用,那岂不是每个仓库都要上传这两个文件?
答对一部分,.gitlab-ci.yml是每个仓库都需要,但是执行的脚本,可以共用,怎么公用?
通过.gitlab-ci.yml里面的指定执行路径即可;

比如仓库A有脚本A,如果想让仓库B也使用脚本A,那可以在仓库B的.gitlab-ci.yml文件里面执行执行仓库A的脚本A,使用绝对路径,如果没有权限,给权限即可;

比如一开始gitrunner安装目录在/home上,那执行仓库A的时候,就会在runner服务器有一个目录:

这个文件只要不删除,都会存在,但是需要注意的,不建议直接hardcode路径,因为builds后面的13c1a0f2感觉是个编号,会变化的,通过正则判断仓库即可;

从此在钉钉上就知道研发提交了什么,点击仓库地址还能看到研发写了什么(前提是你得有仓库权限),给研发review代码不再话下,想想带心动了~

介绍就到这里,代码上面有,这里不重复贴了,就是需要2个文件而已;

小结

本文主要介绍通过gitlab ci获取提交记录,涉及到git log已经gitlab ci.yml的语法以及钉钉接口推送的使用,都是基础知识点,在配置gitlab ci会容易出现问题,无太高难度的事情;

谢谢大家~