diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..9a954a5e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,109 @@ +# CI for shopdb-flask on GitHub Actions. +# +# Mirrors the internal CI pipeline. Four jobs on push + pull_request: +# backend - pytest (SQLite via TestingConfig, no DB service needed) +# naming - the CONTRIBUTING.md naming/style gate +# frontend - vitest + Vue build +# migrations-mysql - the REAL multi-site deploy path: fresh flask db upgrade +# + every plugin's chain on utf8mb4 MySQL 8, idempotent on +# a second run. The pytest suite only exercises SQLite +# create_all(), so this is what catches an Alembic +# regression on MySQL before it ships. + +name: CI + +on: + push: + pull_request: + +jobs: + backend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: pip + - run: pip install -r requirements.txt + - run: python -m pytest -q + + naming: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: bash scripts/check-naming-and-style.sh + + frontend: + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: frontend/package-lock.json + - run: npm ci + - run: npx vitest run + - run: npm run build + + migrations-mysql: + runs-on: ubuntu-latest + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: shopdb_ci + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping -h localhost -uroot -proot" + --health-interval=5s --health-timeout=5s --health-retries=20 + env: + FLASK_APP: shopdb + DATABASE_URL: mysql+pymysql://root:root@127.0.0.1:3306/shopdb_ci?charset=utf8mb4 + SECRET_KEY: ci-secret + JWT_SECRET_KEY: ci-jwt-secret + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: pip + - run: pip install -r requirements.txt + - name: Force utf8mb4 on the CI database + run: | + mysql -h 127.0.0.1 -uroot -proot -e \ + "ALTER DATABASE shopdb_ci CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + - name: Fresh core upgrade from empty + run: flask db upgrade + - name: Install every bundled plugin (runs its chain) + run: | + for p in computers employees geenforce knowledgebase machines \ + measuringtools network notifications printedparts printers \ + slides usb warranty; do + flask plugin install "$p" + done + flask plugin upgrade-all + - name: Assert schema built + utf8mb4 + run: | + python - <<'PY' + from shopdb import create_app + from shopdb.extensions import db + from sqlalchemy import text + app = create_app() + with app.app_context(): + tables = db.inspect(db.engine).get_table_names() + assert len(tables) >= 70, f'only {len(tables)} tables built' + row = db.session.execute(text( + "SELECT default_character_set_name FROM information_schema.schemata " + "WHERE schema_name = 'shopdb_ci'")).first() + assert row[0] == 'utf8mb4', f'charset is {row[0]}, not utf8mb4' + print(f'OK: {len(tables)} tables, charset {row[0]}') + PY + - name: Second core upgrade must be a clean no-op + run: flask db upgrade