【新增】插件git同步模块,用于同步项目内容,加速项目开发

【调整】前端暗色问题
This commit is contained in:
chudong
2025-05-14 16:50:56 +08:00
parent dc43da936b
commit e6947ec5c4
215 changed files with 19918 additions and 9710 deletions

View File

@@ -0,0 +1,660 @@
#!/usr/bin/env bash
#######################################
# Turborepo工作区编译部署自动化工具
#
# 这是一款基于纯Shell脚本开发的自动化工具用于Turborepo项目的
# 应用工作区扫描、编译及Git同步。支持跨平台操作可在Windows、
# macOS和Linux系统上稳定运行。
#
# 作者: chudong
# 版本: 1.1.0
#######################################
# 设置严格模式
set -e
# 避免变量名冲突,重命名为唯一的名称
SYNC_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 导入工具脚本
source "$SYNC_SCRIPT_DIR/tools/git-handle.sh"
source "$SYNC_SCRIPT_DIR/tools/file-handle.sh"
source "$SYNC_SCRIPT_DIR/tools/notice-handle.sh"
source "$SYNC_SCRIPT_DIR/tools/other-handle.sh"
# 全局变量
SYNC_DIR=".sync"
SYNC_CONFIG="$SYNC_DIR/sync-config.yaml"
HISTORY_FILE="$SYNC_DIR/history"
GIT_SYNC_DIR="$SYNC_DIR/git-repos"
# 禁用插件扩展
# PLUGINS_DIR="$SYNC_DIR/plugins"
CONFIG_LOADED="false"
ENVIRONMENT_CHECKED="false"
# 配置变量
# 禁用并行编译模式
# CONFIG_PARALLEL_BUILD="false"
# 禁用干运行模式
# CONFIG_DRY_RUN="false"
#######################################
# 初始化工具环境
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
init_environment() {
# 避免重复初始化环境
if [ "$ENVIRONMENT_CHECKED" = "true" ]; then
return 0
fi
notice_info "正在初始化环境..."
# 检查系统环境
check_environment
# 检查工作区
check_workspace "package.json" "pnpm-workspace.yaml" "turbo.json"
if [ $? -ne 0 ]; then
notice_error "必须在Turborepo项目根目录下运行此脚本"
return 1
fi
# 检查依赖工具
check_command_dependency "pnpm" || return 1
check_command_dependency "git" || return 1
# 确保YQ_PATH变量已设置
if [ -z "$YQ_PATH" ]; then
check_yq_dependency || notice_warning "未安装yq工具部分功能可能受限"
fi
# 创建必要的目录结构 - 全部移至.sync目录
if [ ! -d "$WORKSPACE_ROOT/$SYNC_DIR" ]; then
notice_info "创建同步配置目录..."
create_directory "$WORKSPACE_ROOT/$SYNC_DIR"
fi
if [ ! -d "$WORKSPACE_ROOT/$GIT_SYNC_DIR" ]; then
notice_info "创建Git同步目录..."
create_directory "$WORKSPACE_ROOT/$GIT_SYNC_DIR"
fi
# 禁用插件目录创建
# if [ ! -d "$WORKSPACE_ROOT/$PLUGINS_DIR" ]; then
# notice_info "创建插件目录..."
# create_directory "$WORKSPACE_ROOT/$PLUGINS_DIR"
# fi
# 初始化配置文件
if [ ! -f "$WORKSPACE_ROOT/$SYNC_CONFIG" ]; then
init_config_file
fi
# 初始化历史记录文件
if [ ! -f "$WORKSPACE_ROOT/$HISTORY_FILE" ]; then
create_file "$WORKSPACE_ROOT/$HISTORY_FILE"
fi
ENVIRONMENT_CHECKED="true"
notice_success "环境初始化完成"
return 0
}
#######################################
# 检查命令是否可用
# 参数:
# $1: 命令名称
# 返回值:
# 0 - 命令可用
# 1 - 命令不可用
#######################################
check_command_dependency() {
local cmd="$1"
if ! command -v "$cmd" &> /dev/null; then
notice_error "未找到命令: $cmd"
return 1
fi
notice_success "命令检查通过: $cmd"
return 0
}
#######################################
# 初始化配置文件
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
init_config_file() {
notice_info "初始化配置文件..."
local config_content="# 工具配置
config:
# 禁用并行编译
# parallel_build: false # 是否并行编译
# 禁用干运行
# dry_run: false # 是否干运行
# 工作区配置
workspaces:
# 示例工作区配置
# app-name:
# sync_mappings:
# - git:
# url: \"https://github.com/user/repo.git\" # Git 仓库地址
# branch: \"main\" # 分支名称
# alias: \"repo-name\" # 仓库别名(可选)
# sync: [\"/dist\", \"/build\"] # 要同步的目录列表
# source: false # 是否同步源码
"
write_file_content "$WORKSPACE_ROOT/$SYNC_CONFIG" "$config_content" "force"
if [ $? -eq 0 ]; then
notice_success "配置文件已初始化"
return 0
else
notice_error "配置文件初始化失败"
return 1
fi
}
#######################################
# 扫描所有工作区
# 返回值:
# 0 - 成功
# 1 - 失败
# 全局变量:
# WORKSPACES - 包含所有工作区路径的数组
# DISPLAY_NAMES - 用于显示的工作区名称移除apps/前缀)
#######################################
scan_workspaces() {
notice_info "扫描/apps目录下的应用工作区..."
local apps_dir="$WORKSPACE_ROOT/apps"
if [ ! -d "$apps_dir" ]; then
notice_error "未找到apps目录: $apps_dir"
return 1
fi
# 清空工作区数组
WORKSPACES=()
DISPLAY_NAMES=()
# 直接扫描apps目录下的所有子目录
for dir in $(find "$apps_dir" -maxdepth 1 -mindepth 1 -type d -not -path "*/node_modules/*" -not -path "*/.*/*"); do
if [ -f "$dir/package.json" ]; then
# 添加完整路径(相对于工作区根目录)
local full_path="${dir#$WORKSPACE_ROOT/}"
WORKSPACES+=("$full_path")
# 添加没有apps/前缀的显示名称
local display_name="${full_path#apps/}"
DISPLAY_NAMES+=("$display_name")
fi
done
if [ ${#WORKSPACES[@]} -eq 0 ]; then
notice_warning "未在apps目录下找到应用工作区"
return 1
fi
notice_success "在apps目录下找到 ${#WORKSPACES[@]} 个应用工作区"
for i in "${!WORKSPACES[@]}"; do
notice_info " - ${DISPLAY_NAMES[$i]}"
done
return 0
}
#######################################
# 加载配置文件
# 返回值:
# 0 - 成功
# 1 - 失败
# 全局变量:
# CONFIG_DRY_RUN - 是否干运行模式
#######################################
load_config() {
# 避免重复加载配置
if [ "$CONFIG_LOADED" = "true" ]; then
return 0
fi
notice_info "加载配置文件..."
local config_file="$WORKSPACE_ROOT/$SYNC_CONFIG"
if [ ! -f "$config_file" ]; then
notice_error "配置文件不存在: $config_file"
return 1
fi
# 确保yq可用
if [ -z "$YQ_PATH" ]; then
check_yq_dependency || return 1
fi
# 加载基本配置
# 禁用并行编译设置加载
# CONFIG_PARALLEL_BUILD=$("$YQ_PATH" e '.config.parallel_build // false' "$config_file")
# 禁用干运行设置加载
# CONFIG_DRY_RUN=$("$YQ_PATH" e '.config.dry_run // false' "$config_file")
# 标记配置已加载
CONFIG_LOADED="true"
notice_success "配置文件加载完成"
# 显示当前配置
notice_info "当前配置:"
# notice_info " - 并行编译: $CONFIG_PARALLEL_BUILD"
# notice_info " - 干运行模式: $CONFIG_DRY_RUN"
return 0
}
#######################################
# 选择工作区
# 返回值:
# 0 - 成功
# 1 - 失败
# 全局变量:
# SELECTED_WORKSPACES - 存储用户选择的工作区
#######################################
select_workspaces() {
notice_info "请选择要操作的工作区:"
SELECTED_WORKSPACES=()
local selected_index
# 使用没有apps/前缀的显示名称展示选项
notice_select_menu "选择要编译和同步的工作区" "selected_index" "${DISPLAY_NAMES[@]}"
if [ $? -ne 0 ]; then
notice_error "工作区选择被取消"
return 1
fi
# 添加选择的工作区(使用完整路径)
SELECTED_WORKSPACES+=("${WORKSPACES[$selected_index]}")
# 使用没有apps/前缀的显示名称展示选项
notice_success "已选择工作区: ${DISPLAY_NAMES[$selected_index]}"
return 0
}
#######################################
# 编译工作区
# 参数:
# $1: 工作区名称
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
build_workspace() {
local workspace="$1"
notice_info "正在编译工作区: $workspace..."
# 检查是否为干运行模式
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过实际编译"
# return 0
# fi
# 执行编译命令
(cd "$WORKSPACE_ROOT" && pnpm --filter "$workspace" build)
if [ $? -eq 0 ]; then
notice_success "工作区 $workspace 编译成功"
# 记录到历史文件
echo "$(date '+%Y-%m-%d %H:%M:%S') - 编译工作区 $workspace 成功" >> "$WORKSPACE_ROOT/$HISTORY_FILE"
return 0
else
notice_error "工作区 $workspace 编译失败"
# 记录到历史文件
echo "$(date '+%Y-%m-%d %H:%M:%S') - 编译工作区 $workspace 失败" >> "$WORKSPACE_ROOT/$HISTORY_FILE"
return 1
fi
}
#######################################
# 同步工作区到Git仓库
# 参数:
# $1: 工作区名称
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
sync_workspace() {
local workspace="$1"
notice_info "正在同步工作区: $workspace..."
# 确保配置已加载
if [ "$CONFIG_LOADED" != "true" ]; then
load_config || return 1
fi
# 确保yq可用
if [ -z "$YQ_PATH" ]; then
check_yq_dependency || return 1
fi
# 获取工作区配置
local sync_mappings_count
sync_mappings_count=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings | length // 0" "$WORKSPACE_ROOT/$SYNC_CONFIG")
if [ "$sync_mappings_count" -eq 0 ]; then
notice_warning "工作区 $workspace 没有同步映射配置"
return 1
fi
# 遍历所有同步映射
for i in $(seq 0 $((sync_mappings_count - 1))); do
local git_url
local branch
local alias
local sync_dirs
local sync_source
git_url=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings[$i].git.url" "$WORKSPACE_ROOT/$SYNC_CONFIG")
branch=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings[$i].git.branch // \"main\"" "$WORKSPACE_ROOT/$SYNC_CONFIG")
alias=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings[$i].git.alias // \"\"" "$WORKSPACE_ROOT/$SYNC_CONFIG")
sync_dirs=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings[$i].git.sync | join(\",\")" "$WORKSPACE_ROOT/$SYNC_CONFIG")
sync_source=$("$YQ_PATH" e ".workspaces.$workspace.sync_mappings[$i].git.source // false" "$WORKSPACE_ROOT/$SYNC_CONFIG")
# 如果alias为空从git_url生成
if [ -z "$alias" ]; then
alias=$(basename "$git_url" .git)
fi
notice_info "正在处理同步映射: $git_url -> $branch (别名: $alias)"
# 准备Git仓库
local git_repo_path="$WORKSPACE_ROOT/$GIT_SYNC_DIR/$alias"
if [ ! -d "$git_repo_path" ]; then
notice_info "克隆Git仓库: $git_url"
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过实际克隆"
# else
git clone "$git_url" -b "$branch" "$git_repo_path"
if [ $? -ne 0 ]; then
notice_error "克隆仓库失败: $git_url"
continue
fi
# fi
else
# 确认是正确的仓库
local remote_url
remote_url=$(cd "$git_repo_path" && git config --get remote.origin.url)
if [ "$remote_url" != "$git_url" ]; then
notice_warning "仓库URL不匹配预期: $git_url, 实际: $remote_url"
notice_confirm "是否要重置仓库URL?" "n"
if [ $? -eq 0 ]; then
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式跳过URL重置"
# else
(cd "$git_repo_path" && git remote set-url origin "$git_url")
# fi
else
notice_error "由于URL不匹配跳过同步"
continue
fi
fi
# 拉取最新代码
notice_info "拉取最新代码: $branch"
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过实际拉取"
# else
git_pull "$git_repo_path" "$branch"
if [ $? -ne 0 ]; then
notice_warning "拉取代码失败,尝试继续同步"
fi
# fi
fi
# 同步目录列表
IFS=',' read -ra dirs <<< "$sync_dirs"
# 同步每个指定的目录
for dir in "${dirs[@]}"; do
# 去除前导斜杠
dir="${dir#/}"
# 复制编译结果到Git仓库
local source_dir="$WORKSPACE_ROOT/$workspace/$dir"
local target_dir="$git_repo_path/$dir"
if [ ! -d "$source_dir" ]; then
notice_warning "源目录不存在: $source_dir"
continue
fi
notice_info "同步目录: $source_dir -> $target_dir"
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过实际复制"
# else
# 确保目标目录存在
if [ ! -d "$target_dir" ]; then
create_directory "$target_dir"
else
# 清空目标目录
notice_info "清空目标目录: $target_dir"
rm -rf "$target_dir"/*
fi
# 复制文件
cp -r "$source_dir"/* "$target_dir"/
if [ $? -ne 0 ]; then
notice_error "复制文件失败"
continue
fi
# fi
done
# 如果需要同步源代码
if [ "$sync_source" = "true" ]; then
notice_info "同步源代码..."
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过源代码同步"
# else
# 复制源代码除了node_modules和构建目录
rsync -av --exclude node_modules --exclude .git --exclude dist --exclude build \
"$WORKSPACE_ROOT/$workspace/" "$git_repo_path/"
if [ $? -ne 0 ]; then
notice_error "源代码同步失败"
else
notice_success "源代码同步成功"
fi
# fi
fi
# 提交更改
notice_info "提交更改到Git仓库"
# 禁用干运行判断
# if [ "$CONFIG_DRY_RUN" = "true" ]; then
# notice_info "干运行模式:跳过提交和推送"
# else
local commit_message="自动同步: $workspace 工作区 - $(date '+%Y-%m-%d %H:%M:%S')"
(cd "$git_repo_path" && git add .)
git_commit "$git_repo_path" "$commit_message"
# 即使没有变更需要提交,也尝试推送
git_push "$git_repo_path" "$branch"
if [ $? -eq 0 ]; then
notice_success "同步工作区 $workspace$git_url 成功"
# 记录到历史文件
echo "$(date '+%Y-%m-%d %H:%M:%S') - 同步工作区 $workspace$git_url 成功" >> "$WORKSPACE_ROOT/$HISTORY_FILE"
else
notice_error "推送更改失败"
# 记录到历史文件
echo "$(date '+%Y-%m-%d %H:%M:%S') - 同步工作区 $workspace$git_url 失败" >> "$WORKSPACE_ROOT/$HISTORY_FILE"
continue
fi
# fi
done
return 0
}
#######################################
# 处理命令行参数
# 参数:
# $@: 命令行参数
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
parse_args() {
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
# 禁用并行编译选项
# --parallel|-p)
# CONFIG_PARALLEL_BUILD="true"
# ;;
# 禁用干运行选项
# --dry-run|-d)
# CONFIG_DRY_RUN="true"
# ;;
--help|-h)
show_help
exit 0
;;
*)
notice_error "未知参数: $1"
show_help
return 1
;;
esac
shift
done
return 0
}
#######################################
# 显示帮助信息
#######################################
show_help() {
echo "用法: sync-project.sh [选项]"
echo ""
echo "选项:"
# echo " --parallel, -p 启用并行编译"
# echo " --dry-run, -d 干运行模式,不执行实际操作"
echo " --help, -h 显示此帮助信息"
echo ""
echo "示例:"
# echo " ./sync-project.sh -p # 启用并行编译"
# echo " ./sync-project.sh --dry-run # 干运行模式"
}
#######################################
# 显示历史记录
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
show_history() {
local history_file="$WORKSPACE_ROOT/$HISTORY_FILE"
if [ ! -f "$history_file" ]; then
notice_warning "历史记录文件不存在"
return 1
fi
notice_info "最近的操作历史:"
# 显示最后10条记录
tail -n 10 "$history_file"
return 0
}
#######################################
# 主函数
# 参数:
# $@: 命令行参数
# 返回值:
# 0 - 成功
# 1 - 失败
#######################################
main() {
notice_info "欢迎使用 Turborepo 工作区编译部署自动化工具"
# 解析命令行参数
parse_args "$@"
# 初始化环境(只运行一次)
init_environment || exit 1
# 加载配置(只运行一次)
load_config || exit 1
# 扫描工作区
scan_workspaces || exit 1
# 选择工作区
select_workspaces || exit 1
# 编译和同步选中的工作区
for workspace in "${SELECTED_WORKSPACES[@]}"; do
# 禁用并行模式
# if [ "$CONFIG_PARALLEL_BUILD" = "true" ]; then
# # 并行模式
# build_workspace "$workspace" && sync_workspace "$workspace" &
# else
# 顺序模式
build_workspace "$workspace" && sync_workspace "$workspace"
# fi
done
# 禁用并行模式等待
# if [ "$CONFIG_PARALLEL_BUILD" = "true" ]; then
# wait
# fi
# 显示操作历史
show_history
notice_success "所有操作完成"
return 0
}
# 执行主函数
main "$@"