refactor: 统一多前端工程架构、插件配置与 CI (#131)

* refactor: 重构项目架构

* refactor: 重构ci和测试

* fix: 修复测试

* feat: 新增更多E2E测试

* fix: 修复E2E测试
This commit is contained in:
insistence
2026-10-10 21:15:22 +08:00
committed by GitHub
parent 4bd83bc7cd
commit 025b0822df
1167 changed files with 94684 additions and 5231 deletions
-64
View File
@@ -1,64 +0,0 @@
name: Backend Tests
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
pytest:
runs-on: ubuntu-latest
env:
# Typer otherwise forces ANSI help output when GITHUB_ACTIONS is set.
_TYPER_FORCE_DISABLE_TERMINAL: "1"
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: |
ruoyi-fastapi-backend/requirements.txt
ruoyi-fastapi-backend/plugins/ai/plugin.yaml
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt pytest pytest-asyncio aiosqlite
- name: Install AI plugin dependencies
run: |
pip install \
agno==2.8.6 \
anthropic==0.120.2 \
cerebras-cloud-sdk==1.91.0 \
cohere==7.0.8 \
google-genai==2.16.0 \
groq==1.6.0 \
litellm==1.94.0 \
llama-api-client==0.6.0 \
mistralai==2.8.0 \
ollama==0.6.2 \
openai==2.52.0 \
portkey-ai==2.3.4
- name: Run backend tests
run: pytest -q
- name: Check timezone behavior under independent host timezones
run: |
for zone in UTC Asia/Shanghai America/New_York; do
TZ="$zone" python -m pytest -q tests/common/test_types.py tests/common/test_query_time.py tests/utils/test_time_util.py tests/config/test_scheduler_database.py tests/utils/test_cron_util.py tests/module_admin/controller/test_job_controller.py tests/config/test_scheduler_job_persistence.py
done
+110
View File
@@ -0,0 +1,110 @@
name: CI / Backend
on:
workflow_call:
permissions:
contents: read
env:
_TYPER_FORCE_DISABLE_TERMINAL: '1'
PYTHONUTF8: '1'
jobs:
unit-contract:
name: Python ${{ matrix.python }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python: ['3.10', '3.11', '3.12', '3.13']
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: |
ruoyi-fastapi-backend/requirements*.txt
ruoyi-fastapi-backend/plugins/ai/plugin.yaml
- name: Install test dependencies
run: python -m pip install -r requirements.txt -r requirements-test.txt
- name: Install AI plugin dependencies from its manifest
run: python ../.github/scripts/install_ai_test_dependencies.py
- name: Run backend unit and contract tests
run: python -m pytest tests -q -m 'not browser and not native and not integration' --strict-markers --durations=20 --junitxml=target/ci/backend.xml
- name: Verify tests were executed
run: python ../.github/scripts/check_test_report.py target/ci/backend.xml --allow-skips
- uses: actions/upload-artifact@v6
if: always()
with:
name: backend-python-${{ matrix.python }}
path: ruoyi-fastapi-backend/target/ci/
retention-days: 7
windows-contract:
name: Windows CLI and paths
runs-on: windows-latest
timeout-minutes: 20
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- run: python -m pip install -r requirements.txt -r requirements-test.txt
- name: Verify CLI, paths, artifacts and portable runtime contracts
run: >-
python -m pytest tests/cli
tests/plugins/core/test_frontend_layout.py tests/plugins/core/validation/test_frontend_dependencies.py
tests/plugins/core/native tests/plugins/core/runtime/test_host_services.py tests/plugins/core/runtime/test_job_dispatcher.py
tests/plugins/core/artifacts tests/plugins/core/deployment
tests/plugins/core/management/test_release_dao.py tests/plugins/core/management/test_artifact_views.py
tests/module_plugin/controller/test_plugin_release_controller.py tests/sql/test_plugin_release_schema.py
tests/plugins/examples/test_task_demo.py
-m 'not native and not browser and not integration' -q --strict-markers --durations=15 --junitxml=target/ci/windows-contract.xml
- run: python ../.github/scripts/check_test_report.py target/ci/windows-contract.xml --allow-skips
- uses: actions/upload-artifact@v6
if: always()
with:
name: backend-windows-contract
path: ruoyi-fastapi-backend/target/ci/
retention-days: 7
timezone:
name: Host timezone contracts
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- run: python -m pip install -r requirements.txt -r requirements-test.txt
- name: Verify UTC, Shanghai and New York in separate processes
shell: bash
run: |
for zone in UTC Asia/Shanghai America/New_York; do
report="target/ci/timezone-${zone//\//_}.xml"
TZ="$zone" python -m pytest -q tests/common/test_types.py tests/common/test_query_time.py tests/utils/test_time_util.py tests/config/test_scheduler_database.py tests/utils/test_cron_util.py tests/module_admin/controller/test_job_controller.py tests/config/test_scheduler_job_persistence.py --junitxml="$report"
python ../.github/scripts/check_test_report.py "$report"
done
- uses: actions/upload-artifact@v6
if: always()
with:
name: backend-timezones
path: ruoyi-fastapi-backend/target/ci/
retention-days: 7
+111
View File
@@ -0,0 +1,111 @@
name: CI / E2E
on:
workflow_call:
inputs:
matrix_json:
type: string
required: true
permissions:
contents: read
jobs:
browser:
name: ${{ matrix.framework }} / ${{ matrix.database }} / Python ${{ matrix.python }}
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix: ${{ fromJSON(inputs.matrix_json) }}
env:
COMPOSE_PROJECT_NAME: ruoyi-ci-${{ github.run_id }}-${{ github.run_attempt }}-${{ strategy.job-index }}
COMPOSE_FILE: ${{ github.workspace }}/ruoyi-fastapi-test/target/e2e/compose.json
FRONTEND_FRAMEWORK: ${{ matrix.framework }}
E2E_OUTPUT_DIR: ${{ github.workspace }}/ruoyi-fastapi-test/target/e2e/browser
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: ruoyi-fastapi-test/requirements.txt
- name: Install test runner and Chromium
run: |
python -m pip install -r ruoyi-fastapi-test/requirements.txt
python -m playwright install --with-deps chromium
- name: Verify reusable browser and isolated contexts
working-directory: ruoyi-fastapi-test
run: |
python -m pytest -m harness -q --junitxml=target/e2e/harness.xml
python ../.github/scripts/check_test_report.py target/e2e/harness.xml
- name: Generate isolated Compose project
run: |
python ruoyi-fastapi-test/prepare_e2e_compose.py \
--database '${{ matrix.database }}' --framework '${{ matrix.framework }}' \
--python-version '${{ matrix.python }}' --project "$COMPOSE_PROJECT_NAME" \
--output "$COMPOSE_FILE"
docker compose config --quiet
- uses: docker/setup-buildx-action@v3
- name: Build frontend with reusable layers
uses: docker/build-push-action@v6
with:
context: ruoyi-fastapi-frontend/${{ matrix.framework }}/web
file: ruoyi-fastapi-frontend/${{ matrix.framework }}/web/Dockerfile
load: true
tags: ${{ env.COMPOSE_PROJECT_NAME }}-ruoyi-frontend:ci
cache-from: type=gha,scope=e2e-frontend-${{ matrix.framework }}
cache-to: type=gha,scope=e2e-frontend-${{ matrix.framework }},mode=max
- name: Select database Dockerfile
id: database
env:
DATABASE: ${{ matrix.database }}
run: |
if [ "$DATABASE" = mysql ]; then
echo 'suffix=my' >> "$GITHUB_OUTPUT"
else
echo 'suffix=pg' >> "$GITHUB_OUTPUT"
fi
- name: Build backend with reusable layers
uses: docker/build-push-action@v6
with:
context: ruoyi-fastapi-backend
file: ruoyi-fastapi-backend/Dockerfile.${{ steps.database.outputs.suffix }}
load: true
tags: ${{ env.COMPOSE_PROJECT_NAME }}-ruoyi-backend-${{ steps.database.outputs.suffix }}:ci
build-args: |
PYTHON_VERSION=${{ matrix.python }}
PIP_INDEX_URL=https://pypi.org/simple
cache-from: type=gha,scope=e2e-backend-${{ matrix.database }}-py${{ matrix.python }}
cache-to: type=gha,scope=e2e-backend-${{ matrix.database }}-py${{ matrix.python }},mode=max
- name: Wait for healthy database, API and frontend proxy
run: |
docker compose up --detach --no-build --wait --wait-timeout 240
echo "TEST_FRONTEND_URL=http://$(docker compose port ruoyi-frontend 80)" >> "$GITHUB_ENV"
echo "TEST_BACKEND_URL=http://$(docker compose port ruoyi-backend-${{ steps.database.outputs.suffix }} 9099)" >> "$GITHUB_ENV"
- name: Run all application pages and functional E2E checks
working-directory: ruoyi-fastapi-test
run: |
python -m pytest -m e2e -v --durations=20 --junitxml=target/e2e/junit.xml
python ../.github/scripts/check_test_report.py target/e2e/junit.xml
- name: Collect service diagnostics
if: always()
run: |
mkdir -p ruoyi-fastapi-test/target/e2e
if [ -f "$COMPOSE_FILE" ]; then
docker compose ps --all > ruoyi-fastapi-test/target/e2e/services.txt 2>&1 || true
docker compose logs --no-color --timestamps > ruoyi-fastapi-test/target/e2e/services.log 2>&1 || true
fi
- name: Remove only this test project's containers and data
if: always()
run: |
if [ -f "$COMPOSE_FILE" ]; then
docker compose down --volumes --remove-orphans --timeout 20
fi
- uses: actions/upload-artifact@v6
if: always()
with:
name: e2e-${{ matrix.framework }}-${{ matrix.database }}-py${{ matrix.python }}
path: ruoyi-fastapi-test/target/e2e
retention-days: 7
if-no-files-found: warn
+116
View File
@@ -0,0 +1,116 @@
name: CI / Frontend
on:
workflow_call:
inputs:
matrix_json:
description: 'JSON matrix with framework and target entries under include'
required: true
type: string
full:
description: 'Reserved for callers requesting the full project matrix'
required: false
default: false
type: boolean
permissions:
contents: read
jobs:
frontend:
name: ${{ matrix.framework }} / ${{ matrix.target }}
runs-on: ubuntu-latest
timeout-minutes: 35
strategy:
fail-fast: false
matrix: ${{ fromJSON(inputs.matrix_json) }}
env:
NODE_OPTIONS: ${{ matrix.framework == 'vue2' && '--openssl-legacy-provider' || '' }}
defaults:
run:
working-directory: ruoyi-fastapi-frontend/${{ matrix.framework }}/${{ matrix.target }}
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: '22'
- name: Install the Vue 2 Mobile package manager
if: matrix.framework == 'vue2' && matrix.target == 'mobile'
run: npm install --global yarn@1.22.22
- uses: pnpm/action-setup@v5
if: matrix.framework == 'vue3' && matrix.target == 'mobile'
with:
package_json_file: ruoyi-fastapi-frontend/vue3/mobile/package.json
- name: Locate the package cache
id: package-cache
env:
FRAMEWORK: ${{ matrix.framework }}
TARGET: ${{ matrix.target }}
run: |
if [ "$TARGET" = web ]; then
echo "path=$(npm config get cache)" >> "$GITHUB_OUTPUT"
elif [ "$FRAMEWORK" = vue2 ]; then
echo "path=$(yarn cache dir --silent)" >> "$GITHUB_OUTPUT"
else
echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
fi
- uses: actions/cache@v5
with:
path: ${{ steps.package-cache.outputs.path }}
# Lockfiles are intentionally not tracked in these projects.
key: ${{ runner.os }}-node22-${{ matrix.framework }}-${{ matrix.target }}-${{ hashFiles(format('ruoyi-fastapi-frontend/{0}/{1}/package.json', matrix.framework, matrix.target)) }}
restore-keys: |
${{ runner.os }}-node22-${{ matrix.framework }}-${{ matrix.target }}-
- name: Install Web dependencies
if: matrix.target == 'web'
run: npm install --no-audit --no-fund --package-lock=false
- name: Install Vue 2 Mobile dependencies
if: matrix.framework == 'vue2' && matrix.target == 'mobile'
run: yarn install --non-interactive
- name: Install Vue 3 Mobile dependencies
if: matrix.framework == 'vue3' && matrix.target == 'mobile'
run: pnpm install --no-frozen-lockfile
- name: Run unit and component behavior tests
run: npm run test:unit
- name: Verify time contracts in three host timezones
run: |
for zone in UTC Asia/Shanghai America/New_York; do
TZ="$zone" npm run test:contract
done
- name: Verify the Vue 2 Mobile browser bundle without native Intl
if: matrix.framework == 'vue2' && matrix.target == 'mobile'
run: npm run test:bundle
- name: Build Web production and Docker targets
if: matrix.target == 'web'
run: |
npm run build:prod
npm run build:docker
- name: Build Mobile H5
if: matrix.target == 'mobile'
run: npm run build:h5
- uses: actions/setup-python@v6
if: matrix.target == 'mobile'
with:
python-version: '3.12'
- name: Install the Mobile smoke browser
if: matrix.target == 'mobile'
run: |
python -m pip install playwright==1.62.0
python -m playwright install --with-deps chromium
- name: Verify Mobile H5 login and profile
if: matrix.target == 'mobile'
working-directory: .
run: python .github/scripts/mobile_smoke.py --framework ${{ matrix.framework }}
- name: Build Mobile WeChat target
if: matrix.target == 'mobile'
run: npm run build:mp-weixin
- name: Upload frontend diagnostics
if: always()
uses: actions/upload-artifact@v6
with:
name: frontend-${{ matrix.framework }}-${{ matrix.target }}
path: |
target/ci/mobile-smoke/${{ matrix.framework }}/
ruoyi-fastapi-frontend/${{ matrix.framework }}/${{ matrix.target }}/test-results/
if-no-files-found: ignore
retention-days: 7
+218
View File
@@ -0,0 +1,218 @@
name: CI / Integration
on:
workflow_call:
inputs:
database:
type: boolean
default: false
release:
type: boolean
default: false
network_frameworks:
type: string
default: '[]'
full:
type: boolean
default: false
permissions:
contents: read
jobs:
database-timezone:
name: MySQL and PostgreSQL time contracts
if: inputs.database
runs-on: ubuntu-latest
timeout-minutes: 20
env:
TZ: America/New_York
PYTHONUTF8: '1'
defaults:
run:
working-directory: ruoyi-fastapi-backend
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: timezone_test
TZ: Asia/Shanghai
ports: ['3306:3306']
options: >-
--health-cmd="mysqladmin ping -h localhost -ptimezone_test"
--health-interval=10s --health-timeout=5s --health-retries=12
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: timezone_test
TZ: America/New_York
PGTZ: America/New_York
ports: ['5432:5432']
options: >-
--health-cmd="pg_isready -U postgres"
--health-interval=10s --health-timeout=5s --health-retries=12
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- run: python -m pip install -r requirements.txt -r requirements-pg.txt -r requirements-test.txt
- name: Configure isolated database verification
run: |
mkdir -p target/ci/timezone
python - <<'PY'
import json
from pathlib import Path
for dialect, port, username, database in [('mysql', 3306, 'root', 'mysql'), ('postgresql', 5432, 'postgres', 'postgres')]:
source = dict(db_type=dialect, db_host='127.0.0.1', db_port=port, db_username=username,
db_password='timezone_test', db_database=database)
Path(f'target/ci/timezone/{dialect}.json').write_text(json.dumps(source))
PY
- name: Verify drivers, CRUD and scheduler persistence
run: |
python -m scripts.verify_timezone_database --config target/ci/timezone/mysql.json --report target/ci/timezone/mysql-report.json
python -m scripts.verify_timezone_database --config target/ci/timezone/postgresql.json --report target/ci/timezone/postgresql-report.json
- uses: actions/upload-artifact@v6
if: always()
with:
name: integration-database-timezones
path: ruoyi-fastapi-backend/target/ci/timezone/*-report.json
retention-days: 7
task-bundle:
name: Task plugin bundle
if: inputs.release
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: ruoyi-fastapi-backend/plugins/examples/python/task_demo/web
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: ruoyi-fastapi-backend/plugins/examples/python/task_demo/web/package.json
- run: npm install --no-audit --no-fund --package-lock=false
- run: npm test
- run: npm run build
- uses: actions/upload-artifact@v6
with:
name: integration-task-bundle
path: ruoyi-fastapi-backend/plugins/examples/python/task_demo/web/dist/
if-no-files-found: error
retention-days: 1
release:
name: Plugin maintenance / Python ${{ matrix.python }}
needs: task-bundle
if: inputs.release
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python: ${{ fromJSON(inputs.full && '["3.10","3.11","3.12","3.13"]' || '["3.12"]') }}
defaults:
run:
working-directory: ruoyi-fastapi-backend
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ci-only-mysql
ports: ['3306:3306']
options: >-
--health-cmd="mysqladmin ping -h localhost -pci-only-mysql"
--health-interval=10s --health-timeout=5s --health-retries=12
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: ci-only-postgres
ports: ['5432:5432']
options: >-
--health-cmd="pg_isready -U postgres"
--health-interval=10s --health-timeout=5s --health-retries=12
redis:
image: redis:6.2
ports: ['6379:6379']
options: >-
--health-cmd="redis-cli ping"
--health-interval=10s --health-timeout=5s --health-retries=12
env:
RUOYI_PLUGIN_IT_ALLOW: '1'
RUOYI_IT_MYSQL_PASSWORD: ci-only-mysql
RUOYI_IT_PG_PASSWORD: ci-only-postgres
RUOYI_IT_REDIS_PASSWORD: ''
PYTHONUTF8: '1'
_TYPER_FORCE_DISABLE_TERMINAL: '1'
steps:
- uses: actions/checkout@v5
- uses: actions/download-artifact@v6
with:
name: integration-task-bundle
path: ruoyi-fastapi-backend/plugins/examples/python/task_demo/web/dist
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- run: python -m pip install -r requirements.txt -r requirements-pg.txt
- name: Verify MySQL and PostgreSQL maintenance releases
shell: bash
run: |
mkdir -p target/ci/release
python scripts/plugin_release_integration.py --engine mysql 2>&1 | tee target/ci/release/mysql.log
python scripts/plugin_release_integration.py --engine postgresql 2>&1 | tee target/ci/release/postgresql.log
- uses: actions/upload-artifact@v6
if: always()
with:
name: integration-release-${{ matrix.python }}
path: ruoyi-fastapi-backend/target/ci/release/
retention-days: 7
network:
name: ${{ matrix.framework }} proxy and plugin sessions
if: inputs.network_frameworks != '[]'
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
framework: ${{ fromJSON(inputs.network_frameworks) }}
defaults:
run:
working-directory: ruoyi-fastapi-backend
env:
RUOYI_PLUGIN_NETWORK_SMOKE: '1'
RUOYI_PLUGIN_FRONTEND_FRAMEWORK: ${{ matrix.framework }}
NODE_OPTIONS: ${{ matrix.framework == 'vue2' && '--openssl-legacy-provider' || '' }}
DB_SOURCES: '{"primary":{"db_type":"mysql","db_host":"127.0.0.1","db_port":3306,"db_username":"network-smoke","db_password":"network-smoke","db_database":"network-smoke"}}'
JWT_SECRET_KEY: isolated-plugin-network-smoke-ci-only
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: ruoyi-fastapi-frontend/${{ matrix.framework }}/web/package.json
- run: python -m pip install -r requirements.txt -r requirements-test.txt playwright==1.62.0
- run: python -m playwright install --with-deps chromium
- run: npm --prefix ../ruoyi-fastapi-frontend/${{ matrix.framework }}/web install --no-audit --no-fund --package-lock=false
- name: Verify HTTPS proxy, iframe sessions and long connections
run: python -m pytest tests/plugins/integration/test_network_smoke.py -m browser --strict-markers -v --junitxml=target/plugin-network-smoke/${{ matrix.framework }}/results.xml
- run: python ../.github/scripts/check_test_report.py target/plugin-network-smoke/${{ matrix.framework }}/results.xml
- uses: actions/upload-artifact@v6
if: always()
with:
name: integration-network-${{ matrix.framework }}
path: ruoyi-fastapi-backend/target/plugin-network-smoke/${{ matrix.framework }}/
retention-days: 7
+80
View File
@@ -0,0 +1,80 @@
name: CI / Native
on:
workflow_call:
permissions:
contents: read
env:
PYTHONUTF8: '1'
_TYPER_FORCE_DISABLE_TERMINAL: '1'
jobs:
rust-quality:
name: Rust format and clippy
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
- run: rustup toolchain install 1.99.0 --profile minimal --component rustfmt --component clippy
- run: rustup default 1.99.0
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
ruoyi-fastapi-backend/plugins/examples/rust/rust_demo/target
key: rust-quality-${{ runner.os }}-1.99.0-${{ hashFiles('**/Cargo.lock') }}
- run: cargo fmt --manifest-path plugins/examples/rust/rust_demo/Cargo.toml --check
- run: cargo clippy --manifest-path plugins/examples/rust/rust_demo/Cargo.toml --locked -- -D warnings
runtime:
name: ${{ matrix.os }} / Python ${{ matrix.python }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python: ['3.10', '3.11', '3.12', '3.13']
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- run: python -m pip install -r requirements.txt -r requirements-test.txt 'maturin>=1.15,<2'
- run: rustup toolchain install 1.99.0 --profile minimal
- run: rustup default 1.99.0
- uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
ruoyi-fastapi-backend/plugins/examples/rust/rust_demo/target
key: rust-native-${{ runner.os }}-${{ matrix.python }}-1.99.0-${{ hashFiles('**/Cargo.lock') }}
- name: Build and assemble source-free plugin
run: python scripts/build_native_plugin.py --output target/native-package
- name: Exercise real native runtime and signed artifact loading
env:
RUOYI_NATIVE_PLUGIN_DIR: ${{ github.workspace }}/ruoyi-fastapi-backend/target/native-package/rust_demo
run: python -m pytest tests/plugins/native tests/plugins/core/deployment -m native --strict-markers -q --durations=15 --junitxml=target/ci/native.xml
- name: Require native tests to run without missing-artifact skips
run: python ../.github/scripts/check_test_report.py target/ci/native.xml
- uses: actions/upload-artifact@v6
if: always()
with:
name: native-${{ runner.os }}-${{ matrix.python }}
path: ruoyi-fastapi-backend/target/ci/
retention-days: 7
+54
View File
@@ -0,0 +1,54 @@
name: CI / Quality
on:
workflow_call:
permissions:
contents: read
jobs:
checks:
name: Code and CI contracts
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: .github/requirements.txt
- run: python -m pip install -r .github/requirements.txt
- name: Python lint and format
run: |
ruff check ruoyi-fastapi-backend ruoyi-fastapi-test .github/scripts .github/tests
ruff format --check ruoyi-fastapi-backend ruoyi-fastapi-test .github/scripts .github/tests
- name: Test CI routing, failure gates and deployment contracts
run: python -m pytest .github/tests -q --junitxml=target/ci/quality.xml
- name: Validate every Compose framework selection
run: python .github/scripts/check_compose.py
- name: Install actionlint
env:
ACTIONLINT_VERSION: '1.7.12'
run: |
archive="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
curl --fail --location --retry 3 "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/${archive}" --output "${RUNNER_TEMP}/${archive}"
echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 ${RUNNER_TEMP}/${archive}" | sha256sum --check
tar -xzf "${RUNNER_TEMP}/${archive}" -C "$RUNNER_TEMP" actionlint
"$RUNNER_TEMP/actionlint" -color
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: ruoyi-fastapi-frontend/*/web/package.json
- name: Check Web formatting with the existing project configurations
run: |
for framework in vue2 vue3; do
(cd "ruoyi-fastapi-frontend/$framework/web" && npx --yes prettier@3.6.2 --check .)
done
- uses: actions/upload-artifact@v6
if: always()
with:
name: quality-reports
path: target/ci/
retention-days: 7
+106
View File
@@ -0,0 +1,106 @@
name: CI
on:
pull_request:
branches: [master]
push:
branches: [master]
schedule:
- cron: '21 18 * * *'
workflow_dispatch:
inputs:
full:
description: Run the full compatibility and end-to-end matrix
type: boolean
default: true
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
plan:
name: Plan
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
backend: ${{ steps.plan.outputs.backend }}
frontend: ${{ steps.plan.outputs.frontend }}
integration: ${{ steps.plan.outputs.integration }}
e2e: ${{ steps.plan.outputs.e2e }}
native: ${{ steps.plan.outputs.native }}
full: ${{ steps.plan.outputs.full }}
frontend_matrix: ${{ steps.plan.outputs.frontend_matrix }}
e2e_matrix: ${{ steps.plan.outputs.e2e_matrix }}
network_frameworks: ${{ steps.plan.outputs.network_frameworks }}
database: ${{ steps.plan.outputs.database }}
release: ${{ steps.plan.outputs.release }}
plan_json: ${{ steps.plan.outputs.plan_json }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- id: plan
run: python .github/scripts/ci_plan.py plan
quality:
name: Quality
needs: plan
uses: ./.github/workflows/ci-quality.yml
backend:
name: Backend
needs: plan
if: needs.plan.outputs.backend == 'true'
uses: ./.github/workflows/ci-backend.yml
frontend:
name: Frontend
needs: plan
if: needs.plan.outputs.frontend == 'true'
uses: ./.github/workflows/ci-frontend.yml
with:
matrix_json: ${{ needs.plan.outputs.frontend_matrix }}
full: ${{ needs.plan.outputs.full == 'true' }}
integration:
name: Integration
needs: plan
if: needs.plan.outputs.integration == 'true'
uses: ./.github/workflows/ci-integration.yml
with:
database: ${{ needs.plan.outputs.database == 'true' }}
release: ${{ needs.plan.outputs.release == 'true' }}
network_frameworks: ${{ needs.plan.outputs.network_frameworks }}
full: ${{ needs.plan.outputs.full == 'true' }}
e2e:
name: E2E
needs: plan
if: needs.plan.outputs.e2e == 'true'
uses: ./.github/workflows/ci-e2e.yml
with:
matrix_json: ${{ needs.plan.outputs.e2e_matrix }}
native:
name: Native
needs: plan
if: needs.plan.outputs.native == 'true'
uses: ./.github/workflows/ci-native.yml
result:
name: Result
if: always()
needs: [plan, quality, backend, frontend, integration, e2e, native]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v5
- name: Require every selected category to succeed
env:
PLAN_JSON: ${{ needs.plan.outputs.plan_json }}
NEEDS_JSON: ${{ toJSON(needs) }}
run: python .github/scripts/ci_plan.py gate
-97
View File
@@ -1,97 +0,0 @@
name: Native Plugin
on:
push:
branches: [master]
paths:
- 'ruoyi-fastapi-backend/plugins/core/**'
- 'ruoyi-fastapi-backend/plugins/examples/rust/**'
- 'ruoyi-fastapi-backend/plugins/examples/python/task_demo/**'
- 'ruoyi-fastapi-backend/scripts/plugin_task_integration.py'
- 'ruoyi-fastapi-backend/scripts/build_native_plugin.py'
- 'ruoyi-fastapi-backend/cli/runtime/plugin/scaffold/**'
- 'ruoyi-fastapi-backend/cli/runtime/plugin/sdk.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/developer.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/sdk.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/artifact*.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/artifact_controller.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/command.py'
- 'ruoyi-fastapi-frontend/src/utils/pluginBridge*'
- 'ruoyi-fastapi-backend/pyproject.toml'
- 'ruoyi-fastapi-backend/tests/cli/runtime/plugin/test_runtime_scaffold*.py'
- 'ruoyi-fastapi-backend/tests/cli/runtime/plugin/test_runtime_sdk.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_sdk_commands.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_artifact_commands.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_release_wait.py'
- 'ruoyi-fastapi-backend/tests/plugins/**'
- '.github/workflows/native-plugin.yml'
pull_request:
branches: [master]
paths:
- 'ruoyi-fastapi-backend/plugins/core/**'
- 'ruoyi-fastapi-backend/plugins/examples/rust/**'
- 'ruoyi-fastapi-backend/plugins/examples/python/task_demo/**'
- 'ruoyi-fastapi-backend/scripts/plugin_task_integration.py'
- 'ruoyi-fastapi-backend/scripts/build_native_plugin.py'
- 'ruoyi-fastapi-backend/cli/runtime/plugin/scaffold/**'
- 'ruoyi-fastapi-backend/cli/runtime/plugin/sdk.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/developer.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/sdk.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/commands/artifact*.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/artifact_controller.py'
- 'ruoyi-fastapi-backend/cli/groups/plugin/command.py'
- 'ruoyi-fastapi-frontend/src/utils/pluginBridge*'
- 'ruoyi-fastapi-backend/pyproject.toml'
- 'ruoyi-fastapi-backend/tests/cli/runtime/plugin/test_runtime_scaffold*.py'
- 'ruoyi-fastapi-backend/tests/cli/runtime/plugin/test_runtime_sdk.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_sdk_commands.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_artifact_commands.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_release_wait.py'
- 'ruoyi-fastapi-backend/tests/plugins/**'
- '.github/workflows/native-plugin.yml'
workflow_dispatch:
jobs:
native:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python: ['3.10', '3.11', '3.12', '3.13']
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ruoyi-fastapi-backend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements.txt
- name: Install host and build dependencies
run: python -m pip install -r requirements.txt 'maturin>=1.15,<2' pytest pytest-asyncio aiosqlite
- name: Install Rust
run: rustup toolchain install 1.99.0 --profile minimal --component rustfmt --component clippy
- name: Select Rust
run: rustup default 1.99.0
- name: Check Rust formatting
run: cargo fmt --manifest-path plugins/examples/rust/rust_demo/Cargo.toml --check
- name: Verify v1 and v2 plugin scaffolds
run: python -m pytest tests/cli/runtime/plugin/test_runtime_scaffold.py tests/cli/runtime/plugin/test_runtime_scaffold_v2.py -q
- name: Verify SDK provenance and offline update commands
run: python -m pytest tests/cli/runtime/plugin/test_runtime_sdk.py tests/cli/root/test_plugin_sdk_commands.py -q
- name: Verify persistent task plugin
run: python -m pytest tests/plugins/examples/test_task_demo.py -q
- name: Build and assemble source-free plugin
run: python scripts/build_native_plugin.py --output target/native-package
- name: Check Rust code
run: cargo clippy --manifest-path plugins/examples/rust/rust_demo/Cargo.toml --locked -- -D warnings
- name: Exercise native library through the host runtime
env:
RUOYI_NATIVE_PLUGIN_DIR: ${{ github.workspace }}/ruoyi-fastapi-backend/target/native-package/rust_demo
run: python -m pytest tests/plugins/native tests/plugins/core/native tests/plugins/core/runtime/test_host_services.py tests/plugins/core/runtime/test_job_dispatcher.py -q
- name: Verify signed artifacts and maintenance releases
env:
RUOYI_NATIVE_PLUGIN_DIR: ${{ github.workspace }}/ruoyi-fastapi-backend/target/native-package/rust_demo
run: python -m pytest tests/plugins/core/artifacts tests/plugins/core/deployment tests/plugins/core/management/test_release_dao.py tests/plugins/core/management/test_artifact_views.py tests/module_plugin/controller/test_plugin_release_controller.py tests/cli/root/test_plugin_artifact_commands.py tests/cli/root/test_plugin_release_wait.py tests/sql/test_plugin_release_schema.py -q
-174
View File
@@ -1,174 +0,0 @@
name: Playwright Tests
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
mysql-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.docker_cache
key: ${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('**/Dockerfile*', '**/requirements.txt') }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create temporary Dockerfile with Python ${{ matrix.python-version }}
run: |
# Save original Dockerfile.my
cp ruoyi-fastapi-backend/Dockerfile.my ruoyi-fastapi-backend/Dockerfile.my.bak
# Create temporary Dockerfile with target Python version and default PyPI index
sed -e "s/FROM python:3.10/FROM python:${{ matrix.python-version }}/g" \
-e 's| -i https://pypi.tuna.tsinghua.edu.cn/simple||g' \
ruoyi-fastapi-backend/Dockerfile.my.bak > ruoyi-fastapi-backend/Dockerfile.my
- name: Start services with docker-compose
run: |
cd ruoyi-fastapi-test
docker compose -f docker-compose.test.my.yml up -d --build
- name: Wait for services to be ready
run: |
cd ruoyi-fastapi-test
# Wait for backend to be running
timeout 180 bash -c 'until docker compose -f docker-compose.test.my.yml ps ruoyi-backend-my | grep -q "Up"; do sleep 5; done'
# Wait for frontend to be running
timeout 120 bash -c 'until docker compose -f docker-compose.test.my.yml ps ruoyi-frontend | grep -q "Up"; do sleep 5; done'
# Additional wait for services to be fully ready and listening on ports
sleep 30
# Check that backend is actually responding on the API endpoint
echo "Checking if backend service is ready..."
for i in {1..30}; do
if curl -f http://localhost:9099/captchaImage > /dev/null 2>&1; then
echo "Backend service is ready!"
break
fi
echo "Waiting for backend service to be ready... ($i/30)"
sleep 5
done
# Final check
if ! curl -f http://localhost:9099/captchaImage > /dev/null 2>&1; then
echo "Backend service failed to start properly. Checking logs..."
docker logs ruoyi-backend-my-test
exit 1
fi
- name: Run tests
run: |
cd ruoyi-fastapi-test
pip install -r requirements.txt
playwright install
pytest -v
- name: Stop services
if: always()
run: |
cd ruoyi-fastapi-test
docker compose -f docker-compose.test.my.yml down
- name: Restore original Dockerfile.my
if: always()
run: |
# Restore original Dockerfile.my after test
mv ruoyi-fastapi-backend/Dockerfile.my.bak ruoyi-fastapi-backend/Dockerfile.my
pg-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.docker_cache
key: ${{ runner.os }}-docker-${{ matrix.python-version }}-${{ hashFiles('**/Dockerfile*', '**/requirements.txt') }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Create temporary Dockerfile with Python ${{ matrix.python-version }}
run: |
# Save original Dockerfile.pg
cp ruoyi-fastapi-backend/Dockerfile.pg ruoyi-fastapi-backend/Dockerfile.pg.bak
# Create temporary Dockerfile with target Python version and default PyPI index
sed -e "s/FROM python:3.10/FROM python:${{ matrix.python-version }}/g" \
-e 's| -i https://pypi.tuna.tsinghua.edu.cn/simple||g' \
ruoyi-fastapi-backend/Dockerfile.pg.bak > ruoyi-fastapi-backend/Dockerfile.pg
- name: Start services with docker-compose
run: |
cd ruoyi-fastapi-test
docker compose -f docker-compose.test.pg.yml up -d --build
- name: Wait for services to be ready
run: |
cd ruoyi-fastapi-test
# Wait for backend to be running
timeout 180 bash -c 'until docker compose -f docker-compose.test.pg.yml ps ruoyi-backend-pg | grep -q "Up"; do sleep 5; done'
# Wait for frontend to be running
timeout 120 bash -c 'until docker compose -f docker-compose.test.pg.yml ps ruoyi-frontend | grep -q "Up"; do sleep 5; done'
# Additional wait for services to be fully ready and listening on ports
sleep 30
# Check that backend is actually responding on the API endpoint
echo "Checking if backend service is ready..."
for i in {1..30}; do
if curl -f http://localhost:9099/captchaImage > /dev/null 2>&1; then
echo "Backend service is ready!"
break
fi
echo "Waiting for backend service to be ready... ($i/30)"
sleep 5
done
# Final check
if ! curl -f http://localhost:9099/captchaImage > /dev/null 2>&1; then
echo "Backend service failed to start properly. Checking logs..."
docker logs ruoyi-backend-pg-test
exit 1
fi
- name: Run tests
run: |
cd ruoyi-fastapi-test
pip install -r requirements.txt
playwright install
pytest -v
- name: Stop services
if: always()
run: |
cd ruoyi-fastapi-test
docker compose -f docker-compose.test.pg.yml down
- name: Restore original Dockerfile.pg
if: always()
run: |
# Restore original Dockerfile.pg after test
mv ruoyi-fastapi-backend/Dockerfile.pg.bak ruoyi-fastapi-backend/Dockerfile.pg
-69
View File
@@ -1,69 +0,0 @@
name: Plugin Frontend Tests
on:
push:
branches: [master]
paths:
- 'ruoyi-fastapi-frontend/src/api/system/plugin.js'
- 'ruoyi-fastapi-frontend/src/components/PluginFrame/**'
- 'ruoyi-fastapi-frontend/src/views/system/plugin/**'
- 'ruoyi-fastapi-frontend/src/utils/**'
- 'ruoyi-fastapi-frontend/src/plugins/**'
- 'ruoyi-fastapi-frontend/src/router/**'
- 'ruoyi-fastapi-frontend/src/store/modules/permission.js'
- 'ruoyi-fastapi-frontend/src/store/modules/user.js'
- 'ruoyi-fastapi-frontend/src/permission.js'
- 'ruoyi-fastapi-frontend/plugins/**'
- 'ruoyi-fastapi-frontend/tests/plugins/**'
- 'ruoyi-fastapi-frontend/tests/run-tests.js'
- 'ruoyi-fastapi-frontend/package.json'
- 'ruoyi-fastapi-frontend/package-lock.json'
- 'ruoyi-fastapi-frontend/vite.config.js'
- 'ruoyi-fastapi-frontend/vite/**'
- 'ruoyi-fastapi-backend/plugins/examples/python/bundle_demo/web/**'
- '.github/workflows/plugin-frontend.yml'
pull_request:
branches: [master]
paths:
- 'ruoyi-fastapi-frontend/src/api/system/plugin.js'
- 'ruoyi-fastapi-frontend/src/components/PluginFrame/**'
- 'ruoyi-fastapi-frontend/src/views/system/plugin/**'
- 'ruoyi-fastapi-frontend/src/utils/**'
- 'ruoyi-fastapi-frontend/src/plugins/**'
- 'ruoyi-fastapi-frontend/src/router/**'
- 'ruoyi-fastapi-frontend/src/store/modules/permission.js'
- 'ruoyi-fastapi-frontend/src/store/modules/user.js'
- 'ruoyi-fastapi-frontend/src/permission.js'
- 'ruoyi-fastapi-frontend/plugins/**'
- 'ruoyi-fastapi-frontend/tests/plugins/**'
- 'ruoyi-fastapi-frontend/tests/run-tests.js'
- 'ruoyi-fastapi-frontend/package.json'
- 'ruoyi-fastapi-frontend/package-lock.json'
- 'ruoyi-fastapi-frontend/vite.config.js'
- 'ruoyi-fastapi-frontend/vite/**'
- 'ruoyi-fastapi-backend/plugins/examples/python/bundle_demo/web/**'
- '.github/workflows/plugin-frontend.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
plugins:
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: ruoyi-fastapi-frontend
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: ruoyi-fastapi-frontend/package.json
- name: Install frontend dependencies
# This repository does not commit npm lockfiles, so npm ci is not available.
run: npm install --no-audit --no-fund --package-lock=false
- name: Verify plugin bridge, sessions and management views
run: npm run test:plugin
@@ -1,63 +0,0 @@
name: Plugin Network Smoke
on:
pull_request:
branches: [master]
paths:
- 'ruoyi-fastapi-backend/plugins/**'
- 'ruoyi-fastapi-backend/module_plugin/**'
- 'ruoyi-fastapi-backend/module_admin/service/login_service.py'
- 'ruoyi-fastapi-backend/common/**'
- 'ruoyi-fastapi-backend/config/**'
- 'ruoyi-fastapi-backend/middlewares/**'
- 'ruoyi-fastapi-backend/utils/**'
- 'ruoyi-fastapi-backend/tests/**'
- 'ruoyi-fastapi-backend/requirements.txt'
- 'ruoyi-fastapi-backend/pyproject.toml'
- 'ruoyi-fastapi-frontend/**'
- '.github/workflows/plugin-network-smoke.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
browser:
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: ruoyi-fastapi-backend
env:
RUOYI_PLUGIN_NETWORK_SMOKE: '1'
# The fixture replaces account, DB and Redis access; no external service is used.
DB_SOURCES: '{"primary":{"db_type":"mysql","db_host":"127.0.0.1","db_port":3306,"db_username":"network-smoke","db_password":"network-smoke","db_database":"network-smoke"}}'
JWT_SECRET_KEY: 'isolated-plugin-network-smoke-ci-only'
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements.txt
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: ruoyi-fastapi-frontend/package.json
- name: Install host and browser test dependencies
run: python -m pip install -r requirements.txt pytest pytest-asyncio aiosqlite playwright
- name: Install Chromium
run: python -m playwright install --with-deps chromium
- name: Install frontend dependencies
# This repository does not commit npm lockfiles, so npm ci is not available.
run: npm --prefix ../ruoyi-fastapi-frontend install --no-audit --no-fund --package-lock=false
- name: Verify HTTPS proxy, iframe sessions and long connections
run: python -m pytest tests/plugins/integration/test_network_smoke.py -v --junitxml=target/plugin-network-smoke/results.xml
- name: Upload browser trace, screenshots and proxy log
if: always()
uses: actions/upload-artifact@v4
with:
name: plugin-network-smoke
path: ruoyi-fastapi-backend/target/plugin-network-smoke/
retention-days: 7
@@ -1,94 +0,0 @@
name: Plugin Release Integration
on:
pull_request:
branches: [master]
paths:
- 'ruoyi-fastapi-backend/plugins/core/**'
- 'ruoyi-fastapi-backend/plugins/examples/python/task_demo/**'
- 'ruoyi-fastapi-frontend/src/utils/pluginBridge.js'
- 'ruoyi-fastapi-backend/config/**'
- 'ruoyi-fastapi-backend/cli/groups/plugin/**'
- 'ruoyi-fastapi-backend/cli/runtime/plugin/**'
- 'ruoyi-fastapi-backend/module_plugin/**'
- 'ruoyi-fastapi-backend/server.py'
- 'ruoyi-fastapi-backend/app.py'
- 'ruoyi-fastapi-backend/sql/ruoyi-fastapi*.sql'
- 'ruoyi-fastapi-backend/scripts/plugin_release_integration.py'
- 'ruoyi-fastapi-backend/scripts/plugin_task_integration.py'
- 'ruoyi-fastapi-backend/tests/plugins/**'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_artifact_commands.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_release_wait.py'
- 'ruoyi-fastapi-backend/tests/cli/root/test_plugin_diagnostics.py'
- 'ruoyi-fastapi-backend/tests/cli/runtime/plugin/**'
- 'ruoyi-fastapi-backend/tests/module_plugin/**'
- 'ruoyi-fastapi-backend/tests/server/test_plugin_runtime.py'
- 'ruoyi-fastapi-backend/tests/sql/test_plugin_release_schema.py'
- 'ruoyi-fastapi-backend/pyproject.toml'
- 'ruoyi-fastapi-backend/requirements.txt'
- 'ruoyi-fastapi-backend/requirements-pg.txt'
- '.github/workflows/plugin-release-integration.yml'
workflow_dispatch:
permissions:
contents: read
jobs:
release:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python: ['3.10', '3.11', '3.12', '3.13']
defaults:
run:
working-directory: ruoyi-fastapi-backend
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: ci-only-mysql
ports: ['3306:3306']
options: >-
--health-cmd="mysqladmin ping -h localhost"
--health-interval=10s --health-timeout=5s --health-retries=12
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: ci-only-postgres
ports: ['5432:5432']
options: >-
--health-cmd="pg_isready -U postgres"
--health-interval=10s --health-timeout=5s --health-retries=12
redis:
image: redis:6.2
ports: ['6379:6379']
options: >-
--health-cmd="redis-cli ping"
--health-interval=10s --health-timeout=5s --health-retries=12
env:
RUOYI_PLUGIN_IT_ALLOW: '1'
RUOYI_IT_MYSQL_PASSWORD: ci-only-mysql
RUOYI_IT_PG_PASSWORD: ci-only-postgres
RUOYI_IT_REDIS_PASSWORD: ''
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- name: Install host dependencies
run: python -m pip install -r requirements.txt -r requirements-pg.txt
- uses: actions/setup-node@v5
with:
node-version: '22'
- name: Test and build task plugin bundle
run: |
npm --prefix plugins/examples/python/task_demo/web install --no-audit --no-fund --package-lock=false
npm --prefix plugins/examples/python/task_demo/web test
npm --prefix plugins/examples/python/task_demo/web run build
- name: Verify MySQL and Redis maintenance releases
run: python scripts/plugin_release_integration.py --engine mysql
- name: Verify PostgreSQL and Redis maintenance releases
run: python scripts/plugin_release_integration.py --engine postgresql
-33
View File
@@ -1,33 +0,0 @@
name: Ruff Check
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
lint-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff
- name: Run linting
run: |
ruff check ruoyi-fastapi-backend
ruff check ruoyi-fastapi-test
- name: Run format check
run: |
ruff format ruoyi-fastapi-backend --check
ruff format ruoyi-fastapi-test --check
-106
View File
@@ -1,106 +0,0 @@
name: Timezone Integration
on:
push:
branches: [master]
pull_request:
branches: [master]
workflow_dispatch:
jobs:
databases:
runs-on: ubuntu-latest
env:
TZ: America/New_York
PYTHONUTF8: '1'
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: timezone_test
TZ: Asia/Shanghai
ports: ['3306:3306']
options: >-
--health-cmd="mysqladmin ping -h localhost -ptimezone_test"
--health-interval=10s --health-timeout=5s --health-retries=12
postgres:
image: postgres:14
env:
POSTGRES_PASSWORD: timezone_test
TZ: America/New_York
PGTZ: America/New_York
ports: ['5432:5432']
options: >-
--health-cmd="pg_isready -U postgres"
--health-interval=10s --health-timeout=5s --health-retries=12
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.10'
cache: pip
cache-dependency-path: ruoyi-fastapi-backend/requirements*.txt
- name: Install verification dependencies
working-directory: ruoyi-fastapi-backend
run: python -m pip install -r requirements.txt asyncpg psycopg2-binary pytest pytest-asyncio aiosqlite
- name: Create isolated source configurations
working-directory: ruoyi-fastapi-backend
run: |
mkdir -p .cache/timezone-ci
python - <<'PY'
import json
from pathlib import Path
for dialect, port, username, database in [('mysql', 3306, 'root', 'mysql'), ('postgresql', 5432, 'postgres', 'postgres')]:
source = dict(db_type=dialect, db_host='127.0.0.1', db_port=port, db_username=username,
db_password='timezone_test', db_database=database)
Path(f'.cache/timezone-ci/{dialect}.json').write_text(json.dumps(source))
PY
- name: Verify empty databases, drivers, generated CRUD and persistent schedulers
working-directory: ruoyi-fastapi-backend
run: |
python -m scripts.verify_timezone_database --config .cache/timezone-ci/mysql.json --report .cache/timezone-ci/mysql-report.json
python -m scripts.verify_timezone_database --config .cache/timezone-ci/postgresql.json --report .cache/timezone-ci/postgresql-report.json
- uses: actions/upload-artifact@v6
if: always()
with:
name: timezone-database-reports
path: ruoyi-fastapi-backend/.cache/timezone-ci/*-report.json
include-hidden-files: true
web-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
# Lockfiles are ignored by this repository; cache by the committed manifest.
cache-dependency-path: ruoyi-fastapi-frontend/package.json
- uses: pnpm/action-setup@v5
with:
package_json_file: ruoyi-fastapi-app/package.json
- name: Install Web dependencies
working-directory: ruoyi-fastapi-frontend
run: npm install --no-package-lock
- name: Install App dependencies
working-directory: ruoyi-fastapi-app
run: pnpm install --no-frozen-lockfile
- name: Run time contracts in three host timezones
run: node ruoyi-fastapi-test/time-contract/run-host-timezones.mjs
- name: Build Web targets
working-directory: ruoyi-fastapi-frontend
run: |
npm run build:prod
npm run build:docker
- name: Build App targets
working-directory: ruoyi-fastapi-app
run: |
pnpm build:h5
pnpm build:mp-weixin
- name: Validate all Compose configurations
run: |
docker compose -f docker-compose.my.yml config --quiet
docker compose -f docker-compose.pg.yml config --quiet
docker compose -f ruoyi-fastapi-test/docker-compose.test.my.yml config --quiet
docker compose -f ruoyi-fastapi-test/docker-compose.test.pg.yml config --quiet