diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 20a83ed3..dc06e527 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,9 +1,11 @@ name: CI on: + push: + branches: [dev, staging, main] pull_request: - branches: - - dev + types: [opened, synchronize, reopened] + branches: [dev, staging, main] jobs: test: @@ -25,5 +27,6 @@ jobs: run: yarn test env: CI: true - - name: buld the dist + + - name: Build the dist run: yarn build diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index ffe930cf..9acefc15 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -1,48 +1,61 @@ -name: Build, Test, and Deploy for Dev Branch +name: Deploy to Dev on: - push: - branches: - - dev + workflow_run: + workflows: [CI] + types: + - completed + branches: [dev] jobs: - build-and-deploy: + deploy: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 + + # - name: Install sshpass + # run: sudo apt-get install sshpass - - name: Build Docker images using docker-compose + - name: Fetch .env file from server run: | - docker compose -f docker-compose.yml build - - - name: Save Docker images to tarball - run: | - docker save $(docker compose -f docker-compose.yml config | grep 'image:' | awk '{print $2}') | gzip > docker-images.tar.gz - - - name: Install sshpass - run: sudo apt-get install sshpass - - - name: Upload to server - run: | - sshpass -p ${{ secrets.PASSWORD }} scp -o StrictHostKeyChecking=no docker-images.tar.gz docker-compose.yml ${{ secrets.USERNAME }}@${{ secrets.HOST }}:/tmp/ + sshpass -p ${{ secrets.PASSWORD }} scp -o StrictHostKeyChecking=no ${{ secrets.USERNAME }}@${{ secrets.HOST }}:/var/www/aihomework/dev/.env .env env: SSH_HOST: ${{ secrets.HOST }} SSH_USERNAME: ${{ secrets.USERNAME }} SSH_PASSWORD: ${{ secrets.PASSWORD }} - - name: Deploy and start on remote server + - name: Build Docker images + run: | + docker compose --env-file .env -f docker-compose.yml build + + - name: List Docker images + run: docker images + + - name: Save Docker images to tarball run: | - sshpass -p ${{ secrets.PASSWORD }} ssh -o StrictHostKeyChecking=no ${{ secrets.USERNAME }}@${{ secrets.HOST }} " - cd /var/www/aihomework/dev + docker save hng_boilerplate_expressjs-backend:latest | gzip > dev-images.tar.gz + + - name: Copy Docker images to server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + source: "dev-images.tar.gz" + target: "~/images-tar" + + - name: Deploy to server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + script: | + cd ~/dev-deployment/hng_boilerplate_expressjs git stash - git pull origin dev - docker load -i /tmp/docker-images.tar.gz - docker compose down - docker compose up -d - rm /tmp/docker-images.tar.gz - " - env: - SSH_HOST: ${{ secrets.HOST }} - SSH_USERNAME: ${{ secrets.USERNAME }} - SSH_PASSWORD: ${{ secrets.PASSWORD }} + git checkout dev + git pull + docker load -i ~/images-tar/dev-images.tar.gz + docker compose -f docker-compose.yml down + docker compose -f docker-compose.yml up -d diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 64a6096e..df8f28ae 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -1,35 +1,74 @@ -name: Build, Test, and Deploy for Prod Branch +name: Deploy to Prod on: - push: - branches: [main] + workflow_run: + workflows: [CI] + types: + - completed + branches: [prod] jobs: - build: - runs-on: self-hosted - defaults: - run: - working-directory: /var/www/aihomework/prod - + on-success: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - name: Pull from GitHub + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install sshpass + run: sudo apt-get install sshpass + + - name: Fetch .env file from server + run: | + sshpass -p ${{ secrets.PASSWORD }} scp -o StrictHostKeyChecking=no ${{ secrets.USERNAME }}@${{ secrets.HOST }}:~/prod-deployment/hng_boilerplate_expressjs/.env .env + env: + SSH_HOST: ${{ secrets.HOST }} + SSH_USERNAME: ${{ secrets.USERNAME }} + SSH_PASSWORD: ${{ secrets.PASSWORD }} + + - name: Build Docker images run: | - git stash - git pull origin main + docker compose --env-file .env -f docker-compose.production.yml build - - name: Install dependencies - run: yarn install + - name: List Docker images + run: docker images - - name: Build the dist - run: yarn build + - name: Save Docker images to tarball + run: | + docker save hng_boilerplate_expressjs-backend_prod:latest | gzip > prod-images.tar.gz - - name: migrate - run: yarn migrate + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: prod-images + path: prod-images.tar.gz - - name: Setup service file - run: sudo cp server-script/aihomeworkprod.service /etc/systemd/system + - name: Copy Docker images to server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + source: "prod-images.tar.gz" + target: "~/images-tar" - - name: Start the app - run: | - sudo systemctl daemon-reload - sudo systemctl restart aihomeworkprod + - name: Deploy to server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + script: | + cd ~/prod-deployment/hng_boilerplate_expressjs + git stash + git checkout prod + git pull + docker load -i ~/images-tar/prod-images.tar.gz + docker compose -f docker-compose.production.yml down + docker compose -f docker-compose.production.yml up -d + + on-failure: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + steps: + - run: echo "CI Workflow failed. Prod deployment was not triggered." \ No newline at end of file diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 3e020bd7..9d757dd3 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -1,40 +1,74 @@ -name: Build, Test, and Deploy for Dev Branch +name: Deploy to staging on: - push: - branches: - - dev + workflow_run: + workflows: [CI] + types: + - completed + branches: [staging] jobs: - build: - runs-on: self-hosted - defaults: - run: - working-directory: /var/www/aihomework/staging - + on-success: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - name: Pull from github - id: pull + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install sshpass + run: sudo apt-get install sshpass + + - name: Fetch .env file from server run: | - git stash - git pull origin staging + sshpass -p ${{ secrets.PASSWORD }} scp -o StrictHostKeyChecking=no ${{ secrets.USERNAME }}@${{ secrets.HOST }}:~/staging-deployment/hng_boilerplate_expressjs/.env .env + env: + SSH_HOST: ${{ secrets.HOST }} + SSH_USERNAME: ${{ secrets.USERNAME }} + SSH_PASSWORD: ${{ secrets.PASSWORD }} - - name: install dependencies - run: yarn install + - name: Build Docker images + run: | + docker compose --env-file .env -f docker-compose.staging.yml build - - name: Run Test - run: yarn test + - name: List Docker images + run: docker images - - name: buld the dist - run: yarn build + - name: Save Docker images to tarball + run: | + docker save hng_boilerplate_expressjs-backend_staging:latest | gzip > staging-images.tar.gz - - name: migrate - run: yarn reset-db + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: staging-images + path: staging-images.tar.gz - - name: setup service file - run: sudo cp server-script/aihomeworkstaging.service /etc/systemd/system + - name: Copy Docker images to server + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + source: "staging-images.tar.gz" + target: "~/images-tar" - - name: start the app - run: | - sudo systemctl daemon-reload - sudo systemctl restart aihomeworkstaging + - name: Deploy to server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + password: ${{ secrets.PASSWORD }} + script: | + cd ~/staging-deployment/hng_boilerplate_expressjs + git stash + git checkout staging + git pull + docker load -i ~/images-tar/staging-images.tar.gz + docker compose -f docker-compose.staging.yml down + docker compose -f docker-compose.staging.yml up -d + + on-failure: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + steps: + - run: echo "CI Workflow failed. Staging deployment was not triggered." \ No newline at end of file diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 82eb3069..82ba1d0c 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -1,12 +1,12 @@ services: - backend: + backend_prod: container_name: backend_prod build: context: . ports: - 4444:8000 env_file: - - /var/www/aihomework/prod/.env + - .env environment: NODE_ENV: production DB_HOST: backend_db_prod @@ -24,7 +24,7 @@ services: container_name: backend_db_prod restart: unless-stopped env_file: - - /var/www/aihomework/prod/.env + - .env environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml index 1c49750c..3e9dba04 100644 --- a/docker-compose.staging.yml +++ b/docker-compose.staging.yml @@ -1,12 +1,12 @@ services: - backend: + backend_staging: container_name: backend_staging build: context: . ports: - 3333:8000 env_file: - - /var/www/aihomework/staging/.env + - .env environment: NODE_ENV: staging DB_HOST: backend_db_staging @@ -24,7 +24,7 @@ services: container_name: backend_db_staging restart: unless-stopped env_file: - - /var/www/aihomework/staging/.env + - .env environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} diff --git a/docker-compose.yml b/docker-compose.yml index b3b36c4f..89f740c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: ports: - 2222:8000 env_file: - - /var/www/aihomework/dev/.env + - .env environment: NODE_ENV: development DB_HOST: backend_db @@ -24,7 +24,7 @@ services: container_name: backend_db restart: unless-stopped env_file: - - /var/www/aihomework/dev/.env + - .env environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} diff --git a/src/models/faq.ts b/src/models/faq.ts index 86932bec..8f570d22 100644 --- a/src/models/faq.ts +++ b/src/models/faq.ts @@ -1,4 +1,10 @@ -import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from "typeorm"; import ExtendedBaseEntity from "./extended-base-entity"; import { UserRole } from "../enums/userRoles"; @@ -18,6 +24,12 @@ class FAQ extends ExtendedBaseEntity { @Column({ nullable: false, default: UserRole.SUPER_ADMIN }) createdBy: string; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn() + updated_at: Date; } export { FAQ }; diff --git a/src/models/user.ts b/src/models/user.ts index 03dc0d22..ad88e983 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -68,6 +68,9 @@ export class User extends ExtendedBaseEntity { @Column({ nullable: true }) otp: number; + @Column({ default: false }) + is_superadmin: boolean; + @Column({ nullable: true }) otp_expires_at: Date;