Add deployment workflow and scripts for self-hosted runner

- Add GitHub Actions deployment workflow for staging and production
- Add deployment scripts for automated deployments
- Add GitHub runner management scripts
- Add staging docker-compose configuration
- Enable automatic deployments on push to main (staging) and version tags (production)
This commit is contained in:
Jonathan Flatt
2025-05-23 23:39:06 +00:00
parent 398027ae27
commit c51eba4f0f
6 changed files with 1087 additions and 63 deletions

View File

@@ -0,0 +1,202 @@
#!/bin/bash
# Claude Webhook Production Deployment Script
# Deploys the production environment on port 8082
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m'
# Configuration
COMPOSE_FILE="docker-compose.yml"
SERVICE_NAME="webhook"
HEALTH_CHECK_URL="http://localhost:8082/health"
MAX_HEALTH_RETRIES=30
PRODUCTION_BOT="MCPClaude"
BACKUP_DIR="/home/jonflatt/backups/webhook"
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${RED} Claude Webhook - PRODUCTION Deployment${NC}"
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "Bot: ${GREEN}@${PRODUCTION_BOT}${NC}"
echo -e "Port: ${GREEN}8082${NC}"
echo -e "Time: ${GREEN}$(date)${NC}"
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
# Function to check if service is healthy
check_health() {
local retries=0
echo -e "${YELLOW}Checking service health...${NC}"
while [ $retries -lt $MAX_HEALTH_RETRIES ]; do
if curl -f -s "$HEALTH_CHECK_URL" > /dev/null 2>&1; then
echo -e "${GREEN}✓ Service is healthy!${NC}"
return 0
fi
retries=$((retries + 1))
echo -e " Waiting for service to start... ($retries/$MAX_HEALTH_RETRIES)"
sleep 2
done
echo -e "${RED}✗ Health check failed after $MAX_HEALTH_RETRIES attempts${NC}"
return 1
}
# Function to create backup
create_backup() {
echo -e "${YELLOW}Creating pre-deployment backup...${NC}"
mkdir -p "$BACKUP_DIR"
# Get current container info
CONTAINER_ID=$(docker-compose -f "$COMPOSE_FILE" ps -q 2>/dev/null || echo "")
if [ -n "$CONTAINER_ID" ]; then
BACKUP_FILE="$BACKUP_DIR/backup-$(date +%Y%m%d-%H%M%S).tar.gz"
# Export container
docker export "$CONTAINER_ID" | gzip > "$BACKUP_FILE"
echo -e "${GREEN}✓ Backup created: $BACKUP_FILE${NC}"
# Keep only last 5 backups
ls -t "$BACKUP_DIR"/backup-*.tar.gz 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null || true
else
echo -e "${YELLOW}No running container to backup${NC}"
fi
}
# Step 1: Production safety confirmation
echo -e "${PURPLE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${RED}⚠️ PRODUCTION DEPLOYMENT CONFIRMATION ⚠️${NC}"
echo -e "${PURPLE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${YELLOW}You are about to deploy to PRODUCTION.${NC}"
echo -e "${YELLOW}This will affect the live @${PRODUCTION_BOT} bot.${NC}"
echo -e ""
read -p "Type 'DEPLOY PRODUCTION' to continue: " confirmation
if [ "$confirmation" != "DEPLOY PRODUCTION" ]; then
echo -e "${RED}Deployment cancelled.${NC}"
exit 1
fi
# Step 2: Pre-deployment checks
echo -e "\n${YELLOW}[1/8] Running pre-deployment checks...${NC}"
# Check if docker-compose file exists
if [ ! -f "$COMPOSE_FILE" ]; then
echo -e "${RED}Error: $COMPOSE_FILE not found${NC}"
echo -e "${YELLOW}Please ensure you're running from the project root directory${NC}"
exit 1
fi
# Check Docker daemon
if ! docker info > /dev/null 2>&1; then
echo -e "${RED}Error: Docker daemon is not running${NC}"
exit 1
fi
# Check disk space
DISK_USAGE=$(df -h /var/lib/docker | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 85 ]; then
echo -e "${RED}Warning: Disk usage is at ${DISK_USAGE}%${NC}"
echo -e "${YELLOW}Consider cleaning up Docker images/containers${NC}"
fi
echo -e "${GREEN}✓ Pre-deployment checks passed${NC}\n"
# Step 3: Create backup
echo -e "${YELLOW}[2/8] Creating backup...${NC}"
create_backup
echo -e "${GREEN}✓ Backup complete${NC}\n"
# Step 4: Pull latest images
echo -e "${YELLOW}[3/8] Pulling latest production images...${NC}"
docker-compose -f "$COMPOSE_FILE" pull
echo -e "${GREEN}✓ Images updated${NC}\n"
# Step 5: Graceful shutdown
echo -e "${YELLOW}[4/8] Gracefully shutting down existing container...${NC}"
docker-compose -f "$COMPOSE_FILE" stop || true
sleep 5 # Allow time for graceful shutdown
docker-compose -f "$COMPOSE_FILE" down --remove-orphans || true
echo -e "${GREEN}✓ Existing container stopped${NC}\n"
# Step 6: Start new container
echo -e "${YELLOW}[5/8] Starting new production container...${NC}"
docker-compose -f "$COMPOSE_FILE" up -d
echo -e "${GREEN}✓ Container started${NC}\n"
# Step 7: Health check
echo -e "${YELLOW}[6/8] Running health checks...${NC}"
sleep 5 # Give container time to initialize
if check_health; then
echo -e "${GREEN}✓ Health check passed${NC}\n"
else
echo -e "${RED}✗ Health check failed${NC}"
echo -e "${YELLOW}Rolling back deployment...${NC}"
# Attempt rollback
docker-compose -f "$COMPOSE_FILE" down
# Check if we have a backup to restore
LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/backup-*.tar.gz 2>/dev/null | head -1)
if [ -n "$LATEST_BACKUP" ]; then
echo -e "${YELLOW}Rollback instructions:${NC}"
echo -e "1. Load backup: ${YELLOW}docker load < $LATEST_BACKUP${NC}"
echo -e "2. Start previous version manually"
fi
exit 1
fi
# Step 8: Post-deployment verification
echo -e "${YELLOW}[7/8] Post-deployment verification...${NC}"
# Check container status
CONTAINER_STATUS=$(docker-compose -f "$COMPOSE_FILE" ps -q | xargs docker inspect -f '{{.State.Status}}' 2>/dev/null || echo "not found")
if [ "$CONTAINER_STATUS" = "running" ]; then
echo -e "${GREEN}✓ Container status: Running${NC}"
else
echo -e "${RED}✗ Container status: $CONTAINER_STATUS${NC}"
exit 1
fi
# Test webhook endpoint
echo -e "${YELLOW}Testing webhook endpoint...${NC}"
WEBHOOK_TEST=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$HEALTH_CHECK_URL" -H "Content-Type: application/json" -d '{"test": true}' || echo "000")
if [[ "$WEBHOOK_TEST" =~ ^(200|400|401)$ ]]; then
echo -e "${GREEN}✓ Webhook endpoint responding (HTTP $WEBHOOK_TEST)${NC}"
else
echo -e "${RED}⚠️ Webhook endpoint returned unexpected status: HTTP $WEBHOOK_TEST${NC}"
fi
# Step 9: Final status
echo -e "\n${YELLOW}[8/8] Deployment summary...${NC}"
# Show resource usage
echo -e "\n${BLUE}Container Resource Usage:${NC}"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" $(docker-compose -f "$COMPOSE_FILE" ps -q)
# Show recent logs
echo -e "\n${BLUE}Recent logs:${NC}"
docker-compose -f "$COMPOSE_FILE" logs --tail=20
# Clean up old images
echo -e "\n${YELLOW}Cleaning up old images...${NC}"
docker image prune -f
echo -e "\n${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✓ PRODUCTION deployment completed successfully!${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "Service URL: ${GREEN}http://localhost:8082${NC}"
echo -e "GitHub Bot: ${GREEN}@${PRODUCTION_BOT}${NC}"
echo -e "Backup: ${GREEN}${LATEST_BACKUP:-No backup created}${NC}"
echo -e "Logs: ${YELLOW}docker-compose -f $COMPOSE_FILE logs -f${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}
${PURPLE}Remember to monitor the service for the next few minutes!${NC}"

