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
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:
87
.gitea/workflows/cleanup-glossaries.yml
Normal file
87
.gitea/workflows/cleanup-glossaries.yml
Normal 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)"'
|
||||
Reference in New Issue
Block a user