Comment j'ai industrialisé mon side-project avec Google Jules
Publié le
Temps de lecture 6 min
Dans la tech actuelle, on entend beaucoup parler de Vibe Coding: laisser l'IA générer du code au kilomètre tant que "ça passe", sans trop se soucier de la dette technique ou de la sécurité. Ce n'est pas mon approche.
Mon site est un laboratoire. J'y architecture du Symfony, je teste les dernières features de PHP. C'est un projet sérieux, mais c'est aussi un loisir. Cependant, j'ai une contrainte majeure : j'ai un travail à temps plein la journée. Je ne peux pas consacrer mes soirées à la maintenance, à traquer le respect des normes PSR, à mettre à jour des dépendances mineures ou à vérifier des régressions d'accessibilité.
C'est là qu'intervient https://jules.google.
Je ne l'ai pas configuré pour "coder à ma place", mais pour agir comme une équipe de support asynchrone. Jules s'occupe des tâches de fond (QA, sécurité, perf) pendant que je suis au bureau.
Mais pour qu'une IA puisse interagir avec une stack complexe (Docker, PostgreSQL, Redis, Meilisearch) sans compromettre l'intégrité du projet, un simple accès au dépôt ne suffit pas. Il faut lui fournir un environnement d'exécution. Sans cela, l'agent hallucine ou échoue.
Le défi : rendre l'IA compatible avec Docker
Les agents comme Jules tournent dans des environnements conteneurisés éphémères appelés « sandbox ». Si l'agent essaie de lancer php bin/phpunit, cela échouera immédiatement : pas de base de données, pas d'extensions PHP, pas de Redis.
J'ai donc écrit un script Bash qui configure l'environnement et sert de bootstrapper d'infrastructure. Il transforme l'environnement vide de l'agent en une réplique exacte de mon environnement de développement.
Sous le capot : analyse du script
Ce script est la première instruction que Jules exécute. Il prépare le terrain pour que mes agents spécialisés (Bolt, Sentinel et Palette) puissent travailler. Voici comment il fonctionne :
1. Détection dynamique du contexte (Working Directory)
Les environnements CI/CD ou les agents cloud ne clonent pas toujours le projet au même endroit (/app, /workspace, /home/runner...). Si le script ne s'adapte pas, les commandes Docker (notamment le montage de volumes) échouent.
# DETECT WORKING DIRECTORY
if [ -n "${BASH_SOURCE[0]:-}" ]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
elif [ -d "/app/.git" ]; then
PROJECT_DIR="/app" # Chemin standard Jules
elif [ -d "/workspace/.git" ]; then
PROJECT_DIR="/workspace"
else
PROJECT_DIR="$(pwd)"
fi
# Use absolute path to avoid OCI container issues
cd "$PROJECT_DIR"
Ce bloc garantit que le script trouve toujours la racine du projet, peu importe l'environnement cloud dans lequel il atterrit. L'utilisation de chemins absolus fiabilise les volumes Docker (-v $(pwd):/app).
Le "Hack" des permissions (Docker-in-Docker)
C'est souvent le point de friction des pipelines. L'utilisateur de l'agent n'a pas forcément les droits root ou l'accès au socket Docker de l'hôte.
# Fix Git ownership
git config --global --add safe.directory "$PROJECT_DIR"
git config --global --add safe.directory '*'
# Fix Docker socket permissions
if [ -S /var/run/docker.sock ]; then
sudo chmod 666 /var/run/docker.sock 2>/dev/null || true
fi
safe.directory: Règle l'erreur Git "dubious ownership" fréquente quand l'ID utilisateur du conteneur ne matche pas celui des fichiers.chmod 666 ...docker.sock: Permet au conteneur de l'agent de piloter le daemon Docker de la machine hôte. C'est ce qui permet à Jules de spawner mes services (Postgres, Redis) depuis son environnement.
De plus, le script détecte intelligemment s'il doit préfixer les commandes par sudo en testant l'accès à docker ps.
3. Build ciblé et résilient
Je ne lance pas l'image de production (trop lourde). Le script construit une image php-test dédiée, définie dans compose.test.yaml.
${USE_SUDO} docker compose -f compose.test.yaml build php-test || {
echo "⚠️ Test image build failed, trying with --no-cache..."
${USE_SUDO} docker compose -f compose.test.yaml build --no-cache php-test
}
Elle contient les outils d'analyse (PCOV pour la couverture, Xdebug) mais reste légère (Alpine). Si le build échoue (cache corrompu), le script force automatiquement une reconstruction --no-cache.
4. La stratégie de disponibilité (wait strategy)
C'est la partie la plus critique pour la stabilité. Lancer un conteneur PostgreSQL ne suffit pas : il faut attendre qu'il soit prêt à accepter des connexions TCP. Un simple sleep 10 est une mauvaise pratique (source de "flaky tests").
# Start database
${USE_SUDO} docker compose -f compose.test.yaml up -d database_test_service
# Boucle de vérification active
echo "🗄️ Checking PostgreSQL..."
for i in {1..10}; do
DB_CONTAINER=$(...) # Récupère l'ID du conteneur
if [ -n "$DB_CONTAINER" ]; then
# On demande à Postgres lui-même s'il est prêt (via docker exec)
${USE_SUDO} docker exec "$DB_CONTAINER" pg_isready -U app && break
fi
sleep 3
done
J'utilise pg_isready exécuté à l'intérieur du conteneur via docker exec. C'est la seule méthode déterministe pour garantir à 100% que la base est disponible avant de lancer les migrations.
5. L’abstraction via Makefile
Enfin, le script Bash gère l'infrastructure ("Hardware"), mais délègue la logique applicative ("Software") à un outil standardisé.
${USE_SUDO} make agent-db-test-reset
Cette commande make va :
- Supprimer la base de test existante.
- Jouer les migrations Doctrine.
- Charger les fixtures (jeux de données de test).
Résultat : une CI locale pilotée par IA
Une fois cette infrastructure en place, j'ai configuré Jules pour qu’il utilise des scripts inclus dans l’agent :
- Bolt (Performance) : Chasse les requêtes N+1 et les problèmes de cache.
- Sentinel (Sécurité) : Vérifie la sanitization des inputs et les secrets.
- Palette (UX/Design) : S'assure de l'accessibilité (ARIA) et des micro-interactions.
Grâce à tout ceci, Jules ne "devine" pas si le code fonctionne : il l'exécute. C'est ce qui transforme l'IA d'un simple générateur de texte en un véritable outil d'ingénierie, capable de s’occuper le maintenance de mon site en toute transparence.