# Gitea Actions CI/CD pipeline: lint → test → deploy # Triggers on push to main branch. # Required variables and secrets (set in Gitea repo settings): # Variables: # DEPLOY_HOST — server IP or hostname # DEPLOY_PATH — absolute path to the directory on the server # DEPLOY_USER — SSH username on the server # SSH_KNOWN_HOSTS — SSH known_host fingerprint for security # SSH_PORT — SSH port of the server # Secrets: # SSH_PRIVATE_KEY — SSH private key for deployment name: Deploy on: push: branches: [main] workflow_dispatch: inputs: run_setup_db: description: "Run deploy/setup_db.sh to configure DB and run migrations" required: false type: boolean default: false jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install ruff - run: ruff check app/ test: needs: lint runs-on: ubuntu-latest services: postgres: image: postgres:16 env: POSTGRES_DB: test_db POSTGRES_USER: test_user POSTGRES_PASSWORD: test_pass options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - uses: actions/setup-node@v4 with: node-version: "20" - run: pip install -e ".[dev]" - run: alembic upgrade head env: DATABASE_URL: postgresql+asyncpg://test_user:test_pass@postgres:5432/test_db - run: pytest --tb=short env: DATABASE_URL: postgresql+asyncpg://test_user:test_pass@postgres:5432/test_db - run: | cd frontend npm ci if node -e "require.resolve('vitest/package.json')" >/dev/null 2>&1; then npm test else echo "vitest not configured; skipping frontend tests" fi npm run build deploy: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Deploy to server env: DEPLOY_HOST: ${{ vars.DEPLOY_HOST }} DEPLOY_USER: ${{ vars.DEPLOY_USER }} DEPLOY_PATH: ${{ vars.DEPLOY_PATH }} SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} SSH_KNOWN_HOSTS: ${{ vars.SSH_KNOWN_HOSTS }} SSH_PORT: ${{ vars.SSH_PORT || '22' }} run: | # Install tools missing from runner image sudo apt-get update -qq && sudo apt-get install -y -qq rsync openssh-client > /dev/null 2>&1 || true # Write SSH credentials mkdir -p ~/.ssh echo "$SSH_PRIVATE_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts SSH_OPTS="-i ~/.ssh/deploy_key -o StrictHostKeyChecking=no -p $SSH_PORT" # Sync application files rsync -avz --delete \ --exclude '.git/' \ --exclude '.gitea/' \ --exclude '.env' \ --exclude '.venv/' \ --exclude '__pycache__/' \ --exclude '.pytest_cache/' \ --exclude 'logs/' \ --exclude '*.pyc' \ --exclude 'frontend/node_modules/' \ --exclude 'frontend/dist/' \ -e "ssh $SSH_OPTS" \ ./ ${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/ # Install deps & restart on server ssh $SSH_OPTS ${DEPLOY_USER}@${DEPLOY_HOST} << REMOTE_SCRIPT set -e cd ${DEPLOY_PATH} # Create venv if not exists if [ ! -d ".venv" ]; then python3 -m venv .venv fi source .venv/bin/activate pip install --quiet --upgrade pip pip install --quiet -e . # Setup DB and run migrations if [ "${{ inputs.run_setup_db }}" = "true" ] || [ "${{ github.event.inputs.run_setup_db }}" = "true" ]; then chmod +x deploy/setup_db.sh ./deploy/setup_db.sh else alembic upgrade head fi # Build frontend cd frontend npm ci npm run build cd .. # Restart service sudo systemctl restart stock-data-backend echo "✓ stock-data-backend deployed" REMOTE_SCRIPT # Cleanup rm -f ~/.ssh/deploy_key