fix(web): 选股结果持久化恢复 - 新增历史记录入口并支持刷新恢复 #4295
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| changes: | |
| name: 🔎 Change Detection | |
| runs-on: ubuntu-latest | |
| outputs: | |
| backend: ${{ steps.backend-filter.outputs.backend_non_web == 'true' || steps.filter.outputs.backend_web_contract == 'true' }} | |
| docker: ${{ steps.filter.outputs.docker }} | |
| frontend: ${{ steps.filter.outputs.frontend }} | |
| futu_packaging: ${{ steps.filter.outputs.futu_packaging }} | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🧭 Filter paths | |
| id: filter | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| filters: | | |
| backend_web_contract: | |
| # Public assets are shared runtime inputs: Python loaders and | |
| # packaged deployments may consume them outside the Web app. | |
| - 'apps/dsa-web/public/**' | |
| - 'apps/dsa-web/src/components/settings/llmProviderTemplates.ts' | |
| - 'apps/dsa-web/src/locales/settingsHelp.ts' | |
| docker: | |
| - '*.py' | |
| - 'api/**' | |
| - 'bot/**' | |
| - 'data_provider/**' | |
| - 'src/**' | |
| - 'strategies/**' | |
| - 'apps/dsa-web/**' | |
| - 'docker/**' | |
| - 'requirements.txt' | |
| - '.dockerignore' | |
| - '.github/workflows/ci.yml' | |
| frontend: | |
| - 'apps/dsa-web/**' | |
| futu_packaging: | |
| - 'requirements.txt' | |
| - 'main.py' | |
| - 'src/brokers/futu/**' | |
| - 'scripts/build-backend.ps1' | |
| - 'scripts/build-backend-macos.sh' | |
| - 'scripts/macos-signature-audit.sh' | |
| - 'scripts/build-all.ps1' | |
| - 'scripts/build-all-macos.sh' | |
| - 'apps/dsa-desktop/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/desktop-release.yml' | |
| - name: 🧭 Filter backend-safe frontend paths | |
| id: backend-filter | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| predicate-quantifier: every | |
| filters: | | |
| backend_non_web: | |
| - '**' | |
| - '!apps/dsa-web/**' | |
| ai-governance: | |
| name: ai-governance | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🐍 Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| - name: 🤖 Check AI governance assets | |
| run: python scripts/check_ai_assets.py | |
| backend-tests: | |
| name: backend-tests (${{ matrix.shard }}/3) | |
| runs-on: ubuntu-latest | |
| needs: [changes, ai-governance] | |
| if: needs.changes.outputs.backend == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: [1, 2, 3] | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🐍 Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| cache: 'pip' | |
| cache-dependency-path: | | |
| requirements.txt | |
| .github/requirements-ci.txt | |
| - name: 📦 Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| for attempt in 1 2 3; do | |
| if python -m pip install -r .github/requirements-ci.txt; then | |
| break | |
| fi | |
| if [ "$attempt" -eq 3 ]; then | |
| echo "Dependency install failed after ${attempt} attempts." >&2 | |
| exit 1 | |
| fi | |
| echo "Dependency install attempt ${attempt} failed, retrying in 15s..." >&2 | |
| sleep 15 | |
| done | |
| - name: 🔌 Verify global Futu SDK | |
| if: matrix.shard == 1 | |
| run: python -c "import futu; print('✅ futu SDK import OK')" | |
| - name: ✅ Python syntax check | |
| if: matrix.shard == 1 | |
| run: ./scripts/ci_gate.sh syntax | |
| - name: ✅ Flake8 critical checks | |
| if: matrix.shard == 1 | |
| run: ./scripts/ci_gate.sh flake8 | |
| - name: ✅ Local deterministic checks | |
| if: matrix.shard == 1 | |
| run: ./scripts/ci_gate.sh deterministic | |
| - name: ✅ Offline test suite shard ${{ matrix.shard }}/3 | |
| env: | |
| PYTEST_SPLITS: '3' | |
| PYTEST_GROUP: ${{ matrix.shard }} | |
| PYTEST_FIRST_SHARD_OVERHEAD: '20' | |
| run: ./scripts/ci_gate.sh offline-tests | |
| backend-gate: | |
| name: backend-gate | |
| runs-on: ubuntu-latest | |
| needs: [changes, ai-governance, backend-tests] | |
| if: always() | |
| steps: | |
| - name: ✅ Summarize backend gate | |
| env: | |
| CHANGES_RESULT: ${{ needs.changes.result }} | |
| AI_GOVERNANCE_RESULT: ${{ needs.ai-governance.result }} | |
| BACKEND_REQUIRED: ${{ needs.changes.outputs.backend }} | |
| BACKEND_TESTS_RESULT: ${{ needs.backend-tests.result }} | |
| run: | | |
| if [ "$CHANGES_RESULT" != "success" ] || [ "$AI_GOVERNANCE_RESULT" != "success" ]; then | |
| echo "Prerequisite failed: changes=$CHANGES_RESULT ai-governance=$AI_GOVERNANCE_RESULT" >&2 | |
| exit 1 | |
| fi | |
| if [ "$BACKEND_REQUIRED" = "true" ] && [ "$BACKEND_TESTS_RESULT" != "success" ]; then | |
| echo "Backend shards did not all pass: $BACKEND_TESTS_RESULT" >&2 | |
| exit 1 | |
| fi | |
| echo "backend-gate passed (required=$BACKEND_REQUIRED, shards=$BACKEND_TESTS_RESULT)" | |
| docker-build: | |
| name: docker-build | |
| runs-on: ubuntu-latest | |
| needs: [changes, ai-governance] | |
| if: needs.changes.outputs.docker == 'true' | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🛠️ Setup Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: 🐳 Build image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: docker/Dockerfile | |
| tags: stock-analysis:test | |
| load: true | |
| cache-from: type=gha,scope=stock-analysis-ci-docker | |
| cache-to: type=gha,mode=max,scope=stock-analysis-ci-docker,ignore-error=true | |
| - name: 🐳 Docker smoke | |
| run: docker run --rm stock-analysis:test python -c "print('✅ Docker OK')" | |
| - name: 🔍 Docker smoke imports | |
| run: | | |
| docker run --rm stock-analysis:test python -c " | |
| from src.config import get_config; print('✅ config') | |
| from src.storage import DatabaseManager; print('✅ storage') | |
| from src.notification import NotificationService; print('✅ notification') | |
| from data_provider import DataFetcherManager; print('✅ data_provider') | |
| from src.analyzer import GeminiAnalyzer; print('✅ analyzer') | |
| from src.patches.eastmoney_patch import eastmoney_patch; print('✅ patch') | |
| from bot.dispatcher import CommandDispatcher; print('✅ bot') | |
| from api.app import app; print('✅ api') | |
| import futu; print('✅ futu') | |
| print('✅ All Docker imports OK') | |
| " | |
| desktop-futu-package-windows: | |
| name: desktop-futu-package-windows | |
| runs-on: windows-latest | |
| needs: [changes, ai-governance] | |
| if: needs.changes.outputs.futu_packaging == 'true' | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🐍 Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| cache-dependency-path: requirements.txt | |
| - name: 🟢 Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/dsa-web/package-lock.json | |
| - name: 📦 Install Web dependencies | |
| shell: pwsh | |
| run: npm ci --prefix apps/dsa-web | |
| - name: 🧊 Build and verify frozen backend | |
| shell: pwsh | |
| run: powershell -ExecutionPolicy Bypass -File scripts/build-backend.ps1 | |
| desktop-futu-package-macos: | |
| name: desktop-futu-package-macos | |
| runs-on: macos-15 | |
| needs: [changes, ai-governance] | |
| if: needs.changes.outputs.futu_packaging == 'true' | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🐍 Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: 'pip' | |
| cache-dependency-path: requirements.txt | |
| - name: 🟢 Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/dsa-web/package-lock.json | |
| - name: 📦 Install Web dependencies | |
| run: npm ci --prefix apps/dsa-web | |
| - name: 🧊 Build and verify frozen backend | |
| run: bash scripts/build-backend-macos.sh | |
| - name: 📦 Build and verify unsigned desktop package | |
| run: bash scripts/build-desktop-macos.sh | |
| web-gate: | |
| name: web-gate | |
| runs-on: ubuntu-latest | |
| needs: [changes, ai-governance] | |
| if: needs.changes.outputs.frontend == 'true' | |
| defaults: | |
| run: | |
| working-directory: apps/dsa-web | |
| steps: | |
| - name: 📥 Checkout | |
| uses: actions/checkout@v5 | |
| - name: 🟢 Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: apps/dsa-web/package-lock.json | |
| - name: 📦 Install | |
| run: npm ci | |
| - name: 🔎 Lint | |
| run: npm run lint | |
| - name: 🏗️ Build | |
| run: npm run build |