简化革命:杀死微服务下的Gitlab批量合并请求(MR)的手动操作
使用编程来批量完成执行各个微服务仓库的统一操作,完成在Gitlab上快速、发起、合并、请求、MR的操作
在日常工作中,在Gitlab上合并请求的任务并不陌生,在网页上点击几个操作即可完成,但是如果在微服务架构下,如果需要修改多个微服务的配置文件、编排文件,每个微服务都单独由一个Git仓库进行维护,那么在网页上点击合并请求将是一个重复又重复的过程,因此,需要命令式的方式在Gitlab上进行合并请求,在此基础之上,实现批量发起合并请求的快速方式。
1. 获取Access-Token



F
可以考虑将权限拉满

2. 获取项目id
如果公司内网使用Gitlab,需要调整下方的:gitlab.com,例如:你们公司访问路径:https://xxxx/...,那就将gitlab.com换成xxxx即可。具体需看各个公司的Gitlab访问路径。
curl -ks --header "PRIVATE-TOKEN: <Your private-token>" \
"https://gitlab.com/api/v4/groups/<namespace-urlpath>" \
| grep -oP '"id":([0-9]+),"description":.*?,"name":".*?"' \
| grep "<projectName>" | awk -F, '{print $1}' | awk -F: '{print $NF}'
里面有三个参数:
-
<Your private-token>:上一步获取的Token
-
<namespace-urlpath>:命令空间的URL路径,打开你的项目,看上面的URL,如下图。我的项目名为three,前面的路径为“first2671847”,所以,这里<namespace-urlpath>替换成:first2671847

-
<projectName>:你的项目名字,如下图所示。

3. 获取当前项目下的用户id【可选】
如果你需要指定提交合并请求的:Assignee和Reviewer。接下来需要获取这两个的Id。

curl -ks --header "PRIVATE-TOKEN: <你的access token>" \
"https://gitlab.com/api/v4/projects/<项目id>/members/all"
结果类似如下,可以根据username、name等信息来获取对应的id。

4. 请求合并
curl -ks --request POST \
--header "PRIVATE-TOKEN: <你的access token>" \
--data "source_branch=uat" \
--data "target_branch=main" \
--data "title=%E9%A6%96%E6%AC%A1%E7%BC%96%E7%A8%8B" \
--data "description=%e7%ac%ac%e4%b8%80%e4%b8%aa%e5%90%88%e5%b9%b6%e8%af%b7%e6%b1%82" \
--data "assignee_ids[]=24746290" \
--data "reviewer_ids[]=24746290" \
--data "remove_source_branch=false" \
"https://gitlab.com/api/v4/projects/64615122/merge_requests"
注意点:
-
source_branch:表示你从那个分支发起合并
-
target_branch:表示你要合并到那个分支
-
title:标题。中文需要使用url编码,否则响应结果为一个:Bad Request。使用Linux进行URL编码后使用。方法如下。
echo -n "首次编程" | xxd -plain | sed 's/\(..\)/%\1/g' %e9%a6%96%e6%ac%a1%e7%bc%96%e7%a8%8b -
description:描述,同样含有中文需要URL编码,方法如上。
-
assignee_ids:assignee的Id List,如果是多个。另起一行,在新增:
--data "assignee_ids[]=<assigneeID>" -
reviewer_ids:reviewer的Id List,和reviewer_ids的写法一样。
-
remove_source_branch:合并以后是否删除源分支,true表示是,false表示否。
5. 命令化
为了简化,需要将上述的命令处理成一个脚本,这里命名为:mr.sh
#!/bin/bash
if [ "$1" -z ];then
echo "请输入需要合并的分支"
exit
fi
if [ "$2" -z ];then
echo "请输入标题"
exit
fi
# 变量赋值
source_branch="$1"
# gitlab不直接接收中文,需要URL编码后才可以
title=$(echo -n "$2" | xxd -plain | sed 's/\(..\)/%\1/g')
# 对于描述可有可无
description=$(echo -n "$3" | xxd -plain | sed 's/\(..\)/%\1/g')
# target_branch、assignee_ids、reviewer_ids一般是固定的
# 因此不作为变量传入,需要变化时,使用IDEA进行全量替换
# -k表示不验证证书,-s 表示不显示进度
curl -ks --request POST \
--header "PRIVATE-TOKEN: <你的access token>" \
--data "source_branch=$source_branch" \
--data "target_branch=main" \
--data "title=$title" \
--data "description=$description" \
--data "assignee_ids[]=24746290" \
--data "reviewer_ids[]=24746290" \
--data "remove_source_branch=false" \
"https://gitlab.com/api/v4/projects/64615122/merge_requests"
运行上述脚本:
sh mr.sh "dev" "标题是首次推动" "可有可无的描述"
执行上述脚本的结果就是:在sample项目(id是64615122)中,dev分支发起对main分支的合并请求,标题内容为:“标题是首次推动”,描述为:“可有可无的描述”,assignee和reviewer都为24746290,而且合并以后不会删除dev分支。
这样确实简单了很多,但是如果在微服务架构下,假设有N个微服务,每个服务都由一个Git仓库管理,是不是要准备N份的mr.sh脚本,而且每份还要调整项目id(上面的64615122),是不是要手动运行N次脚本,这是万万不可接受的。由此,引入 批量执行的篇章。
6.批量执行
由于有N个微服务,而且操作都是相同或者相似的,因此能不能只提供一个命令,让程序自动去每个微服务所在仓库中自动去执行一遍这个脚本,这样就可以实现:“一次实现,处处运行”的效果。
先看一下作者的多个微服务的结构图(假设是一些微服务,嘻嘻),然后作者提供一个shell脚本,来完成这种需求。

