diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..10f5ac1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git/ +.github/ +.gitignore + +__pycache__/ +frontend/ +README.md +*.png + +.session +credentials.json +token.json +erpcreds.py +erpcreds.py.template \ No newline at end of file diff --git a/.github/workflows/deploy-gh-pages.yaml b/.github/workflows/deploy-gh-pages.yaml new file mode 100644 index 0000000..a037cc0 --- /dev/null +++ b/.github/workflows/deploy-gh-pages.yaml @@ -0,0 +1,51 @@ +name: Deploy frontend to github pages + +on: + push: + branches: + - main + paths: + - "frontend/**" + - ".github/workflows/deploy-gh-pages.yaml" + +jobs: + gh-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.2.0 + + - name: Install pnpm + run: | + cd frontend + npm install -g pnpm + + - name: Cache pnpm store + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + if: steps.pnpm-cache.outputs.cache-hit != 'true' + run: | + cd frontend + pnpm install + + - name: Build the application + run: | + cd frontend + pnpm run build + + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: ./frontend/dist \ No newline at end of file diff --git a/.github/workflows/deploy-gyfe-do.yaml b/.github/workflows/deploy-gyfe-do.yaml new file mode 100644 index 0000000..f5f46c3 --- /dev/null +++ b/.github/workflows/deploy-gyfe-do.yaml @@ -0,0 +1,122 @@ +name: Deploy GYFE Backend to DO + +on: + push: + branches: + - "main" + paths-ignore: + - "**.md" + - "LICENSE" + - "LICENSE.txt" + - "frontend/**" + - ".gitignore" + - "erpcreds.py.template" + - "**.png" + +jobs: + dockerhub: + name: Publish Docker Image(s) to Dockerhub + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Cache Docker layers for GYFE + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache-gyfe-api + key: ${{ runner.os }}-buildx-gyfe-api-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx-gyfe-api- + + - name: Build & Push GYFE + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/gyfe-api:latest + cache-from: type=local,src=/tmp/.buildx-cache-gyfe-api + cache-to: type=local,dest=/tmp/.buildx-cache-gyfe-api-new,mode=max + + - name: Move GYFE cache + run: | + rm -rf /tmp/.buildx-cache-gyfe-api + mv /tmp/.buildx-cache-gyfe-api-new /tmp/.buildx-cache-gyfe-api + + push: + name: Push Code Stage + needs: dockerhub + runs-on: ubuntu-latest + + steps: + - name: Sync local repo with remote repo + uses: appleboy/ssh-action@master + env: + PROJECT_DIR: ${{ secrets.PROJECT_DIR }} + with: + host: ${{ secrets.SSH_HOSTNAME }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + passphrase: ${{ secrets.SSH_PRIVATE_KEY_PASSPHRASE }} + envs: PROJECT_DIR + script_stop: true + script: | + cd "${PROJECT_DIR}/" + sudo git fetch origin + sudo git reset --hard origin/main + + pull: + name: Pull Image Stage + needs: push + runs-on: ubuntu-latest + + steps: + - name: Pull the latest images(s) + uses: appleboy/ssh-action@master + env: + PROJECT_DIR: ${{ secrets.PROJECT_DIR }} + with: + host: ${{ secrets.SSH_HOSTNAME }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + passphrase: ${{ secrets.SSH_PRIVATE_KEY_PASSPHRASE }} + envs: PROJECT_DIR + script_stop: true + script: | + cd "${PROJECT_DIR}/" + sudo docker compose pull + + deploy: + name: Deploy Stage + needs: pull + runs-on: ubuntu-latest + + steps: + - name: Deploy the latest build(s) + uses: appleboy/ssh-action@master + env: + PROJECT_DIR: ${{ secrets.PROJECT_DIR }} + with: + host: ${{ secrets.SSH_HOSTNAME }} + username: ${{ secrets.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + passphrase: ${{ secrets.SSH_PRIVATE_KEY_PASSPHRASE }} + envs: PROJECT_DIR + script_stop: true + script: | + cd "${PROJECT_DIR}/" + sudo docker compose down + sudo docker compose up -d diff --git a/.github/workflows/frontend-ci-test.yaml b/.github/workflows/frontend-ci-test.yaml new file mode 100644 index 0000000..41b51a4 --- /dev/null +++ b/.github/workflows/frontend-ci-test.yaml @@ -0,0 +1,49 @@ +name: Integration Test (Build) for frontend + +on: + pull_request: + types: + - opened + - synchronize + branches: + - main + paths: + - "frontend/**" + - ".github/workflows/frontend-ci-test.yaml" + +jobs: + frontend-ci: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.2.0 + + - name: Install pnpm + run: | + cd frontend + npm install -g pnpm + + - name: Cache pnpm store + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + if: steps.pnpm-cache.outputs.cache-hit != 'true' + run: | + cd frontend + pnpm install + + - name: Build the application + run: | + cd frontend + pnpm run build \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e1abef8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.11.9-slim + +ENV TZ="Asia/Kolkata" + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +COPY metaploy/ ./ + +RUN chmod +x ./postinstall.sh + +COPY . . + +CMD [ "./postinstall.sh", "gunicorn", "--bind", "0.0.0.0:8000", "wsgi:app" ] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..671a450 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,24 @@ +version: "3" + +services: + backend: + image: metakgporg/gyfe-api + container_name: gyfe-api + build: . + restart: always + networks: + metaploy-network: + aliases: + - gyfe-api + volumes: + - nginx-config-volume:/etc/nginx/sites-enabled + +networks: + metaploy-network: + external: true + name: metaploy-network + +volumes: + nginx-config-volume: + external: true + name: metaploy-nginx-config-volume diff --git a/metaploy/gyfe-api.metaploy.conf b/metaploy/gyfe-api.metaploy.conf new file mode 100644 index 0000000..fd1cb39 --- /dev/null +++ b/metaploy/gyfe-api.metaploy.conf @@ -0,0 +1,16 @@ +upstream gyfe_api { + server gyfe-api:8000; +} + +server { + server_name gyfe-api.metakgp.org; + + location / { + proxy_pass http://gyfe_api; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} \ No newline at end of file diff --git a/metaploy/postinstall.sh b/metaploy/postinstall.sh new file mode 100644 index 0000000..a46050e --- /dev/null +++ b/metaploy/postinstall.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +cleanup() { + echo "Container stopped. Removing nginx configuration." + rm /etc/nginx/sites-enabled/gyfe-api.metaploy.conf +} + +trap 'cleanup' SIGQUIT SIGTERM SIGHUP + +"${@}" & + +cp ./gyfe-api.metaploy.conf /etc/nginx/sites-enabled + +wait $! \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e2cbe58..2de3e5c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ requests==2.31.0 tabulate==0.9.0 Flask==3.0.3 Flask-Cors==4.0.1 +gunicorn==22.0.0 \ No newline at end of file diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..11e7de6 --- /dev/null +++ b/wsgi.py @@ -0,0 +1,4 @@ +from app import app + +if __name__ == "__main__": + app.run() \ No newline at end of file