Files
opsxsql/.gitlab-ci.yml
logan 2cfd45c9d1 feat: run.sh restart/stop/status + real DB connector + GitLab CI
1. run.sh: start/stop/restart/status/logs/build/test
   - PID file management in .pids/
   - Colored output, health check wait, log files
   - Auto alembic migrate on start

2. DB Connector (replaces mock aiomysql):
   - MySQL: aiomysql (connect/query/dml/test)
   - PostgreSQL: asyncpg (connect/query/dml/test)
   - SQLite: sqlite3 via executor (connect/query/dml/test)
   - Unified interface: DBConnector.test_connection/execute_query/execute_dml
   - Connection test returns version + latency

3. GitLab CI/CD pipeline:
   - test: backend pytest + frontend build
   - build: Docker images (manual trigger)
   - deploy: SSH deploy (manual trigger)
   - Cache: pip + node_modules

Tests: 128 passing, frontend build: OK
2026-05-22 15:16:59 +08:00

98 lines
2.4 KiB
YAML

stages:
- test
- build
- deploy
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
# Cache
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- backend/venv/
- frontend/node_modules/
- .cache/pip/
# ===== Test Stage =====
backend-test:
stage: test
image: python:3.11-slim
before_script:
- cd backend
- python -m venv venv
- source venv/bin/activate
- pip install -r requirements.txt -q
script:
- source venv/bin/activate
- python -m pytest tests/ -v --tb=short --junitxml=report.xml
artifacts:
reports:
junit: backend/report.xml
when: always
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "master"'
frontend-build:
stage: test
image: node:20-alpine
before_script:
- cd frontend
- npm ci
script:
- npm run build
artifacts:
paths:
- frontend/dist/
expire_in: 1 day
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "master"'
# ===== Build Stage =====
docker-build:
stage: build
image: docker:24
services:
- docker:24-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" 2>/dev/null || true
script:
- docker build -t $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_SHORT_SHA ./backend
- docker build -t $CI_REGISTRY_IMAGE/frontend:$CI_COMMIT_SHORT_SHA ./frontend
- docker push $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_SHORT_SHA 2>/dev/null || true
- docker push $CI_REGISTRY_IMAGE/frontend:$CI_COMMIT_SHORT_SHA 2>/dev/null || true
- echo "Build complete: $CI_COMMIT_SHORT_SHA"
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: manual
tags:
- docker
# ===== Deploy Stage =====
deploy:
stage: deploy
image: alpine:3.19
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$DEPLOY_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- echo "$DEPLOY_SSH_HOST_KEY" > ~/.ssh/known_hosts 2>/dev/null || true
script:
- ssh $DEPLOY_USER@$DEPLOY_HOST "cd $DEPLOY_PATH && docker compose pull && docker compose up -d && echo 'Deploy done'"
environment:
name: production
url: http://$DEPLOY_HOST
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: manual
tags:
- deploy