diff --git a/.github/workflows/autodeploy.yml b/.github/workflows/autodeploy.yml new file mode 100644 index 00000000..8f1cec18 --- /dev/null +++ b/.github/workflows/autodeploy.yml @@ -0,0 +1,135 @@ +name: CI/CD Pipeline + +on: + push: + branches: develop +jobs: + CI-PIPELINE: + runs-on: ubuntu-latest + + steps: + # Step 1: Installs needed dependencies to set up our code + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + # Step 2: Tests code too ensure it passes all tests + - name: Run frontend tests + run: cd course-matrix/frontend && npm install && npm run test + - name: Run backend tests + run: cd course-matrix/backend && npm install && npm run test + + # Step 3: Set up Docker Buildx + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Step 4: Sets our our application's environment + - name: setup application env + run: | + cd course-matrix + + # Update frontend .env + cd frontend + echo "VITE_SERVER_URL=\"http://34.130.253.243:8081\"" > .env && \ + echo "VITE_PUBLIC_ASSISTANT_BASE_URL=\"${{ secrets.VITE_PUBLIC_ASSISTANT_BASE_URL }}\"" >> .env && \ + echo "VITE_ASSISTANT_UI_KEY=\"${{ secrets.VITE_ASSISTANT_UI_KEY }}\"" >> .env + + # Update backend .env + cd ../backend + echo "NODE_ENV=\"development\"" > .env && \ + echo "PORT=8081" >> .env && \ + echo "CLIENT_APP_URL=\"http://34.130.253.243:5173\"" >> .env && \ + echo "DATABASE_URL=\"${{ secrets.DATABASE_URL }}\"" >> .env && \ + echo "DATABASE_KEY=\"${{ secrets.DATABASE_KEY }}\"" >> .env && \ + echo "OPENAI_API_KEY=\"${{ secrets.OPENAI_API_KEY }}\"" >> .env && \ + echo "PINECONE_API_KEY=\"${{ secrets.PINECONE_API_KEY }}\"" >> .env && \ + echo "PINECONE_INDEX_NAME=\"course-matrix\"" >> .env && \ + echo "BREVO_API_KEY=\"${{ secrets.BREVO_API_KEY }}\"" >> .env && \ + echo "SENDER_EMAIL=\"${{ secrets.SENDER_EMAIL }}\"" >> .env && \ + echo "SENDER_NAME=\"Course Matrix Notifications\"" >> .env + + cd ../ + + # Step 5: Logging in to dockerhub + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Step 6: Build all required doccker images + - name: Build Docker Image + run: | + cd course-matrix + docker compose build + + # Step 7: Check if images exist before tagging + - name: List Docker Images (Debugging) + run: docker images + + # Step 8: Tags created images with version using github commit tags + - name: Tag Images With Version + run: | + docker tag course-matrix/frontend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:${{ github.sha }} + docker tag course-matrix/backend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:${{ github.sha }} + + # Step 9: Push Docker images version to Docker Hub + - name: Push Docker images version to Docker Hub + run: | + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:${{ github.sha }} + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:${{ github.sha }} + + # Step 10: Tags created images for the master branch + - name: Tag Images for Master Branch + run: | + docker tag course-matrix/frontend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker tag course-matrix/backend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 11: Push Docker images to Docker Hub master branch + - name: Push images to Master Branch + run: | + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + CD-PIPELINE: + needs: CI-PIPELINE + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + # Step 12: Connect to virtual machine + - name: Setup SSH Connection + run: | + echo "${{ secrets.GCP_SSH_PRIVATE_KEY }}" > private_key + chmod 600 private_key + + - name: Deploy to Google Cloud VM + run: | + ssh -i private_key -o StrictHostKeyChecking=no ${{ secrets.GCP_USERNAME }}@${{ secrets.GCP_VM_IP }} << 'EOF' + cd /home/masahisasekita/term-group-project-c01w25-project-course-matrix || { echo "Error: Directory /root/myapp does not exist!"; exit 1; } + + # Step 13: Clears deployment environment + sudo docker rmi -f $(sudo docker images -q) + sudo docker system prune -a --volumes -f + + # Step 14: Pull the latest images + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 15: Run the docker containers + docker run -d -p 5173:5173 ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker run -d -p 8081:8081 ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 16: Run post deployment tests + docker compose down + docker compose up -d --pull always + docker ps + docker exec -it ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master npm test + docker exec -it ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master npm test + EOF \ No newline at end of file diff --git a/CICD/Dockerfile(backend) b/CICD/Dockerfile(backend) new file mode 100644 index 00000000..e6f7b00e --- /dev/null +++ b/CICD/Dockerfile(backend) @@ -0,0 +1,20 @@ +# Use an official Node.js image +FROM node:18 + +# Set the working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application files +COPY . . + +# Expose the backend port +EXPOSE 8081 + +# Start the application +CMD ["npm", "run", "dev"] diff --git a/CICD/Dockerfile(frontend) b/CICD/Dockerfile(frontend) new file mode 100644 index 00000000..87a156fd --- /dev/null +++ b/CICD/Dockerfile(frontend) @@ -0,0 +1,21 @@ +# Use an official Node.js image +FROM node:18 + +# Set the working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application files +COPY . . + +# Expose the frontend port +EXPOSE 8081 +EXPOSE 5173 + +# Start the application +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/CICD/ReadME.pdf b/CICD/ReadME.pdf new file mode 100644 index 00000000..e4594216 Binary files /dev/null and b/CICD/ReadME.pdf differ diff --git a/CICD/autodeploy.yml b/CICD/autodeploy.yml new file mode 100644 index 00000000..8f1cec18 --- /dev/null +++ b/CICD/autodeploy.yml @@ -0,0 +1,135 @@ +name: CI/CD Pipeline + +on: + push: + branches: develop +jobs: + CI-PIPELINE: + runs-on: ubuntu-latest + + steps: + # Step 1: Installs needed dependencies to set up our code + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + # Step 2: Tests code too ensure it passes all tests + - name: Run frontend tests + run: cd course-matrix/frontend && npm install && npm run test + - name: Run backend tests + run: cd course-matrix/backend && npm install && npm run test + + # Step 3: Set up Docker Buildx + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Step 4: Sets our our application's environment + - name: setup application env + run: | + cd course-matrix + + # Update frontend .env + cd frontend + echo "VITE_SERVER_URL=\"http://34.130.253.243:8081\"" > .env && \ + echo "VITE_PUBLIC_ASSISTANT_BASE_URL=\"${{ secrets.VITE_PUBLIC_ASSISTANT_BASE_URL }}\"" >> .env && \ + echo "VITE_ASSISTANT_UI_KEY=\"${{ secrets.VITE_ASSISTANT_UI_KEY }}\"" >> .env + + # Update backend .env + cd ../backend + echo "NODE_ENV=\"development\"" > .env && \ + echo "PORT=8081" >> .env && \ + echo "CLIENT_APP_URL=\"http://34.130.253.243:5173\"" >> .env && \ + echo "DATABASE_URL=\"${{ secrets.DATABASE_URL }}\"" >> .env && \ + echo "DATABASE_KEY=\"${{ secrets.DATABASE_KEY }}\"" >> .env && \ + echo "OPENAI_API_KEY=\"${{ secrets.OPENAI_API_KEY }}\"" >> .env && \ + echo "PINECONE_API_KEY=\"${{ secrets.PINECONE_API_KEY }}\"" >> .env && \ + echo "PINECONE_INDEX_NAME=\"course-matrix\"" >> .env && \ + echo "BREVO_API_KEY=\"${{ secrets.BREVO_API_KEY }}\"" >> .env && \ + echo "SENDER_EMAIL=\"${{ secrets.SENDER_EMAIL }}\"" >> .env && \ + echo "SENDER_NAME=\"Course Matrix Notifications\"" >> .env + + cd ../ + + # Step 5: Logging in to dockerhub + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Step 6: Build all required doccker images + - name: Build Docker Image + run: | + cd course-matrix + docker compose build + + # Step 7: Check if images exist before tagging + - name: List Docker Images (Debugging) + run: docker images + + # Step 8: Tags created images with version using github commit tags + - name: Tag Images With Version + run: | + docker tag course-matrix/frontend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:${{ github.sha }} + docker tag course-matrix/backend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:${{ github.sha }} + + # Step 9: Push Docker images version to Docker Hub + - name: Push Docker images version to Docker Hub + run: | + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:${{ github.sha }} + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:${{ github.sha }} + + # Step 10: Tags created images for the master branch + - name: Tag Images for Master Branch + run: | + docker tag course-matrix/frontend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker tag course-matrix/backend:latest ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 11: Push Docker images to Docker Hub master branch + - name: Push images to Master Branch + run: | + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker push ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + CD-PIPELINE: + needs: CI-PIPELINE + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + # Step 12: Connect to virtual machine + - name: Setup SSH Connection + run: | + echo "${{ secrets.GCP_SSH_PRIVATE_KEY }}" > private_key + chmod 600 private_key + + - name: Deploy to Google Cloud VM + run: | + ssh -i private_key -o StrictHostKeyChecking=no ${{ secrets.GCP_USERNAME }}@${{ secrets.GCP_VM_IP }} << 'EOF' + cd /home/masahisasekita/term-group-project-c01w25-project-course-matrix || { echo "Error: Directory /root/myapp does not exist!"; exit 1; } + + # Step 13: Clears deployment environment + sudo docker rmi -f $(sudo docker images -q) + sudo docker system prune -a --volumes -f + + # Step 14: Pull the latest images + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 15: Run the docker containers + docker run -d -p 5173:5173 ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master + docker run -d -p 8081:8081 ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master + + # Step 16: Run post deployment tests + docker compose down + docker compose up -d --pull always + docker ps + docker exec -it ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-frontend:master npm test + docker exec -it ${{ secrets.DOCKERHUB_USERNAME }}/course-matrix-backend:master npm test + EOF \ No newline at end of file diff --git a/CICD/docker-compose.yml b/CICD/docker-compose.yml new file mode 100644 index 00000000..65619ff3 --- /dev/null +++ b/CICD/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.8' + +services: + backend: + image: course-matrix/backend:latest + build: + context: ./backend + ports: + - "8081:8081" + env_file: + - ./backend/.env + volumes: + - ./backend:/app + - /app/node_modules + command: ["npm", "run", "dev"] + networks: + - course-matrix-net + + frontend: + image: course-matrix/frontend:latest + build: + context: ./frontend + args: + VITE_SERVER_URL: "http://34.130.253.243:8081" + ports: + - "5173:5173" + volumes: + - ./frontend:/app + - /app/node_modules + command: ["npm", "run", "dev"] + depends_on: + - backend + networks: + - course-matrix-net + +networks: + course-matrix-net: + driver: bridge \ No newline at end of file diff --git a/course-matrix/backend/Dockerfile b/course-matrix/backend/Dockerfile new file mode 100644 index 00000000..e6f7b00e --- /dev/null +++ b/course-matrix/backend/Dockerfile @@ -0,0 +1,20 @@ +# Use an official Node.js image +FROM node:18 + +# Set the working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application files +COPY . . + +# Expose the backend port +EXPOSE 8081 + +# Start the application +CMD ["npm", "run", "dev"] diff --git a/course-matrix/backend/package.json b/course-matrix/backend/package.json index a1d58c4c..744d707d 100644 --- a/course-matrix/backend/package.json +++ b/course-matrix/backend/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "ts-node -r dotenv/config src/index.ts", "test": "jest", - "test:watch": "jest --watch" + "test:watch": "jest --watch", + "build": "vite build" }, "keywords": [], "author": "", diff --git a/course-matrix/docker-compose.yml b/course-matrix/docker-compose.yml new file mode 100644 index 00000000..65619ff3 --- /dev/null +++ b/course-matrix/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.8' + +services: + backend: + image: course-matrix/backend:latest + build: + context: ./backend + ports: + - "8081:8081" + env_file: + - ./backend/.env + volumes: + - ./backend:/app + - /app/node_modules + command: ["npm", "run", "dev"] + networks: + - course-matrix-net + + frontend: + image: course-matrix/frontend:latest + build: + context: ./frontend + args: + VITE_SERVER_URL: "http://34.130.253.243:8081" + ports: + - "5173:5173" + volumes: + - ./frontend:/app + - /app/node_modules + command: ["npm", "run", "dev"] + depends_on: + - backend + networks: + - course-matrix-net + +networks: + course-matrix-net: + driver: bridge \ No newline at end of file diff --git a/course-matrix/frontend/Dockerfile b/course-matrix/frontend/Dockerfile new file mode 100644 index 00000000..87a156fd --- /dev/null +++ b/course-matrix/frontend/Dockerfile @@ -0,0 +1,21 @@ +# Use an official Node.js image +FROM node:18 + +# Set the working directory +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application files +COPY . . + +# Expose the frontend port +EXPOSE 8081 +EXPOSE 5173 + +# Start the application +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/course-matrix/frontend/package.json b/course-matrix/frontend/package.json index 00b11f8c..efee9c5e 100644 --- a/course-matrix/frontend/package.json +++ b/course-matrix/frontend/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -b && vite build", + "build": "vite build", "lint": "eslint .", "preview": "vite preview", "test": "jest", diff --git a/course-matrix/frontend/vite.config.ts b/course-matrix/frontend/vite.config.ts index 26808894..fa3675c0 100644 --- a/course-matrix/frontend/vite.config.ts +++ b/course-matrix/frontend/vite.config.ts @@ -10,4 +10,10 @@ export default defineConfig({ "@": path.resolve(__dirname, "./src"), }, }, + server: { + host: "0.0.0.0", // Allow access from external devices + port: 5173, // Ensure it's using the correct port + strictPort: true, // Ensure it doesn't pick a different port if 5173 is in use + open: false, // Prevent auto-opening a browser on the server + }, });