diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index bec082412..e5aad63db 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -33,7 +33,43 @@ concurrency: group: ci-cd-${{ gitea.event_name }}-${{ gitea.ref }} cancel-in-progress: true jobs: + check-frontend-only: + name: Check if frontend-only change + runs-on: ci-l1 + if: github.event_name == 'pull_request' + outputs: + skip_backend: ${{ steps.check.outputs.skip_backend }} + steps: + - name: Checkout code + shell: sh + env: + GITHUB_TOKEN: ${{ github.token }} + run: "set -eu\npython3 - <<'PY'\nimport io, os, tarfile, time, urllib.request, urllib.error\nurl = f\"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz\"\nrequest = urllib.request.Request(url, headers={\"Authorization\": f\"token {os.environ['GITHUB_TOKEN']}\"})\nlast_err = None\nfor attempt in range(5):\n try:\n with urllib.request.urlopen(request, timeout=120) as response:\n archive = response.read()\n break\n except urllib.error.HTTPError as e:\n last_err = e\n if e.code >= 500 and attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\n except Exception as e:\n last_err = e\n if attempt < 4:\n wait = 2 ** attempt\n print(f\"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...\")\n time.sleep(wait)\n continue\n raise\nelse:\n raise last_err\nwith tarfile.open(fileobj=io.BytesIO(archive), mode='r:gz') as tar:\n root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/'\n for member in tar.getmembers():\n name = member.name\n if name == root_prefix[:-1]:\n continue\n if name.startswith(root_prefix):\n member.name = name[len(root_prefix):]\n if member.name:\n tar.extract(member, '.')\nPY\n" + - name: Check changed files + id: check + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + set -eu + PR_NUMBER=$(echo "$GITHUB_REF" | sed 's|refs/pull/||; s|/.*||') + API_URL="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/files?limit=300" + FILES=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "$API_URL" | python3 -c "import sys,json; [print(f['filename']) for f in json.load(sys.stdin)]") + FRONTEND_COUNT=$(echo "$FILES" | grep -c '^apps/web/' || true) + BACKEND_COUNT=$(echo "$FILES" | grep -cv '^apps/web/' || true) + TOTAL=$(echo "$FILES" | grep -cv '^$' || true) + echo "变更文件: ${TOTAL} 个 (前端: ${FRONTEND_COUNT}, 后端/公共: ${BACKEND_COUNT})" + if [ "$BACKEND_COUNT" = "0" ] && [ "$FRONTEND_COUNT" -gt "0" ]; then + echo "skip_backend=true" >> $GITHUB_OUTPUT + echo "✅ 纯前端改动,跳过后端检查" + else + echo "skip_backend=false" >> $GITHUB_OUTPUT + echo "🔧 包含后端/公共变更,运行完整CI" + fi + validate: + needs: check-frontend-only + if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' name: Validate Code Quality And Tests runs-on: ci-l1 timeout-minutes: 10 @@ -190,6 +226,8 @@ jobs: ' unit-tests: + needs: check-frontend-only + if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' name: Unit Tests runs-on: ci-l2 timeout-minutes: 8 @@ -264,8 +302,10 @@ jobs: name: Integration Tests runs-on: ci-l2 timeout-minutes: 30 - if: always() - needs: validate + if: always() && needs.check-frontend-only.outputs.skip_backend != 'true' + needs: + - check-frontend-only + - validate env: DATABASE_URL: postgresql+psycopg://postgres:postgres@127.0.0.1:5432/xiaoxia_saas USE_IN_MEMORY_DB: 'false'