【Shell】自动替换指定项目tag并提merge request

背景

日常开发中会涉及到许多升级基础包tag的工作,微服务又比较多,基本都是重复的工作在不同的服务执行,这种情况下用脚本自动完成比较合适。

本文介绍了一个自动化升级Go项目依赖的Shell脚本。该脚本可以批量处理多个微服务项目,自动完成以下操作:

  • 根据配置升级go.mod中的依赖版本
  • 执行go mod tidy
  • 自动创建Git分支并提交代码
  • 推送变更并创建合并请求(MR)

脚本通过配置区域可灵活设置:

  • 需要处理的项目列表
  • 依赖库路径
  • 待升级的依赖包及版本
  • Git分支和提交信息等参数

执行后会输出详细的处理日志,并汇总显示每个项目的处理结果和MR链接,适用于需要批量升级大量微服务依赖版本的场景。

脚本代码

脚本功能 :升级go mod中的包,为UPGRADE_DEPS中配置的版本,并执行go mod tidy,自动提mr,对于超多微服务需要升级tag的工作比较合适。
脚本使用:只需要根据配置区域中的介绍配置即可。

shell 复制代码
#!/bin/bash

# ================= 配置区域 =================

# 1. 业务项目列表
PROJECTS=(
    "testproject"
)

# 2. 依赖库路径
LIBS=(
    "lib"
    "../lib"
)

# 3. 需要升级的依赖列表 "包名:版本"
UPGRADE_DEPS=(
    "https://github.com/DHButterfly/go-spring:v0.0.11"
)

# 4. Git 配置
BASE_BRANCH="master"
TARGET_BRANCH="optimize_dl_update_tag"
COMMIT_MSG="update tag & go mod tidy"
MR_TITLE=$COMMIT_MSG

# ===========================================

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'

START_DIR=$(pwd)
# 初始化一个数组,用来存储最后生成的 MR 地址
MR_SUMMARY=()

# --- 1. 准备依赖库 (略) ---
echo -e "${YELLOW}>>> 1. 准备本地依赖库环境...${NC}"
for lib_path in "${LIBS[@]}"; do
    if [ -d "$lib_path" ]; then
        (
            cd "$lib_path" || exit
            if [ -n "$(git status --porcelain)" ]; then
                echo -e "${RED}[警告] $lib_path 有未提交更改${NC}"
            else
                git fetch origin "$BASE_BRANCH" > /dev/null 2>&1
                git checkout "$BASE_BRANCH" > /dev/null 2>&1
                git reset --hard "origin/$BASE_BRANCH" > /dev/null 2>&1
                echo -e "${GREEN}$lib_path 已同步${NC}"
            fi
        )
    fi
done

echo -e "${YELLOW}>>> 2. 开始处理业务项目...${NC}"
echo -e "${YELLOW}------------------------------------------------------${NC}"

# --- 2. 处理业务项目 ---

