From 42e64d7161313c6ceebfac5beb17abbedb7e279a Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 11:32:34 +0200 Subject: [PATCH 1/7] conditional file restoring added --- .github/workflows/restore-site.yml | 45 +++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 1b60a5ce..629bb2f2 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -171,8 +171,8 @@ jobs: PRIVATE_FILES_BACKUP=\"\${TIMESTAMP}-*-private-files.tar\" DB_FILE=\$(ls \$DB_BACKUP 2>/dev/null | head -n 1) - FILES_FILE=$(ls ${TIMESTAMP}-*-files.tar ${TIMESTAMP}-*-files.tgz 2>/dev/null | head -n 1) - PRIVATE_FILES_FILE=$(ls ${TIMESTAMP}-*-private-files.tar ${TIMESTAMP}-*-private-files.tgz 2>/dev/null | head -n 1) + FILES_FILE=\$(ls \${TIMESTAMP}-*-files.tar \${TIMESTAMP}-*-files.tgz 2>/dev/null | head -n 1) + PRIVATE_FILES_FILE=\$(ls \${TIMESTAMP}-*-private-files.tar \${TIMESTAMP}-*-private-files.tgz 2>/dev/null | head -n 1) if [ -z \"\$DB_FILE\" ]; then echo \"ERROR: Database backup not found for timestamp \$TIMESTAMP\" @@ -237,25 +237,46 @@ jobs: fi docker compose exec -T backend bash -c ' - BACKUP_DIR=\"${{ steps.find_backup.outputs.backup_dir }}\" - TIMESTAMP=\"${{ steps.find_backup.outputs.timestamp }}\" + set -e + + BACKUP_DIR="${{ steps.find_backup.outputs.backup_dir }}" + TIMESTAMP="${{ steps.find_backup.outputs.timestamp }}" - DB_FILE=\$(ls \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-database.sql.gz 2>/dev/null | head -n 1) + DB_FILE=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-database.sql.gz 2>/dev/null | head -n 1) PUBLIC_FILES=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-files.tar "$BACKUP_DIR"/${TIMESTAMP}-*-files.tgz 2>/dev/null | head -n 1) PRIVATE_FILES=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-private-files.tar "$BACKUP_DIR"/${TIMESTAMP}-*-private-files.tgz 2>/dev/null | head -n 1) - if [ -z \"\$DB_FILE\" ]; then - echo \"❌ Database backup file not found\" + if [ -z "$DB_FILE" ]; then + echo "❌ Database backup file not found" exit 1 fi - echo \"Restoring from: \$DB_FILE\" + echo "Restoring from: $DB_FILE" + + # Construct command dynamically to handle missing file backups + CMD="bench --site ${{ github.event.inputs.site_name }} --force restore '$DB_FILE'" + + if [ -n "$PUBLIC_FILES" ]; then + echo "With public files: $PUBLIC_FILES" + CMD="$CMD --with-public-files '$PUBLIC_FILES'" + else + echo "⚠️ No public files backup found, skipping files restore" + fi + + if [ -n "$PRIVATE_FILES" ]; then + echo "With private files: $PRIVATE_FILES" + CMD="$CMD --with-private-files '$PRIVATE_FILES'" + else + echo "⚠️ No private files backup found, skipping private files restore" + fi # Restore the database - bench --site ${{ github.event.inputs.site_name }} --force restore \"\$DB_FILE\" --with-public-files \"\$PUBLIC_FILES\" --with-private-files \"\$PRIVATE_FILES\" + echo "Running: $CMD" + eval "$CMD" - echo \"✅ Database restored successfully\" + echo "✅ Database restored successfully" ' + " - name: Run database migrations @@ -265,6 +286,8 @@ jobs: ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " cd ${{ env.DEPLOY_PATH }} + + set -e docker compose exec -T backend bench --site ${{ github.event.inputs.site_name }} migrate echo '✅ Migrations completed successfully' @@ -277,6 +300,8 @@ jobs: ssh ${{ env.HETZNER_USER }}@${{ env.HETZNER_HOST }} " cd ${{ env.DEPLOY_PATH }} + + set -e docker compose exec -T backend bench --site ${{ github.event.inputs.site_name }} clear-cache docker compose exec -T backend bench --site ${{ github.event.inputs.site_name }} clear-website-cache From 86af18c90ab9382f8e98d581db362aab4e3dc45f Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 11:43:18 +0200 Subject: [PATCH 2/7] some escaping fixed --- .github/workflows/restore-site.yml | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 629bb2f2..453cec11 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -239,42 +239,42 @@ jobs: docker compose exec -T backend bash -c ' set -e - BACKUP_DIR="${{ steps.find_backup.outputs.backup_dir }}" - TIMESTAMP="${{ steps.find_backup.outputs.timestamp }}" + BACKUP_DIR=\"${{ steps.find_backup.outputs.backup_dir }}\" + TIMESTAMP=\"${{ steps.find_backup.outputs.timestamp }}\" - DB_FILE=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-database.sql.gz 2>/dev/null | head -n 1) - PUBLIC_FILES=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-files.tar "$BACKUP_DIR"/${TIMESTAMP}-*-files.tgz 2>/dev/null | head -n 1) - PRIVATE_FILES=$(ls "$BACKUP_DIR"/${TIMESTAMP}-*-private-files.tar "$BACKUP_DIR"/${TIMESTAMP}-*-private-files.tgz 2>/dev/null | head -n 1) + DB_FILE=\$(ls \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-database.sql.gz 2>/dev/null | head -n 1) + PUBLIC_FILES=\$(ls \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-files.tar \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-files.tgz 2>/dev/null | head -n 1) + PRIVATE_FILES=\$(ls \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-private-files.tar \"\$BACKUP_DIR\"/\${TIMESTAMP}-*-private-files.tgz 2>/dev/null | head -n 1) - if [ -z "$DB_FILE" ]; then - echo "❌ Database backup file not found" + if [ -z \"\$DB_FILE\" ]; then + echo \"❌ Database backup file not found\" exit 1 fi - echo "Restoring from: $DB_FILE" + echo \"Restoring from: \$DB_FILE\" # Construct command dynamically to handle missing file backups - CMD="bench --site ${{ github.event.inputs.site_name }} --force restore '$DB_FILE'" + CMD=\"bench --site ${{ github.event.inputs.site_name }} --force restore '\$DB_FILE'\" - if [ -n "$PUBLIC_FILES" ]; then - echo "With public files: $PUBLIC_FILES" - CMD="$CMD --with-public-files '$PUBLIC_FILES'" + if [ -n \"\$PUBLIC_FILES\" ]; then + echo \"With public files: \$PUBLIC_FILES\" + CMD=\"\$CMD --with-public-files '\$PUBLIC_FILES'\" else - echo "⚠️ No public files backup found, skipping files restore" + echo \"⚠️ No public files backup found, skipping files restore\" fi - if [ -n "$PRIVATE_FILES" ]; then - echo "With private files: $PRIVATE_FILES" - CMD="$CMD --with-private-files '$PRIVATE_FILES'" + if [ -n \"\$PRIVATE_FILES\" ]; then + echo \"With private files: \$PRIVATE_FILES\" + CMD=\"\$CMD --with-private-files '\$PRIVATE_FILES'\" else - echo "⚠️ No private files backup found, skipping private files restore" + echo \"⚠️ No private files backup found, skipping private files restore\" fi # Restore the database - echo "Running: $CMD" - eval "$CMD" + echo \"Running: \$CMD\" + eval \"\$CMD\" - echo "✅ Database restored successfully" + echo \"✅ Database restored successfully\" ' " From 55c02b184326440354d4e4c6e2364c7793ed4d35 Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 12:04:08 +0200 Subject: [PATCH 3/7] quote issues fixed --- .github/workflows/restore-site.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 453cec11..165a8bb7 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -253,26 +253,26 @@ jobs: echo \"Restoring from: \$DB_FILE\" - # Construct command dynamically to handle missing file backups - CMD=\"bench --site ${{ github.event.inputs.site_name }} --force restore '\$DB_FILE'\" + # Construct command using array to handle arguments safely + ARGS=(bench --site ${{ github.event.inputs.site_name }} --force restore \"\$DB_FILE\") if [ -n \"\$PUBLIC_FILES\" ]; then echo \"With public files: \$PUBLIC_FILES\" - CMD=\"\$CMD --with-public-files '\$PUBLIC_FILES'\" + ARGS+=(--with-public-files \"\$PUBLIC_FILES\") else echo \"⚠️ No public files backup found, skipping files restore\" fi if [ -n \"\$PRIVATE_FILES\" ]; then echo \"With private files: \$PRIVATE_FILES\" - CMD=\"\$CMD --with-private-files '\$PRIVATE_FILES'\" + ARGS+=(--with-private-files \"\$PRIVATE_FILES\") else echo \"⚠️ No private files backup found, skipping private files restore\" fi # Restore the database - echo \"Running: \$CMD\" - eval \"\$CMD\" + echo \"Running: \${ARGS[*]}\" + \"\${ARGS[@]}\" echo \"✅ Database restored successfully\" ' From 23c4d3afe210ef21dea19f86f3125eefbbde88a6 Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 12:26:31 +0200 Subject: [PATCH 4/7] required passwords added for db restoration --- .github/workflows/restore-site.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 165a8bb7..1c8d3159 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -254,7 +254,7 @@ jobs: echo \"Restoring from: \$DB_FILE\" # Construct command using array to handle arguments safely - ARGS=(bench --site ${{ github.event.inputs.site_name }} --force restore \"\$DB_FILE\") + ARGS=(bench --site ${{ github.event.inputs.site_name }} --force restore \"\$DB_FILE\" --db-root-password \"'\"\$MARIADB_ROOT_PASSWORD\"'\" --admin-password \"'\"\$ADMIN_PASSWORD\"'\") if [ -n \"\$PUBLIC_FILES\" ]; then echo \"With public files: \$PUBLIC_FILES\" From 4d7ec83b4e1f55d620cb7a6f02abf24bc7867076 Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 14:05:10 +0200 Subject: [PATCH 5/7] timestamps are searched in multiple arhcived sites --- .github/workflows/restore-site.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 1c8d3159..bf4e901e 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -136,8 +136,28 @@ jobs: exit 1 fi - # Find the archived site directory - ARCHIVED_SITE=\$(ls -td \$ARCHIVED_BASE/${{ github.event.inputs.site_name }}* 2>/dev/null | head -n 1) + # Find the archived site directory matching criteria + INPUT_TIMESTAMP=\"${{ github.event.inputs.backup_timestamp }}\" + + if [ -n \"\$INPUT_TIMESTAMP\" ]; then + echo \"Searching for archived site containing backup timestamp: \$INPUT_TIMESTAMP\" + ARCHIVED_SITE=\"\" + # Loop through all matching site directories to find one with the specific backup + for site_dir in \$(ls -d \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null); do + if ls \"\$site_dir/private/backups/\${INPUT_TIMESTAMP}\"-*-database.sql.gz 1> /dev/null 2>&1; then + ARCHIVED_SITE=\"\$site_dir\" + break + fi + done + + if [ -z \"\$ARCHIVED_SITE\" ]; then + echo \"ERROR: No archived site folder for ${{ github.event.inputs.site_name }} contains backup \$INPUT_TIMESTAMP\" + exit 1 + fi + else + # Default: take the latest archived folder + ARCHIVED_SITE=\$(ls -td \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null | head -n 1) + fi if [ -z \"\$ARCHIVED_SITE\" ]; then echo \"ERROR: No archived backup found for site ${{ github.event.inputs.site_name }}\" From 39949bb7db472001e551749316abe4601c3ddc1b Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 14:37:30 +0200 Subject: [PATCH 6/7] custom backup dir path can be specified from now on --- .github/workflows/restore-site.yml | 76 +++++++++++++++++------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index bf4e901e..7b6240d1 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -17,7 +17,11 @@ on: required: true type: string backup_timestamp: - description: 'Backup timestamp (e.g., 20260109_142920) - leave empty to use latest' + description: '(Optional) Backup timestamp (e.g., 20260109_142920) - leave empty to use latest' + required: false + type: string + absolute_backup_dir_path: + description: '(Optional) Absolute path to the backup directory (the backup files contained in the directory should match the the following naming convention: --database.sql.gz, --files.tar, --private-files.tar.gz)' required: false type: string @@ -126,46 +130,50 @@ jobs: cd ${{ env.DEPLOY_PATH }} docker compose exec -T backend bash -c ' - # Check both possible archived locations - if [ -d /home/frappe/frappe-bench/archived/sites ]; then - ARCHIVED_BASE=/home/frappe/frappe-bench/archived/sites - elif [ -d /home/frappe/frappe-bench/archived_sites ]; then - ARCHIVED_BASE=/home/frappe/frappe-bench/archived_sites + if [ -n \"${{ github.event.inputs.absolute_backup_dir_path }}\" ]; then + BACKUP_DIR=\"${{ github.event.inputs.absolute_backup_dir_path }}\" else - echo \"ERROR: No archived sites directory found\" - exit 1 - fi - - # Find the archived site directory matching criteria - INPUT_TIMESTAMP=\"${{ github.event.inputs.backup_timestamp }}\" - - if [ -n \"\$INPUT_TIMESTAMP\" ]; then - echo \"Searching for archived site containing backup timestamp: \$INPUT_TIMESTAMP\" - ARCHIVED_SITE=\"\" - # Loop through all matching site directories to find one with the specific backup - for site_dir in \$(ls -d \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null); do - if ls \"\$site_dir/private/backups/\${INPUT_TIMESTAMP}\"-*-database.sql.gz 1> /dev/null 2>&1; then - ARCHIVED_SITE=\"\$site_dir\" - break + # Check both possible archived locations + if [ -d /home/frappe/frappe-bench/archived/sites ]; then + ARCHIVED_BASE=/home/frappe/frappe-bench/archived/sites + elif [ -d /home/frappe/frappe-bench/archived_sites ]; then + ARCHIVED_BASE=/home/frappe/frappe-bench/archived_sites + else + echo \"ERROR: No archived sites directory found\" + exit 1 + fi + + # Find the archived site directory matching criteria + INPUT_TIMESTAMP=\"${{ github.event.inputs.backup_timestamp }}\" + + if [ -n \"\$INPUT_TIMESTAMP\" ]; then + echo \"Searching for archived site containing backup timestamp: \$INPUT_TIMESTAMP\" + ARCHIVED_SITE=\"\" + # Loop through all matching site directories to find one with the specific backup + for site_dir in \$(ls -d \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null); do + if ls \"\$site_dir/private/backups/\${INPUT_TIMESTAMP}\"-*-database.sql.gz 1> /dev/null 2>&1; then + ARCHIVED_SITE=\"\$site_dir\" + break + fi + done + + if [ -z \"\$ARCHIVED_SITE\" ]; then + echo \"ERROR: No archived site folder for ${{ github.event.inputs.site_name }} contains backup \$INPUT_TIMESTAMP\" + exit 1 fi - done + else + # Default: take the latest archived folder + ARCHIVED_SITE=\$(ls -td \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null | head -n 1) + fi if [ -z \"\$ARCHIVED_SITE\" ]; then - echo \"ERROR: No archived site folder for ${{ github.event.inputs.site_name }} contains backup \$INPUT_TIMESTAMP\" - exit 1 + echo \"ERROR: No archived backup found for site ${{ github.event.inputs.site_name }}\" + exit 1 fi - else - # Default: take the latest archived folder - ARCHIVED_SITE=\$(ls -td \"\$ARCHIVED_BASE\"/${{ github.event.inputs.site_name }}* 2>/dev/null | head -n 1) + + BACKUP_DIR=\"\$ARCHIVED_SITE/private/backups\" fi - if [ -z \"\$ARCHIVED_SITE\" ]; then - echo \"ERROR: No archived backup found for site ${{ github.event.inputs.site_name }}\" - exit 1 - fi - - BACKUP_DIR=\"\$ARCHIVED_SITE/private/backups\" - if [ ! -d \"\$BACKUP_DIR\" ]; then echo \"ERROR: Backup directory not found: \$BACKUP_DIR\" exit 1 From 0de9e393b713a9fb8ccae4c1cd6ce05733a517f7 Mon Sep 17 00:00:00 2001 From: Mate Majoros Date: Tue, 13 Jan 2026 14:45:40 +0200 Subject: [PATCH 7/7] description updated and echo added --- .github/workflows/restore-site.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/restore-site.yml b/.github/workflows/restore-site.yml index 7b6240d1..a48be475 100644 --- a/.github/workflows/restore-site.yml +++ b/.github/workflows/restore-site.yml @@ -21,7 +21,7 @@ on: required: false type: string absolute_backup_dir_path: - description: '(Optional) Absolute path to the backup directory (the backup files contained in the directory should match the the following naming convention: --database.sql.gz, --files.tar, --private-files.tar.gz)' + description: '(Optional) Absolute path to the backup directory (the backup files contained in the directory should match the the following naming convention: --database.sql.gz, --files.tar, --private-files.tar)' required: false type: string @@ -131,6 +131,7 @@ jobs: docker compose exec -T backend bash -c ' if [ -n \"${{ github.event.inputs.absolute_backup_dir_path }}\" ]; then + echo "Using absolute backup directory: ${{ github.event.inputs.absolute_backup_dir_path }}" BACKUP_DIR=\"${{ github.event.inputs.absolute_backup_dir_path }}\" else # Check both possible archived locations