feat(glossaries): add backup + delete scripts and Gitea workflow for duplicate cleanup
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 6m31s

- scripts/backup_duplicate_glossaries.py : exporte en JSON les doublons
  (meme user_id + template_id) sans rien supprimer. Schema validation,
  tri stable, mode degrade si colonne template_id absente.
- scripts/delete_duplicate_glossaries.py : lit un backup JSON et supprime
  les doublons listes. Validation IDs, confirmation interactive,
  commit par user, mode --dry-run / --yes.
- .gitea/workflows/cleanup-glossaries.yml : workflow_dispatch qui SSH
  sur le serveur de prod et execute le script dans le conteneur backend
  (postgres demarre, .env charge, env_file docker-compose).
This commit is contained in:
Sepehr
2026-06-03 21:21:11 +02:00
parent e1f9f3db04
commit cd32a42b1a
3 changed files with 715 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
name: Cleanup Duplicate Glossaries
on:
workflow_dispatch:
inputs:
user_id:
description: 'User ID dont on nettoie les doublons (obligatoire).'
required: true
type: string
dry_run:
description: 'Mode relecture seule — aucune suppression.'
required: false
default: true
type: boolean
yes:
description: 'Confirme la suppression (ignoré si dry_run=true).'
required: false
default: false
type: boolean
jobs:
cleanup:
name: Backup and delete duplicate glossaries on production
runs-on: ubuntu-24.04
steps:
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H 192.168.1.151 >> ~/.ssh/known_hosts
- name: Run cleanup on production server
env:
USER_ID: ${{ inputs.user_id }}
DRY_RUN: ${{ inputs.dry_run }}
YES: ${{ inputs.yes }}
run: |
ssh root@192.168.1.151 << ENDSSH
set -euo pipefail
cd /opt/wordly
# S'assurer que le code local est à jour (les scripts font partie du repo).
git config --global --add safe.directory /opt/wordly
git fetch origin production-deployment
git reset --hard origin/production-deployment
# S'assurer que postgres tourne (le script lit via DATABASE_URL du .env).
docker compose up -d postgres redis
# Attendre postgres (max 60s).
for i in \$(seq 1 30); do
if docker compose exec -T postgres pg_isready -U translate >/dev/null 2>&1; then
echo "Postgres ready after \$((i * 2))s"
break
fi
[ "\$i" -eq 30 ] && { echo "Postgres not ready after 60s"; exit 1; }
sleep 2
done
# Construire les flags.
FLAGS="--user \${USER_ID} --allow-missing-template-id"
if [ "\${DRY_RUN}" = "true" ]; then
FLAGS="\${FLAGS} --dry-run"
fi
if [ "\${YES}" = "true" ]; then
FLAGS="\${FLAGS} --yes"
fi
echo "════════════════════════════════════════"
echo " USER_ID=\${USER_ID}"
echo " DRY_RUN=\${DRY_RUN}"
echo " YES=\${YES}"
echo " FLAGS=\${FLAGS}"
echo "════════════════════════════════════════"
# Le service "backend" charge .env via env_file et l'entrypoint
# fait `exec "\$@"` si on passe des args. DATABASE_URL est résolu
# vers le hostname docker "postgres:5432" via la variable d'env.
docker compose run --rm backend \
python scripts/delete_duplicate_glossaries.py \${FLAGS}
ENDSSH
- name: List backup artifacts
if: always()
run: |
ssh root@192.168.1.151 'ls -la /opt/wordly/backups/ 2>/dev/null || echo "(no backups dir)"'