for dir in "${PROJECTS[@]}"; do
    cd "$START_DIR" || exit
    if [ ! -d "$dir" ]; then continue; fi

    echo -e "${YELLOW}正在处理项目: ${dir} ...${NC}"
    cd "$dir" || continue

    if [ ! -d ".git" ] || [ -n "$(git status --porcelain)" ]; then
        echo -e "${RED}[跳过] 非 git 仓库或有未提交更改${NC}"
        continue
    fi

    # 切分支
    git fetch origin "$BASE_BRANCH" > /dev/null 2>&1
    git checkout "$BASE_BRANCH" > /dev/null 2>&1
    git reset --hard "origin/$BASE_BRANCH" > /dev/null 2>&1
    git checkout -B "$TARGET_BRANCH" > /dev/null 2>&1

    # 修改依赖
    has_update=false
    for dep_config in "${UPGRADE_DEPS[@]}"; do
        mod_name="${dep_config%%:*}"
        mod_ver="${dep_config#*:}"
        if grep -q "$mod_name" go.mod; then
            echo -e "更新依赖: $mod_name -> $mod_ver"
            go mod edit -require="${mod_name}@${mod_ver}"
            has_update=true
        fi
    done

    # Tidy
    echo -e "执行 go mod tidy..."
    if ! go mod tidy; then
        echo -e "${RED}[失败] tidy 报错${NC}"
        MR_SUMMARY+=("${RED}[失败]${NC} ${dir}: go mod tidy 执行失败")
        continue
    fi

    # 提交 & 推送 & 捕获输出
    if [ -z "$(git status --porcelain)" ]; then
        echo -e "${GREEN}[无变化] 跳过${NC}"
        MR_SUMMARY+=("${YELLOW}[跳过]${NC} ${dir}: 无文件变化")
    else
        echo -e "${GREEN}[提交并推送]...${NC}"
        git add .
        git commit -m "$COMMIT_MSG" > /dev/null 2>&1
        
        # === 关键修改 ===
        # 1. 执行推送,并将 stderr (2) 重定向到 stdout (1),以便变量 capturing
        # 2. 同时保留输出显示在屏幕上 (虽然变量捕获了,但我们用 echo 再打一遍)
        
        echo -e "正在推送请求 GitLab 创建 MR..."
        
        # 捕获输出
        push_output=$(git push \
            -o merge_request.create \
            -o merge_request.target="$BASE_BRANCH" \
            -o merge_request.title="$MR_TITLE" \
            -o merge_request.remove_source_branch \
            origin "$TARGET_BRANCH" --force 2>&1)
        
        # 打印输出给用户看(因为被变量捕获了,屏幕上如果不 echo 就会一片空白)
        echo "$push_output"

        # 使用正则提取 URL
        # 匹配 https://.../merge_requests/数字
        mr_url=$(echo "$push_output" | grep -o "https://.*/merge_requests/[0-9]*" | head -n 1)

        if [ -n "$mr_url" ]; then
            echo -e "${GREEN}[成功] MR: $mr_url${NC}"
            MR_SUMMARY+=("${GREEN}[成功]${NC} ${dir}: $mr_url")
        else
            # 有时候是已经存在 MR,GitLab 不会返回 URL,或者推送失败
            if echo "$push_output" | grep -q "Everything up-to-date"; then
                 MR_SUMMARY+=("${YELLOW}[跳过]${NC} ${dir}: 代码已是最新,未产生新提交")
            else
                 MR_SUMMARY+=("${YELLOW}[未知]${NC} ${dir}: 推送完成但未捕获到 URL (可能 MR 已存在)")
            fi
        fi
    fi
    echo -e "${YELLOW}------------------------------------------------------${NC}"
done

# --- 3. 最终汇总打印 ---
echo -e "\n\n"
echo -e "${YELLOW}================= 自动化执行汇总 =================${NC}"
for item in "${MR_SUMMARY[@]}"; do
    echo -e "$item"
done
echo -e "${YELLOW}==================================================${NC}"
相关推荐
岚天start1 天前
[K8S监控]-K8S容器pod异常状态监控脚本并推送钉钉告警
容器·kubernetes·钉钉·shell·告警
AlbertS4 天前
Shell脚本中set -e和set -o pipefail的作用
shell·pipefail·trap·脚本错误·控制流程
阿海5745 天前
安装php7.4.33的shell脚本
php·shell
阿海5745 天前
卸载redis7.2.4的shell脚本
linux·redis·shell
小嘟嘟136 天前
从基础到进阶:掌握 userdel,玩转 Linux 用户管理的 “减法” 艺术
linux·运维·网络·shell
gis分享者6 天前
如何在 Shell 脚本中实现文件的读写操作?(容易)
shell·文件·awk·echo·cat··
eight *7 天前
源码部署docker自动化脚本
docker·shell
gis分享者8 天前
如何在 Shell 脚本中使用管道(pipeline)实现数据传递?(容易)
linux·pipeline·shell·脚本·管道·数据传递
シ風箏10 天前
Shell【脚本 06】监测文件数据量并压缩及查看远程服务器状态并删除文件脚本分享
linux·运维·服务器·github·shell