diff --git a/README.md b/README.md index 2aff563..ebf8914 100644 --- a/README.md +++ b/README.md @@ -86,12 +86,8 @@ bash ENABLE_SLACK="false" SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" -Notification Setup -Email Notifications -Option 1: Using msmtp (Recommended) ``` - ### Usage Manual Execution diff --git a/gitea_update.sh b/gitea_update.sh index bc16d35..42b18fa 100644 --- a/gitea_update.sh +++ b/gitea_update.sh @@ -1,7 +1,6 @@ #!/bin/bash # Gitea Backup and Update Script with Notifications -# Supports email and Discord/Slack webhook notifications set -e @@ -11,30 +10,27 @@ GITEA_USER="git" GITEA_BIN="/usr/local/bin/gitea" BACKUP_DIR="/var/backups/gitea" LOG_FILE="/var/log/gitea-backup-update.log" + TIMESTAMP=$(date +"%Y%m%d_%H%M%S") BACKUP_NAME="gitea_backup_${TIMESTAMP}" HOSTNAME=$(hostname) # Notification Settings + # Email notifications ENABLE_EMAIL="false" EMAIL_FROM="noreply@example.com" EMAIL_TO="admin@example.com" -SMTP_SERVER="smtp.gmail.com" -SMTP_PORT="587" -SMTP_USER="your-email@gmail.com" -SMTP_PASS="your-app-password" # Discord webhook ENABLE_DISCORD="false" DISCORD_WEBHOOK_URL="https://discordapp.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN" - # Slack webhook ENABLE_SLACK="false" SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" -# Colors for output +# Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -46,40 +42,42 @@ STATUS="RUNNING" STATUS_MESSAGE="" START_TIME=$(date +%s) -# Logging function +# ------------------------------------------------------------ +# Logging +# ------------------------------------------------------------ + log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } -# Error handler -error_exit() { - log "${RED}ERROR: $1${NC}" - STATUS="FAILED" - STATUS_MESSAGE="$1" - send_notifications - exit 1 -} +# ------------------------------------------------------------ +# Notifications +# ------------------------------------------------------------ -# Send email notification send_email() { local subject="$1" local body="$2" - + if [ "$ENABLE_EMAIL" != "true" ]; then return fi - + log "Sending email notification..." - - # Using msmtp (lightweight SMTP client) - if command -v msmtp &> /dev/null; then - echo "$body" | msmtp -a default "$EMAIL_TO" + + if command -v msmtp >/dev/null 2>&1; then + { + echo "To: $EMAIL_TO" + echo "From: $EMAIL_FROM" + echo "Subject: $subject" + echo "" + echo "$body" + } | msmtp "$EMAIL_TO" + log "${GREEN}Email sent successfully${NC}" return fi - - # Fallback to ssmtp - if command -v ssmtp &> /dev/null; then + + if command -v ssmtp >/dev/null 2>&1; then { echo "To: $EMAIL_TO" echo "From: $EMAIL_FROM" @@ -87,44 +85,51 @@ send_email() { echo "" echo "$body" } | ssmtp "$EMAIL_TO" + log "${GREEN}Email sent successfully${NC}" return fi - - # Fallback to mail command - if command -v mail &> /dev/null; then + + if command -v mail >/dev/null 2>&1; then echo "$body" | mail -s "$subject" "$EMAIL_TO" log "${GREEN}Email sent successfully${NC}" return fi - - log "${YELLOW}Warning: No mail client found. Install msmtp, ssmtp, or mailutils${NC}" + + log "${YELLOW}Warning: No mail client found${NC}" } -# Send Discord notification send_discord() { - local status_color="" - local status_emoji="" - + if [ "$ENABLE_DISCORD" != "true" ] || [ -z "$DISCORD_WEBHOOK_URL" ]; then + return + fi + + local status_color + local status_emoji + case "$STATUS" in - "RUNNING") - status_color="3447525" # Blue + RUNNING) + status_color="3447525" status_emoji="⏳" ;; - "SUCCESS") - status_color="3066993" # Green + SUCCESS) + status_color="3066993" status_emoji="✅" ;; - "FAILED") - status_color="15158332" # Red + FAILED) + status_color="15158332" status_emoji="❌" ;; esac - - local duration=$(($(date +%s) - START_TIME)) - local duration_formatted="$((duration / 60))m $((duration % 60))s" - - local payload=$(cat < /dev/null 2>&1 || log "${YELLOW}Warning: Discord notification failed${NC}" - fi + + curl --silent --show-error \ + --request POST "$DISCORD_WEBHOOK_URL" \ + --header "Content-Type: application/json" \ + --data "$payload" \ + >/dev/null 2>&1 \ + || log "${YELLOW}Warning: Discord notification failed${NC}" } -# Send Slack notification send_slack() { - local status_color="" - local status_emoji="" - + if [ "$ENABLE_SLACK" != "true" ] || [ -z "$SLACK_WEBHOOK_URL" ]; then + return + fi + + local status_color + local status_emoji + case "$STATUS" in - "RUNNING") + RUNNING) status_color="warning" status_emoji="⏳" ;; - "SUCCESS") + SUCCESS) status_color="good" status_emoji="✅" ;; - "FAILED") + FAILED) status_color="danger" status_emoji="❌" ;; esac - - local duration=$(($(date +%s) - START_TIME)) - local duration_formatted="$((duration / 60))m $((duration % 60))s" - - local payload=$(cat < /dev/null 2>&1 || log "${YELLOW}Warning: Slack notification failed${NC}" - fi + + curl --silent --show-error \ + --request POST "$SLACK_WEBHOOK_URL" \ + --header "Content-Type: application/json" \ + --data "$payload" \ + >/dev/null 2>&1 \ + || log "${YELLOW}Warning: Slack notification failed${NC}" } -# Send all notifications send_notifications() { log "Sending notifications..." - - local subject="Gitea Backup & Update - $STATUS" - local body="Gitea Backup and Update Script Results + + local subject + local body + + subject="Gitea Backup & Update - $STATUS" + + body="Gitea Backup and Update Script Results Server: $HOSTNAME Status: $STATUS @@ -255,65 +272,105 @@ Details: $STATUS_MESSAGE Backup Location: $BACKUP_DIR" - + send_email "$subject" "$body" send_discord send_slack } -# Check if running as root +error_exit() { + log "${RED}ERROR: $1${NC}" + + STATUS="FAILED" + STATUS_MESSAGE="$1" + + send_notifications + exit 1 +} + +# ------------------------------------------------------------ +# Initial checks +# ------------------------------------------------------------ + if [[ $EUID -ne 0 ]]; then - error_exit "This script must be run as root" + STATUS="FAILED" + STATUS_MESSAGE="This script must be run as root" + echo "$STATUS_MESSAGE" + exit 1 fi +if [ ! -x "$GITEA_BIN" ]; then + error_exit "Gitea binary not found or is not executable: $GITEA_BIN" +fi + +if ! command -v curl >/dev/null 2>&1; then + error_exit "curl is required but was not found" +fi + +mkdir -p "$(dirname "$LOG_FILE")" + log "${GREEN}=== Gitea Backup and Update Started ===${NC}" + STATUS="RUNNING" send_discord -# Create backup directory if it doesn't exist -mkdir -p "$BACKUP_DIR" +# ------------------------------------------------------------ +# Check installed and latest versions +# ------------------------------------------------------------ -# Step 1: Stop Gitea service -log "Stopping Gitea service..." -systemctl stop gitea || error_exit "Failed to stop Gitea service" -sleep 2 +log "Checking installed Gitea version..." -# Step 2: Backup Gitea data -log "Creating backup of Gitea data..." -mkdir -p "$BACKUP_DIR/$BACKUP_NAME" +INSTALLED_VERSION=$( + "$GITEA_BIN" --version 2>/dev/null | + grep -oE 'version [0-9]+\.[0-9]+\.[0-9]+' | + awk '{print $2}' | + head -n 1 +) -# Backup the main Gitea directory -cp -r "$GITEA_HOME" "$BACKUP_DIR/$BACKUP_NAME/gitea_home" || error_exit "Failed to backup Gitea home directory" +if [ -z "$INSTALLED_VERSION" ]; then + error_exit "Could not determine installed Gitea version" +fi -# Backup the binary -cp "$GITEA_BIN" "$BACKUP_DIR/$BACKUP_NAME/gitea_bin_backup" || error_exit "Failed to backup Gitea binary" +log "Checking latest Gitea release..." -log "${GREEN}Backup created at: $BACKUP_DIR/$BACKUP_NAME${NC}" -STATUS_MESSAGE="Backup created successfully" -send_discord - -# Step 3: Compress backup -log "Compressing backup..." -cd "$BACKUP_DIR" -tar -czf "${BACKUP_NAME}.tar.gz" "$BACKUP_NAME" || error_exit "Failed to compress backup" -rm -rf "$BACKUP_DIR/$BACKUP_NAME" -log "${GREEN}Backup compressed: ${BACKUP_NAME}.tar.gz${NC}" - -# Step 4: Download latest Gitea release -log "Downloading latest Gitea release..." -LATEST_VERSION=$(curl -s https://api.github.com/repos/go-gitea/gitea/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")') +LATEST_VERSION=$( + curl --fail --silent --show-error \ + https://api.github.com/repos/go-gitea/gitea/releases/latest | + grep -oP '"tag_name":\s*"\K[^"]+' | + head -n 1 +) if [ -z "$LATEST_VERSION" ]; then error_exit "Failed to fetch latest Gitea version" fi -log "Latest version: $LATEST_VERSION" -STATUS_MESSAGE="Fetched latest version: $LATEST_VERSION" +LATEST_VERSION_NUMBER="${LATEST_VERSION#v}" + +log "Installed version: $INSTALLED_VERSION" +log "Latest version: $LATEST_VERSION_NUMBER" + +# Exit before stopping Gitea or creating a backup if already current +if [ "$INSTALLED_VERSION" = "$LATEST_VERSION_NUMBER" ]; then + STATUS="SUCCESS" + STATUS_MESSAGE="Gitea is already up to date at version $INSTALLED_VERSION" + + log "${GREEN}$STATUS_MESSAGE${NC}" + send_notifications + exit 0 +fi + +log "${YELLOW}Update available: $INSTALLED_VERSION -> $LATEST_VERSION_NUMBER${NC}" + +STATUS_MESSAGE="Update available: $INSTALLED_VERSION -> $LATEST_VERSION_NUMBER" send_discord -# Determine system architecture +# ------------------------------------------------------------ +# Determine architecture +# ------------------------------------------------------------ + ARCH=$(uname -m) -case $ARCH in + +case "$ARCH" in x86_64) DOWNLOAD_ARCH="amd64" ;; @@ -328,42 +385,125 @@ case $ARCH in ;; esac -DOWNLOAD_URL="https://github.com/go-gitea/gitea/releases/download/${LATEST_VERSION}/gitea-${LATEST_VERSION#v}-linux-${DOWNLOAD_ARCH}" +DOWNLOAD_URL="https://github.com/go-gitea/gitea/releases/download/${LATEST_VERSION}/gitea-${LATEST_VERSION_NUMBER}-linux-${DOWNLOAD_ARCH}" -log "Downloading from: $DOWNLOAD_URL" -curl -L -o /tmp/gitea_new "$DOWNLOAD_URL" || error_exit "Failed to download Gitea" +# ------------------------------------------------------------ +# Stop Gitea +# ------------------------------------------------------------ -# Step 5: Verify and install new binary -log "Installing new Gitea binary..." -chmod +x /tmp/gitea_new -cp /tmp/gitea_new "$GITEA_BIN" || error_exit "Failed to install new binary" -chown "$GITEA_USER:$GITEA_USER" "$GITEA_BIN" -rm /tmp/gitea_new +log "Stopping Gitea service..." -log "${GREEN}Gitea binary updated to $LATEST_VERSION${NC}" -STATUS_MESSAGE="Gitea updated to $LATEST_VERSION" +systemctl stop gitea || + error_exit "Failed to stop Gitea service" + +sleep 2 + +# ------------------------------------------------------------ +# Create backup +# ------------------------------------------------------------ + +log "Creating backup of Gitea data..." + +mkdir -p "$BACKUP_DIR/$BACKUP_NAME" + +cp -r "$GITEA_HOME" "$BACKUP_DIR/$BACKUP_NAME/gitea_home" || + error_exit "Failed to backup Gitea home directory" + +cp "$GITEA_BIN" "$BACKUP_DIR/$BACKUP_NAME/gitea_bin_backup" || + error_exit "Failed to backup Gitea binary" + +log "${GREEN}Backup created at: $BACKUP_DIR/$BACKUP_NAME${NC}" + +STATUS_MESSAGE="Backup created successfully" send_discord -# Step 6: Start Gitea service -log "Starting Gitea service..." -systemctl start gitea || error_exit "Failed to start Gitea service" -sleep 3 +# ------------------------------------------------------------ +# Compress backup +# ------------------------------------------------------------ -# Step 7: Verify service is running -if systemctl is-active --quiet gitea; then - log "${GREEN}=== Gitea service is running ===${NC}" -else - error_exit "Gitea service failed to start. Check logs for details." +log "Compressing backup..." + +cd "$BACKUP_DIR" + +tar -czf "${BACKUP_NAME}.tar.gz" "$BACKUP_NAME" || + error_exit "Failed to compress backup" + +rm -rf "$BACKUP_DIR/$BACKUP_NAME" + +log "${GREEN}Backup compressed: $BACKUP_DIR/${BACKUP_NAME}.tar.gz${NC}" + +# ------------------------------------------------------------ +# Download and install Gitea +# ------------------------------------------------------------ + +log "Downloading Gitea $LATEST_VERSION_NUMBER..." +log "Download URL: $DOWNLOAD_URL" + +TMP_BINARY=$(mktemp /tmp/gitea_new.XXXXXX) + +curl --fail --location --silent --show-error \ + --output "$TMP_BINARY" \ + "$DOWNLOAD_URL" || { + rm -f "$TMP_BINARY" + error_exit "Failed to download Gitea" + } + +if [ ! -s "$TMP_BINARY" ]; then + rm -f "$TMP_BINARY" + error_exit "Downloaded Gitea binary is empty" fi -# Step 8: Cleanup old backups (keep only last 5) -log "Cleaning up old backups (keeping last 5)..." +log "Installing new Gitea binary..." + +chmod 755 "$TMP_BINARY" +chown "$GITEA_USER:$GITEA_USER" "$TMP_BINARY" + +mv "$TMP_BINARY" "$GITEA_BIN" || + error_exit "Failed to install new Gitea binary" + +log "${GREEN}Gitea binary updated to $LATEST_VERSION_NUMBER${NC}" + +STATUS_MESSAGE="Gitea updated from $INSTALLED_VERSION to $LATEST_VERSION_NUMBER" +send_discord + +# ------------------------------------------------------------ +# Start and verify Gitea +# ------------------------------------------------------------ + +log "Starting Gitea service..." + +systemctl start gitea || + error_exit "Failed to start Gitea service" + +sleep 3 + +if systemctl is-active --quiet gitea; then + log "${GREEN}Gitea service is running${NC}" +else + error_exit "Gitea service failed to start. Check the service logs." +fi + +# ------------------------------------------------------------ +# Clean up old backups +# ------------------------------------------------------------ + +log "Cleaning up old backups; keeping the last five..." + cd "$BACKUP_DIR" -ls -t *.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -log "${GREEN}Cleanup completed${NC}" + +ls -t *.tar.gz 2>/dev/null | + tail -n +6 | + xargs -r rm -- + +log "${GREEN}Backup cleanup completed${NC}" + +# ------------------------------------------------------------ +# Finish +# ------------------------------------------------------------ log "${GREEN}=== Gitea Backup and Update Completed Successfully ===${NC}" -STATUS="SUCCESS" -STATUS_MESSAGE="Backup completed and Gitea updated to $LATEST_VERSION successfully" -send_notifications +STATUS="SUCCESS" +STATUS_MESSAGE="Backup completed and Gitea updated from $INSTALLED_VERSION to $LATEST_VERSION_NUMBER successfully" + +send_notifications