This commit is contained in:
parent
ec3d9711b2
commit
447387c0a5
196
.gitea/workflows/docker.yml
Normal file
196
.gitea/workflows/docker.yml
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
name: site-dist-deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- develop
|
||||||
|
|
||||||
|
|
||||||
|
env:
|
||||||
|
VITE_APP_BASE_URL: /
|
||||||
|
SSH_HOST: ${{ vars.PRO_SSH_HOST }}
|
||||||
|
SSH_PORT: ${{ vars.PRO_SSH_PORT }}
|
||||||
|
SSH_USER: ${{ vars.PRO_SSH_USER }}
|
||||||
|
SSH_PASSWORD: ${{ vars.PRO_SSH_PASSWORD }}
|
||||||
|
DEPLOY_PATH: /var/www/hi-download
|
||||||
|
# TG通知
|
||||||
|
TG_BOT_TOKEN: 8114337882:AAHkEx03HSu7RxN4IHBJJEnsK9aPPzNLIk0
|
||||||
|
TG_CHAT_ID: "-4940243803"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: hi-download
|
||||||
|
steps:
|
||||||
|
- name: Manual checkout (no Node required)
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
git fetch --all --tags
|
||||||
|
git checkout "${{ github.ref_name }}"
|
||||||
|
git reset --hard "origin/${{ github.ref_name }}"
|
||||||
|
else
|
||||||
|
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
|
||||||
|
echo "Cloning $REPO_URL"
|
||||||
|
git clone --depth=1 --branch "${{ github.ref_name }}" "$REPO_URL" .
|
||||||
|
git fetch --tags
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build dist with Unified Script
|
||||||
|
env:
|
||||||
|
VITE_APP_BASE_URL: "/"
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/ci-build.sh
|
||||||
|
./scripts/ci-build.sh
|
||||||
|
|
||||||
|
- name: Check Artifacts
|
||||||
|
run: |
|
||||||
|
echo "Current directory: $(pwd)"
|
||||||
|
echo "Listing all files in workspace:"
|
||||||
|
find . -maxdepth 2 -not -path '*/.*'
|
||||||
|
if [ -f "site_dist.tgz" ]; then
|
||||||
|
echo "✅ File exists: site_dist.tgz"
|
||||||
|
ls -lh site_dist.tgz
|
||||||
|
echo "File path: $(readlink -f site_dist.tgz)"
|
||||||
|
else
|
||||||
|
echo "❌ File NOT found: site_dist.tgz"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Deploy to Host (Native SSH/SCP)
|
||||||
|
run: |
|
||||||
|
echo "Installing SSH tools..."
|
||||||
|
if command -v apk &> /dev/null; then
|
||||||
|
echo "Detected Alpine Linux. Installing sshpass openssh-client via apk..."
|
||||||
|
apk add --no-cache sshpass openssh-client
|
||||||
|
elif command -v apt-get &> /dev/null; then
|
||||||
|
echo "Detected Debian/Ubuntu. Installing sshpass openssh-client via apt..."
|
||||||
|
apt-get update -y && apt-get install -y sshpass openssh-client
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
echo "Detected RHEL/CentOS. Installing sshpass openssh-clients via yum..."
|
||||||
|
yum install -y sshpass openssh-clients
|
||||||
|
elif command -v dnf &> /dev/null; then
|
||||||
|
echo "Detected Fedora/RHEL8+. Installing sshpass openssh-clients via dnf..."
|
||||||
|
dnf install -y sshpass openssh-clients
|
||||||
|
elif command -v zypper &> /dev/null; then
|
||||||
|
echo "Detected OpenSUSE. Installing sshpass openssh via zypper..."
|
||||||
|
zypper install -y sshpass openssh
|
||||||
|
else
|
||||||
|
echo "Error: No known package manager found. Cannot install sshpass."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Uploading artifact..."
|
||||||
|
# 使用 sshpass 传递密码 (更安全的方式是使用 key,但此处沿用 password)
|
||||||
|
export SSHPASS="${{ env.SSH_PASSWORD }}"
|
||||||
|
|
||||||
|
# 1. 检查连接并创建目录 (包含 /tmp/ci-upload 和 目标目录的准备)
|
||||||
|
sshpass -e ssh -o StrictHostKeyChecking=no -p ${{ env.SSH_PORT }} ${{ env.SSH_USER }}@${{ env.SSH_HOST }} "mkdir -p /tmp/ci-upload"
|
||||||
|
|
||||||
|
# 2. SCP 上传 (直接使用当前目录下的 site_dist.tgz,规避跨容器挂载问题)
|
||||||
|
if [ ! -f "site_dist.tgz" ]; then
|
||||||
|
echo "❌ Error: site_dist.tgz not found in current directory!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sshpass -e scp -o StrictHostKeyChecking=no -P ${{ env.SSH_PORT }} site_dist.tgz ${{ env.SSH_USER }}@${{ env.SSH_HOST }}:/tmp/ci-upload/site_dist.tgz
|
||||||
|
|
||||||
|
# 3. 解压并重启 Nginx
|
||||||
|
echo "Deploying on remote host..."
|
||||||
|
sshpass -e ssh -o StrictHostKeyChecking=no -p ${{ env.SSH_PORT }} ${{ env.SSH_USER }}@${{ env.SSH_HOST }} "
|
||||||
|
echo 'Preparing target directory ${{ env.DEPLOY_PATH }}...'
|
||||||
|
mkdir -p ${{ env.DEPLOY_PATH }}
|
||||||
|
|
||||||
|
# 切换到目录,确保操作安全
|
||||||
|
cd ${{ env.DEPLOY_PATH }} || exit 1
|
||||||
|
|
||||||
|
echo 'Cleaning up old files (preserving download/downsload)...'
|
||||||
|
|
||||||
|
# 使用更安全的策略:
|
||||||
|
# 1. 创建临时备份目录
|
||||||
|
mkdir -p /tmp/site_backup_safe
|
||||||
|
rm -rf /tmp/site_backup_safe/*
|
||||||
|
|
||||||
|
# 2. 将需要保留的文件夹移到备份目录 (如果存在)
|
||||||
|
if [ -d 'download' ]; then
|
||||||
|
echo 'Backing up download folder...'
|
||||||
|
mv download /tmp/site_backup_safe/
|
||||||
|
fi
|
||||||
|
if [ -d 'downsload' ]; then
|
||||||
|
echo 'Backing up downsload folder...'
|
||||||
|
mv downsload /tmp/site_backup_safe/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. 清空当前目录 (此时 download/downsload 已经移走,安全删除所有)
|
||||||
|
# 注意:不删除当前目录本身,只删除内容
|
||||||
|
find . -mindepth 1 -delete
|
||||||
|
|
||||||
|
# 4. 移回备份的文件夹
|
||||||
|
if [ -d '/tmp/site_backup_safe/download' ]; then
|
||||||
|
echo 'Restoring download folder...'
|
||||||
|
mv /tmp/site_backup_safe/download .
|
||||||
|
fi
|
||||||
|
if [ -d '/tmp/site_backup_safe/downsload' ]; then
|
||||||
|
echo 'Restoring downsload folder...'
|
||||||
|
mv /tmp/site_backup_safe/downsload .
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. 清理备份目录
|
||||||
|
rm -rf /tmp/site_backup_safe
|
||||||
|
|
||||||
|
echo 'Extracting to ${{ env.DEPLOY_PATH }}...'
|
||||||
|
# 解压覆盖
|
||||||
|
tar -xzf /tmp/ci-upload/site_dist.tgz -C ${{ env.DEPLOY_PATH }}
|
||||||
|
|
||||||
|
echo 'Reloading Nginx...'
|
||||||
|
# 尝试多种 reload 方式
|
||||||
|
nginx -s reload || systemctl reload nginx || echo 'Warning: Nginx reload returned non-zero'
|
||||||
|
|
||||||
|
echo 'Cleanup...'
|
||||||
|
rm -f /tmp/ci-upload/site_dist.tgz
|
||||||
|
"
|
||||||
|
echo "✅ Deployment complete!"
|
||||||
|
|
||||||
|
|
||||||
|
# 步骤6: TG通知 (成功)
|
||||||
|
- name: 📱 发送成功通知到Telegram
|
||||||
|
if: success()
|
||||||
|
uses: appleboy/telegram-action@master
|
||||||
|
with:
|
||||||
|
token: ${{ env.TG_BOT_TOKEN }}
|
||||||
|
to: ${{ env.TG_CHAT_ID }}
|
||||||
|
message: |
|
||||||
|
✅ 部署成功!
|
||||||
|
|
||||||
|
📦 项目: ${{ github.repository }}
|
||||||
|
🌿 分支: ${{ github.ref_name }}
|
||||||
|
📝 提交: ${{ github.sha }}
|
||||||
|
👤 提交者: ${{ github.actor }}
|
||||||
|
🕐 时间: ${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
|
🚀 服务已成功部署到生产环境
|
||||||
|
parse_mode: Markdown
|
||||||
|
|
||||||
|
# 步骤5: TG通知 (失败)
|
||||||
|
- name: 📱 发送失败通知到Telegram
|
||||||
|
if: failure()
|
||||||
|
uses: appleboy/telegram-action@master
|
||||||
|
with:
|
||||||
|
token: ${{ env.TG_BOT_TOKEN }}
|
||||||
|
to: ${{ env.TG_CHAT_ID }}
|
||||||
|
message: |
|
||||||
|
❌ 部署失败!
|
||||||
|
|
||||||
|
📦 项目: ${{ github.repository }}
|
||||||
|
🌿 分支: ${{ github.ref_name }}
|
||||||
|
📝 提交: ${{ github.sha }}
|
||||||
|
👤 提交者: ${{ github.actor }}
|
||||||
|
🕐 时间: ${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
|
⚠️ 请检查构建日志获取详细信息
|
||||||
|
parse_mode: Markdown
|
||||||
|
|
||||||
133
scripts/ci-build.sh
Normal file
133
scripts/ci-build.sh
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 统一构建脚本 (CI Build Script)
|
||||||
|
# 功能:自动检测环境、安装 Node.js (不依赖系统预装)、构建项目、打包产物
|
||||||
|
# 解决:Runner 环境缺失 Node/Docker/Python 等工具导致的问题
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
# 配置节点版本
|
||||||
|
NODE_VERSION="20.10.0"
|
||||||
|
DIST_FILE="site_dist.tgz"
|
||||||
|
|
||||||
|
echo ">>> [Init] Starting CI Build Script..."
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 1. 基础工具检测与安装 (curl, tar, xz)
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
ensure_tools() {
|
||||||
|
echo ">>> [Tools] Checking basic tools..."
|
||||||
|
local missing_tools=()
|
||||||
|
|
||||||
|
for tool in curl tar xz; do
|
||||||
|
if ! command -v "$tool" &> /dev/null; then
|
||||||
|
missing_tools+=("$tool")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${#missing_tools[@]} -eq 0 ]; then
|
||||||
|
echo " All tools present."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Missing tools: ${missing_tools[*]}. Attempting installation..."
|
||||||
|
|
||||||
|
if command -v apk &> /dev/null; then
|
||||||
|
apk add --no-cache curl tar xz
|
||||||
|
elif command -v apt-get &> /dev/null; then
|
||||||
|
apt-get update && apt-get install -y curl tar xz-utils
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
yum install -y curl tar xz
|
||||||
|
elif command -v dnf &> /dev/null; then
|
||||||
|
dnf install -y curl tar xz
|
||||||
|
elif command -v zypper &> /dev/null; then
|
||||||
|
zypper install -y curl tar xz
|
||||||
|
else
|
||||||
|
echo "!!! Error: Cannot install missing tools. No known package manager found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 2. 环境安装 (System Node.js - Most Reliable on Alpine)
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
install_env() {
|
||||||
|
echo ">>> [Env] Setting up System Node.js environment..."
|
||||||
|
|
||||||
|
# 尝试使用系统包管理器安装 Node.js 和 npm
|
||||||
|
if command -v apk &> /dev/null; then
|
||||||
|
echo " Detected Alpine Linux. Installing nodejs and npm via apk..."
|
||||||
|
apk add --no-cache nodejs npm
|
||||||
|
elif command -v apt-get &> /dev/null; then
|
||||||
|
echo " Detected Debian/Ubuntu. Installing nodejs and npm via apt..."
|
||||||
|
apt-get update && apt-get install -y nodejs npm
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
yum install -y nodejs npm
|
||||||
|
elif command -v dnf &> /dev/null; then
|
||||||
|
dnf install -y nodejs npm
|
||||||
|
elif command -v zypper &> /dev/null; then
|
||||||
|
zypper install -y nodejs npm
|
||||||
|
else
|
||||||
|
echo "!!! Warning: No package manager found. Checking if Node is pre-installed..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 验证安装
|
||||||
|
if ! command -v node &> /dev/null; then
|
||||||
|
echo "!!! Error: Node.js not found and could not be installed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v npm &> /dev/null; then
|
||||||
|
echo "!!! Error: npm not found and could not be installed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Node version: $(node -v)"
|
||||||
|
echo " npm version: $(npm -v)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 3. 项目构建与打包
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
build_project() {
|
||||||
|
echo ">>> [Build] Starting project build..."
|
||||||
|
|
||||||
|
# 注入环境变量
|
||||||
|
if [ -n "$VITE_APP_BASE_URL" ]; then
|
||||||
|
echo " Setting VITE_APP_BASE_URL=${VITE_APP_BASE_URL}"
|
||||||
|
# 兼容 package.json 中的 mode: pord (Typo in original project)
|
||||||
|
echo "VITE_APP_BASE_URL=${VITE_APP_BASE_URL}" > .env.pord
|
||||||
|
# 同时写入 .env 以防万一
|
||||||
|
echo "VITE_APP_BASE_URL=${VITE_APP_BASE_URL}" >> .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Installing dependencies..."
|
||||||
|
# 使用 npm install 而不是 npm ci,以避免因 lockfile 版本不匹配或 engines 检查导致的失败
|
||||||
|
npm install --no-audit --progress=false
|
||||||
|
|
||||||
|
echo " Building..."
|
||||||
|
# 使用 package.json 中定义的 build:prod 命令
|
||||||
|
npm run build:prod
|
||||||
|
|
||||||
|
echo ">>> [Package] Compressing artifacts..."
|
||||||
|
if [ ! -d "dist" ]; then
|
||||||
|
echo "!!! Error: 'dist' directory not found after build."
|
||||||
|
# 列出当前目录以便调试
|
||||||
|
ls -la
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 直接打包 dist 目录下的内容
|
||||||
|
tar -C dist -czf "$DIST_FILE" .
|
||||||
|
|
||||||
|
echo " Success! Artifact created: $DIST_FILE"
|
||||||
|
ls -lh "$DIST_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# Main Execution Flow
|
||||||
|
# ==========================================
|
||||||
|
ensure_tools
|
||||||
|
install_env
|
||||||
|
build_project
|
||||||
Loading…
x
Reference in New Issue
Block a user