- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
375 lines
14 KiB
Python
375 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Script de vérification du ZIP VWB propre
|
|
Auteur : Dom, Alice, Kiro - 8 janvier 2026
|
|
"""
|
|
|
|
import zipfile
|
|
import os
|
|
import json
|
|
import tempfile
|
|
import shutil
|
|
|
|
class VerificateurZipVWB:
|
|
"""Classe pour vérifier la qualité du ZIP VWB"""
|
|
|
|
def __init__(self, nom_zip):
|
|
self.nom_zip = nom_zip
|
|
self.dossier_temp = None
|
|
self.resultats = {}
|
|
|
|
def extraire_zip_temporaire(self):
|
|
"""Extraire le ZIP dans un dossier temporaire"""
|
|
self.dossier_temp = tempfile.mkdtemp(prefix="verif_vwb_")
|
|
|
|
with zipfile.ZipFile(self.nom_zip, 'r') as zipf:
|
|
zipf.extractall(self.dossier_temp)
|
|
|
|
print(f"📁 ZIP extrait dans: {self.dossier_temp}")
|
|
return True
|
|
|
|
def verifier_structure_generale(self):
|
|
"""Vérifier la structure générale du projet"""
|
|
print("🏗️ Vérification de la structure...")
|
|
|
|
dossiers_requis = [
|
|
"visual_workflow_builder",
|
|
"visual_workflow_builder/backend",
|
|
"visual_workflow_builder/frontend",
|
|
"visual_workflow_builder/backend/api",
|
|
"visual_workflow_builder/frontend/src",
|
|
"visual_workflow_builder/frontend/src/components",
|
|
]
|
|
|
|
fichiers_requis = [
|
|
"README.md",
|
|
"version.json",
|
|
"diagnostic_backend_complet.py",
|
|
"demarrer_backend_propre.py",
|
|
"test_systeme_complet.py",
|
|
"visual_workflow_builder/backend/app.py",
|
|
"visual_workflow_builder/frontend/package.json",
|
|
]
|
|
|
|
structure_ok = True
|
|
|
|
# Vérifier les dossiers
|
|
for dossier in dossiers_requis:
|
|
chemin = os.path.join(self.dossier_temp, dossier)
|
|
if os.path.exists(chemin):
|
|
print(f" ✅ Dossier: {dossier}")
|
|
else:
|
|
print(f" ❌ Dossier manquant: {dossier}")
|
|
structure_ok = False
|
|
|
|
# Vérifier les fichiers
|
|
for fichier in fichiers_requis:
|
|
chemin = os.path.join(self.dossier_temp, fichier)
|
|
if os.path.exists(chemin):
|
|
print(f" ✅ Fichier: {fichier}")
|
|
else:
|
|
print(f" ❌ Fichier manquant: {fichier}")
|
|
structure_ok = False
|
|
|
|
self.resultats['structure'] = structure_ok
|
|
return structure_ok
|
|
|
|
def verifier_conformite_attribution(self):
|
|
"""Vérifier la conformité de l'attribution"""
|
|
print("👥 Vérification de l'attribution...")
|
|
|
|
fichiers_python = []
|
|
fichiers_typescript = []
|
|
fichiers_css = []
|
|
|
|
# Parcourir tous les fichiers
|
|
for root, dirs, files in os.walk(self.dossier_temp):
|
|
for file in files:
|
|
chemin_complet = os.path.join(root, file)
|
|
extension = os.path.splitext(file)[1].lower()
|
|
|
|
if extension == '.py':
|
|
fichiers_python.append(chemin_complet)
|
|
elif extension in ['.ts', '.tsx']:
|
|
fichiers_typescript.append(chemin_complet)
|
|
elif extension == '.css':
|
|
fichiers_css.append(chemin_complet)
|
|
|
|
conformes = 0
|
|
total = 0
|
|
|
|
# Vérifier les fichiers Python
|
|
for fichier in fichiers_python:
|
|
total += 1
|
|
try:
|
|
with open(fichier, 'r', encoding='utf-8') as f:
|
|
contenu = f.read()
|
|
|
|
if ('Auteur : Dom, Alice, Kiro' in contenu or 'Auteur: Dom, Alice, Kiro' in contenu) and '8 janvier 2026' in contenu:
|
|
conformes += 1
|
|
print(f" ✅ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
else:
|
|
print(f" ❌ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
except:
|
|
print(f" ⚠️ Erreur lecture: {os.path.relpath(fichier, self.dossier_temp)}")
|
|
|
|
# Vérifier les fichiers TypeScript
|
|
for fichier in fichiers_typescript:
|
|
total += 1
|
|
try:
|
|
with open(fichier, 'r', encoding='utf-8') as f:
|
|
contenu = f.read()
|
|
|
|
if 'Auteur : Dom, Alice, Kiro' in contenu and '8 janvier 2026' in contenu:
|
|
conformes += 1
|
|
print(f" ✅ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
else:
|
|
print(f" ❌ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
except:
|
|
print(f" ⚠️ Erreur lecture: {os.path.relpath(fichier, self.dossier_temp)}")
|
|
|
|
# Vérifier les fichiers CSS
|
|
for fichier in fichiers_css:
|
|
total += 1
|
|
try:
|
|
with open(fichier, 'r', encoding='utf-8') as f:
|
|
contenu = f.read()
|
|
|
|
if 'Auteur : Dom, Alice, Kiro' in contenu and '8 janvier 2026' in contenu:
|
|
conformes += 1
|
|
print(f" ✅ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
else:
|
|
print(f" ❌ {os.path.relpath(fichier, self.dossier_temp)}")
|
|
except:
|
|
print(f" ⚠️ Erreur lecture: {os.path.relpath(fichier, self.dossier_temp)}")
|
|
|
|
taux_conformite = (conformes / total) * 100 if total > 0 else 100
|
|
print(f" 📊 Conformité attribution: {conformes}/{total} ({taux_conformite:.1f}%)")
|
|
|
|
self.resultats['attribution'] = taux_conformite >= 80
|
|
return taux_conformite >= 80
|
|
|
|
def verifier_version_info(self):
|
|
"""Vérifier les informations de version"""
|
|
print("📋 Vérification des informations de version...")
|
|
|
|
chemin_version = os.path.join(self.dossier_temp, "version.json")
|
|
|
|
if not os.path.exists(chemin_version):
|
|
print(" ❌ Fichier version.json manquant")
|
|
self.resultats['version'] = False
|
|
return False
|
|
|
|
try:
|
|
with open(chemin_version, 'r', encoding='utf-8') as f:
|
|
version_data = json.load(f)
|
|
|
|
champs_requis = ['version', 'date_creation', 'auteurs', 'description', 'conformite']
|
|
|
|
for champ in champs_requis:
|
|
if champ in version_data:
|
|
print(f" ✅ {champ}: {version_data[champ]}")
|
|
else:
|
|
print(f" ❌ Champ manquant: {champ}")
|
|
self.resultats['version'] = False
|
|
return False
|
|
|
|
# Vérifier la conformité
|
|
conformite = version_data.get('conformite', {})
|
|
if conformite.get('langue') == 'français' and conformite.get('tests_reels') == True:
|
|
print(" ✅ Conformité française validée")
|
|
self.resultats['version'] = True
|
|
return True
|
|
else:
|
|
print(" ❌ Conformité française non validée")
|
|
self.resultats['version'] = False
|
|
return False
|
|
|
|
except json.JSONDecodeError as e:
|
|
print(f" ❌ Erreur JSON: {e}")
|
|
self.resultats['version'] = False
|
|
return False
|
|
|
|
def verifier_readme(self):
|
|
"""Vérifier le README principal"""
|
|
print("📄 Vérification du README...")
|
|
|
|
chemin_readme = os.path.join(self.dossier_temp, "README.md")
|
|
|
|
if not os.path.exists(chemin_readme):
|
|
print(" ❌ README.md manquant")
|
|
self.resultats['readme'] = False
|
|
return False
|
|
|
|
try:
|
|
with open(chemin_readme, 'r', encoding='utf-8') as f:
|
|
contenu = f.read()
|
|
|
|
elements_requis = [
|
|
"Visual Workflow Builder",
|
|
"Auteur : Dom, Alice, Kiro",
|
|
"8 janvier 2026",
|
|
"Démarrage rapide",
|
|
"Backend",
|
|
"Frontend",
|
|
"Tests",
|
|
]
|
|
|
|
elements_presents = 0
|
|
for element in elements_requis:
|
|
if element in contenu:
|
|
elements_presents += 1
|
|
print(f" ✅ {element}")
|
|
else:
|
|
print(f" ❌ Manquant: {element}")
|
|
|
|
taux_completude = (elements_presents / len(elements_requis)) * 100
|
|
print(f" 📊 Complétude README: {elements_presents}/{len(elements_requis)} ({taux_completude:.1f}%)")
|
|
|
|
self.resultats['readme'] = taux_completude >= 80
|
|
return taux_completude >= 80
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Erreur lecture README: {e}")
|
|
self.resultats['readme'] = False
|
|
return False
|
|
|
|
def compter_fichiers_par_type(self):
|
|
"""Compter les fichiers par type"""
|
|
print("📊 Statistiques des fichiers...")
|
|
|
|
compteurs = {
|
|
'python': 0,
|
|
'typescript': 0,
|
|
'css': 0,
|
|
'json': 0,
|
|
'markdown': 0,
|
|
'autres': 0
|
|
}
|
|
|
|
for root, dirs, files in os.walk(self.dossier_temp):
|
|
for file in files:
|
|
extension = os.path.splitext(file)[1].lower()
|
|
|
|
if extension == '.py':
|
|
compteurs['python'] += 1
|
|
elif extension in ['.ts', '.tsx']:
|
|
compteurs['typescript'] += 1
|
|
elif extension == '.css':
|
|
compteurs['css'] += 1
|
|
elif extension == '.json':
|
|
compteurs['json'] += 1
|
|
elif extension == '.md':
|
|
compteurs['markdown'] += 1
|
|
else:
|
|
compteurs['autres'] += 1
|
|
|
|
total = sum(compteurs.values())
|
|
|
|
for type_fichier, count in compteurs.items():
|
|
pourcentage = (count / total) * 100 if total > 0 else 0
|
|
print(f" 📁 {type_fichier.capitalize()}: {count} fichiers ({pourcentage:.1f}%)")
|
|
|
|
print(f" 📈 Total: {total} fichiers")
|
|
return compteurs
|
|
|
|
def generer_rapport_final(self):
|
|
"""Générer le rapport final de vérification"""
|
|
print("\n" + "=" * 60)
|
|
print("📊 RAPPORT DE VÉRIFICATION DU ZIP VWB")
|
|
print("=" * 60)
|
|
|
|
tests_reussis = sum(1 for resultat in self.resultats.values() if resultat)
|
|
total_tests = len(self.resultats)
|
|
taux_reussite = (tests_reussis / total_tests) * 100 if total_tests > 0 else 0
|
|
|
|
print(f"📈 Résultats: {tests_reussis}/{total_tests} ({taux_reussite:.1f}%)")
|
|
print("\n📋 Détail des vérifications:")
|
|
|
|
for test, resultat in self.resultats.items():
|
|
icone = "✅" if resultat else "❌"
|
|
print(f" {icone} {test.replace('_', ' ').title()}")
|
|
|
|
# Déterminer la qualité
|
|
if taux_reussite == 100:
|
|
qualite = "🏆 EXCELLENTE - ZIP parfaitement conforme"
|
|
code_sortie = 0
|
|
elif taux_reussite >= 80:
|
|
qualite = "✅ BONNE - ZIP majoritairement conforme"
|
|
code_sortie = 0
|
|
elif taux_reussite >= 60:
|
|
qualite = "⚠️ ACCEPTABLE - Quelques améliorations nécessaires"
|
|
code_sortie = 1
|
|
else:
|
|
qualite = "❌ INSUFFISANTE - Corrections majeures requises"
|
|
code_sortie = 2
|
|
|
|
print(f"\n🎯 QUALITÉ GLOBALE: {qualite}")
|
|
|
|
# Informations sur le ZIP
|
|
taille_zip = os.path.getsize(self.nom_zip)
|
|
taille_mb = taille_zip / (1024 * 1024)
|
|
print(f"\n📦 Informations ZIP:")
|
|
print(f" 📁 Nom: {self.nom_zip}")
|
|
print(f" 📏 Taille: {taille_mb:.2f} MB")
|
|
|
|
return code_sortie
|
|
|
|
def nettoyer_dossier_temp(self):
|
|
"""Nettoyer le dossier temporaire"""
|
|
if self.dossier_temp and os.path.exists(self.dossier_temp):
|
|
shutil.rmtree(self.dossier_temp)
|
|
print(f"🧹 Dossier temporaire supprimé")
|
|
|
|
def executer_verification_complete(self):
|
|
"""Exécuter la vérification complète"""
|
|
print("🔍 VÉRIFICATION COMPLÈTE DU ZIP VWB")
|
|
print("=" * 50)
|
|
|
|
if not os.path.exists(self.nom_zip):
|
|
print(f"❌ Fichier ZIP introuvable: {self.nom_zip}")
|
|
return 1
|
|
|
|
try:
|
|
# Extraire le ZIP
|
|
self.extraire_zip_temporaire()
|
|
|
|
# Exécuter les vérifications
|
|
self.verifier_structure_generale()
|
|
self.verifier_conformite_attribution()
|
|
self.verifier_version_info()
|
|
self.verifier_readme()
|
|
self.compter_fichiers_par_type()
|
|
|
|
# Générer le rapport
|
|
code_sortie = self.generer_rapport_final()
|
|
|
|
return code_sortie
|
|
|
|
except Exception as e:
|
|
print(f"💥 Erreur critique: {e}")
|
|
return 3
|
|
finally:
|
|
self.nettoyer_dossier_temp()
|
|
|
|
def main():
|
|
"""Fonction principale"""
|
|
import sys
|
|
|
|
if len(sys.argv) != 2:
|
|
print("Usage: python3 verifier_zip_vwb.py <nom_du_zip>")
|
|
return 1
|
|
|
|
nom_zip = sys.argv[1]
|
|
verificateur = VerificateurZipVWB(nom_zip)
|
|
|
|
try:
|
|
return verificateur.executer_verification_complete()
|
|
except KeyboardInterrupt:
|
|
print("\n⚠️ Vérification interrompue")
|
|
verificateur.nettoyer_dossier_temp()
|
|
return 2
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
sys.exit(main()) |