- 在 all-upload-release.sh 中添加临时打包目录,复制二进制文件及必要的脚本和配置文件。 - 修改 install.sh 以支持新格式发布包的提取,简化安装流程,无需从 Git 克隆。 - 更新 INSTALL.md 和 README.md,说明新格式发布包的优点和安装步骤。 - 确保安装脚本能够处理旧格式发布包,保持向后兼容性。
986 lines
30 KiB
Bash
Executable File
986 lines
30 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# 发布上传脚本
|
||
# 支持多种上传方式:GitHub Releases、Gitea Releases、SCP、FTP、本地复制
|
||
|
||
set -e
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 项目信息
|
||
PROJECT_NAME="agent"
|
||
BUILD_DIR="bin"
|
||
RELEASE_DIR="release"
|
||
TEMP_DIR=$(mktemp -d)
|
||
|
||
|
||
|
||
# Gitea Token (硬编码)
|
||
GITEA_TOKEN="3becb08eee31b422481ce1b8986de1cd645b468e"
|
||
|
||
# 版本配置文件路径
|
||
VERSION_FILE="version.json"
|
||
|
||
# 从版本配置文件读取版本信息
|
||
read_version_config() {
|
||
local version_file="${VERSION_FILE}"
|
||
|
||
if [ ! -f "$version_file" ]; then
|
||
return 1
|
||
fi
|
||
|
||
# 检查是否有 jq 命令
|
||
if command -v jq &> /dev/null; then
|
||
local version=$(jq -r '.version' "$version_file" 2>/dev/null)
|
||
local tag=$(jq -r '.tag' "$version_file" 2>/dev/null)
|
||
|
||
if [ -n "$version" ] && [ "$version" != "null" ]; then
|
||
echo "$version|$tag"
|
||
return 0
|
||
fi
|
||
else
|
||
# 如果没有 jq,使用 grep 和 sed 解析 JSON
|
||
local version=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$version_file" 2>/dev/null | sed 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
|
||
local tag=$(grep -o '"tag"[[:space:]]*:[[:space:]]*"[^"]*"' "$version_file" 2>/dev/null | sed 's/.*"tag"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
|
||
|
||
if [ -n "$version" ]; then
|
||
echo "$version|$tag"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
return 1
|
||
}
|
||
|
||
# 初始化版本号(从配置文件读取,如果失败则使用时间戳)
|
||
VERSION_CONFIG=$(read_version_config)
|
||
if [ $? -eq 0 ] && [ -n "$VERSION_CONFIG" ]; then
|
||
IFS='|' read -r config_version config_tag <<< "$VERSION_CONFIG"
|
||
VERSION="${VERSION:-$config_version}"
|
||
DEFAULT_TAG="${config_tag}"
|
||
else
|
||
VERSION="${VERSION:-$(date +%Y%m%d-%H%M%S)}"
|
||
DEFAULT_TAG=""
|
||
fi
|
||
|
||
# 支持的平台列表
|
||
PLATFORMS=(
|
||
"linux/amd64"
|
||
"linux/arm64"
|
||
"darwin/amd64"
|
||
"darwin/arm64"
|
||
"windows/amd64"
|
||
"windows/arm64"
|
||
)
|
||
|
||
# 清理函数
|
||
cleanup() {
|
||
if [ -d "$TEMP_DIR" ]; then
|
||
rm -rf "$TEMP_DIR"
|
||
fi
|
||
}
|
||
trap cleanup EXIT
|
||
|
||
# 显示使用说明
|
||
usage() {
|
||
echo -e "${BLUE}使用方法:${NC}"
|
||
echo " $0 [选项]"
|
||
echo ""
|
||
echo -e "${BLUE}选项:${NC}"
|
||
echo " -h, --help 显示帮助信息"
|
||
echo " -m, --method METHOD 上传方式: github|gitea|scp|ftp|local (默认: gitea)"
|
||
echo " -v, --version VERSION 版本号 (默认: 时间戳)"
|
||
echo " -p, --platform PLATFORM 只上传指定平台 (例如: linux/amd64)"
|
||
echo " -t, --tag TAG Git标签 (GitHub/Gitea Releases需要)"
|
||
echo " -r, --repo REPO 仓库 (格式: owner/repo,默认从.git/config读取)"
|
||
echo " -b, --base-url URL Gitea基础URL (默认从.git/config读取)"
|
||
echo " -T, --token TOKEN 访问令牌 (已硬编码,此选项已废弃)"
|
||
echo " -d, --dest DEST 目标路径 (SCP/FTP/local需要)"
|
||
echo " -H, --host HOST 主机地址 (SCP/FTP需要)"
|
||
echo " -u, --user USER 用户名 (SCP/FTP需要)"
|
||
echo " -P, --port PORT 端口号 (SCP/FTP需要,默认: SCP=22, FTP=21)"
|
||
echo " -k, --key KEY 私钥路径 (SCP需要)"
|
||
echo " --pack-only 只打包不上传"
|
||
echo " --no-pack 不上传压缩包,直接上传二进制文件"
|
||
echo " --notes NOTES 发布说明 (GitHub/Gitea Releases)"
|
||
echo " --notes-file FILE 从文件读取发布说明"
|
||
echo ""
|
||
echo -e "${BLUE}上传方式说明:${NC}"
|
||
echo ""
|
||
echo -e "${CYAN}Gitea Releases (自动从.git/config和version.json读取):${NC}"
|
||
echo " $0 -m gitea"
|
||
echo " $0 -m gitea -t v1.0.0 -v 1.0.0"
|
||
echo ""
|
||
echo -e "${CYAN}GitHub Releases:${NC}"
|
||
echo " $0 -m github -r owner/repo -t v1.0.0 -v 1.0.0"
|
||
echo ""
|
||
echo -e "${CYAN}SCP上传:${NC}"
|
||
echo " $0 -m scp -H example.com -u user -d /path/to/release"
|
||
echo " $0 -m scp -H example.com -u user -d /path/to/release -k ~/.ssh/id_rsa"
|
||
echo ""
|
||
echo -e "${CYAN}FTP上传:${NC}"
|
||
echo " $0 -m ftp -H ftp.example.com -u user -d /path/to/release"
|
||
echo ""
|
||
echo -e "${CYAN}本地复制:${NC}"
|
||
echo " $0 -m local -d /path/to/release"
|
||
echo ""
|
||
echo -e "${CYAN}只打包:${NC}"
|
||
echo " $0 --pack-only -v 1.0.0"
|
||
}
|
||
|
||
# 从 .git/config 读取 Git 信息
|
||
read_git_info() {
|
||
local git_config=".git/config"
|
||
|
||
if [ ! -f "$git_config" ]; then
|
||
return 1
|
||
fi
|
||
|
||
# 读取 origin URL
|
||
local url=$(git config --get remote.origin.url 2>/dev/null || echo "")
|
||
|
||
if [ -z "$url" ]; then
|
||
return 1
|
||
fi
|
||
|
||
# 解析 URL
|
||
# 支持格式:
|
||
# - https://user:pass@host/owner/repo.git
|
||
# - https://host/owner/repo.git
|
||
# - git@host:owner/repo.git
|
||
# - ssh://user@host/owner/repo.git
|
||
|
||
local base_url=""
|
||
local owner=""
|
||
local repo_name=""
|
||
local token=""
|
||
|
||
# 提取 token (如果有)
|
||
if [[ "$url" =~ https://([^:]+):([^@]+)@(.+) ]]; then
|
||
token="${BASH_REMATCH[2]}"
|
||
url="https://${BASH_REMATCH[1]}@${BASH_REMATCH[3]}"
|
||
fi
|
||
|
||
# 提取 base_url, owner, repo
|
||
if [[ "$url" =~ https://([^/]+)/([^/]+)/([^/]+)\.git ]]; then
|
||
base_url="https://${BASH_REMATCH[1]}"
|
||
owner="${BASH_REMATCH[2]}"
|
||
repo_name="${BASH_REMATCH[3]}"
|
||
elif [[ "$url" =~ git@([^:]+):([^/]+)/([^/]+)\.git ]]; then
|
||
base_url="https://${BASH_REMATCH[1]}"
|
||
owner="${BASH_REMATCH[2]}"
|
||
repo_name="${BASH_REMATCH[3]}"
|
||
elif [[ "$url" =~ ssh://[^@]+@([^/]+)/([^/]+)/([^/]+)\.git ]]; then
|
||
base_url="https://${BASH_REMATCH[1]}"
|
||
owner="${BASH_REMATCH[2]}"
|
||
repo_name="${BASH_REMATCH[3]}"
|
||
fi
|
||
|
||
if [ -n "$base_url" ] && [ -n "$owner" ] && [ -n "$repo_name" ]; then
|
||
echo "$base_url|$owner|$repo_name|$token"
|
||
return 0
|
||
fi
|
||
|
||
return 1
|
||
}
|
||
|
||
# 检查必要的工具
|
||
check_dependencies() {
|
||
local method=$1
|
||
local missing_tools=()
|
||
|
||
case $method in
|
||
github)
|
||
if ! command -v gh &> /dev/null; then
|
||
missing_tools+=("gh (GitHub CLI)")
|
||
fi
|
||
;;
|
||
gitea)
|
||
if ! command -v curl &> /dev/null; then
|
||
missing_tools+=("curl")
|
||
fi
|
||
if ! command -v jq &> /dev/null; then
|
||
echo -e "${YELLOW}警告: jq 未安装,某些功能可能受限${NC}"
|
||
fi
|
||
;;
|
||
scp)
|
||
if ! command -v scp &> /dev/null; then
|
||
missing_tools+=("scp")
|
||
fi
|
||
;;
|
||
ftp)
|
||
if ! command -v curl &> /dev/null && ! command -v ftp &> /dev/null; then
|
||
missing_tools+=("curl 或 ftp")
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
if [ ${#missing_tools[@]} -gt 0 ]; then
|
||
echo -e "${RED}错误: 缺少必要的工具:${NC}"
|
||
for tool in "${missing_tools[@]}"; do
|
||
echo " - $tool"
|
||
done
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 检查构建文件是否存在
|
||
check_build_files() {
|
||
if [ ! -d "$BUILD_DIR" ] || [ -z "$(ls -A $BUILD_DIR 2>/dev/null)" ]; then
|
||
echo -e "${RED}错误: 构建目录为空或不存在${NC}"
|
||
echo "请先运行 ./all-build.sh 编译项目"
|
||
exit 1
|
||
fi
|
||
|
||
local found=0
|
||
for platform in "${PLATFORMS[@]}"; do
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local file="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
if [ "$os" = "windows" ]; then
|
||
file="${file}.exe"
|
||
fi
|
||
|
||
if [ -f "$file" ]; then
|
||
found=1
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ $found -eq 0 ]; then
|
||
echo -e "${RED}错误: 未找到任何构建文件${NC}"
|
||
echo "请先运行 ./all-build.sh 编译项目"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 打包文件
|
||
pack_files() {
|
||
local platform=$1
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
|
||
if [ "$os" = "windows" ]; then
|
||
binary="${binary}.exe"
|
||
fi
|
||
|
||
if [ ! -f "$binary" ]; then
|
||
echo -e "${YELLOW}[跳过]${NC} ${platform} - 文件不存在"
|
||
return 1
|
||
fi
|
||
|
||
local pack_name="${PROJECT_NAME}-${os}-${arch}-${VERSION}"
|
||
local pack_file
|
||
|
||
# 创建临时打包目录
|
||
local pack_dir="${TEMP_DIR}/${pack_name}"
|
||
mkdir -p "$pack_dir"
|
||
|
||
# 复制二进制文件并重命名为 agent
|
||
if [ "$os" = "windows" ]; then
|
||
cp "$binary" "$pack_dir/agent.exe"
|
||
else
|
||
cp "$binary" "$pack_dir/agent"
|
||
chmod +x "$pack_dir/agent"
|
||
fi
|
||
|
||
# 复制必要的脚本文件
|
||
local scripts=("install.sh" "run.sh" "start-systemd.sh" "uninstall.sh")
|
||
for script in "${scripts[@]}"; do
|
||
if [ -f "$script" ]; then
|
||
cp "$script" "$pack_dir/"
|
||
chmod +x "$pack_dir/$script"
|
||
echo -e "${BLUE} [包含]${NC} $script"
|
||
else
|
||
echo -e "${YELLOW} [警告]${NC} $script 不存在,跳过"
|
||
fi
|
||
done
|
||
|
||
# 复制示例配置文件
|
||
if [ -f "config.yaml.example" ]; then
|
||
cp "config.yaml.example" "$pack_dir/config.yaml.example"
|
||
echo -e "${BLUE} [包含]${NC} config.yaml.example"
|
||
else
|
||
echo -e "${YELLOW} [警告]${NC} config.yaml.example 不存在,跳过"
|
||
fi
|
||
|
||
# 打包
|
||
if [ "$os" = "windows" ]; then
|
||
pack_file="${TEMP_DIR}/${pack_name}.zip"
|
||
echo -e "${BLUE}[打包]${NC} ${platform} -> ${pack_name}.zip"
|
||
(cd "$TEMP_DIR" && zip -q -r "${pack_file}" "$(basename $pack_dir)")
|
||
else
|
||
pack_file="${TEMP_DIR}/${pack_name}.tar.gz"
|
||
echo -e "${BLUE}[打包]${NC} ${platform} -> ${pack_name}.tar.gz"
|
||
tar -czf "$pack_file" -C "$TEMP_DIR" "$(basename $pack_dir)"
|
||
fi
|
||
|
||
# 清理临时目录
|
||
rm -rf "$pack_dir"
|
||
|
||
echo "$pack_file"
|
||
return 0
|
||
}
|
||
|
||
# 创建发布说明
|
||
create_release_notes() {
|
||
local notes_file="${TEMP_DIR}/release_notes.md"
|
||
cat > "$notes_file" <<EOF
|
||
# ${PROJECT_NAME} ${VERSION}
|
||
|
||
## 版本信息
|
||
- **版本号**: ${VERSION}
|
||
- **发布日期**: $(date '+%Y-%m-%d %H:%M:%S')
|
||
- **Git提交**: $(git rev-parse --short HEAD 2>/dev/null || echo "N/A")
|
||
- **Git分支**: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "N/A")
|
||
|
||
## 支持的平台
|
||
EOF
|
||
|
||
for platform in "${PLATFORMS[@]}"; do
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
if [ "$os" = "windows" ]; then
|
||
binary="${binary}.exe"
|
||
fi
|
||
|
||
if [ -f "$binary" ]; then
|
||
local size=$(ls -lh "$binary" | awk '{print $5}')
|
||
echo "- ${os}/${arch} (${size})" >> "$notes_file"
|
||
fi
|
||
done
|
||
|
||
echo "" >> "$notes_file"
|
||
echo "## 安装说明" >> "$notes_file"
|
||
echo "" >> "$notes_file"
|
||
echo "### Linux/macOS" >> "$notes_file"
|
||
echo "\`\`\`bash" >> "$notes_file"
|
||
echo "tar -xzf ${PROJECT_NAME}-linux-amd64-${VERSION}.tar.gz" >> "$notes_file"
|
||
echo "chmod +x ${PROJECT_NAME}-linux-amd64" >> "$notes_file"
|
||
echo "./${PROJECT_NAME}-linux-amd64" >> "$notes_file"
|
||
echo "\`\`\`" >> "$notes_file"
|
||
echo "" >> "$notes_file"
|
||
echo "### Windows" >> "$notes_file"
|
||
echo "\`\`\`powershell" >> "$notes_file"
|
||
echo "Expand-Archive ${PROJECT_NAME}-windows-amd64-${VERSION}.zip" >> "$notes_file"
|
||
echo ".\\${PROJECT_NAME}-windows-amd64.exe" >> "$notes_file"
|
||
echo "\`\`\`" >> "$notes_file"
|
||
|
||
echo "$notes_file"
|
||
}
|
||
|
||
# GitHub Releases 上传
|
||
upload_github() {
|
||
local repo=$1
|
||
local tag=$2
|
||
local notes_file=$3
|
||
|
||
if [ -z "$repo" ]; then
|
||
echo -e "${RED}错误: GitHub仓库未指定,使用 -r owner/repo${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$tag" ]; then
|
||
echo -e "${RED}错误: Git标签未指定,使用 -t TAG${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}上传到 GitHub Releases${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "仓库: ${BLUE}${repo}${NC}"
|
||
echo -e "标签: ${BLUE}${tag}${NC}"
|
||
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||
echo ""
|
||
|
||
# 检查是否已存在release
|
||
if gh release view "$tag" --repo "$repo" &>/dev/null; then
|
||
echo -e "${YELLOW}警告: Release ${tag} 已存在${NC}"
|
||
read -p "是否删除并重新创建? (y/N): " confirm
|
||
if [[ "$confirm" =~ ^[Yy]$ ]]; then
|
||
gh release delete "$tag" --repo "$repo" --yes
|
||
else
|
||
echo "取消上传"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# 创建release
|
||
echo -e "${BLUE}[创建Release]${NC} ${tag}"
|
||
if [ -f "$notes_file" ]; then
|
||
gh release create "$tag" \
|
||
--repo "$repo" \
|
||
--title "${PROJECT_NAME} ${VERSION}" \
|
||
--notes-file "$notes_file" \
|
||
--draft=false \
|
||
--prerelease=false
|
||
else
|
||
gh release create "$tag" \
|
||
--repo "$repo" \
|
||
--title "${PROJECT_NAME} ${VERSION}" \
|
||
--notes "Release ${VERSION}" \
|
||
--draft=false \
|
||
--prerelease=false
|
||
fi
|
||
|
||
# 上传文件
|
||
local upload_count=0
|
||
shopt -s nullglob
|
||
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||
if [ -f "$file" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||
gh release upload "$tag" "$file" --repo "$repo" --clobber
|
||
((upload_count++))
|
||
fi
|
||
done
|
||
shopt -u nullglob
|
||
|
||
if [ $upload_count -eq 0 ] && [ "$NO_PACK" != "true" ]; then
|
||
echo -e "${YELLOW}警告: 没有找到要上传的文件${NC}"
|
||
else
|
||
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||
echo -e "${CYAN}Release链接:${NC} https://github.com/${repo}/releases/tag/${tag}"
|
||
fi
|
||
}
|
||
|
||
# Gitea Releases 上传
|
||
upload_gitea() {
|
||
local base_url=$1
|
||
local owner=$2
|
||
local repo=$3
|
||
local tag=$4
|
||
local token=$5
|
||
local notes_file=$6
|
||
|
||
if [ -z "$base_url" ] || [ -z "$owner" ] || [ -z "$repo" ]; then
|
||
echo -e "${RED}错误: Gitea仓库信息不完整${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
if [ -z "$tag" ]; then
|
||
echo -e "${RED}错误: Git标签未指定,使用 -t TAG${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# Token 已硬编码,确保使用硬编码的 token
|
||
if [ -z "$token" ]; then
|
||
token="${GITEA_TOKEN}"
|
||
fi
|
||
|
||
if [ -z "$token" ]; then
|
||
echo -e "${RED}错误: 访问令牌未配置${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}上传到 Gitea Releases${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "基础URL: ${BLUE}${base_url}${NC}"
|
||
echo -e "仓库: ${BLUE}${owner}/${repo}${NC}"
|
||
echo -e "标签: ${BLUE}${tag}${NC}"
|
||
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||
echo ""
|
||
|
||
local api_base="${base_url}/api/v1"
|
||
local repo_api="${api_base}/repos/${owner}/${repo}"
|
||
|
||
# 读取发布说明
|
||
local notes="Release ${VERSION}"
|
||
if [ -f "$notes_file" ]; then
|
||
notes=$(cat "$notes_file")
|
||
fi
|
||
|
||
# 转义 JSON 字符串(不使用 jq)
|
||
local notes_escaped=$(echo "$notes" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
|
||
|
||
# 检查是否已存在release
|
||
local existing_release=$(curl -s -X GET \
|
||
"${repo_api}/releases/tags/${tag}" \
|
||
-H "Authorization: token ${token}" \
|
||
-H "Content-Type: application/json" 2>/dev/null)
|
||
|
||
if echo "$existing_release" | grep -q '"id"'; then
|
||
echo -e "${YELLOW}警告: Release ${tag} 已存在${NC}"
|
||
read -p "是否删除并重新创建? (y/N): " confirm
|
||
if [[ "$confirm" =~ ^[Yy]$ ]]; then
|
||
local release_id=$(echo "$existing_release" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
|
||
if [ -n "$release_id" ]; then
|
||
curl -s -X DELETE \
|
||
"${repo_api}/releases/${release_id}" \
|
||
-H "Authorization: token ${token}" > /dev/null
|
||
echo -e "${BLUE}[删除]${NC} 已删除现有 Release"
|
||
fi
|
||
else
|
||
echo "取消上传"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# 创建release
|
||
echo -e "${BLUE}[创建Release]${NC} ${tag}"
|
||
local release_data=$(cat <<EOF
|
||
{
|
||
"tag_name": "${tag}",
|
||
"target_commitish": "main",
|
||
"name": "${PROJECT_NAME} ${VERSION}",
|
||
"body": "${notes_escaped}",
|
||
"draft": false,
|
||
"prerelease": false
|
||
}
|
||
EOF
|
||
)
|
||
|
||
local create_response=$(curl -s -X POST \
|
||
"${repo_api}/releases" \
|
||
-H "Authorization: token ${token}" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$release_data")
|
||
|
||
if echo "$create_response" | grep -q '"id"'; then
|
||
local release_id=$(echo "$create_response" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
|
||
echo -e "${GREEN}[成功]${NC} Release 已创建 (ID: ${release_id})"
|
||
else
|
||
echo -e "${RED}[失败]${NC} 创建 Release 失败"
|
||
echo "$create_response" | head -20
|
||
exit 1
|
||
fi
|
||
|
||
# 上传文件
|
||
local upload_count=0
|
||
shopt -s nullglob
|
||
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||
if [ -f "$file" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||
local upload_response=$(curl -s -X POST \
|
||
"${repo_api}/releases/${release_id}/assets?name=$(basename $file)" \
|
||
-H "Authorization: token ${token}" \
|
||
-H "Content-Type: application/octet-stream" \
|
||
--data-binary "@${file}")
|
||
|
||
if echo "$upload_response" | grep -q '"id"'; then
|
||
echo -e " ${GREEN}✓${NC} 上传成功"
|
||
((upload_count++))
|
||
else
|
||
echo -e " ${RED}✗${NC} 上传失败"
|
||
echo "$upload_response" | head -5
|
||
fi
|
||
fi
|
||
done
|
||
shopt -u nullglob
|
||
|
||
if [ $upload_count -eq 0 ] && [ "$NO_PACK" != "true" ]; then
|
||
echo -e "${YELLOW}警告: 没有找到要上传的文件${NC}"
|
||
else
|
||
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||
echo -e "${CYAN}Release链接:${NC} ${base_url}/${owner}/${repo}/releases/tag/${tag}"
|
||
fi
|
||
}
|
||
|
||
# SCP上传
|
||
upload_scp() {
|
||
local host=$1
|
||
local user=$2
|
||
local dest=$3
|
||
local port=${4:-22}
|
||
local key=$5
|
||
|
||
if [ -z "$host" ] || [ -z "$user" ] || [ -z "$dest" ]; then
|
||
echo -e "${RED}错误: SCP需要指定主机(-H)、用户(-u)和目标路径(-d)${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}上传到 SCP${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "主机: ${BLUE}${user}@${host}:${port}${NC}"
|
||
echo -e "目标: ${BLUE}${dest}${NC}"
|
||
echo ""
|
||
|
||
local scp_opts="-P $port"
|
||
if [ -n "$key" ]; then
|
||
scp_opts="$scp_opts -i $key"
|
||
fi
|
||
|
||
# 创建远程目录
|
||
local ssh_cmd="ssh"
|
||
if [ -n "$key" ]; then
|
||
ssh_cmd="$ssh_cmd -i $key"
|
||
fi
|
||
ssh -p "$port" $([ -n "$key" ] && echo "-i $key") "$user@$host" "mkdir -p $dest" || true
|
||
|
||
# 上传文件
|
||
local upload_count=0
|
||
if [ "$NO_PACK" = "true" ]; then
|
||
# 直接上传二进制文件
|
||
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
if [ "$os" = "windows" ]; then
|
||
binary="${binary}.exe"
|
||
fi
|
||
|
||
if [ -f "$binary" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $binary)"
|
||
scp $scp_opts "$binary" "$user@$host:$dest/"
|
||
((upload_count++))
|
||
fi
|
||
done
|
||
else
|
||
# 上传压缩包
|
||
shopt -s nullglob
|
||
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||
if [ -f "$file" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||
scp $scp_opts "$file" "$user@$host:$dest/"
|
||
((upload_count++))
|
||
fi
|
||
done
|
||
shopt -u nullglob
|
||
fi
|
||
|
||
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||
}
|
||
|
||
# FTP上传
|
||
upload_ftp() {
|
||
local host=$1
|
||
local user=$2
|
||
local dest=$3
|
||
local port=${4:-21}
|
||
|
||
if [ -z "$host" ] || [ -z "$user" ] || [ -z "$dest" ]; then
|
||
echo -e "${RED}错误: FTP需要指定主机(-H)、用户(-u)和目标路径(-d)${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}上传到 FTP${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "主机: ${BLUE}${host}:${port}${NC}"
|
||
echo -e "用户: ${BLUE}${user}${NC}"
|
||
echo -e "目标: ${BLUE}${dest}${NC}"
|
||
echo ""
|
||
|
||
read -sp "请输入FTP密码: " ftp_pass
|
||
echo ""
|
||
|
||
local upload_count=0
|
||
|
||
if [ "$NO_PACK" = "true" ]; then
|
||
# 直接上传二进制文件
|
||
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
if [ "$os" = "windows" ]; then
|
||
binary="${binary}.exe"
|
||
fi
|
||
|
||
if [ -f "$binary" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $binary)"
|
||
curl -T "$binary" \
|
||
"ftp://${host}:${port}${dest}/$(basename $binary)" \
|
||
--user "${user}:${ftp_pass}" \
|
||
--ftp-create-dirs
|
||
((upload_count++))
|
||
fi
|
||
done
|
||
else
|
||
# 上传压缩包
|
||
shopt -s nullglob
|
||
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||
if [ -f "$file" ]; then
|
||
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||
curl -T "$file" \
|
||
"ftp://${host}:${port}${dest}/$(basename $file)" \
|
||
--user "${user}:${ftp_pass}" \
|
||
--ftp-create-dirs
|
||
((upload_count++))
|
||
fi
|
||
done
|
||
shopt -u nullglob
|
||
fi
|
||
|
||
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||
}
|
||
|
||
# 本地复制
|
||
upload_local() {
|
||
local dest=$1
|
||
|
||
if [ -z "$dest" ]; then
|
||
echo -e "${RED}错误: 本地复制需要指定目标路径(-d)${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}复制到本地目录${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "目标: ${BLUE}${dest}${NC}"
|
||
echo ""
|
||
|
||
mkdir -p "$dest"
|
||
|
||
local copy_count=0
|
||
|
||
if [ "$NO_PACK" = "true" ]; then
|
||
# 直接复制二进制文件
|
||
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||
local os=$(echo $platform | cut -d'/' -f1)
|
||
local arch=$(echo $platform | cut -d'/' -f2)
|
||
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||
if [ "$os" = "windows" ]; then
|
||
binary="${binary}.exe"
|
||
fi
|
||
|
||
if [ -f "$binary" ]; then
|
||
echo -e "${BLUE}[复制]${NC} $(basename $binary)"
|
||
cp "$binary" "$dest/"
|
||
((copy_count++))
|
||
fi
|
||
done
|
||
else
|
||
# 复制压缩包
|
||
shopt -s nullglob
|
||
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||
if [ -f "$file" ]; then
|
||
echo -e "${BLUE}[复制]${NC} $(basename $file)"
|
||
cp "$file" "$dest/"
|
||
((copy_count++))
|
||
fi
|
||
done
|
||
shopt -u nullglob
|
||
fi
|
||
|
||
echo -e "${GREEN}[完成]${NC} 已复制 ${copy_count} 个文件"
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
local method="gitea"
|
||
local selected_platforms=()
|
||
local tag="${DEFAULT_TAG}"
|
||
local repo=""
|
||
local base_url=""
|
||
local token="${GITEA_TOKEN}" # 使用硬编码的 token
|
||
local dest=""
|
||
local host=""
|
||
local user=""
|
||
local port=""
|
||
local key=""
|
||
local pack_only=false
|
||
local notes=""
|
||
local notes_file=""
|
||
|
||
# 解析参数
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
-h|--help)
|
||
usage
|
||
exit 0
|
||
;;
|
||
-m|--method)
|
||
method="$2"
|
||
shift 2
|
||
;;
|
||
-v|--version)
|
||
VERSION="$2"
|
||
shift 2
|
||
;;
|
||
-p|--platform)
|
||
selected_platforms+=("$2")
|
||
shift 2
|
||
;;
|
||
-t|--tag)
|
||
tag="$2"
|
||
shift 2
|
||
;;
|
||
-r|--repo)
|
||
repo="$2"
|
||
shift 2
|
||
;;
|
||
-b|--base-url)
|
||
base_url="$2"
|
||
shift 2
|
||
;;
|
||
-T|--token)
|
||
echo -e "${YELLOW}警告: Token 已硬编码,-T 参数将被忽略${NC}"
|
||
shift 2
|
||
;;
|
||
-d|--dest)
|
||
dest="$2"
|
||
shift 2
|
||
;;
|
||
-H|--host)
|
||
host="$2"
|
||
shift 2
|
||
;;
|
||
-u|--user)
|
||
user="$2"
|
||
shift 2
|
||
;;
|
||
-P|--port)
|
||
port="$2"
|
||
shift 2
|
||
;;
|
||
-k|--key)
|
||
key="$2"
|
||
shift 2
|
||
;;
|
||
--pack-only)
|
||
pack_only=true
|
||
shift
|
||
;;
|
||
--no-pack)
|
||
NO_PACK=true
|
||
shift
|
||
;;
|
||
--notes)
|
||
notes="$2"
|
||
shift 2
|
||
;;
|
||
--notes-file)
|
||
notes_file="$2"
|
||
shift 2
|
||
;;
|
||
*)
|
||
echo -e "${RED}未知参数: $1${NC}"
|
||
usage
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# 确定要处理的平台
|
||
if [ ${#selected_platforms[@]} -eq 0 ]; then
|
||
SELECTED_PLATFORMS=("${PLATFORMS[@]}")
|
||
else
|
||
SELECTED_PLATFORMS=("${selected_platforms[@]}")
|
||
fi
|
||
|
||
# 检查构建文件
|
||
check_build_files
|
||
|
||
# 检查依赖
|
||
if [ "$pack_only" != "true" ]; then
|
||
check_dependencies "$method"
|
||
fi
|
||
|
||
# 打包文件
|
||
if [ "$NO_PACK" != "true" ]; then
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}开始打包${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||
echo -e "平台数量: ${BLUE}${#SELECTED_PLATFORMS[@]}${NC}"
|
||
echo ""
|
||
|
||
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||
pack_files "$platform" > /dev/null
|
||
done
|
||
|
||
echo ""
|
||
echo -e "${GREEN}打包完成${NC}"
|
||
echo -e "${BLUE}打包文件:${NC}"
|
||
shopt -s nullglob
|
||
ls -lh "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
|
||
shopt -u nullglob
|
||
echo ""
|
||
fi
|
||
|
||
# 如果只是打包,则复制到release目录
|
||
if [ "$pack_only" = "true" ]; then
|
||
mkdir -p "$RELEASE_DIR"
|
||
shopt -s nullglob
|
||
cp "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip "$RELEASE_DIR/" 2>/dev/null || true
|
||
shopt -u nullglob
|
||
echo -e "${GREEN}文件已复制到 ${RELEASE_DIR} 目录${NC}"
|
||
exit 0
|
||
fi
|
||
|
||
# 创建发布说明
|
||
local release_notes=""
|
||
if [ -n "$notes_file" ] && [ -f "$notes_file" ]; then
|
||
release_notes="$notes_file"
|
||
elif [ -n "$notes" ]; then
|
||
echo "$notes" > "${TEMP_DIR}/release_notes.md"
|
||
release_notes="${TEMP_DIR}/release_notes.md"
|
||
elif [ "$method" = "github" ] || [ "$method" = "gitea" ]; then
|
||
release_notes=$(create_release_notes)
|
||
fi
|
||
|
||
# 根据方法上传
|
||
case $method in
|
||
gitea)
|
||
# 从 .git/config 读取信息(如果未指定)
|
||
local git_info=""
|
||
if [ -z "$base_url" ] || [ -z "$repo" ]; then
|
||
git_info=$(read_git_info)
|
||
if [ $? -eq 0 ] && [ -n "$git_info" ]; then
|
||
IFS='|' read -r git_base_url git_owner git_repo_name git_token <<< "$git_info"
|
||
if [ -z "$base_url" ]; then
|
||
base_url="$git_base_url"
|
||
fi
|
||
if [ -z "$repo" ]; then
|
||
repo="${git_owner}/${git_repo_name}"
|
||
fi
|
||
# Token 已硬编码,不从 git config 读取
|
||
# if [ -z "$token" ] && [ -n "$git_token" ]; then
|
||
# token="$git_token"
|
||
# fi
|
||
echo -e "${CYAN}[信息]${NC} 从 .git/config 读取仓库信息: ${repo}"
|
||
fi
|
||
fi
|
||
|
||
if [ -z "$base_url" ] || [ -z "$repo" ]; then
|
||
echo -e "${RED}错误: Gitea仓库信息不完整${NC}"
|
||
echo "请指定 -b BASE_URL 和 -r owner/repo,或确保 .git/config 中有正确的远程仓库配置"
|
||
exit 1
|
||
fi
|
||
|
||
IFS='/' read -r owner repo_name <<< "$repo"
|
||
if [ -z "$owner" ] || [ -z "$repo_name" ]; then
|
||
echo -e "${RED}错误: 仓库格式不正确,应为 owner/repo${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
upload_gitea "$base_url" "$owner" "$repo_name" "$tag" "$token" "$release_notes"
|
||
;;
|
||
github)
|
||
upload_github "$repo" "$tag" "$release_notes"
|
||
;;
|
||
scp)
|
||
upload_scp "$host" "$user" "$dest" "$port" "$key"
|
||
;;
|
||
ftp)
|
||
upload_ftp "$host" "$user" "$dest" "$port"
|
||
;;
|
||
local)
|
||
upload_local "$dest"
|
||
;;
|
||
*)
|
||
echo -e "${RED}错误: 不支持的上传方式: ${method}${NC}"
|
||
echo "支持的方式: gitea, github, scp, ftp, local"
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
echo ""
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}发布完成${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
}
|
||
|
||
# 运行主函数
|
||
main "$@"
|
||
|