name: Build and Deploy on: push: branches: - main workflow_dispatch: env: REGISTRY: ghcr.io VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL || '' }} jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write strategy: fail-fast: false matrix: service: - name: web dockerfile: apps/web/Dockerfile - name: api dockerfile: apps/api/Dockerfile - name: ml dockerfile: apps/ml-service/Dockerfile steps: - name: Checkout repository uses: actions/checkout@v4 with: lfs: true - name: Set image prefix run: echo "IMAGE_PREFIX=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Set up Python for ONNX conversion if: matrix.service.name == 'ml' uses: actions/setup-python@v5 with: python-version: '3.11' - name: Generate ONNX model artifact if: matrix.service.name == 'ml' working-directory: Machine_Learning run: | python -m pip install --upgrade pip python -m pip install 'tensorflow>=2.13.0' 'tf2onnx>=1.16.1' 'onnx>=1.16.0' python convert_onnx.py - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE_PREFIX }}/${{ matrix.service.name }} tags: | type=ref,event=branch type=sha - name: Build and push image uses: docker/build-push-action@v5 with: context: . file: ${{ matrix.service.dockerfile }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | VITE_API_BASE_URL=${{ env.VITE_API_BASE_URL }} cache-from: type=gha,scope=${{ matrix.service.name }} cache-to: type=gha,mode=max,scope=${{ matrix.service.name }} deploy: needs: build runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: contents: read packages: read steps: - name: Validate deploy secrets env: VPS_HOST: ${{ secrets.VPS_HOST }} VPS_USER: ${{ secrets.VPS_USER }} VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }} run: | if [ -z "$VPS_HOST" ] || [ -z "$VPS_USER" ] || [ -z "$VPS_SSH_KEY" ]; then echo "Missing deploy secrets: VPS_HOST, VPS_USER, VPS_SSH_KEY." >&2 exit 1 fi - name: Deploy to VPS uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_SSH_KEY }} passphrase: ${{ secrets.VPS_SSH_PASSPHRASE }} port: ${{ secrets.VPS_PORT || 22 }} script: | set -e DEPLOY_PATH="${DEPLOY_PATH:-/opt/ZeaVis-Edu}" REPO_SLUG="$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" if [ ! -d "$DEPLOY_PATH/.git" ]; then mkdir -p "$DEPLOY_PATH" git clone https://github.com/${{ github.repository }}.git "$DEPLOY_PATH" fi cd "$DEPLOY_PATH" git checkout main git pull --ff-only origin main { printf 'GITHUB_REPOSITORY=%s\n' "$REPO_SLUG" cat << 'ENVEOF' DATABASE_URL=${{ secrets.DATABASE_URL }} SESSION_SECRET=${{ secrets.SESSION_SECRET }} WEB_APP_URL=https://zeavisedu.asepharyana.tech ML_SERVICE_URL=http://zeavis-ml:8000 ENVEOF } > .env docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} docker network create app-shared-net 2>/dev/null || true docker compose pull docker compose up -d docker compose ps docker compose ps | grep -q "zeavis-web.*Up" || exit 1 docker compose ps | grep -q "zeavis-api.*Up" || exit 1 docker compose ps | grep -q "zeavis-ml.*Up" || exit 1