Git使用-利用钩子实现自动化

2024/05/15 | 字数2365 | 阅读5分钟


什么是钩子(Hooks)

钩子是git提供的一个扩展机制,允许用户在某个重要操作的【前&后】执行一段程序(可以是脚本,当然也可以是二进制可执行文件),以此来触发一个外部事件。利用这个机制,可以用来做合规性检查、触发持续集成、自动化测试等。

依照不同分类规则,钩子程序可以分为:

按执行位置分类:

按触发时机分类:

目前git(v2.41.0)中支持的钩子包括:

想了解每个hook的触发时机,可以阅读git help hooks文档,这里不做赘述。

怎么用

知道了有哪些钩子,以及触发时机,下面我们看看如何添加一个钩子程序

客户端:

客户端的钩子存放在.git/hooks/目录下,需要用到哪个钩子,只需要添加一个对应的文件就可以了,注意钩子文件的名称,需要和上一节中的名称保持一致,同时为钩子文件增加执行权限。

类unix系统,可以执行chmod u+x <hook-file>增加执行权限;

服务端:

至于服务端,就比较麻烦一点,一般的git服务器软件都提供了web配置页面,供用户定制,一般不会通过修改脚本文件的方式。下面分别是github和gitlab的webhook配置页面:

不过,如果你通过标准的ssh服务来搭建git服务,而不是复杂的gitlab或github服务,也可以通过修改.git/hooks目录下的脚本来实现钩子。

举个例子

这里我们利用post-receive钩子来关闭gitlab issue的功能。这是一个服务器端的钩子,在收到客户端的push后触发。我们的钩子脚本会检查是否是一个bugfix提交,同时检查里面是否包含issue的编号,如果有,修改对应的issue状态为close。我们这里用的语言是python,代码如下:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python3

# post-receive
# run: pip install gitpython requests
import git
import logging
import sys
import re
import requests

# change THIS to your own token and project id
GITLAB_TOKEN = ""
GITLAB_PROJECT_ID = ""

logging.basicConfig(level=logging.INFO, filename='/tmp/post-recv.log', filemode = 'a', format = '%(asctime)s - %(levelname)s: %(message)s')

def close_issue(IID):
    GITLAB_URL = f"https://gitlab.com/api/v4/projects/{GITLAB_PROJECT_ID}/issues/{IID}?state_event=close"
    HEADERS = {"PRIVATE-TOKEN": GITLAB_TOKEN}
    result = requests.put(GITLAB_URL, headers=HEADERS)
    if result.status_code == 200:
        # logging.info(f"issue {IID} closed")
    else:
        logging.error(f"failed with status:{result.status_code}")


def extract_issue_id(msg):
    if msg.startswith("fix: "):
        match = re.search(r'#(\d+)\s+', msg)
        if match:
            return match.group(1)
        else:
            return ""
    else:
        return ""


repo = git.Repo('.')
for oneline in sys.stdin:
    # logging.info(oneline)
    # oneline format: HASH1 HASH2 refname
    # example: 50d688ea0b85ac401450bbeae897fd2e38ed1b21 dc0f390584b057c11a865c486b293ff593279e13 refs/heads/master
    record = re.split(r'\s+', oneline)
    str = record[0] + ".." + record[1]
    for one_commit in repo.iter_commits(str):
        # logging.info(one_commit.message)
        iid = extract_issue_id(one_commit.message)
        if iid != "":
            logging.info(iid)
            close_issue(iid)

上面的脚本中,需要修改GITLAB_TOKENGITLAB_PROJECT_ID,在你的项目中创建一个访问的TOKEN(Settings > Access Tokens),项目ID在Settings > General页面可以看到。修改完成后,将上面的脚本放到服务器端your-project.git/hooks/post-receive中,并添加执行权限chmod +x your-project.git/hooks/post-receive。这个钩子程序需要用到python3、pip3以及三方库:pip3 install requests gitpython

然后在客户端增加一个提交记录,在提交的消息中包含git commit -m "fix: #1 issue 1 fixed",这里以fix: 开头,同时issue编号是以#开头的数字。

这样你在客户端执行git push的时候,就会在服务端触发post-receive脚本,关闭对应的issue。上面的logging是为了调试使用,调试通过后,建议关闭日志打印。这个程序也能处理多个commit记录,一次性push到git服务器的场景。

这个脚本也可以扩展,用来修改Jira/Github等平台的issue状态;

局限

  1. .git/hooks目录下的钩子程序在执行git clone时,并不会被下载到客户端,因此对于本地钩子需要通过其他方式来存储;比较好的方式是将这些钩子程序保存到git库上,可以单独存放在一个目录,例如.githooks/目录下,克隆仓库完成后,执行一下git config --local core.hooksPath .githooks/,将hooks对应的目录设置到新的目录下;
  2. gitlab/github等服务端默认的webhook需要自建一个HTTP服务器,来实现事件通知;另外存放在服务器上的your-project.git/hooks/下的服务器端的钩子程序,并没有提供web页面以供修改,需要登陆到git服务器上,手动修改对应的钩子文件,存在一定的安全隐患;
  3. 对于钩子程序中用到的基础软件、依赖包等,需要提前在git服务器上安装,否则无法执行;

注意事项

参考

上一篇:高效Git-如何快速下载代码 下一篇:Git使用-commit信息怎么写

【文章不错,鼓励一下】