提供的"一次实现,处处运行"的脚本就是上述的go.sh,内容如下:
#!/bin/bash
if [ -z "$1" ];then
echo "请输入有效命令"
exit
fi
command="$1"
for dir in ./*;do
if [ -d "$dir" ];then
cd ./"$dir"
isGit=$(ls -la | grep .git | wc -l)
if [ $isGit -ge 1 ];then
# 获取当前项目名
projectName=$(echo "$dir" | awk -F/ '{print $NF}')
# 替换后的新命令
new_command=$(echo $command | sed "s/_name_/$projectName/g")
# 执行
/bin/bash -c "$new_command"
echo -e "\033[31;40m 【$projectName】已执行完毕【$new_command】命令. \033[0m"
fi
cd ../
fi
done
命令格式就是:
sh go.sh "<command>"
<command>就是你想在每个仓库里面执行的命令,这里以一个需求为引,进行举例演示。
需求:在每个仓库里面生成一个test.txt脚本,内容为"Hello World",提交给git,并推送至远程dev。
# 分解任务
# 1.git checkout -b dev
# 2.echo "Hello world" > test.txt
# 3.git add test.txt
# 4.git commit -m "首次提交"
# 4.git push --set-upstream origin dev
# 注意,如果命令参数里面有双引号,那么外面那个就用单引号。如果参数里面有单引号,那外面那个就用双引号
# 多个命令用;隔开
sh go.sh 'git checkout -b dev;echo "Hello world" > test.txt;git add test.txt;git commit -m "首次提交";git push --set-upstream origin dev'
# 不得不提的例子:
# 这里的_name_在运行时,会被替换成项目的名字(看go.sh),因此有需要用到项目名字时,可用_name_代替
sh go.sh 'echo _name_'
先看本地

再看远程Gitlab

嗯,符合预期,结果还是非常赞的。
现在需要将那个发起合并请求的mr.sh脚本复制到每个仓库中,然后将里面的 项目号(64615122)替换成每个项目真正对应的项目号。然后在使用go.sh脚本,运行mr.sh脚本就可以实现批量推送了。
- 先复制
mr.sh到每个仓库
sh go.sh "cp ../mr.sh ./mr.sh"
- 替换
mr.sh的项目id的脚本都给你准备好了,注意这个脚本在all目录下,记得用你的 TOKEN 、 命名空间URL变量、要替换的项目ID。
#!/bin/bash
# 提供你的Token
TOKEN="your token"
# 提供你的URL路径上的命名空间
NAMESPACE="first2671847"
curl -ks --header "PRIVATE-TOKEN: ${TOKEN}" \
"https://gitlab.com/api/v4/groups/${NAMESPACE}" \
| grep -oP '"id":([0-9]+),"description":.*?,"name":".*?"' > ./projects.txt
echo "您的命名空间内包含的项目如下:"
cat ./projects.txt
echo -e "\n"
for dir in ./*;do
if [ -d "$dir" ];then
cd ./"$dir"
# shellcheck disable=SC2010
isGit=$(ls -la | grep .git | wc -l)
if [ $isGit -ge 1 ];then
# 获取当前项目名
projectName=$(echo "$dir" | awk -F/ '{print $NF}')
pid=$(cat ../projects.txt | grep "\"$projectName\"" | awk -F, '{print $1}' | awk -F: '{print $NF}')
if [ -z "$pid" ];then
echo "获取项目【$projectName】ID为空"
else
# 这里是将我的项目ID替换,你要换成你自己
sed -i s/64615122/"$pid"/g ./mr.sh
fi
fi
cd ../
fi
done
你可以查看一下所有项目的mr.sh有没有被替换.
sh go.sh "cat ./mr.sh"
-
批量发起合并请求吧!
现在就是见证奇迹的时刻,使用
go.sh运行mr.sh,假设如下:
sh go.sh "sh ./mr.sh 'dev' '全球首次提交' '我不喜欢描述'"
快去看远程!

哈哈,大功告成,以后直接使用一行命令发起合并请求,真是太赞了,不值得一个赞吗?
7.结束
有人觉得,还是不够快。那么如果在疯狂一点,就直接增加文件、提交Git、推送远程、发起合并请求,一气呵成。
# 1. git checkout -b sit
# 2. echo "Hello Sit!" > sit.txt
# 3. git add sit.txt
# 4. git commit -m "增加sit.txt文件"
# 5. git push --set-upstream origin sit
# 6. sh mr.sh "sit" "全球第二次提交"
sh go.sh 'git checkout -b sit;echo "Hello Sit!" > sit.txt;git add sit.txt;git commit -m "增加sit.txt文件";git push --set-upstream origin sit;sh mr.sh "sit" "全球第二次提交"'
快去看你的远程验证吧!!
7.1 别名简化命令
或许有人觉得sh go.sh太不简洁了,当然你可以通过起别名的方法来让其简单:
vim ~/.bashrc
# 打开上面的文件,然后新增下面
alias go="sh go.sh"
# 退出文件以后,进行重新加载
source ~/.bashrc
以后,我们就可以使用如下命令:
go "git pull;git checkout -b uat"
# 不仅可以运行Git命令,所有在Git Bash里面的运行的都可以,赶快试试吧!
go "mvn clean package"
7.2 并行处理加速速度
当前的go.sh脚本中的命令,是逐个项目执行的,是一种阻塞式的执行,如果涉及到 I/O密集型,例如:向远程推送、发合并请求,速度是变慢。因此,可以考虑下方利用shell的后台运行,来提升速度。
#!/bin/bash
if [ -z "$1" ];then
echo "请输入有效命令"
exit
fi
command="$1"
for dir in ./*;do
if [ -d "$dir" ];then
cd ./"$dir"
isGit=$(ls -la | grep .git | wc -l)
if [ $isGit -ge 1 ];then
# 获取当前项目名
projectName=$(echo "$dir" | awk -F/ '{print $NF}')
# 替换后的新命令
new_command=$(echo $command | sed "s/_name_/$projectName/g")
# 后台执行
/bin/bash -c "$new_command" &
echo -e "\033[31;40m 【$projectName】已执行完毕【$new_command】命令. \033[0m"
fi
cd ../
fi
done
# 等待所有的进程执行完毕
wait
echo -e "\n所有项目执行完毕!"
有此神器,还怕什么微服务调整配置呀,给我来10个,我要搞10个。哈哈
更多推荐




所有评论(0)