当我们接收一份新的代码,代码拿到手要做的第一件事就是 git log,看看这份代码的提交记录,最近提交的情况,做了些什么。但往往看到的 git log 杂乱无章,不知道每次提交到底是做了些什么。由此可见,在团队中,CHANGELOG 的重要性不言而喻,不仅有助于他人帮忙 review 代码,熟悉代码,也能高效的输出 CHANGELOG,对项目管理也至关重要。我们本文介绍使用 git 的服务端 hook 来针对 change log 进行校验,拦截不符合我们规范的提交。

服务端 hook 介绍

服务端 git hook 分为三种,分别是 pre-receive、update、post-receive,这三个步骤就是我们本地 push 完代码服务端要做的事情,如图所示:

1080×429 45.2 KB

我们可以在 pre-receive 阶段来做提交信息的校验,如果不符合我们的要求,直接返回非 0,则该推送便不会推送到 gitlab 仓库中去。

配置服务端 hook

环境配置

gitlab 版本:13.2

hook 配置

  1. 找到要配置仓库在 gitlab 中存储的路径,但因 gitlab 的仓库自某个版本开始采用 hash 存储,我们想要知道仓库对应的物理路径,需要到 gitlab 的 postgresql 数据库中的表 project_repositories 中,根据 project_id 能拿到对应的物理路径;

  2. 当拿到仓库对应的物理路径后,我们打开,目录如下:

#!/bin/bash

echo "开始提交信息检查..."

# 从标准输入获取本次提交的commit id及分支的信息
read normalInput
ARR=($normalInput)
parentCommitId=${ARR[0]}
currentCommitId=${ARR[1]}
branch=${ARR[2]}

echo "您提交的分支为:$branch"

# 获取coomit的信息,用户,邮箱,msg等
user=$(git log --pretty=format:"%an" $currentCommitId -1)
echo "提交者为:$user"

commitDate=$(git log --pretty=format:"%cd" $currentCommitId -1)
echo "提交日期为:$commitDate"

msg=$(git log --pretty=format:"%s" $currentCommitId -1)
echo "提交的备注为:$msg"

flag=$(echo $msg | grep "modify.*")
if [ -z "$flag" ]; then
    echo "[ERROR]提交信息校验未通过,需以modify开头"
    exit 1
fi

Python版本的代码如下:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-

import sys, re, datetime
import fileinput
import shlex, subprocess
import dateutil.parser
import pytz


def datestring2timezone(datestring,timezone='Asia/Shanghai',dateformat='%Y-%m-%d %H:%M:%S'):
    """将带有时区的时间统一化规定的时区时间
    :param datestring:svn/git时间,eg:2011-01-19T05:13:13.421543Z,2018-11-09 17:38:37 +0800
    :param timezone:统一时区,默认是中国时区
    :param dateformat:转换成时间格式
    :return:
    """
    local_time = dateutil.parser.parse(datestring).astimezone(pytz.timezone(timezone))   # 解析string 并转换为北京时区
    # print(local_time , type(local_time))  # datetime 类型
    da = datetime.datetime.strftime(local_time, dateformat) # 将datetime转换为string
    return da


print("Begin check your commit info")
"""获取用户提交的信息"""
origin_commit, curr_commit, branch = None, None, None
# 读取用户试图更新的所有引用
for line in fileinput.input():
    line_list = line.strip().split()
    if len(line_list) >= 3:
        origin_commit, curr_commit, branch = line_list[:3]
        break

# TODO: 目前2.27.0版本的git有点问题,在部署的时候需要额外注意
# git_version = subprocess.check_output(shlex.split('git --version'), shell=False)
# print("git version: {}".format(str(git_version)))
# which_git = subprocess.check_output(shlex.split('which git'), shell=False)
# print("which git: {}".format(str(which_git)))

# 获取commit的信息,用户,邮箱,msg等
commit_user = subprocess.check_output(shlex.split('git log --pretty=format:"%an" {} -1'.format(curr_commit)), shell=False)
commit_date = subprocess.check_output(shlex.split('git log --pretty=format:"%cd" {} -1'.format(curr_commit)), shell=False)
commit_msg = subprocess.check_output(shlex.split('git log --pretty=format:"%s" {} -1'.format(curr_commit)), shell=False)


# 针对merge request的请求,取最新一条非merge request的提交信息进行判断
RULE_MERGE_REQUEST = r'^Merge branch .*(into|.*)'
if re.search(RULE_MERGE_REQUEST, str(commit_msg), flags=0):
    # 获取最新一条非merge request的commit的信息,用户,邮箱,msg等
    commit_user = subprocess.check_output(shlex.split('git log --no-merges --date-order --pretty=format:"%an" -1'), shell=False)
    commit_date = subprocess.check_output(shlex.split('git log --no-merges --date-order --pretty=format:"%cd" -1'), shell=False)
    commit_msg = subprocess.check_output(shlex.split('git log --no-merges --date-order --pretty=format:"%s" -1'), shell=False)

start_date = "2021-07-07 19:00:00"
# 提交日期大于给定的开始时间才校验
if start_date >= datestring2timezone(commit_date):
    sys.exit(0)


if not re.search(r'^JIRA-[0-9]{4,6}', str(commit_msg), flags=0):
    print("ERROR:Comment must start with DPT-<ID>. E.g.: DPT-1234")
    sys.exit(1)
sys.exit(0)

  1. 在本地尝试推送,推送显示如下,如果不符合规范则无法提交成功

如探索更多关于服务端 hook 的功能,可以与第三方系统,例如 jira 等做交互,打造属于自己团队更适用的工具。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