自动创建 GitLab Merge Request

最近规范代码提交流程,所有提交必须走 GitLab 的 Merge Request。
所以就很烦,每一个功能改动都要提交三份 MR(test/uat/master),一系列操作下来,人都麻了…
此时就要祭出杀器 Python大法

库选择

站在巨人的肩膀上

目前有一个现成的库: python-gitlab

实现方式

  • 选择代码库
  • 选择项目
  • 使用传入的参数创建 MR
  • 添加命令行快捷指令

具体实现

工具文件

辅助工具,获取当前工作空间中的git 分支名称,用来快速合并分支用。

1
2
3
4
5
6
7
8
9
10
11
import subprocess


def get_git_branch(folder_path):
try:
process = subprocess.Popen(["git", "-C", folder_path, "rev-parse", "--abbrev-ref", "HEAD"],
stdout=subprocess.PIPE)
branch_name = process.stdout.read().strip().decode('utf-8')
return branch_name
except:
return None

主文件

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
51
# -*- coding: utf-8 -*-
import gitlab
import argparse
from get_git_branch import get_git_branch


def main():
# 定义命令行参数
parser = argparse.ArgumentParser(description="Create a merge request using python-gitlab")
parser.add_argument("-s", "--source", help="Source branch")
# parser.add_argument("target_branch", help="Target branch")
parser.add_argument("-m", "--title", help="Merge request title")
# parser.add_argument("description", help="Merge request description")

parser.add_argument("-t", "--target", help="Merge target")

args = parser.parse_args()

# 连接 GitLab API
gl = gitlab.Gitlab(url='https://address.gitlab.com', private_token='my token')

# 选择项目
project = gl.projects.get(40)

# 项目文件夹的当前分支
current_branch = get_git_branch('当前的项目工作目录')

# 优先用传入的分支名
source_branch = args.source or current_branch

if args.target is None:
return print('请输入目标分支,-t = test|uat|master|all, 可同时输入多个')

# 创建合并请求列表
target_branches = ['test', 'uat', 'master']

for target_branch in target_branches:
if target_branch in args.target or 'all' in args.target:
merge_request = project.mergerequests.create({
"source_branch": source_branch,
"target_branch": target_branch,
"title": args.title,
"description": ""
})

print(f"{merge_request.target_branch} Merge request created: {merge_request.web_url}")


if __name__ == '__main__':
main()

用法

1
python3 main.py [-s xxx] -t xxx -m "xxx"

其中 -s 为可选,-t 为字符串,如果想发到哪个分支就包含哪些分支字符串,如 “test|uat”,或者使用 “all”

添加系统快捷指令(alias)

通过 alias 添加快捷命令,以 zsh 为例,如果不知道这是啥,自行百度一下哈。

1
2
3
4
vim .zshrc

# 加入一行
alias cm="python3 /Users/zhukejin/work/tools/gitlab/main.py"

用法

1
cm -t uat -m "merge uat"

完事

手动 dog


更新:用了几天后,感觉少了点什么东西…

获取最近一次提交的 message

新建辅助文件 get_git_message.py

1
2
3
4
5
6
import subprocess


def get_latest_commit_message(folder_path):
result = subprocess.run(["git", "-C", folder_path, "log", "-1", "--pretty=%B"], stdout=subprocess.PIPE)
return result.stdout.decode("utf-8")

主文件中引入此方法,并添加逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 最后一次提交的 message
message =args.title or get_latest_commit_message(work_path)

...
...

merge_request = project.mergerequests.create({
"source_branch": source_branch,
"target_branch": target_branch,
- "title": args.title,
+ "title": message,
"description": ""
})

这样每次连 ‘-t xxx’ 都不用写了(前提是git message 提交要规范)

添加二次确认

因为执行后就直接提交了, 万一写错了怎么办?很慌。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 添加二次确认
user_input = input(f'''
提交信息为:

source: {source_branch}
target: {args.target}
message: {message}

是否确认提交 MR?请输入 y/n ?
''')

if user_input.lower() == 'y':
for target_branch in target_branches:
if target_branch in args.target or 'all' in args.target:
merge_request = project.mergerequests.create({
"source_branch": source_branch,
"target_branch": target_branch,
"title": message,
"description": ""
})

print(f"{merge_request.target_branch} Merge request created: {merge_request.web_url}")
else:
print("取消提交")

完整代码

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# -*- coding: utf-8 -*-
import gitlab
import argparse
from get_git_branch import get_git_branch
from get_git_message import get_latest_commit_message

work_path = '/Users/work/lbank-front'

def main():
# 定义命令行参数
parser = argparse.ArgumentParser(description="Create a merge request using python-gitlab")
# parser.add_argument("private_token", help="GitLab private token")
# parser.add_argument("project_id", help="Project ID")
parser.add_argument("-s", "--source", help="Source branch")
# parser.add_argument("target_branch", help="Target branch")
parser.add_argument("-m", "--title", help="Merge request title")
# parser.add_argument("description", help="Merge request description")

parser.add_argument("-t", "--target", help="Merge target")

args = parser.parse_args()

# 连接 GitLab API
gl = gitlab.Gitlab(url='https://gitlab.ex.com/', private_token='xxx')

# 选择项目, 这里要看一下项目id 是什么
project = gl.projects.get(40)

# lbank-front 文件夹的当前分支
current_branch = get_git_branch(work_path)

# 优先用传入的分支名
source_branch = args.source or current_branch

# 最后一次提交的 message
message =args.title or get_latest_commit_message(work_path)



if args.target is None:
return print('请输入目标分支,-t = test|uat|master|all, 可同时输入多个')

# 创建合并请求列表
target_branches = ['test', 'uat', 'master']


# 命令行确认
user_input = input(f'''
提交信息为:

source: {source_branch}
target: {args.target}
message: {message}

是否确认提交 MR?请输入 y/n ?
''')

if user_input.lower() == 'y':
for target_branch in target_branches:
if target_branch in args.target or 'all' in args.target:
merge_request = project.mergerequests.create({
"source_branch": source_branch,
"target_branch": target_branch,
"title": message,
"description": ""
})

print(f"{merge_request.target_branch} Merge request created: {merge_request.web_url}")
else:
print("")


if __name__ == '__main__':
main()