diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..8b0302a --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,244 @@ +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 "✅ 正式环境已更新" diff --git a/.gitignore b/.gitignore index cff34d8..29239f5 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ config.php !/deploy/ !/tests/ !/src/ +!/.gitea/