V0.1 de la migration vers systemd
This commit is contained in:
parent
b23c0dde53
commit
016ac85bc7
9 changed files with 142 additions and 24 deletions
17
README.md
17
README.md
|
|
@ -61,6 +61,9 @@ Kuby est un bot Discord complet développé en Python avec `discord.py`. Il offr
|
|||
|
||||
### Prérequis
|
||||
|
||||
- systemd installé sur la machine cible
|
||||
- utilisateur `discord` existant (ou adapter `User=` dans les fichiers de service)
|
||||
|
||||
- Python 3.10 ou supérieur
|
||||
- pip (gestionnaire de paquets Python)
|
||||
|
||||
|
|
@ -86,6 +89,20 @@ source venv/bin/activate # Linux/Mac
|
|||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 4. Installer les services systemd
|
||||
|
||||
```bash
|
||||
sudo chmod +x scripts/*.sh
|
||||
sudo ./scripts/install_systemd_services.sh
|
||||
```
|
||||
|
||||
### 5. Vérifier les services
|
||||
|
||||
```bash
|
||||
sudo systemctl status kuby-bot.service kuby-flask.service
|
||||
sudo journalctl -u kuby-bot.service -f
|
||||
```
|
||||
|
||||
Les dépendances incluent :
|
||||
- `discord.py>=2.3.0` - Framework Discord
|
||||
- `python-dotenv>=1.0.0` - Variables d'environnement
|
||||
|
|
|
|||
2
bot.py
2
bot.py
|
|
@ -102,7 +102,7 @@ class MyBot(commands.Bot):
|
|||
self.advanced_logger = AdvancedLogger(self)
|
||||
kuby_logger.info("✅ Advanced logger initialized")
|
||||
|
||||
# Flask est géré par PM2 (kuby-flask), pas besoin de le lancer ici
|
||||
# Flask est géré par le service systemd kuby-flask, pas besoin de le lancer ici
|
||||
|
||||
async def do_async_setup(self):
|
||||
kuby_logger.info("🚀 Configuration initiale du bot Kuby...")
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ def classify_webhook_event(payload: Dict[str, Any]) -> Optional[str]:
|
|||
if "comment" in payload or payload.get("comment") or "comment" in action:
|
||||
return "note"
|
||||
|
||||
if payload.get("issue") or payload.get("object_attributes") or action in {"open", "reopen", "close", "closed", "updated", "created", "edited"}:
|
||||
if payload.get("issue") or payload.get("object_attributes") or action in {"open", "reopen", "close", "closed", "updated", "created", "edited", "label_updated", "label_added", "label_removed", "label_changed"}:
|
||||
return "issue"
|
||||
|
||||
return None
|
||||
|
|
@ -82,24 +82,47 @@ def normalize_labels(labels: Any) -> list[str]:
|
|||
|
||||
def extract_label_change(payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Extrait le changement de labels d’un payload d’issue."""
|
||||
changes = payload.get("changes") or {}
|
||||
labels_change = changes.get("labels") or changes.get("label")
|
||||
if not isinstance(labels_change, dict):
|
||||
action = str(payload.get("action") or payload.get("event") or "").lower()
|
||||
if not action.startswith("label"):
|
||||
return None
|
||||
|
||||
previous = normalize_labels(labels_change.get("previous"))
|
||||
current = normalize_labels(labels_change.get("current"))
|
||||
if not previous and not current:
|
||||
issue = payload.get("issue") or {}
|
||||
current_labels = normalize_labels(issue.get("labels") or payload.get("labels"))
|
||||
if not current_labels:
|
||||
return None
|
||||
|
||||
added = [label for label in current if label not in previous]
|
||||
removed = [label for label in previous if label not in current]
|
||||
if not added and not removed:
|
||||
return None
|
||||
label_payload = payload.get("label")
|
||||
label_name = None
|
||||
if isinstance(label_payload, dict):
|
||||
label_name = label_payload.get("name") or label_payload.get("title") or label_payload.get("label")
|
||||
elif isinstance(label_payload, str):
|
||||
label_name = label_payload
|
||||
|
||||
previous_labels = []
|
||||
if isinstance(payload.get("changes"), dict):
|
||||
prev = payload["changes"].get("labels") or payload["changes"].get("label")
|
||||
if isinstance(prev, dict):
|
||||
previous_labels = normalize_labels(prev.get("previous"))
|
||||
|
||||
if not previous_labels and issue.get("labels"):
|
||||
previous_labels = []
|
||||
|
||||
if action in {"label_removed", "label_deleted"}:
|
||||
return {
|
||||
"previous": previous_labels or ([label_name] if label_name else []),
|
||||
"current": current_labels,
|
||||
"added": [],
|
||||
"removed": [label_name] if label_name else [],
|
||||
}
|
||||
|
||||
added = [label for label in current_labels if label not in previous_labels]
|
||||
removed = [label for label in previous_labels if label not in current_labels]
|
||||
if not added and not removed and label_name:
|
||||
added = [label_name]
|
||||
|
||||
return {
|
||||
"previous": previous,
|
||||
"current": current,
|
||||
"previous": previous_labels,
|
||||
"current": current_labels,
|
||||
"added": added,
|
||||
"removed": removed,
|
||||
}
|
||||
|
|
|
|||
20
scripts/install_systemd_services.sh
Executable file
20
scripts/install_systemd_services.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Ce script doit être exécuté avec sudo." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p /var/log/kuby
|
||||
|
||||
for service in kuby-bot.service kuby-flask.service; do
|
||||
sed "s#__KUBY_DIR__#${ROOT_DIR}#g" "$ROOT_DIR/systemd/$service" > "/etc/systemd/system/$service"
|
||||
done
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now kuby-bot.service kuby-flask.service
|
||||
|
||||
echo "Services systemd installés et démarrés."
|
||||
16
scripts/run_kuby_bot.sh
Executable file
16
scripts/run_kuby_bot.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
export PYTHONUNBUFFERED=1
|
||||
|
||||
if [ -x "$ROOT_DIR/.venv/bin/python" ]; then
|
||||
exec "$ROOT_DIR/.venv/bin/python" "$ROOT_DIR/kuby.py"
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
exec python3 "$ROOT_DIR/kuby.py"
|
||||
else
|
||||
echo "python3 introuvable" >&2
|
||||
exit 1
|
||||
fi
|
||||
16
scripts/run_kuby_flask.sh
Executable file
16
scripts/run_kuby_flask.sh
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
export PYTHONUNBUFFERED=1
|
||||
|
||||
if [ -x "$ROOT_DIR/.venv/bin/python" ]; then
|
||||
exec "$ROOT_DIR/.venv/bin/python" "$ROOT_DIR/serveur_flask.py"
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
exec python3 "$ROOT_DIR/serveur_flask.py"
|
||||
else
|
||||
echo "python3 introuvable" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -17,9 +17,6 @@ PROCESS_NAME = "kuby"
|
|||
# webhook de logs Discord
|
||||
DISCORD_LOG_URL = "https://discord.com/api/webhooks/1482148910888652910/IA9CcOWtjGswbuxMaOu_6uaclv5zojZo4ttxtV6RYyZzJ9gW7BF7xp_Zv3oPIjYEuh8o"
|
||||
|
||||
# Chemin vers PM2
|
||||
PM2_BINARY = "/home/discord/.nvm/versions/node/v24.15.0/bin/pm2"
|
||||
|
||||
# Bot Local Proxy (Relai vers le Cog de ton bot)
|
||||
BOT_LOCAL_URL = "http://127.0.0.1:5001/bot_event"
|
||||
|
||||
|
|
@ -88,13 +85,8 @@ def run_mep_logic(author, commit_msg, branch="main"):
|
|||
if use_rsync:
|
||||
subprocess.run(["rsync", "-a", "--exclude=.git", "--exclude=venv", "--exclude=.venv", "--exclude=__pycache__", f"{target_path}/", f"{PROJECT_PATH}/"], check=True)
|
||||
|
||||
# 3. PM2 Restart
|
||||
subprocess.run(
|
||||
[PM2_BINARY, "restart", PROCESS_NAME],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
# 3. Redémarrage via systemd
|
||||
subprocess.run(["systemctl", "restart", "kuby-bot.service"], check=True, capture_output=True, text=True)
|
||||
|
||||
duration = (datetime.now() - start_time).total_seconds()
|
||||
msg = f"✅ **Déploiement réussi en {duration:.2f}s**\nLe bot est à jour sur Forgejo et redémarré."
|
||||
|
|
|
|||
17
systemd/kuby-bot.service
Normal file
17
systemd/kuby-bot.service
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[Unit]
|
||||
Description=Kuby Discord Bot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=discord
|
||||
WorkingDirectory=__KUBY_DIR__
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__KUBY_DIR__/scripts/run_kuby_bot.sh
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:/var/log/kuby/bot.log
|
||||
StandardError=append:/var/log/kuby/bot.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
17
systemd/kuby-flask.service
Normal file
17
systemd/kuby-flask.service
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[Unit]
|
||||
Description=Kuby Flask webhook service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=discord
|
||||
WorkingDirectory=__KUBY_DIR__
|
||||
Environment=PYTHONUNBUFFERED=1
|
||||
ExecStart=__KUBY_DIR__/scripts/run_kuby_flask.sh
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:/var/log/kuby/flask.log
|
||||
StandardError=append:/var/log/kuby/flask.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Add table
Add a link
Reference in a new issue