name: CI/CD Pipeline on: push: branches: - main - 'feature/*' - 'develop' pull_request: branches: - main env: DEPLOY_HOST: micecola.top DEPLOY_USER: root TEST_DIR: /www/wwwroot/kb-web-test PROD_DIR: /www/wwwroot/kb-web jobs: # ==================== 测试环境部署 ==================== deploy-test: runs-on: ubuntu-latest if: github.ref != 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Deploy to test environment uses: appleboy/ssh-action@v1 with: host: ${{ env.DEPLOY_HOST }} username: ${{ env.DEPLOY_USER }} key: ${{ secrets.DEPLOY_KEY }} script: | mkdir -p ${{ env.TEST_DIR }} cd ${{ env.TEST_DIR }} # 备份需要保留的文件 BACKUP_DIR="/tmp/kb-web-backup-$$" mkdir -p $BACKUP_DIR [ -f config.php ] && cp config.php $BACKUP_DIR/ for dir in */; do if [ -d "$dir" ] && [ "$dir" != "demo/" ]; then cp -r "$dir" $BACKUP_DIR/ 2>/dev/null || true fi done # 部署代码 if [ -d .git ]; then git fetch origin git checkout ${{ github.ref_name }} 2>/dev/null || git checkout -b ${{ github.ref_name }} origin/${{ github.ref_name }} git reset --hard origin/${{ github.ref_name }} # 清理未跟踪的文件(保留 .git 和备份目录) git clean -fd else git clone -b ${{ github.ref_name }} ssh://gitea-external/starmen1265/kb-web.git . fi # 恢复配置和用户数据 [ -f $BACKUP_DIR/config.php ] && cp $BACKUP_DIR/config.php . && chown www:www config.php for dir in $BACKUP_DIR/*/; do dirname=$(basename "$dir") if [ "$dirname" != "demo" ] && [ "$dirname" != "deploy" ] && [ "$dirname" != "tests" ]; then cp -r "$dir" . 2>/dev/null || true fi done rm -rf $BACKUP_DIR chown -R www:www ${{ env.TEST_DIR }} 2>/dev/null || true echo "✅ 测试环境部署完成" - name: Notify deployment run: echo "✅ 测试环境: http://${{ env.DEPLOY_HOST }}:8081" # ==================== 运行测试 ==================== test: runs-on: ubuntu-latest needs: deploy-test if: github.ref != 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' extensions: mbstring, xml, mysql - name: Install dependencies run: composer install --prefer-dist --no-progress || true - name: Run tests run: | if [ -f "vendor/bin/phpunit" ]; then ./vendor/bin/phpunit --testdox || exit 1 else echo "执行 PHP 语法检查..." for f in index.php dashboard.php view.php; do php -l $f done echo "✅ 检查通过" fi # ==================== 回退(测试失败时) ==================== rollback: runs-on: ubuntu-latest needs: test if: failure() steps: - name: Rollback test environment uses: appleboy/ssh-action@v1 with: host: ${{ env.DEPLOY_HOST }} username: ${{ env.DEPLOY_USER }} key: ${{ secrets.DEPLOY_KEY }} script: | cd ${{ env.TEST_DIR }} git reset --hard HEAD~1 echo "🔄 已回退" - name: Notify failure run: echo "❌ 测试失败,已回退" # ==================== 自动合并到 main ==================== auto-merge: runs-on: ubuntu-latest needs: test if: success() && startsWith(github.ref, 'refs/heads/feature/') steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.GITEA_TOKEN }} - name: Configure git run: | git config user.name "CI Bot" git config user.email "ci-bot@micecola.top" - name: Merge to main run: | git checkout main git pull origin main git merge --no-ff ${{ github.ref_name }} -m "Merge ${{ github.ref_name }} into main [skip ci]" git push origin main - name: Notify merge run: echo "✅ 已合并到 main" # ==================== 正式环境部署 ==================== deploy-prod: runs-on: ubuntu-latest needs: auto-merge if: success() steps: - name: Backup and deploy uses: appleboy/ssh-action@v1 with: host: ${{ env.DEPLOY_HOST }} username: ${{ env.DEPLOY_USER }} key: ${{ secrets.DEPLOY_KEY }} script: | cd ${{ env.PROD_DIR }} # 备份 BACKUP_DIR="/www/backup/kb-web" mkdir -p $BACKUP_DIR TIMESTAMP=$(date +%Y%m%d_%H%M%S) tar -czf $BACKUP_DIR/backup_$TIMESTAMP.tar.gz --exclude='.git' . 2>/dev/null || true cd $BACKUP_DIR && ls -t | tail -n +6 | xargs rm -f 2>/dev/null || true # 备份配置和用户数据 TEMP_DIR="/tmp/kb-web-prod-$$" mkdir -p $TEMP_DIR cd ${{ env.PROD_DIR }} [ -f config.php ] && cp config.php $TEMP_DIR/ for dir in */; do if [ -d "$dir" ] && [ "$dir" != "demo/" ]; then cp -r "$dir" $TEMP_DIR/ 2>/dev/null || true fi done # 部署 cd ${{ env.PROD_DIR }} git fetch origin git reset --hard origin/main git clean -fd # 恢复配置和用户数据 [ -f $TEMP_DIR/config.php ] && cp $TEMP_DIR/config.php . && chown www:www config.php for dir in $TEMP_DIR/*/; do dirname=$(basename "$dir") if [ "$dirname" != "demo" ] && [ "$dirname" != "deploy" ] && [ "$dirname" != "tests" ]; then cp -r "$dir" . 2>/dev/null || true fi done rm -rf $TEMP_DIR chown -R www:www ${{ env.PROD_DIR }} 2>/dev/null || true echo "✅ 正式环境部署完成" # ==================== main 分支直接部署 ==================== direct-deploy: runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Deploy to production uses: appleboy/ssh-action@v1 with: host: ${{ env.DEPLOY_HOST }} username: ${{ env.DEPLOY_USER }} key: ${{ secrets.DEPLOY_KEY }} script: | cd ${{ env.PROD_DIR }} # 备份配置和用户数据 TEMP_DIR="/tmp/kb-web-prod-$$" mkdir -p $TEMP_DIR [ -f config.php ] && cp config.php $TEMP_DIR/ for dir in */; do if [ -d "$dir" ] && [ "$dir" != "demo/" ]; then cp -r "$dir" $TEMP_DIR/ 2>/dev/null || true fi done # 部署 git fetch origin git reset --hard origin/main git clean -fd # 恢复配置和用户数据 [ -f $TEMP_DIR/config.php ] && cp $TEMP_DIR/config.php . && chown www:www config.php for dir in $TEMP_DIR/*/; do dirname=$(basename "$dir") if [ "$dirname" != "demo" ] && [ "$dirname" != "deploy" ] && [ "$dirname" != "tests" ]; then cp -r "$dir" . 2>/dev/null || true fi done rm -rf $TEMP_DIR chown -R www:www ${{ env.PROD_DIR }} 2>/dev/null || true echo "✅ 正式环境已更新"