From 05f3822b479eac93fe4f8bef5c4f4b000ffeadcd Mon Sep 17 00:00:00 2001 From: Dekode1859 Date: Mon, 5 Jan 2026 01:11:33 +0530 Subject: [PATCH 1/8] Set up Github Workflows for Checks and Deployments for DEV and PROD --- .github/workflows/deploy-dev.yml | 38 ++++++++++++++++++++ .github/workflows/deploy-prod.yml | 54 +++++++++++++++++++++++++++++ .github/workflows/pr-check-dev.yml | 36 +++++++++++++++++++ .github/workflows/pr-check-prod.yml | 51 +++++++++++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 .github/workflows/deploy-dev.yml create mode 100644 .github/workflows/deploy-prod.yml create mode 100644 .github/workflows/pr-check-dev.yml create mode 100644 .github/workflows/pr-check-prod.yml diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml new file mode 100644 index 0000000..446fa0d --- /dev/null +++ b/.github/workflows/deploy-dev.yml @@ -0,0 +1,38 @@ +name: Deploy to Development + +on: + push: + branches: [develop] + +jobs: + deploy-dev: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Stop existing dev containers + run: | + docker-compose -f docker-compose.dev.yml down || true + + - name: Build and start dev environment + run: | + docker-compose -f docker-compose.dev.yml up -d --build + + - name: Wait for services to start + run: sleep 10 + + - name: Health check backend + run: | + curl -f http://localhost:8002/health || exit 1 + + - name: Verify database connectivity + run: | + docker exec mantis-dev-db psql -U mantis_user -d mantis_dev -c "SELECT 1" || exit 1 + + - name: Deployment summary + run: | + echo "βœ… Dev deployment successful" + echo "🌐 Frontend: http://192.168.1.51:3001" + echo "πŸ”§ Backend: http://192.168.1.51:8002" + echo "πŸ“Š Commit: ${{ github.sha }}" diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..b6b6aa3 --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,54 @@ +name: Deploy to Production + +on: + push: + branches: [master] + +jobs: + deploy-production: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Create pre-deployment backup + run: | + ./scripts/backup-prod.sh + echo "βœ… Pre-deployment backup created" + + - name: Build new production containers + run: | + docker-compose -f docker-compose.prod.yml build + + - name: Deploy with zero downtime + run: | + # Start new containers (will replace old ones) + docker-compose -f docker-compose.prod.yml up -d + + - name: Wait for services to initialize + run: sleep 15 + + - name: Verify backend health + run: | + curl -f http://localhost:8001/health || exit 1 + + - name: Verify database connectivity + run: | + docker exec mantis-prod-db psql -U mantis_user -d mantis_production -c "\dt" + + - name: Verify tunnel is running + run: | + docker ps | grep mantis-prod-tunnel || exit 1 + + - name: Cleanup old Docker images + run: | + docker image prune -f + + - name: Deployment summary + run: | + echo "πŸš€ Production deployment successful" + echo "🌐 Live at: https://mantis.dekode.live" + echo "πŸ“Š Commit: ${{ github.sha }}" + echo "" + echo "πŸ“¦ Running containers:" + docker ps --filter "name=mantis-prod-" --format "table {{.Names}}\t{{.Status}}" diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml new file mode 100644 index 0000000..985b09b --- /dev/null +++ b/.github/workflows/pr-check-dev.yml @@ -0,0 +1,36 @@ +name: Dev PR Checks + +on: + pull_request: + branches: [develop] + +jobs: + validate: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate docker-compose syntax + run: | + docker-compose -f docker-compose.dev.yml config + + - name: Build test (no deployment) + run: | + docker-compose -f docker-compose.dev.yml build + + - name: Check .env.dev exists + run: | + test -f .env.dev || exit 1 + + - name: Verify backend Dockerfile + run: | + test -f backend/Dockerfile || exit 1 + + - name: Verify frontend Dockerfile + run: | + test -f mantis/Dockerfile || exit 1 + + - name: Check disk space + run: | + df -h | grep -E 'Filesystem|/$' diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml new file mode 100644 index 0000000..77d5177 --- /dev/null +++ b/.github/workflows/pr-check-prod.yml @@ -0,0 +1,51 @@ +name: Production PR Checks + +on: + pull_request: + branches: [master] + +jobs: + pre-deployment-checks: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check prod environment status + run: | + docker ps | grep mantis-prod-backend || echo "⚠️ Prod not running (first deploy?)" + + - name: Verify backup system ready + run: | + test -d deployments/prod/backups || mkdir -p deployments/prod/backups + test -f scripts/backup-prod.sh || exit 1 + + - name: Validate docker-compose syntax + run: | + docker-compose -f docker-compose.prod.yml config + + - name: Build test containers + run: | + docker-compose -f docker-compose.prod.yml build + + - name: Check disk space + run: | + df -h | grep -E 'Filesystem|/$' + SPACE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') + if [ $SPACE -gt 80 ]; then + echo "⚠️ Warning: Disk usage above 80%" + exit 1 + fi + + - name: Verify environment variables + run: | + test -f .env.prod || exit 1 + grep -q "CLOUDFLARE_TUNNEL_TOKEN" .env.prod || echo "⚠️ Tunnel token missing" + + - name: Verify database exists + run: | + docker exec mantis-prod-db psql -U mantis_user -d mantis_production -c "\dt" || echo "⚠️ First deployment - tables will be created" + + - name: Check backend health + run: | + curl -f http://localhost:8001/health || echo "⚠️ Backend not responding (will restart on deploy)" From 68c925f43556f986b42b28f4c459556242c0e85b Mon Sep 17 00:00:00 2001 From: Pratik Dwivedi <93965493+Dekode1859@users.noreply.github.com> Date: Mon, 5 Jan 2026 01:17:23 +0530 Subject: [PATCH 2/8] Set up Github Workflows for Checks and Deployments for DEV and PROD (#7) --- .github/workflows/deploy-dev.yml | 38 ++++++++++++++++++++ .github/workflows/deploy-prod.yml | 54 +++++++++++++++++++++++++++++ .github/workflows/pr-check-dev.yml | 36 +++++++++++++++++++ .github/workflows/pr-check-prod.yml | 51 +++++++++++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 .github/workflows/deploy-dev.yml create mode 100644 .github/workflows/deploy-prod.yml create mode 100644 .github/workflows/pr-check-dev.yml create mode 100644 .github/workflows/pr-check-prod.yml diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml new file mode 100644 index 0000000..446fa0d --- /dev/null +++ b/.github/workflows/deploy-dev.yml @@ -0,0 +1,38 @@ +name: Deploy to Development + +on: + push: + branches: [develop] + +jobs: + deploy-dev: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Stop existing dev containers + run: | + docker-compose -f docker-compose.dev.yml down || true + + - name: Build and start dev environment + run: | + docker-compose -f docker-compose.dev.yml up -d --build + + - name: Wait for services to start + run: sleep 10 + + - name: Health check backend + run: | + curl -f http://localhost:8002/health || exit 1 + + - name: Verify database connectivity + run: | + docker exec mantis-dev-db psql -U mantis_user -d mantis_dev -c "SELECT 1" || exit 1 + + - name: Deployment summary + run: | + echo "βœ… Dev deployment successful" + echo "🌐 Frontend: http://192.168.1.51:3001" + echo "πŸ”§ Backend: http://192.168.1.51:8002" + echo "πŸ“Š Commit: ${{ github.sha }}" diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..b6b6aa3 --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,54 @@ +name: Deploy to Production + +on: + push: + branches: [master] + +jobs: + deploy-production: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Create pre-deployment backup + run: | + ./scripts/backup-prod.sh + echo "βœ… Pre-deployment backup created" + + - name: Build new production containers + run: | + docker-compose -f docker-compose.prod.yml build + + - name: Deploy with zero downtime + run: | + # Start new containers (will replace old ones) + docker-compose -f docker-compose.prod.yml up -d + + - name: Wait for services to initialize + run: sleep 15 + + - name: Verify backend health + run: | + curl -f http://localhost:8001/health || exit 1 + + - name: Verify database connectivity + run: | + docker exec mantis-prod-db psql -U mantis_user -d mantis_production -c "\dt" + + - name: Verify tunnel is running + run: | + docker ps | grep mantis-prod-tunnel || exit 1 + + - name: Cleanup old Docker images + run: | + docker image prune -f + + - name: Deployment summary + run: | + echo "πŸš€ Production deployment successful" + echo "🌐 Live at: https://mantis.dekode.live" + echo "πŸ“Š Commit: ${{ github.sha }}" + echo "" + echo "πŸ“¦ Running containers:" + docker ps --filter "name=mantis-prod-" --format "table {{.Names}}\t{{.Status}}" diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml new file mode 100644 index 0000000..985b09b --- /dev/null +++ b/.github/workflows/pr-check-dev.yml @@ -0,0 +1,36 @@ +name: Dev PR Checks + +on: + pull_request: + branches: [develop] + +jobs: + validate: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate docker-compose syntax + run: | + docker-compose -f docker-compose.dev.yml config + + - name: Build test (no deployment) + run: | + docker-compose -f docker-compose.dev.yml build + + - name: Check .env.dev exists + run: | + test -f .env.dev || exit 1 + + - name: Verify backend Dockerfile + run: | + test -f backend/Dockerfile || exit 1 + + - name: Verify frontend Dockerfile + run: | + test -f mantis/Dockerfile || exit 1 + + - name: Check disk space + run: | + df -h | grep -E 'Filesystem|/$' diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml new file mode 100644 index 0000000..77d5177 --- /dev/null +++ b/.github/workflows/pr-check-prod.yml @@ -0,0 +1,51 @@ +name: Production PR Checks + +on: + pull_request: + branches: [master] + +jobs: + pre-deployment-checks: + runs-on: self-hosted + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check prod environment status + run: | + docker ps | grep mantis-prod-backend || echo "⚠️ Prod not running (first deploy?)" + + - name: Verify backup system ready + run: | + test -d deployments/prod/backups || mkdir -p deployments/prod/backups + test -f scripts/backup-prod.sh || exit 1 + + - name: Validate docker-compose syntax + run: | + docker-compose -f docker-compose.prod.yml config + + - name: Build test containers + run: | + docker-compose -f docker-compose.prod.yml build + + - name: Check disk space + run: | + df -h | grep -E 'Filesystem|/$' + SPACE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') + if [ $SPACE -gt 80 ]; then + echo "⚠️ Warning: Disk usage above 80%" + exit 1 + fi + + - name: Verify environment variables + run: | + test -f .env.prod || exit 1 + grep -q "CLOUDFLARE_TUNNEL_TOKEN" .env.prod || echo "⚠️ Tunnel token missing" + + - name: Verify database exists + run: | + docker exec mantis-prod-db psql -U mantis_user -d mantis_production -c "\dt" || echo "⚠️ First deployment - tables will be created" + + - name: Check backend health + run: | + curl -f http://localhost:8001/health || echo "⚠️ Backend not responding (will restart on deploy)" From bfd810fbad8fae90fa729bed05dfd5c6f5aefbe7 Mon Sep 17 00:00:00 2001 From: Dekode1859 Date: Mon, 5 Jan 2026 01:57:30 +0530 Subject: [PATCH 3/8] fix: update workflows to use docker compose V2 command and add runner setup scripts --- .github/workflows/deploy-dev.yml | 8 +- .github/workflows/deploy-prod.yml | 4 +- .github/workflows/pr-check-dev.yml | 4 +- .github/workflows/pr-check-prod.yml | 15 +- scripts/check-runner-status.sh | 122 ++++++++++++++++ scripts/setup-github-runner.sh | 214 ++++++++++++++++++++++++++++ scripts/update-runner.sh | 173 ++++++++++++++++++++++ 7 files changed, 530 insertions(+), 10 deletions(-) create mode 100755 scripts/check-runner-status.sh create mode 100755 scripts/setup-github-runner.sh create mode 100755 scripts/update-runner.sh diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 446fa0d..ceb504c 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -13,11 +13,11 @@ jobs: - name: Stop existing dev containers run: | - docker-compose -f docker-compose.dev.yml down || true + docker compose -f docker-compose.dev.yml down || true - name: Build and start dev environment run: | - docker-compose -f docker-compose.dev.yml up -d --build + docker compose -f docker-compose.dev.yml up -d --build - name: Wait for services to start run: sleep 10 @@ -33,6 +33,6 @@ jobs: - name: Deployment summary run: | echo "βœ… Dev deployment successful" - echo "🌐 Frontend: http://192.168.1.51:3001" - echo "πŸ”§ Backend: http://192.168.1.51:8002" + echo "🌐 Frontend: http://192.168.1.25:3001" + echo "πŸ”§ Backend: http://192.168.1.25:8002" echo "πŸ“Š Commit: ${{ github.sha }}" diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index b6b6aa3..d7fb12c 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -18,12 +18,12 @@ jobs: - name: Build new production containers run: | - docker-compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml build - name: Deploy with zero downtime run: | # Start new containers (will replace old ones) - docker-compose -f docker-compose.prod.yml up -d + docker compose -f docker-compose.prod.yml up -d - name: Wait for services to initialize run: sleep 15 diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml index 985b09b..9458296 100644 --- a/.github/workflows/pr-check-dev.yml +++ b/.github/workflows/pr-check-dev.yml @@ -13,11 +13,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker-compose -f docker-compose.dev.yml config + docker compose -f docker-compose.dev.yml config - name: Build test (no deployment) run: | - docker-compose -f docker-compose.dev.yml build + docker compose -f docker-compose.dev.yml build - name: Check .env.dev exists run: | diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml index 77d5177..3eb9784 100644 --- a/.github/workflows/pr-check-prod.yml +++ b/.github/workflows/pr-check-prod.yml @@ -8,6 +8,17 @@ jobs: pre-deployment-checks: runs-on: self-hosted steps: + - name: Enforce source branch is develop + run: | + SOURCE_BRANCH="${{ github.head_ref }}" + if [ "$SOURCE_BRANCH" != "develop" ]; then + echo "❌ ERROR: Pull requests to master must come from 'develop' branch only!" + echo " Current source branch: $SOURCE_BRANCH" + echo " Please merge your changes to 'develop' first, then create a PR from develop to master." + exit 1 + fi + echo "βœ… Source branch validation passed: $SOURCE_BRANCH β†’ master" + - name: Checkout code uses: actions/checkout@v4 @@ -22,11 +33,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker-compose -f docker-compose.prod.yml config + docker compose -f docker-compose.prod.yml config - name: Build test containers run: | - docker-compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml build - name: Check disk space run: | diff --git a/scripts/check-runner-status.sh b/scripts/check-runner-status.sh new file mode 100755 index 0000000..45a6901 --- /dev/null +++ b/scripts/check-runner-status.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# scripts/check-runner-status.sh +# Check GitHub Actions runner health and status + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +RUNNER_DIR="/root/actions-runner" +SERVICE_NAME="actions.runner.Dekode1859-Mantis.mantis-lxc-runner" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Runner Status Check β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if runner directory exists +if [ ! -d "$RUNNER_DIR" ]; then + echo -e "${RED}❌ Runner not installed${NC}" + echo -e " Directory not found: $RUNNER_DIR" + echo -e " Run: ${GREEN}/root/Mantis/scripts/setup-github-runner.sh${NC}" + exit 1 +fi + +# Check service status +echo -e "${BLUE}πŸ” Service Status:${NC}" +if systemctl is-active --quiet "$SERVICE_NAME"; then + echo -e " ${GREEN}βœ… Service is running${NC}" + SERVICE_STATUS="running" +else + echo -e " ${RED}❌ Service is not running${NC}" + SERVICE_STATUS="stopped" +fi + +# Get detailed service status +echo "" +echo -e "${BLUE}πŸ“Š Detailed Service Status:${NC}" +systemctl status "$SERVICE_NAME" --no-pager | head -15 + +# Check if runner is enabled on boot +echo "" +echo -e "${BLUE}πŸ”„ Auto-start on Boot:${NC}" +if systemctl is-enabled --quiet "$SERVICE_NAME"; then + echo -e " ${GREEN}βœ… Enabled${NC}" +else + echo -e " ${YELLOW}⚠️ Disabled${NC}" +fi + +# Check disk space in work directory +echo "" +echo -e "${BLUE}πŸ’Ύ Disk Space:${NC}" +WORK_DIR="$RUNNER_DIR/_work" +if [ -d "$WORK_DIR" ]; then + WORK_SIZE=$(du -sh "$WORK_DIR" 2>/dev/null | cut -f1) + echo -e " Work directory: ${GREEN}$WORK_SIZE${NC}" +else + echo -e " Work directory: ${YELLOW}Not created yet${NC}" +fi + +# Overall system disk space +DISK_USAGE=$(df -h / | tail -1 | awk '{print $5}' | sed 's/%//') +DISK_AVAIL=$(df -h / | tail -1 | awk '{print $4}') +if [ "$DISK_USAGE" -gt 80 ]; then + echo -e " System disk: ${RED}$DISK_USAGE% used (${DISK_AVAIL} available)${NC}" + echo -e " ${YELLOW}⚠️ Warning: Disk usage above 80%${NC}" +else + echo -e " System disk: ${GREEN}$DISK_USAGE% used (${DISK_AVAIL} available)${NC}" +fi + +# Show recent logs if service is running +if [ "$SERVICE_STATUS" = "running" ]; then + echo "" + echo -e "${BLUE}πŸ“œ Recent Logs (last 10 lines):${NC}" + journalctl -u "$SERVICE_NAME" -n 10 --no-pager | sed 's/^/ /' +fi + +# Check runner configuration +echo "" +echo -e "${BLUE}βš™οΈ Runner Configuration:${NC}" +if [ -f "$RUNNER_DIR/.runner" ]; then + RUNNER_NAME=$(grep -o '"AgentName":"[^"]*"' "$RUNNER_DIR/.runner" | cut -d'"' -f4) + RUNNER_ID=$(grep -o '"AgentId":[0-9]*' "$RUNNER_DIR/.runner" | cut -d':' -f2) + echo -e " Name: ${GREEN}$RUNNER_NAME${NC}" + echo -e " ID: ${GREEN}$RUNNER_ID${NC}" +else + echo -e " ${YELLOW}Configuration file not found${NC}" +fi + +# Summary +echo "" +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ Summary β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +if [ "$SERVICE_STATUS" = "running" ]; then + echo -e "${GREEN}βœ… Runner is operational${NC}" + echo "" + echo -e "${BLUE}Verify in GitHub:${NC}" + echo -e " https://github.com/Dekode1859/Mantis/settings/actions/runners" + echo -e " Status should show: ${GREEN}Idle${NC} or ${GREEN}Active${NC}" + echo "" + echo -e "${BLUE}Useful Commands:${NC}" + echo -e " View live logs: ${GREEN}journalctl -u $SERVICE_NAME -f${NC}" + echo -e " Restart service: ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh restart${NC}" + echo -e " Stop service: ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh stop${NC}" +else + echo -e "${RED}❌ Runner is not running${NC}" + echo "" + echo -e "${YELLOW}To start the runner:${NC}" + echo -e " ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh start${NC}" + echo "" + echo -e "${YELLOW}To check for errors:${NC}" + echo -e " ${GREEN}journalctl -u $SERVICE_NAME -n 50${NC}" +fi + +echo "" diff --git a/scripts/setup-github-runner.sh b/scripts/setup-github-runner.sh new file mode 100755 index 0000000..e1a166e --- /dev/null +++ b/scripts/setup-github-runner.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# scripts/setup-github-runner.sh +# Setup GitHub Actions self-hosted runner on LXC container +# Runner will be installed at: /root/actions-runner (outside Mantis directory) + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +RUNNER_VERSION="2.319.1" +RUNNER_DIR="/root/actions-runner" +REPO_URL="https://github.com/Dekode1859/Mantis" +RUNNER_NAME="mantis-lxc-runner" +RUNNER_LABELS="self-hosted,linux,x64,mantis" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Self-Hosted Runner Setup β•‘${NC}" +echo -e "${BLUE}β•‘ For Mantis Project β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if running as root - we'll need to use a workaround +RUNNING_AS_ROOT=false +if [ "$EUID" -eq 0 ]; then + RUNNING_AS_ROOT=true + echo -e "${YELLOW}⚠️ Running as root detected${NC}" + echo -e "${YELLOW} GitHub runner config cannot run as root for security${NC}" + echo -e "${YELLOW} Script will use RUNNER_ALLOW_RUNASROOT=1 workaround${NC}" + echo "" +fi + +# Check if runner already exists +if [ -d "$RUNNER_DIR" ]; then + echo -e "${YELLOW}⚠️ Runner directory already exists: $RUNNER_DIR${NC}" + read -p "Do you want to remove it and reinstall? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo -e "${BLUE}πŸ—‘οΈ Removing existing runner...${NC}" + cd "$RUNNER_DIR" + # Stop and remove service if it exists + if [ -f "svc.sh" ]; then + if [ "$EUID" -eq 0 ]; then + ./svc.sh stop 2>/dev/null || true + ./svc.sh uninstall 2>/dev/null || true + else + sudo ./svc.sh stop 2>/dev/null || true + sudo ./svc.sh uninstall 2>/dev/null || true + fi + fi + cd /root + if [ "$EUID" -eq 0 ]; then + rm -rf "$RUNNER_DIR" + else + sudo rm -rf "$RUNNER_DIR" + fi + else + echo -e "${RED}❌ Installation cancelled${NC}" + exit 1 + fi +fi + +# Create runner directory +echo -e "${BLUE}πŸ“ Creating runner directory: $RUNNER_DIR${NC}" +if [ "$RUNNING_AS_ROOT" = true ]; then + mkdir -p "$RUNNER_DIR" +else + sudo mkdir -p "$RUNNER_DIR" + sudo chown $USER:$USER "$RUNNER_DIR" +fi +cd "$RUNNER_DIR" + +# Download runner +echo -e "${BLUE}⬇️ Downloading GitHub Actions Runner v${RUNNER_VERSION}...${NC}" +RUNNER_FILE="actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" +DOWNLOAD_URL="https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/${RUNNER_FILE}" + +curl -o "$RUNNER_FILE" -L "$DOWNLOAD_URL" + +if [ ! -f "$RUNNER_FILE" ]; then + echo -e "${RED}❌ Failed to download runner${NC}" + exit 1 +fi + +# Extract runner +echo -e "${BLUE}πŸ“¦ Extracting runner...${NC}" +tar xzf "$RUNNER_FILE" + +# Cleanup downloaded archive +rm "$RUNNER_FILE" + +echo "" +echo -e "${GREEN}βœ… Runner downloaded and extracted${NC}" +echo "" + +# Get registration token from user +echo -e "${YELLOW}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${YELLOW}β•‘ REGISTRATION TOKEN REQUIRED β•‘${NC}" +echo -e "${YELLOW}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" +echo -e "${BLUE}To get your registration token:${NC}" +echo -e "1. Open: ${GREEN}https://github.com/Dekode1859/Mantis/settings/actions/runners/new${NC}" +echo -e "2. Select: ${GREEN}Linux${NC} and ${GREEN}x64${NC}" +echo -e "3. Copy the token from the ${GREEN}Configure${NC} section" +echo -e " (It starts with 'A' and is very long)" +echo "" +echo -e "${YELLOW}Note: Token expires in 1 hour. Generate a new one if expired.${NC}" +echo "" + +read -p "Enter your registration token: " REGISTRATION_TOKEN + +if [ -z "$REGISTRATION_TOKEN" ]; then + echo -e "${RED}❌ Registration token cannot be empty${NC}" + exit 1 +fi + +# Configure runner +echo "" +echo -e "${BLUE}βš™οΈ Configuring runner...${NC}" +echo "" + +# If running as root, set environment variable to allow it +if [ "$RUNNING_AS_ROOT" = true ]; then + export RUNNER_ALLOW_RUNASROOT=1 +fi + +./config.sh \ + --url "$REPO_URL" \ + --token "$REGISTRATION_TOKEN" \ + --name "$RUNNER_NAME" \ + --labels "$RUNNER_LABELS" \ + --work _work \ + --unattended \ + --replace + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Runner configuration failed${NC}" + exit 1 +fi + +echo "" +echo -e "${GREEN}βœ… Runner configured successfully${NC}" +echo "" + +# Install as service (requires root) +echo -e "${BLUE}πŸ”§ Installing runner as systemd service...${NC}" + +if [ "$RUNNING_AS_ROOT" = true ]; then + ./svc.sh install +else + sudo ./svc.sh install +fi + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Service installation failed${NC}" + exit 1 +fi + +# Start service (requires root) +echo -e "${BLUE}▢️ Starting runner service...${NC}" + +if [ "$RUNNING_AS_ROOT" = true ]; then + ./svc.sh start +else + sudo ./svc.sh start +fi + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Service start failed${NC}" + exit 1 +fi + +# Wait a moment for service to start +sleep 3 + +# Check service status +echo "" +echo -e "${BLUE}πŸ₯ Checking service status...${NC}" +./svc.sh status + +echo "" +echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}β•‘ βœ… INSTALLATION COMPLETE! β•‘${NC}" +echo -e "${GREEN}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" +echo -e "${BLUE}Runner Details:${NC}" +echo -e " πŸ“ Location: ${GREEN}$RUNNER_DIR${NC}" +echo -e " 🏷️ Name: ${GREEN}$RUNNER_NAME${NC}" +echo -e " 🏷️ Labels: ${GREEN}$RUNNER_LABELS${NC}" +echo -e " πŸ“¦ Repository: ${GREEN}$REPO_URL${NC}" +echo "" +echo -e "${BLUE}Service Management:${NC}" +echo -e " Status: ${GREEN}sudo systemctl status actions.runner.Dekode1859-Mantis.mantis-lxc-runner${NC}" +echo -e " Stop: ${GREEN}cd $RUNNER_DIR && ./svc.sh stop${NC}" +echo -e " Start: ${GREEN}cd $RUNNER_DIR && ./svc.sh start${NC}" +echo -e " Restart: ${GREEN}cd $RUNNER_DIR && ./svc.sh restart${NC}" +echo "" +echo -e "${BLUE}Verify in GitHub:${NC}" +echo -e " Go to: ${GREEN}https://github.com/Dekode1859/Mantis/settings/actions/runners${NC}" +echo -e " You should see: ${GREEN}mantis-lxc-runner${NC} with status ${GREEN}Idle${NC}" +echo "" +echo -e "${BLUE}Check Runner Status:${NC}" +echo -e " Run: ${GREEN}/root/Mantis/scripts/check-runner-status.sh${NC}" +echo "" +echo -e "${YELLOW}Next Steps:${NC}" +echo -e " 1. Verify runner appears in GitHub (link above)" +echo -e " 2. Test by creating a PR to the 'develop' branch" +echo -e " 3. Watch the workflow run on your self-hosted runner!" +echo "" diff --git a/scripts/update-runner.sh b/scripts/update-runner.sh new file mode 100755 index 0000000..c26d0d1 --- /dev/null +++ b/scripts/update-runner.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# scripts/update-runner.sh +# Update GitHub Actions runner to latest version + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +RUNNER_DIR="/root/actions-runner" +SERVICE_NAME="actions.runner.Dekode1859-Mantis.mantis-lxc-runner" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Runner Update β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}❌ This script must be run as root${NC}" + exit 1 +fi + +# Check if runner exists +if [ ! -d "$RUNNER_DIR" ]; then + echo -e "${RED}❌ Runner not installed at: $RUNNER_DIR${NC}" + echo -e " Run setup script first: ${GREEN}/root/Mantis/scripts/setup-github-runner.sh${NC}" + exit 1 +fi + +cd "$RUNNER_DIR" + +# Get current version +if [ -f "./bin/Runner.Listener" ]; then + CURRENT_VERSION=$(./bin/Runner.Listener --version 2>/dev/null | head -1 || echo "unknown") + echo -e "${BLUE}πŸ“¦ Current version: ${GREEN}$CURRENT_VERSION${NC}" +else + echo -e "${YELLOW}⚠️ Could not determine current version${NC}" + CURRENT_VERSION="unknown" +fi + +# Prompt for new version +echo "" +echo -e "${YELLOW}Enter the new runner version to install:${NC}" +echo -e " (e.g., 2.319.1)" +echo -e " Find latest: ${GREEN}https://github.com/actions/runner/releases${NC}" +echo "" +read -p "Version: " NEW_VERSION + +if [ -z "$NEW_VERSION" ]; then + echo -e "${RED}❌ Version cannot be empty${NC}" + exit 1 +fi + +# Confirm update +echo "" +echo -e "${YELLOW}⚠️ This will:${NC}" +echo -e " 1. Stop the runner service" +echo -e " 2. Download runner v$NEW_VERSION" +echo -e " 3. Replace binaries" +echo -e " 4. Restart the service" +echo "" +echo -e "${YELLOW}Configuration will be preserved (.runner, .credentials, etc.)${NC}" +echo "" +read -p "Continue? (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${RED}❌ Update cancelled${NC}" + exit 1 +fi + +# Stop service +echo "" +echo -e "${BLUE}πŸ›‘ Stopping runner service...${NC}" +./svc.sh stop + +# Wait for service to stop +sleep 2 + +# Backup current configuration +echo -e "${BLUE}πŸ’Ύ Backing up configuration...${NC}" +BACKUP_DIR="/root/runner-backup-$(date +%Y%m%d_%H%M%S)" +mkdir -p "$BACKUP_DIR" + +# Backup critical files +for file in .runner .credentials .credentials_rsaparams; do + if [ -f "$file" ]; then + cp "$file" "$BACKUP_DIR/" + fi +done + +echo -e " ${GREEN}βœ… Backup saved to: $BACKUP_DIR${NC}" + +# Download new runner +echo -e "${BLUE}⬇️ Downloading runner v$NEW_VERSION...${NC}" +RUNNER_FILE="actions-runner-linux-x64-${NEW_VERSION}.tar.gz" +DOWNLOAD_URL="https://github.com/actions/runner/releases/download/v${NEW_VERSION}/${RUNNER_FILE}" + +# Create temp directory for download +TEMP_DIR="/tmp/runner-update-$$" +mkdir -p "$TEMP_DIR" + +cd "$TEMP_DIR" +if ! curl -o "$RUNNER_FILE" -L "$DOWNLOAD_URL"; then + echo -e "${RED}❌ Failed to download runner v$NEW_VERSION${NC}" + echo -e " Check if version exists: $DOWNLOAD_URL" + rm -rf "$TEMP_DIR" + cd "$RUNNER_DIR" + ./svc.sh start + exit 1 +fi + +# Extract new runner +echo -e "${BLUE}πŸ“¦ Extracting new runner...${NC}" +cd "$RUNNER_DIR" + +# Remove old binaries but keep configuration +echo -e "${BLUE}πŸ—‘οΈ Removing old binaries...${NC}" +rm -rf bin externals + +# Extract new binaries +echo -e "${BLUE}πŸ“‚ Installing new binaries...${NC}" +tar xzf "$TEMP_DIR/$RUNNER_FILE" + +# Cleanup +rm -rf "$TEMP_DIR" + +# Verify extraction +if [ ! -f "./bin/Runner.Listener" ]; then + echo -e "${RED}❌ Update failed - binaries not found${NC}" + echo -e " Restoring from backup: $BACKUP_DIR" + # Note: This is a simplified restore - you may need to re-run setup in practice + exit 1 +fi + +# Start service +echo -e "${BLUE}▢️ Starting runner service...${NC}" +./svc.sh start + +# Wait for service to start +sleep 3 + +# Verify service is running +if systemctl is-active --quiet "$SERVICE_NAME"; then + NEW_INSTALLED_VERSION=$(./bin/Runner.Listener --version 2>/dev/null | head -1 || echo "unknown") + echo "" + echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}β•‘ βœ… UPDATE COMPLETE! β•‘${NC}" + echo -e "${GREEN}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" + echo "" + echo -e "${BLUE}Version Update:${NC}" + echo -e " Previous: ${YELLOW}$CURRENT_VERSION${NC}" + echo -e " Current: ${GREEN}$NEW_INSTALLED_VERSION${NC}" + echo "" + echo -e "${BLUE}Service Status:${NC}" + echo -e " ${GREEN}βœ… Running${NC}" + echo "" + echo -e "${BLUE}Backup Location:${NC}" + echo -e " ${GREEN}$BACKUP_DIR${NC}" + echo "" + echo -e "${BLUE}Verify in GitHub:${NC}" + echo -e " https://github.com/Dekode1859/Mantis/settings/actions/runners" + echo "" +else + echo -e "${RED}❌ Service failed to start after update${NC}" + echo -e " Check logs: ${GREEN}journalctl -u $SERVICE_NAME -n 50${NC}" + echo -e " Backup available: ${GREEN}$BACKUP_DIR${NC}" + exit 1 +fi From 45f272c25845a1b7e5d0c932f25892476f7268bb Mon Sep 17 00:00:00 2001 From: Dekode1859 Date: Mon, 5 Jan 2026 02:31:19 +0530 Subject: [PATCH 4/8] Update Github Workflows to run using github environments --- .github/workflows/deploy-dev.yml | 30 ++++++++++++++++++++++++++ .github/workflows/deploy-prod.yml | 33 +++++++++++++++++++++++++++++ .github/workflows/pr-check-dev.yml | 30 ++++++++++++++++++++++++++ .github/workflows/pr-check-prod.yml | 33 +++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index ceb504c..59ffa86 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -7,10 +7,35 @@ on: jobs: deploy-dev: runs-on: self-hosted + environment: development + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.dev from GitHub secrets + run: | + cat > .env.dev << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGINS=${{ secrets.CORS_ALLOW_ORIGINS }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + EOF + - name: Stop existing dev containers run: | docker compose -f docker-compose.dev.yml down || true @@ -36,3 +61,8 @@ jobs: echo "🌐 Frontend: http://192.168.1.25:3001" echo "πŸ”§ Backend: http://192.168.1.25:8002" echo "πŸ“Š Commit: ${{ github.sha }}" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.dev diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index d7fb12c..6938a00 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -7,10 +7,38 @@ on: jobs: deploy-production: runs-on: self-hosted + environment: production + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.prod from GitHub secrets + run: | + cat > .env.prod << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGIN_REGEX=${{ secrets.CORS_ALLOW_ORIGIN_REGEX }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + + # Cloudflare Tunnel Token + CLOUDFLARE_TUNNEL_TOKEN=${{ secrets.CLOUDFLARE_TUNNEL_TOKEN }} + EOF + - name: Create pre-deployment backup run: | ./scripts/backup-prod.sh @@ -52,3 +80,8 @@ jobs: echo "" echo "πŸ“¦ Running containers:" docker ps --filter "name=mantis-prod-" --format "table {{.Names}}\t{{.Status}}" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.prod diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml index 9458296..53fe852 100644 --- a/.github/workflows/pr-check-dev.yml +++ b/.github/workflows/pr-check-dev.yml @@ -7,10 +7,35 @@ on: jobs: validate: runs-on: self-hosted + environment: development + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.dev from GitHub secrets + run: | + cat > .env.dev << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGINS=${{ secrets.CORS_ALLOW_ORIGINS }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + EOF + - name: Validate docker-compose syntax run: | docker compose -f docker-compose.dev.yml config @@ -34,3 +59,8 @@ jobs: - name: Check disk space run: | df -h | grep -E 'Filesystem|/$' + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.dev diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml index 3eb9784..c594b33 100644 --- a/.github/workflows/pr-check-prod.yml +++ b/.github/workflows/pr-check-prod.yml @@ -7,6 +7,8 @@ on: jobs: pre-deployment-checks: runs-on: self-hosted + environment: production + steps: - name: Enforce source branch is develop run: | @@ -22,6 +24,32 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.prod from GitHub secrets + run: | + cat > .env.prod << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGIN_REGEX=${{ secrets.CORS_ALLOW_ORIGIN_REGEX }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + + # Cloudflare Tunnel Token + CLOUDFLARE_TUNNEL_TOKEN=${{ secrets.CLOUDFLARE_TUNNEL_TOKEN }} + EOF + - name: Check prod environment status run: | docker ps | grep mantis-prod-backend || echo "⚠️ Prod not running (first deploy?)" @@ -60,3 +88,8 @@ jobs: - name: Check backend health run: | curl -f http://localhost:8001/health || echo "⚠️ Backend not responding (will restart on deploy)" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.prod From c404f98cfcd90f7e59249582ca90acbcf4ee98ca Mon Sep 17 00:00:00 2001 From: Pratik Dwivedi <93965493+Dekode1859@users.noreply.github.com> Date: Mon, 5 Jan 2026 02:32:38 +0530 Subject: [PATCH 5/8] cicd/dev prod checks deploy (#8) * Set up Github Workflows for Checks and Deployments for DEV and PROD * fix: update workflows to use docker compose V2 command and add runner setup scripts * Update Github Workflows to run using github environments --- .github/workflows/deploy-dev.yml | 38 ++++- .github/workflows/deploy-prod.yml | 37 ++++- .github/workflows/pr-check-dev.yml | 34 ++++- .github/workflows/pr-check-prod.yml | 48 ++++++- scripts/check-runner-status.sh | 122 ++++++++++++++++ scripts/setup-github-runner.sh | 214 ++++++++++++++++++++++++++++ scripts/update-runner.sh | 173 ++++++++++++++++++++++ 7 files changed, 656 insertions(+), 10 deletions(-) create mode 100755 scripts/check-runner-status.sh create mode 100755 scripts/setup-github-runner.sh create mode 100755 scripts/update-runner.sh diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 446fa0d..59ffa86 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -7,17 +7,42 @@ on: jobs: deploy-dev: runs-on: self-hosted + environment: development + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.dev from GitHub secrets + run: | + cat > .env.dev << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGINS=${{ secrets.CORS_ALLOW_ORIGINS }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + EOF + - name: Stop existing dev containers run: | - docker-compose -f docker-compose.dev.yml down || true + docker compose -f docker-compose.dev.yml down || true - name: Build and start dev environment run: | - docker-compose -f docker-compose.dev.yml up -d --build + docker compose -f docker-compose.dev.yml up -d --build - name: Wait for services to start run: sleep 10 @@ -33,6 +58,11 @@ jobs: - name: Deployment summary run: | echo "βœ… Dev deployment successful" - echo "🌐 Frontend: http://192.168.1.51:3001" - echo "πŸ”§ Backend: http://192.168.1.51:8002" + echo "🌐 Frontend: http://192.168.1.25:3001" + echo "πŸ”§ Backend: http://192.168.1.25:8002" echo "πŸ“Š Commit: ${{ github.sha }}" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.dev diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index b6b6aa3..6938a00 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -7,10 +7,38 @@ on: jobs: deploy-production: runs-on: self-hosted + environment: production + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.prod from GitHub secrets + run: | + cat > .env.prod << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGIN_REGEX=${{ secrets.CORS_ALLOW_ORIGIN_REGEX }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + + # Cloudflare Tunnel Token + CLOUDFLARE_TUNNEL_TOKEN=${{ secrets.CLOUDFLARE_TUNNEL_TOKEN }} + EOF + - name: Create pre-deployment backup run: | ./scripts/backup-prod.sh @@ -18,12 +46,12 @@ jobs: - name: Build new production containers run: | - docker-compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml build - name: Deploy with zero downtime run: | # Start new containers (will replace old ones) - docker-compose -f docker-compose.prod.yml up -d + docker compose -f docker-compose.prod.yml up -d - name: Wait for services to initialize run: sleep 15 @@ -52,3 +80,8 @@ jobs: echo "" echo "πŸ“¦ Running containers:" docker ps --filter "name=mantis-prod-" --format "table {{.Names}}\t{{.Status}}" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.prod diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml index 985b09b..53fe852 100644 --- a/.github/workflows/pr-check-dev.yml +++ b/.github/workflows/pr-check-dev.yml @@ -7,17 +7,42 @@ on: jobs: validate: runs-on: self-hosted + environment: development + steps: - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.dev from GitHub secrets + run: | + cat > .env.dev << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGINS=${{ secrets.CORS_ALLOW_ORIGINS }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + EOF + - name: Validate docker-compose syntax run: | - docker-compose -f docker-compose.dev.yml config + docker compose -f docker-compose.dev.yml config - name: Build test (no deployment) run: | - docker-compose -f docker-compose.dev.yml build + docker compose -f docker-compose.dev.yml build - name: Check .env.dev exists run: | @@ -34,3 +59,8 @@ jobs: - name: Check disk space run: | df -h | grep -E 'Filesystem|/$' + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.dev diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml index 77d5177..c594b33 100644 --- a/.github/workflows/pr-check-prod.yml +++ b/.github/workflows/pr-check-prod.yml @@ -7,10 +7,49 @@ on: jobs: pre-deployment-checks: runs-on: self-hosted + environment: production + steps: + - name: Enforce source branch is develop + run: | + SOURCE_BRANCH="${{ github.head_ref }}" + if [ "$SOURCE_BRANCH" != "develop" ]; then + echo "❌ ERROR: Pull requests to master must come from 'develop' branch only!" + echo " Current source branch: $SOURCE_BRANCH" + echo " Please merge your changes to 'develop' first, then create a PR from develop to master." + exit 1 + fi + echo "βœ… Source branch validation passed: $SOURCE_BRANCH β†’ master" + - name: Checkout code uses: actions/checkout@v4 + - name: Create .env.prod from GitHub secrets + run: | + cat > .env.prod << EOF + # Database Configuration + DB_USER=${{ secrets.DB_USER }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + + # JWT Authentication Configuration + JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + JWT_ALGORITHM=${{ secrets.JWT_ALGORITHM }} + JWT_EXPIRATION_MINUTES=${{ secrets.JWT_EXPIRATION_MINUTES }} + + # CORS Configuration + CORS_ALLOW_ORIGIN_REGEX=${{ secrets.CORS_ALLOW_ORIGIN_REGEX }} + + # Email Verification (Resend) + RESEND_API_KEY=${{ secrets.RESEND_API_KEY }} + RESEND_FROM_EMAIL=${{ secrets.RESEND_FROM_EMAIL }} + + # OTP Configuration + OTP_EXPIRATION_MINUTES=${{ secrets.OTP_EXPIRATION_MINUTES }} + + # Cloudflare Tunnel Token + CLOUDFLARE_TUNNEL_TOKEN=${{ secrets.CLOUDFLARE_TUNNEL_TOKEN }} + EOF + - name: Check prod environment status run: | docker ps | grep mantis-prod-backend || echo "⚠️ Prod not running (first deploy?)" @@ -22,11 +61,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker-compose -f docker-compose.prod.yml config + docker compose -f docker-compose.prod.yml config - name: Build test containers run: | - docker-compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml build - name: Check disk space run: | @@ -49,3 +88,8 @@ jobs: - name: Check backend health run: | curl -f http://localhost:8001/health || echo "⚠️ Backend not responding (will restart on deploy)" + + - name: Cleanup secrets + if: always() + run: | + rm -f .env.prod diff --git a/scripts/check-runner-status.sh b/scripts/check-runner-status.sh new file mode 100755 index 0000000..45a6901 --- /dev/null +++ b/scripts/check-runner-status.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# scripts/check-runner-status.sh +# Check GitHub Actions runner health and status + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +RUNNER_DIR="/root/actions-runner" +SERVICE_NAME="actions.runner.Dekode1859-Mantis.mantis-lxc-runner" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Runner Status Check β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if runner directory exists +if [ ! -d "$RUNNER_DIR" ]; then + echo -e "${RED}❌ Runner not installed${NC}" + echo -e " Directory not found: $RUNNER_DIR" + echo -e " Run: ${GREEN}/root/Mantis/scripts/setup-github-runner.sh${NC}" + exit 1 +fi + +# Check service status +echo -e "${BLUE}πŸ” Service Status:${NC}" +if systemctl is-active --quiet "$SERVICE_NAME"; then + echo -e " ${GREEN}βœ… Service is running${NC}" + SERVICE_STATUS="running" +else + echo -e " ${RED}❌ Service is not running${NC}" + SERVICE_STATUS="stopped" +fi + +# Get detailed service status +echo "" +echo -e "${BLUE}πŸ“Š Detailed Service Status:${NC}" +systemctl status "$SERVICE_NAME" --no-pager | head -15 + +# Check if runner is enabled on boot +echo "" +echo -e "${BLUE}πŸ”„ Auto-start on Boot:${NC}" +if systemctl is-enabled --quiet "$SERVICE_NAME"; then + echo -e " ${GREEN}βœ… Enabled${NC}" +else + echo -e " ${YELLOW}⚠️ Disabled${NC}" +fi + +# Check disk space in work directory +echo "" +echo -e "${BLUE}πŸ’Ύ Disk Space:${NC}" +WORK_DIR="$RUNNER_DIR/_work" +if [ -d "$WORK_DIR" ]; then + WORK_SIZE=$(du -sh "$WORK_DIR" 2>/dev/null | cut -f1) + echo -e " Work directory: ${GREEN}$WORK_SIZE${NC}" +else + echo -e " Work directory: ${YELLOW}Not created yet${NC}" +fi + +# Overall system disk space +DISK_USAGE=$(df -h / | tail -1 | awk '{print $5}' | sed 's/%//') +DISK_AVAIL=$(df -h / | tail -1 | awk '{print $4}') +if [ "$DISK_USAGE" -gt 80 ]; then + echo -e " System disk: ${RED}$DISK_USAGE% used (${DISK_AVAIL} available)${NC}" + echo -e " ${YELLOW}⚠️ Warning: Disk usage above 80%${NC}" +else + echo -e " System disk: ${GREEN}$DISK_USAGE% used (${DISK_AVAIL} available)${NC}" +fi + +# Show recent logs if service is running +if [ "$SERVICE_STATUS" = "running" ]; then + echo "" + echo -e "${BLUE}πŸ“œ Recent Logs (last 10 lines):${NC}" + journalctl -u "$SERVICE_NAME" -n 10 --no-pager | sed 's/^/ /' +fi + +# Check runner configuration +echo "" +echo -e "${BLUE}βš™οΈ Runner Configuration:${NC}" +if [ -f "$RUNNER_DIR/.runner" ]; then + RUNNER_NAME=$(grep -o '"AgentName":"[^"]*"' "$RUNNER_DIR/.runner" | cut -d'"' -f4) + RUNNER_ID=$(grep -o '"AgentId":[0-9]*' "$RUNNER_DIR/.runner" | cut -d':' -f2) + echo -e " Name: ${GREEN}$RUNNER_NAME${NC}" + echo -e " ID: ${GREEN}$RUNNER_ID${NC}" +else + echo -e " ${YELLOW}Configuration file not found${NC}" +fi + +# Summary +echo "" +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ Summary β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +if [ "$SERVICE_STATUS" = "running" ]; then + echo -e "${GREEN}βœ… Runner is operational${NC}" + echo "" + echo -e "${BLUE}Verify in GitHub:${NC}" + echo -e " https://github.com/Dekode1859/Mantis/settings/actions/runners" + echo -e " Status should show: ${GREEN}Idle${NC} or ${GREEN}Active${NC}" + echo "" + echo -e "${BLUE}Useful Commands:${NC}" + echo -e " View live logs: ${GREEN}journalctl -u $SERVICE_NAME -f${NC}" + echo -e " Restart service: ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh restart${NC}" + echo -e " Stop service: ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh stop${NC}" +else + echo -e "${RED}❌ Runner is not running${NC}" + echo "" + echo -e "${YELLOW}To start the runner:${NC}" + echo -e " ${GREEN}cd $RUNNER_DIR && sudo ./svc.sh start${NC}" + echo "" + echo -e "${YELLOW}To check for errors:${NC}" + echo -e " ${GREEN}journalctl -u $SERVICE_NAME -n 50${NC}" +fi + +echo "" diff --git a/scripts/setup-github-runner.sh b/scripts/setup-github-runner.sh new file mode 100755 index 0000000..e1a166e --- /dev/null +++ b/scripts/setup-github-runner.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# scripts/setup-github-runner.sh +# Setup GitHub Actions self-hosted runner on LXC container +# Runner will be installed at: /root/actions-runner (outside Mantis directory) + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +RUNNER_VERSION="2.319.1" +RUNNER_DIR="/root/actions-runner" +REPO_URL="https://github.com/Dekode1859/Mantis" +RUNNER_NAME="mantis-lxc-runner" +RUNNER_LABELS="self-hosted,linux,x64,mantis" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Self-Hosted Runner Setup β•‘${NC}" +echo -e "${BLUE}β•‘ For Mantis Project β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if running as root - we'll need to use a workaround +RUNNING_AS_ROOT=false +if [ "$EUID" -eq 0 ]; then + RUNNING_AS_ROOT=true + echo -e "${YELLOW}⚠️ Running as root detected${NC}" + echo -e "${YELLOW} GitHub runner config cannot run as root for security${NC}" + echo -e "${YELLOW} Script will use RUNNER_ALLOW_RUNASROOT=1 workaround${NC}" + echo "" +fi + +# Check if runner already exists +if [ -d "$RUNNER_DIR" ]; then + echo -e "${YELLOW}⚠️ Runner directory already exists: $RUNNER_DIR${NC}" + read -p "Do you want to remove it and reinstall? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo -e "${BLUE}πŸ—‘οΈ Removing existing runner...${NC}" + cd "$RUNNER_DIR" + # Stop and remove service if it exists + if [ -f "svc.sh" ]; then + if [ "$EUID" -eq 0 ]; then + ./svc.sh stop 2>/dev/null || true + ./svc.sh uninstall 2>/dev/null || true + else + sudo ./svc.sh stop 2>/dev/null || true + sudo ./svc.sh uninstall 2>/dev/null || true + fi + fi + cd /root + if [ "$EUID" -eq 0 ]; then + rm -rf "$RUNNER_DIR" + else + sudo rm -rf "$RUNNER_DIR" + fi + else + echo -e "${RED}❌ Installation cancelled${NC}" + exit 1 + fi +fi + +# Create runner directory +echo -e "${BLUE}πŸ“ Creating runner directory: $RUNNER_DIR${NC}" +if [ "$RUNNING_AS_ROOT" = true ]; then + mkdir -p "$RUNNER_DIR" +else + sudo mkdir -p "$RUNNER_DIR" + sudo chown $USER:$USER "$RUNNER_DIR" +fi +cd "$RUNNER_DIR" + +# Download runner +echo -e "${BLUE}⬇️ Downloading GitHub Actions Runner v${RUNNER_VERSION}...${NC}" +RUNNER_FILE="actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" +DOWNLOAD_URL="https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/${RUNNER_FILE}" + +curl -o "$RUNNER_FILE" -L "$DOWNLOAD_URL" + +if [ ! -f "$RUNNER_FILE" ]; then + echo -e "${RED}❌ Failed to download runner${NC}" + exit 1 +fi + +# Extract runner +echo -e "${BLUE}πŸ“¦ Extracting runner...${NC}" +tar xzf "$RUNNER_FILE" + +# Cleanup downloaded archive +rm "$RUNNER_FILE" + +echo "" +echo -e "${GREEN}βœ… Runner downloaded and extracted${NC}" +echo "" + +# Get registration token from user +echo -e "${YELLOW}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${YELLOW}β•‘ REGISTRATION TOKEN REQUIRED β•‘${NC}" +echo -e "${YELLOW}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" +echo -e "${BLUE}To get your registration token:${NC}" +echo -e "1. Open: ${GREEN}https://github.com/Dekode1859/Mantis/settings/actions/runners/new${NC}" +echo -e "2. Select: ${GREEN}Linux${NC} and ${GREEN}x64${NC}" +echo -e "3. Copy the token from the ${GREEN}Configure${NC} section" +echo -e " (It starts with 'A' and is very long)" +echo "" +echo -e "${YELLOW}Note: Token expires in 1 hour. Generate a new one if expired.${NC}" +echo "" + +read -p "Enter your registration token: " REGISTRATION_TOKEN + +if [ -z "$REGISTRATION_TOKEN" ]; then + echo -e "${RED}❌ Registration token cannot be empty${NC}" + exit 1 +fi + +# Configure runner +echo "" +echo -e "${BLUE}βš™οΈ Configuring runner...${NC}" +echo "" + +# If running as root, set environment variable to allow it +if [ "$RUNNING_AS_ROOT" = true ]; then + export RUNNER_ALLOW_RUNASROOT=1 +fi + +./config.sh \ + --url "$REPO_URL" \ + --token "$REGISTRATION_TOKEN" \ + --name "$RUNNER_NAME" \ + --labels "$RUNNER_LABELS" \ + --work _work \ + --unattended \ + --replace + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Runner configuration failed${NC}" + exit 1 +fi + +echo "" +echo -e "${GREEN}βœ… Runner configured successfully${NC}" +echo "" + +# Install as service (requires root) +echo -e "${BLUE}πŸ”§ Installing runner as systemd service...${NC}" + +if [ "$RUNNING_AS_ROOT" = true ]; then + ./svc.sh install +else + sudo ./svc.sh install +fi + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Service installation failed${NC}" + exit 1 +fi + +# Start service (requires root) +echo -e "${BLUE}▢️ Starting runner service...${NC}" + +if [ "$RUNNING_AS_ROOT" = true ]; then + ./svc.sh start +else + sudo ./svc.sh start +fi + +if [ $? -ne 0 ]; then + echo -e "${RED}❌ Service start failed${NC}" + exit 1 +fi + +# Wait a moment for service to start +sleep 3 + +# Check service status +echo "" +echo -e "${BLUE}πŸ₯ Checking service status...${NC}" +./svc.sh status + +echo "" +echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${GREEN}β•‘ βœ… INSTALLATION COMPLETE! β•‘${NC}" +echo -e "${GREEN}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" +echo -e "${BLUE}Runner Details:${NC}" +echo -e " πŸ“ Location: ${GREEN}$RUNNER_DIR${NC}" +echo -e " 🏷️ Name: ${GREEN}$RUNNER_NAME${NC}" +echo -e " 🏷️ Labels: ${GREEN}$RUNNER_LABELS${NC}" +echo -e " πŸ“¦ Repository: ${GREEN}$REPO_URL${NC}" +echo "" +echo -e "${BLUE}Service Management:${NC}" +echo -e " Status: ${GREEN}sudo systemctl status actions.runner.Dekode1859-Mantis.mantis-lxc-runner${NC}" +echo -e " Stop: ${GREEN}cd $RUNNER_DIR && ./svc.sh stop${NC}" +echo -e " Start: ${GREEN}cd $RUNNER_DIR && ./svc.sh start${NC}" +echo -e " Restart: ${GREEN}cd $RUNNER_DIR && ./svc.sh restart${NC}" +echo "" +echo -e "${BLUE}Verify in GitHub:${NC}" +echo -e " Go to: ${GREEN}https://github.com/Dekode1859/Mantis/settings/actions/runners${NC}" +echo -e " You should see: ${GREEN}mantis-lxc-runner${NC} with status ${GREEN}Idle${NC}" +echo "" +echo -e "${BLUE}Check Runner Status:${NC}" +echo -e " Run: ${GREEN}/root/Mantis/scripts/check-runner-status.sh${NC}" +echo "" +echo -e "${YELLOW}Next Steps:${NC}" +echo -e " 1. Verify runner appears in GitHub (link above)" +echo -e " 2. Test by creating a PR to the 'develop' branch" +echo -e " 3. Watch the workflow run on your self-hosted runner!" +echo "" diff --git a/scripts/update-runner.sh b/scripts/update-runner.sh new file mode 100755 index 0000000..c26d0d1 --- /dev/null +++ b/scripts/update-runner.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# scripts/update-runner.sh +# Update GitHub Actions runner to latest version + +set -e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +RUNNER_DIR="/root/actions-runner" +SERVICE_NAME="actions.runner.Dekode1859-Mantis.mantis-lxc-runner" + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}β•‘ GitHub Actions Runner Update β•‘${NC}" +echo -e "${BLUE}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" +echo "" + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}❌ This script must be run as root${NC}" + exit 1 +fi + +# Check if runner exists +if [ ! -d "$RUNNER_DIR" ]; then + echo -e "${RED}❌ Runner not installed at: $RUNNER_DIR${NC}" + echo -e " Run setup script first: ${GREEN}/root/Mantis/scripts/setup-github-runner.sh${NC}" + exit 1 +fi + +cd "$RUNNER_DIR" + +# Get current version +if [ -f "./bin/Runner.Listener" ]; then + CURRENT_VERSION=$(./bin/Runner.Listener --version 2>/dev/null | head -1 || echo "unknown") + echo -e "${BLUE}πŸ“¦ Current version: ${GREEN}$CURRENT_VERSION${NC}" +else + echo -e "${YELLOW}⚠️ Could not determine current version${NC}" + CURRENT_VERSION="unknown" +fi + +# Prompt for new version +echo "" +echo -e "${YELLOW}Enter the new runner version to install:${NC}" +echo -e " (e.g., 2.319.1)" +echo -e " Find latest: ${GREEN}https://github.com/actions/runner/releases${NC}" +echo "" +read -p "Version: " NEW_VERSION + +if [ -z "$NEW_VERSION" ]; then + echo -e "${RED}❌ Version cannot be empty${NC}" + exit 1 +fi + +# Confirm update +echo "" +echo -e "${YELLOW}⚠️ This will:${NC}" +echo -e " 1. Stop the runner service" +echo -e " 2. Download runner v$NEW_VERSION" +echo -e " 3. Replace binaries" +echo -e " 4. Restart the service" +echo "" +echo -e "${YELLOW}Configuration will be preserved (.runner, .credentials, etc.)${NC}" +echo "" +read -p "Continue? (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${RED}❌ Update cancelled${NC}" + exit 1 +fi + +# Stop service +echo "" +echo -e "${BLUE}πŸ›‘ Stopping runner service...${NC}" +./svc.sh stop + +# Wait for service to stop +sleep 2 + +# Backup current configuration +echo -e "${BLUE}πŸ’Ύ Backing up configuration...${NC}" +BACKUP_DIR="/root/runner-backup-$(date +%Y%m%d_%H%M%S)" +mkdir -p "$BACKUP_DIR" + +# Backup critical files +for file in .runner .credentials .credentials_rsaparams; do + if [ -f "$file" ]; then + cp "$file" "$BACKUP_DIR/" + fi +done + +echo -e " ${GREEN}βœ… Backup saved to: $BACKUP_DIR${NC}" + +# Download new runner +echo -e "${BLUE}⬇️ Downloading runner v$NEW_VERSION...${NC}" +RUNNER_FILE="actions-runner-linux-x64-${NEW_VERSION}.tar.gz" +DOWNLOAD_URL="https://github.com/actions/runner/releases/download/v${NEW_VERSION}/${RUNNER_FILE}" + +# Create temp directory for download +TEMP_DIR="/tmp/runner-update-$$" +mkdir -p "$TEMP_DIR" + +cd "$TEMP_DIR" +if ! curl -o "$RUNNER_FILE" -L "$DOWNLOAD_URL"; then + echo -e "${RED}❌ Failed to download runner v$NEW_VERSION${NC}" + echo -e " Check if version exists: $DOWNLOAD_URL" + rm -rf "$TEMP_DIR" + cd "$RUNNER_DIR" + ./svc.sh start + exit 1 +fi + +# Extract new runner +echo -e "${BLUE}πŸ“¦ Extracting new runner...${NC}" +cd "$RUNNER_DIR" + +# Remove old binaries but keep configuration +echo -e "${BLUE}πŸ—‘οΈ Removing old binaries...${NC}" +rm -rf bin externals + +# Extract new binaries +echo -e "${BLUE}πŸ“‚ Installing new binaries...${NC}" +tar xzf "$TEMP_DIR/$RUNNER_FILE" + +# Cleanup +rm -rf "$TEMP_DIR" + +# Verify extraction +if [ ! -f "./bin/Runner.Listener" ]; then + echo -e "${RED}❌ Update failed - binaries not found${NC}" + echo -e " Restoring from backup: $BACKUP_DIR" + # Note: This is a simplified restore - you may need to re-run setup in practice + exit 1 +fi + +# Start service +echo -e "${BLUE}▢️ Starting runner service...${NC}" +./svc.sh start + +# Wait for service to start +sleep 3 + +# Verify service is running +if systemctl is-active --quiet "$SERVICE_NAME"; then + NEW_INSTALLED_VERSION=$(./bin/Runner.Listener --version 2>/dev/null | head -1 || echo "unknown") + echo "" + echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}" + echo -e "${GREEN}β•‘ βœ… UPDATE COMPLETE! β•‘${NC}" + echo -e "${GREEN}β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•${NC}" + echo "" + echo -e "${BLUE}Version Update:${NC}" + echo -e " Previous: ${YELLOW}$CURRENT_VERSION${NC}" + echo -e " Current: ${GREEN}$NEW_INSTALLED_VERSION${NC}" + echo "" + echo -e "${BLUE}Service Status:${NC}" + echo -e " ${GREEN}βœ… Running${NC}" + echo "" + echo -e "${BLUE}Backup Location:${NC}" + echo -e " ${GREEN}$BACKUP_DIR${NC}" + echo "" + echo -e "${BLUE}Verify in GitHub:${NC}" + echo -e " https://github.com/Dekode1859/Mantis/settings/actions/runners" + echo "" +else + echo -e "${RED}❌ Service failed to start after update${NC}" + echo -e " Check logs: ${GREEN}journalctl -u $SERVICE_NAME -n 50${NC}" + echo -e " Backup available: ${GREEN}$BACKUP_DIR${NC}" + exit 1 +fi From 73ae0b6ad1c48139a8ae2ff355e54b36f0a06310 Mon Sep 17 00:00:00 2001 From: Dekode1859 Date: Sun, 11 Jan 2026 16:42:46 +0530 Subject: [PATCH 6/8] feat: complete CI/CD pipeline with GitHub Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workflow Improvements: - Integrate GitHub Environments for secret management - Add --env-file flag to all docker compose commands - Add --remove-orphans to prevent container conflicts - Add explicit container cleanup before deployments - Auto-generate .env files from GitHub secrets - Enforce developβ†’master PR restriction Backend Improvements: - Add uvicorn workers (4) for production performance - Enable concurrent request handling Runner Setup: - Add self-hosted runner setup scripts - Add runner monitoring and update scripts - Complete documentation for setup and troubleshooting Fixes: - Fix Docker Compose not reading environment variables - Fix container name conflicts during deployment - Fix tunnel container blocking new deployments --- .github/workflows/deploy-dev.yml | 4 ++-- .github/workflows/deploy-prod.yml | 8 ++++++-- .github/workflows/pr-check-dev.yml | 4 ++-- .github/workflows/pr-check-prod.yml | 4 ++-- backend/Dockerfile | 6 ++++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 59ffa86..95a9dfb 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -38,11 +38,11 @@ jobs: - name: Stop existing dev containers run: | - docker compose -f docker-compose.dev.yml down || true + docker compose -f docker-compose.dev.yml --env-file .env.dev down --remove-orphans || true - name: Build and start dev environment run: | - docker compose -f docker-compose.dev.yml up -d --build + docker compose -f docker-compose.dev.yml --env-file .env.dev up -d --build - name: Wait for services to start run: sleep 10 diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 6938a00..9b91e4d 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -44,14 +44,18 @@ jobs: ./scripts/backup-prod.sh echo "βœ… Pre-deployment backup created" + - name: Stop existing prod containers (to avoid conflicts) + run: | + docker compose -f docker-compose.prod.yml --env-file .env.prod down --remove-orphans || true + - name: Build new production containers run: | - docker compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml --env-file .env.prod build - name: Deploy with zero downtime run: | # Start new containers (will replace old ones) - docker compose -f docker-compose.prod.yml up -d + docker compose -f docker-compose.prod.yml --env-file .env.prod up -d - name: Wait for services to initialize run: sleep 15 diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml index 53fe852..b77d55c 100644 --- a/.github/workflows/pr-check-dev.yml +++ b/.github/workflows/pr-check-dev.yml @@ -38,11 +38,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker compose -f docker-compose.dev.yml config + docker compose -f docker-compose.dev.yml --env-file .env.dev config - name: Build test (no deployment) run: | - docker compose -f docker-compose.dev.yml build + docker compose -f docker-compose.dev.yml --env-file .env.dev build - name: Check .env.dev exists run: | diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml index c594b33..1e2bd48 100644 --- a/.github/workflows/pr-check-prod.yml +++ b/.github/workflows/pr-check-prod.yml @@ -61,11 +61,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker compose -f docker-compose.prod.yml config + docker compose -f docker-compose.prod.yml --env-file .env.prod config - name: Build test containers run: | - docker compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml --env-file .env.prod build - name: Check disk space run: | diff --git a/backend/Dockerfile b/backend/Dockerfile index 414ca04..3121bcf 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -25,5 +25,7 @@ COPY . . # Expose port 8000 EXPOSE 8000 -# Run uvicorn server -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] +# Run uvicorn server with multiple workers for production +# Workers: 2 * CPU cores + 1 (let's use 4 workers as a good default) +# This allows handling concurrent requests and provides redundancy +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] From 0c2528215fe84693c8958405fef9531dd0bff62a Mon Sep 17 00:00:00 2001 From: Pratik Dwivedi <93965493+Dekode1859@users.noreply.github.com> Date: Sun, 11 Jan 2026 16:45:35 +0530 Subject: [PATCH 7/8] Cicd/dev prod checks deploy (#10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Set up Github Workflows for Checks and Deployments for DEV and PROD * fix: update workflows to use docker compose V2 command and add runner setup scripts * Update Github Workflows to run using github environments * feat: complete CI/CD pipeline with GitHub Actions Workflow Improvements: - Integrate GitHub Environments for secret management - Add --env-file flag to all docker compose commands - Add --remove-orphans to prevent container conflicts - Add explicit container cleanup before deployments - Auto-generate .env files from GitHub secrets - Enforce developβ†’master PR restriction Backend Improvements: - Add uvicorn workers (4) for production performance - Enable concurrent request handling Runner Setup: - Add self-hosted runner setup scripts - Add runner monitoring and update scripts - Complete documentation for setup and troubleshooting Fixes: - Fix Docker Compose not reading environment variables - Fix container name conflicts during deployment - Fix tunnel container blocking new deployments --- .github/workflows/deploy-dev.yml | 4 ++-- .github/workflows/deploy-prod.yml | 8 ++++++-- .github/workflows/pr-check-dev.yml | 4 ++-- .github/workflows/pr-check-prod.yml | 4 ++-- backend/Dockerfile | 6 ++++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 59ffa86..95a9dfb 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -38,11 +38,11 @@ jobs: - name: Stop existing dev containers run: | - docker compose -f docker-compose.dev.yml down || true + docker compose -f docker-compose.dev.yml --env-file .env.dev down --remove-orphans || true - name: Build and start dev environment run: | - docker compose -f docker-compose.dev.yml up -d --build + docker compose -f docker-compose.dev.yml --env-file .env.dev up -d --build - name: Wait for services to start run: sleep 10 diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 6938a00..9b91e4d 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -44,14 +44,18 @@ jobs: ./scripts/backup-prod.sh echo "βœ… Pre-deployment backup created" + - name: Stop existing prod containers (to avoid conflicts) + run: | + docker compose -f docker-compose.prod.yml --env-file .env.prod down --remove-orphans || true + - name: Build new production containers run: | - docker compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml --env-file .env.prod build - name: Deploy with zero downtime run: | # Start new containers (will replace old ones) - docker compose -f docker-compose.prod.yml up -d + docker compose -f docker-compose.prod.yml --env-file .env.prod up -d - name: Wait for services to initialize run: sleep 15 diff --git a/.github/workflows/pr-check-dev.yml b/.github/workflows/pr-check-dev.yml index 53fe852..b77d55c 100644 --- a/.github/workflows/pr-check-dev.yml +++ b/.github/workflows/pr-check-dev.yml @@ -38,11 +38,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker compose -f docker-compose.dev.yml config + docker compose -f docker-compose.dev.yml --env-file .env.dev config - name: Build test (no deployment) run: | - docker compose -f docker-compose.dev.yml build + docker compose -f docker-compose.dev.yml --env-file .env.dev build - name: Check .env.dev exists run: | diff --git a/.github/workflows/pr-check-prod.yml b/.github/workflows/pr-check-prod.yml index c594b33..1e2bd48 100644 --- a/.github/workflows/pr-check-prod.yml +++ b/.github/workflows/pr-check-prod.yml @@ -61,11 +61,11 @@ jobs: - name: Validate docker-compose syntax run: | - docker compose -f docker-compose.prod.yml config + docker compose -f docker-compose.prod.yml --env-file .env.prod config - name: Build test containers run: | - docker compose -f docker-compose.prod.yml build + docker compose -f docker-compose.prod.yml --env-file .env.prod build - name: Check disk space run: | diff --git a/backend/Dockerfile b/backend/Dockerfile index 414ca04..3121bcf 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -25,5 +25,7 @@ COPY . . # Expose port 8000 EXPOSE 8000 -# Run uvicorn server -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] +# Run uvicorn server with multiple workers for production +# Workers: 2 * CPU cores + 1 (let's use 4 workers as a good default) +# This allows handling concurrent requests and provides redundancy +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] From 3c0666386857b4991d60cf6c2691a2f41c9b1c12 Mon Sep 17 00:00:00 2001 From: Dekode1859 Date: Sun, 11 Jan 2026 17:07:58 +0530 Subject: [PATCH 8/8] fix: add force removal of all containers to prevent naming conflicts - Add two-step cleanup: compose down + force remove - Ensures tunnel container is always removed - Prevents 'container name already in use' errors - Applies to both dev and prod deployments --- .github/workflows/deploy-dev.yml | 6 ++++++ .github/workflows/deploy-prod.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 95a9dfb..e485c70 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -38,8 +38,14 @@ jobs: - name: Stop existing dev containers run: | + # First try docker compose down docker compose -f docker-compose.dev.yml --env-file .env.dev down --remove-orphans || true + # Force remove any lingering mantis-dev containers + docker ps -a --filter "name=mantis-dev-" --format "{{.Names}}" | xargs -r docker rm -f || true + + echo "βœ… All existing dev containers removed" + - name: Build and start dev environment run: | docker compose -f docker-compose.dev.yml --env-file .env.dev up -d --build diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 9b91e4d..94b7fac 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -46,8 +46,14 @@ jobs: - name: Stop existing prod containers (to avoid conflicts) run: | + # First try docker compose down docker compose -f docker-compose.prod.yml --env-file .env.prod down --remove-orphans || true + # Force remove any lingering mantis-prod containers (especially tunnel) + docker ps -a --filter "name=mantis-prod-" --format "{{.Names}}" | xargs -r docker rm -f || true + + echo "βœ… All existing prod containers removed" + - name: Build new production containers run: | docker compose -f docker-compose.prod.yml --env-file .env.prod build