121
scripts/deploy/deploy-staging.sh Executable file
View File

@@ -0,0 +1,121 @@
#!/bin/bash
# Claude Webhook Staging Deployment Script
# Deploys the staging environment on port 8083
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
COMPOSE_FILE="docker-compose.staging.yml"
SERVICE_NAME="webhook-staging"
HEALTH_CHECK_URL="http://localhost:8083/health"
MAX_HEALTH_RETRIES=30
STAGING_BOT="MCPClaude-Staging"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE} Claude Webhook - Staging Deployment${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "Bot: ${GREEN}@${STAGING_BOT}${NC}"
echo -e "Port: ${GREEN}8083${NC}"
echo -e "Time: ${GREEN}$(date)${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
# Function to check if service is healthy
check_health() {
local retries=0
echo -e "${YELLOW}Checking service health...${NC}"
while [ $retries -lt $MAX_HEALTH_RETRIES ]; do
if curl -f -s "$HEALTH_CHECK_URL" > /dev/null 2>&1; then
echo -e "${GREEN}✓ Service is healthy!${NC}"
return 0
fi
retries=$((retries + 1))
echo -e " Waiting for service to start... ($retries/$MAX_HEALTH_RETRIES)"
sleep 2
done
echo -e "${RED}✗ Health check failed after $MAX_HEALTH_RETRIES attempts${NC}"
return 1
}
# Step 1: Pre-deployment checks
echo -e "${YELLOW}[1/6] Running pre-deployment checks...${NC}"
# Check if docker-compose file exists
if [ ! -f "$COMPOSE_FILE" ]; then
echo -e "${RED}Error: $COMPOSE_FILE not found${NC}"
echo -e "${YELLOW}Please ensure you're running from the project root directory${NC}"
exit 1
fi
# Check Docker daemon
if ! docker info > /dev/null 2>&1; then
echo -e "${RED}Error: Docker daemon is not running${NC}"
exit 1
fi
echo -e "${GREEN}✓ Pre-deployment checks passed${NC}\n"
# Step 2: Pull latest images
echo -e "${YELLOW}[2/6] Pulling latest staging images...${NC}"
docker-compose -f "$COMPOSE_FILE" pull
echo -e "${GREEN}✓ Images updated${NC}\n"
# Step 3: Stop existing container
echo -e "${YELLOW}[3/6] Stopping existing staging container...${NC}"
docker-compose -f "$COMPOSE_FILE" down --remove-orphans || true
echo -e "${GREEN}✓ Existing container stopped${NC}\n"
# Step 4: Start new container
echo -e "${YELLOW}[4/6] Starting new staging container...${NC}"
docker-compose -f "$COMPOSE_FILE" up -d
echo -e "${GREEN}✓ Container started${NC}\n"
# Step 5: Health check
echo -e "${YELLOW}[5/6] Running health checks...${NC}"
sleep 5 # Give container time to initialize
if check_health; then
echo -e "${GREEN}✓ Health check passed${NC}\n"
else
echo -e "${RED}✗ Health check failed${NC}"
echo -e "${YELLOW}Checking container logs...${NC}"
docker-compose -f "$COMPOSE_FILE" logs --tail=50
exit 1
fi
# Step 6: Post-deployment verification
echo -e "${YELLOW}[6/6] Post-deployment verification...${NC}"
# Check container status
CONTAINER_STATUS=$(docker-compose -f "$COMPOSE_FILE" ps -q | xargs docker inspect -f '{{.State.Status}}' 2>/dev/null || echo "not found")
if [ "$CONTAINER_STATUS" = "running" ]; then
echo -e "${GREEN}✓ Container status: Running${NC}"
else
echo -e "${RED}✗ Container status: $CONTAINER_STATUS${NC}"
exit 1
fi
# Show resource usage
echo -e "\n${BLUE}Container Resource Usage:${NC}"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" $(docker-compose -f "$COMPOSE_FILE" ps -q)
# Show recent logs
echo -e "\n${BLUE}Recent logs:${NC}"
docker-compose -f "$COMPOSE_FILE" logs --tail=10
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✓ Staging deployment completed successfully!${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "Service URL: ${GREEN}http://localhost:8083${NC}"
echo -e "GitHub Bot: ${GREEN}@${STAGING_BOT}${NC}"
echo -e "Logs: ${YELLOW}docker-compose -f $COMPOSE_FILE logs -f${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"

336
scripts/manage-runner.sh Executable file
View File

@@ -0,0 +1,336 @@
#!/bin/bash
# GitHub Actions Runner Management Script
# Manage the webhook deployment runner service
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
SERVICE_NAME="webhook-deployment-runner"
RUNNER_DIR="/home/jonflatt/github-actions-runner"
RUNNER_USER="jonflatt"
# Function to print usage
usage() {
echo -e "${BLUE}GitHub Actions Runner Management Tool${NC}"
echo -e "${BLUE}=====================================${NC}"
echo -e "\nUsage: $0 [command]"
echo -e "\nCommands:"
echo -e " ${GREEN}start${NC} - Start the runner service"
echo -e " ${GREEN}stop${NC} - Stop the runner service"
echo -e " ${GREEN}restart${NC} - Restart the runner service"
echo -e " ${GREEN}status${NC} - Check runner service status"
echo -e " ${GREEN}logs${NC} - View runner logs (live)"
echo -e " ${GREEN}logs-tail${NC} - View last 50 lines of logs"
echo -e " ${GREEN}update${NC} - Update runner to latest version"
echo -e " ${GREEN}config${NC} - Show runner configuration"
echo -e " ${GREEN}health${NC} - Check runner health"
echo -e " ${GREEN}jobs${NC} - Show recent job history"
echo -e " ${GREEN}cleanup${NC} - Clean up work directory"
echo -e " ${GREEN}info${NC} - Show runner information"
exit 1
}
# Check if running with correct permissions
check_permissions() {
if [[ $EUID -ne 0 ]] && [[ "$1" =~ ^(start|stop|restart|update)$ ]]; then
echo -e "${RED}Error: This command requires sudo privileges${NC}"
echo -e "${YELLOW}Run: sudo $0 $1${NC}"
exit 1
fi
}
# Start the runner
start_runner() {
echo -e "${YELLOW}Starting runner service...${NC}"
systemctl start $SERVICE_NAME
sleep 2
if systemctl is-active --quiet $SERVICE_NAME; then
echo -e "${GREEN}✓ Runner started successfully${NC}"
systemctl status $SERVICE_NAME --no-pager | head -n 10
else
echo -e "${RED}✗ Failed to start runner${NC}"
systemctl status $SERVICE_NAME --no-pager
exit 1
fi
}
# Stop the runner
stop_runner() {
echo -e "${YELLOW}Stopping runner service...${NC}"
systemctl stop $SERVICE_NAME
echo -e "${GREEN}✓ Runner stopped${NC}"
}
# Restart the runner
restart_runner() {
echo -e "${YELLOW}Restarting runner service...${NC}"
systemctl restart $SERVICE_NAME
sleep 2
if systemctl is-active --quiet $SERVICE_NAME; then
echo -e "${GREEN}✓ Runner restarted successfully${NC}"
systemctl status $SERVICE_NAME --no-pager | head -n 10
else
echo -e "${RED}✗ Failed to restart runner${NC}"
systemctl status $SERVICE_NAME --no-pager
exit 1
fi
}
# Check runner status
check_status() {
echo -e "${BLUE}Runner Service Status${NC}"
echo -e "${BLUE}===================${NC}"
systemctl status $SERVICE_NAME --no-pager
echo -e "\n${BLUE}Runner Process Info${NC}"
echo -e "${BLUE}===================${NC}"
ps aux | grep -E "(Runner.Listener|run.sh)" | grep -v grep || echo "No runner processes found"
}
# View logs
view_logs() {
echo -e "${YELLOW}Viewing live logs (Ctrl+C to exit)...${NC}"
journalctl -u $SERVICE_NAME -f
}
# View last 50 lines of logs
view_logs_tail() {
echo -e "${BLUE}Last 50 lines of runner logs${NC}"
echo -e "${BLUE}===========================${NC}"
journalctl -u $SERVICE_NAME -n 50 --no-pager
}
# Update runner
update_runner() {
echo -e "${YELLOW}Updating GitHub Actions Runner...${NC}"
# Stop the service
systemctl stop $SERVICE_NAME
# Get current version
CURRENT_VERSION=$($RUNNER_DIR/bin/Runner.Listener --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo "unknown")
echo -e "Current version: ${YELLOW}$CURRENT_VERSION${NC}"
# Get latest version
LATEST_VERSION=$(curl -s https://api.github.com/repos/actions/runner/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
echo -e "Latest version: ${GREEN}$LATEST_VERSION${NC}"
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo -e "${GREEN}✓ Runner is already up to date${NC}"
systemctl start $SERVICE_NAME
return
fi
# Backup current runner
echo -e "${YELLOW}Backing up current runner...${NC}"
cd $RUNNER_DIR
tar -czf runner-backup-$(date +%Y%m%d-%H%M%S).tar.gz bin externals
# Download and extract new version
echo -e "${YELLOW}Downloading new version...${NC}"
curl -o actions-runner-linux-x64.tar.gz -L "https://github.com/actions/runner/releases/download/v${LATEST_VERSION}/actions-runner-linux-x64-${LATEST_VERSION}.tar.gz"
tar xzf ./actions-runner-linux-x64.tar.gz
rm actions-runner-linux-x64.tar.gz
# Start the service
systemctl start $SERVICE_NAME
echo -e "${GREEN}✓ Runner updated to version $LATEST_VERSION${NC}"
}
# Show configuration
show_config() {
echo -e "${BLUE}Runner Configuration${NC}"
echo -e "${BLUE}===================${NC}"
if [ -f "$RUNNER_DIR/.runner" ]; then
echo -e "\n${GREEN}Runner Settings:${NC}"
cat "$RUNNER_DIR/.runner" | jq '.' 2>/dev/null || cat "$RUNNER_DIR/.runner"
fi
if [ -f "$RUNNER_DIR/.credentials" ]; then
echo -e "\n${GREEN}Runner Registration:${NC}"
echo "Runner is registered (credentials file exists)"
else
echo -e "\n${RED}Runner is not configured${NC}"
fi
echo -e "\n${GREEN}Service Configuration:${NC}"
systemctl show $SERVICE_NAME | grep -E "(LoadState|ActiveState|SubState|MainPID|Environment)"
}
# Check health
check_health() {
echo -e "${BLUE}Runner Health Check${NC}"
echo -e "${BLUE}==================${NC}"
# Check service status
if systemctl is-active --quiet $SERVICE_NAME; then
echo -e "${GREEN}✓ Service is running${NC}"
else
echo -e "${RED}✗ Service is not running${NC}"
fi
# Check disk space
DISK_USAGE=$(df -h $RUNNER_DIR | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -lt 80 ]; then
echo -e "${GREEN}✓ Disk usage: ${DISK_USAGE}%${NC}"
else
echo -e "${RED}✗ Disk usage: ${DISK_USAGE}% (High)${NC}"
fi
# Check work directory size
if [ -d "$RUNNER_DIR/_work" ]; then
WORK_SIZE=$(du -sh "$RUNNER_DIR/_work" 2>/dev/null | cut -f1)
echo -e "${BLUE}Work directory size: $WORK_SIZE${NC}"
fi
# Check runner connectivity
if [ -f "$RUNNER_DIR/.runner" ]; then
GITHUB_URL=$(cat "$RUNNER_DIR/.runner" | jq -r '.gitHubUrl' 2>/dev/null || echo "")
if [ -n "$GITHUB_URL" ] && curl -s -o /dev/null -w "%{http_code}" "$GITHUB_URL" | grep -q "200"; then
echo -e "${GREEN}✓ GitHub connectivity OK${NC}"
else
echo -e "${YELLOW}⚠ Cannot verify GitHub connectivity${NC}"
fi
fi
}
# Show recent jobs
show_jobs() {
echo -e "${BLUE}Recent Runner Jobs${NC}"
echo -e "${BLUE}=================${NC}"
# Check for job history in work directory
if [ -d "$RUNNER_DIR/_work" ]; then
echo -e "\n${GREEN}Recent job directories:${NC}"
ls -la "$RUNNER_DIR/_work" 2>/dev/null | tail -n 10 || echo "No job directories found"
fi
# Show recent log entries
echo -e "\n${GREEN}Recent job activity:${NC}"
journalctl -u $SERVICE_NAME --since "1 hour ago" | grep -E "(Running job|Job .* completed|Completed request)" | tail -n 20 || echo "No recent job activity"
}
# Cleanup work directory
cleanup_work() {
echo -e "${YELLOW}Cleaning up work directory...${NC}"
if [ ! -d "$RUNNER_DIR/_work" ]; then
echo -e "${GREEN}Work directory doesn't exist${NC}"
return
fi
# Show current size
BEFORE_SIZE=$(du -sh "$RUNNER_DIR/_work" 2>/dev/null | cut -f1)
echo -e "Current size: ${YELLOW}$BEFORE_SIZE${NC}"
# Confirm
read -p "Are you sure you want to clean the work directory? (y/N): " confirm
if [ "$confirm" != "y" ]; then
echo -e "${YELLOW}Cleanup cancelled${NC}"
return
fi
# Stop runner
systemctl stop $SERVICE_NAME
# Clean work directory
rm -rf "$RUNNER_DIR/_work"/*
# Start runner
systemctl start $SERVICE_NAME
echo -e "${GREEN}✓ Work directory cleaned${NC}"
}
# Show runner info
show_info() {
echo -e "${BLUE}GitHub Actions Runner Information${NC}"
echo -e "${BLUE}=================================${NC}"
echo -e "\n${GREEN}Basic Info:${NC}"
echo -e "Service Name: ${YELLOW}$SERVICE_NAME${NC}"
echo -e "Runner Directory: ${YELLOW}$RUNNER_DIR${NC}"
echo -e "Runner User: ${YELLOW}$RUNNER_USER${NC}"
if [ -f "$RUNNER_DIR/bin/Runner.Listener" ]; then
VERSION=$($RUNNER_DIR/bin/Runner.Listener --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo "unknown")
echo -e "Runner Version: ${YELLOW}$VERSION${NC}"
fi
echo -e "\n${GREEN}System Info:${NC}"
echo -e "Hostname: ${YELLOW}$(hostname)${NC}"
echo -e "OS: ${YELLOW}$(lsb_release -d | cut -f2)${NC}"
echo -e "Kernel: ${YELLOW}$(uname -r)${NC}"
echo -e "Architecture: ${YELLOW}$(uname -m)${NC}"
echo -e "\n${GREEN}Docker Info:${NC}"
if command -v docker &> /dev/null; then
DOCKER_VERSION=$(docker --version | awk '{print $3}' | sed 's/,$//')
echo -e "Docker Version: ${YELLOW}$DOCKER_VERSION${NC}"
if groups $RUNNER_USER | grep -q docker; then
echo -e "Docker Access: ${GREEN}✓ User in docker group${NC}"
else
echo -e "Docker Access: ${RED}✗ User not in docker group${NC}"
fi
else
echo -e "${RED}Docker not installed${NC}"
fi
echo -e "\n${GREEN}Labels:${NC}"
echo -e "${YELLOW}self-hosted,linux,x64,deployment,webhook-cd${NC}"
}
# Main logic
check_permissions "$1"
case "$1" in
start)
start_runner
;;
stop)
stop_runner
;;
restart)
restart_runner
;;
status)
check_status
;;
logs)
view_logs
;;
logs-tail)
view_logs_tail
;;
update)
update_runner
;;
config)
show_config
;;
health)
check_health
;;
jobs)
show_jobs
;;
cleanup)
cleanup_work
;;
info)
show_info
;;
*)
usage
;;
esac

View File

@@ -0,0 +1,91 @@
#!/bin/bash
# Setup GitHub Actions self-hosted runner for claude-github-webhook
set -e
# Configuration
RUNNER_DIR="/home/jonflatt/github-actions-runner"
RUNNER_VERSION="2.324.0"
REPO_URL="https://github.com/intelligence-assist/claude-github-webhook"
RUNNER_NAME="claude-webhook-runner"
RUNNER_LABELS="self-hosted,linux,x64,claude-webhook"
echo "🚀 Setting up GitHub Actions self-hosted runner..."
# Create runner directory
mkdir -p "$RUNNER_DIR"
cd "$RUNNER_DIR"
# Download runner if not exists
if [ ! -f "actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" ]; then
echo "📦 Downloading runner v${RUNNER_VERSION}..."
curl -o "actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" -L \
"https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz"
fi
# Extract runner
echo "📂 Extracting runner..."
tar xzf "./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz"
# Install dependencies if needed
echo "🔧 Installing dependencies..."
sudo ./bin/installdependencies.sh || true
echo ""
echo "⚠️ IMPORTANT: You need to get a runner registration token from GitHub!"
echo ""
echo "1. Go to: https://github.com/intelligence-assist/claude-github-webhook/settings/actions/runners/new"
echo "2. Copy the registration token"
echo "3. Run the configuration command below with your token:"
echo ""
echo "cd $RUNNER_DIR"
echo "./config.sh --url $REPO_URL --token YOUR_TOKEN_HERE --name $RUNNER_NAME --labels $RUNNER_LABELS --unattended --replace"
echo ""
echo "4. After configuration, install as a service:"
echo "sudo ./svc.sh install"
echo "sudo ./svc.sh start"
echo ""
echo "5. Check status:"
echo "sudo ./svc.sh status"
echo ""
# Create systemd service file for the runner
cat > "$RUNNER_DIR/actions.runner.service" << 'EOF'
[Unit]
Description=GitHub Actions Runner (claude-webhook-runner)
After=network-online.target
[Service]
Type=simple
User=jonflatt
WorkingDirectory=/home/jonflatt/github-actions-runner
ExecStart=/home/jonflatt/github-actions-runner/run.sh
Restart=on-failure
RestartSec=5
KillMode=process
KillSignal=SIGTERM
StandardOutput=journal
StandardError=journal
SyslogIdentifier=github-runner
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/jonflatt/github-actions-runner
ReadWritePaths=/home/jonflatt/n8n/claude-repo
ReadWritePaths=/var/run/docker.sock
[Install]
WantedBy=multi-user.target
EOF
echo "📄 Systemd service file created at: $RUNNER_DIR/actions.runner.service"
echo ""
echo "Alternative: Use systemd directly instead of ./svc.sh:"
echo "sudo cp $RUNNER_DIR/actions.runner.service /etc/systemd/system/github-runner-claude.service"
echo "sudo systemctl daemon-reload"
echo "sudo systemctl enable github-runner-claude"
echo "sudo systemctl start github-runner-claude"