ci: add GitHub Actions CI/CD workflows and deploy scripts

feature/20260628/refactor-frontend-modernization
Lxy 3 weeks ago
parent e5cbd477be
commit 780e85bde4

@ -0,0 +1,93 @@
name: Backend CI
on:
push:
branches: [ main, develop, feature/** ]
paths:
- 'pom.xml'
- 'ruoyi-*/**'
- 'book-system/**'
pull_request:
branches: [ main, develop ]
paths:
- 'pom.xml'
- 'ruoyi-*/**'
- 'book-system/**'
jobs:
build:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ry-vue
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
cache: maven
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: mvn clean compile -DskipTests
- name: Run Checkstyle
run: mvn checkstyle:checkstyle
continue-on-error: true
- name: Run tests
run: mvn test
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: '**/surefire-reports/*.xml'
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
files: '**/jacoco.xml'
fail_ci_if_error: false
- name: Package application
run: mvn package -DskipTests
- name: Upload JAR
uses: actions/upload-artifact@v4
with:
name: ruoyi-admin
path: ruoyi-admin/target/*.jar

@ -0,0 +1,125 @@
name: Full CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
# 后端构建
backend:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ry-vue
ports:
- 3306:3306
redis:
image: redis:7
ports:
- 6379:6379
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
cache: maven
- name: Build and test
run: mvn clean verify
- name: Package
run: mvn package -DskipTests
- name: Upload JAR
uses: actions/upload-artifact@v4
with:
name: backend-jar
path: ruoyi-admin/target/*.jar
# 前端构建
frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ruoyi-ui-next
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: ruoyi-ui-next/package-lock.json
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Build
run: npm run build
- name: Upload dist
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: ruoyi-ui-next/dist/
# 集成测试
integration-test:
needs: [backend, frontend]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download backend JAR
uses: actions/download-artifact@v4
with:
name: backend-jar
- name: Download frontend dist
uses: actions/download-artifact@v4
with:
name: frontend-dist
- name: Run integration tests
run: |
echo "Integration tests would run here"
echo "Backend JAR and Frontend dist are available"
# 部署(仅 main 分支)
deploy:
needs: [backend, frontend, integration-test]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Deploy to server
run: |
echo "Deploy scripts would run here"
echo "In production, use SSH or deployment tools"
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}

@ -0,0 +1,56 @@
name: Frontend CI
on:
push:
branches: [ main, develop, feature/** ]
paths:
- 'ruoyi-ui-next/**'
pull_request:
branches: [ main, develop ]
paths:
- 'ruoyi-ui-next/**'
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ruoyi-ui-next
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: ruoyi-ui-next/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
continue-on-error: true
- name: Type check
run: npx vue-tsc --noEmit
continue-on-error: true
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: ruoyi-ui-next/dist/
- name: Upload coverage reports
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ruoyi-ui-next/coverage/

@ -0,0 +1,13 @@
FROM eclipse-temurin:11-jre
LABEL maintainer="ruoyi"
WORKDIR /app
COPY ruoyi-admin/target/*.jar app.jar
EXPOSE 8080
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Dspring.profiles.active=prod"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

@ -0,0 +1,48 @@
version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ry-vue
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./sql:/docker-entrypoint-initdb.d
command: --default-authentication-plugin=mysql_native_password
redis:
image: redis:7
ports:
- "6379:6379"
volumes:
- redis-data:/data
backend:
build: .
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
SPRING_REDIS_HOST: redis
depends_on:
- mysql
- redis
frontend:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./ruoyi-ui-next/dist:/usr/share/nginx/html
- ./scripts/deploy/nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend
volumes:
mysql-data:
redis-data:

@ -0,0 +1,101 @@
#!/bin/bash
# ============================================
# RuoYi-Vue 后端部署脚本
# 使用方式: ./scripts/deploy/backend-deploy.sh
# ============================================
set -e
# 配置
APP_NAME="ruoyi-admin"
DEPLOY_DIR="/opt/ruoyi"
JAR_FILE="${DEPLOY_DIR}/${APP_NAME}.jar"
BACKUP_DIR="${DEPLOY_DIR}/backup"
LOG_DIR="${DEPLOY_DIR}/logs"
PID_FILE="${DEPLOY_DIR}/${APP_NAME}.pid"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
echo_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
echo_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 JAR 文件
if [ ! -f "$1" ]; then
echo_error "JAR 文件不存在: $1"
exit 1
fi
echo_info "========================================"
echo_info "RuoYi-Vue 后端部署"
echo_info "========================================"
# 创建目录
mkdir -p $DEPLOY_DIR $BACKUP_DIR $LOG_DIR
# 备份现有版本
if [ -f "$JAR_FILE" ]; then
echo_info "备份现有版本..."
cp $JAR_FILE ${BACKUP_DIR}/${APP_NAME}-$(date +%Y%m%d_%H%M%S).jar
fi
# 停止现有服务
if [ -f "$PID_FILE" ]; then
PID=$(cat $PID_FILE)
if ps -p $PID > /dev/null 2>&1; then
echo_info "停止现有服务 (PID: $PID)..."
kill $PID
sleep 5
# 强制停止
if ps -p $PID > /dev/null 2>&1; then
echo_warn "服务未正常停止,强制终止..."
kill -9 $PID
fi
fi
fi
# 部署新版本
echo_info "部署新版本..."
cp $1 $JAR_FILE
# 启动服务
echo_info "启动服务..."
nohup java -jar \
-Dspring.profiles.active=prod \
-Xms512m -Xmx1024m \
$JAR_FILE \
> ${LOG_DIR}/app.log 2>&1 &
echo $! > $PID_FILE
echo_info "服务已启动 (PID: $(cat $PID_FILE))"
# 等待启动
echo_info "等待服务启动..."
sleep 10
# 健康检查
if curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then
echo_info "✅ 部署成功!服务运行正常"
else
echo_error "❌ 部署失败!服务未正常启动"
echo_error "请查看日志: tail -f ${LOG_DIR}/app.log"
exit 1
fi
echo_info "========================================"
echo_info "部署完成"
echo_info "日志: ${LOG_DIR}/app.log"
echo_info "========================================"

@ -0,0 +1,54 @@
#!/bin/bash
# ============================================
# RuoYi-Vue 前端部署脚本
# 使用方式: ./scripts/deploy/frontend-deploy.sh <dist-dir>
# ============================================
set -e
# 配置
DEPLOY_DIR="/usr/share/nginx/html/ruoyi-ui"
BACKUP_DIR="/usr/share/nginx/html/backup"
NGINX_CONF="/etc/nginx/conf.d/ruoyi-ui.conf"
echo_info() {
echo -e "\033[0;32m[INFO]\033[0m $1"
}
echo_error() {
echo -e "\033[0;31m[ERROR]\033[0m $1"
}
if [ ! -d "$1" ]; then
echo_error "构建目录不存在: $1"
exit 1
fi
echo_info "========================================"
echo_info "RuoYi-Vue 前端部署"
echo_info "========================================"
# 创建目录
mkdir -p $DEPLOY_DIR $BACKUP_DIR
# 备份现有版本
if [ -d "$DEPLOY_DIR" ] && [ "$(ls -A $DEPLOY_DIR)" ]; then
echo_info "备份现有版本..."
tar -czf ${BACKUP_DIR}/frontend-$(date +%Y%m%d_%H%M%S).tar.gz -C $(dirname $DEPLOY_DIR) $(basename $DEPLOY_DIR)
fi
# 部署新版本
echo_info "部署新版本..."
rm -rf ${DEPLOY_DIR}/*
cp -r $1/* $DEPLOY_DIR/
# 设置权限
chown -R nginx:nginx $DEPLOY_DIR
chmod -R 755 $DEPLOY_DIR
# 重新加载 Nginx
echo_info "重新加载 Nginx..."
nginx -t && systemctl reload nginx
echo_info "✅ 部署成功!"
echo_info "========================================"

@ -0,0 +1,47 @@
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /usr/share/nginx/html/ruoyi-ui;
index index.html;
try_files $uri $uri/ /index.html;
# 缓存策略
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# 后端 API 代理
location /dev-api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 后端 API 代理(生产环境)
location /prod-api/ {
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
}
Loading…
Cancel
Save