veza/dev-environment/tools/generators/generate-feature.sh

426 lines
11 KiB
Bash
Raw Normal View History

#!/bin/bash
# 🎯 GÉNÉRATEUR DE FEATURE - VEZA
# Script pour générer une nouvelle feature complète
set -e
# Couleurs
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Fonction pour afficher les messages
log_info() {
echo -e "${BLUE} $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
# Vérification des arguments
if [ $# -eq 0 ]; then
echo "Usage: $0 <feature-name>"
echo "Exemple: $0 user-authentication"
exit 1
fi
FEATURE_NAME=$1
FEATURE_DIR="features/feature-$(date +%Y%m%d)-${FEATURE_NAME}"
log_info "Génération de la feature: $FEATURE_NAME"
# Création de la structure de la feature
mkdir -p "$FEATURE_DIR"/{backend,frontend,mobile,tests,docs}
log_success "Structure de répertoires créée"
# Génération du backend (Go)
log_info "Génération du code backend..."
cat > "$FEATURE_DIR/backend/${FEATURE_NAME}_service.go" << 'GOEOF'
package main
import (
"context"
"fmt"
"time"
)
// ${FEATURE_NAME^}Service gère les fonctionnalités de ${FEATURE_NAME}
type ${FEATURE_NAME^}Service struct {
// Ajoutez vos dépendances ici
}
// New${FEATURE_NAME^}Service crée une nouvelle instance du service
func New${FEATURE_NAME^}Service() *${FEATURE_NAME^}Service {
return &${FEATURE_NAME^}Service{}
}
// Exemple de méthode - remplacez par vos méthodes
func (s *${FEATURE_NAME^}Service) Process${FEATURE_NAME^}(ctx context.Context, input string) (string, error) {
// Implémentation de votre logique métier
return fmt.Sprintf("Processed: %s", input), nil
}
// Health check pour le service
func (s *${FEATURE_NAME^}Service) HealthCheck() error {
// Implémentation du health check
return nil
}
GOEOF
cat > "$FEATURE_DIR/backend/${FEATURE_NAME}_handler.go" << 'GOEOF'
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// ${FEATURE_NAME^}Handler gère les endpoints HTTP pour ${FEATURE_NAME}
type ${FEATURE_NAME^}Handler struct {
service *${FEATURE_NAME^}Service
}
// New${FEATURE_NAME^}Handler crée un nouveau handler
func New${FEATURE_NAME^}Handler(service *${FEATURE_NAME^}Service) *${FEATURE_NAME^}Handler {
return &${FEATURE_NAME^}Handler{
service: service,
}
}
// SetupRoutes configure les routes pour cette feature
func (h *${FEATURE_NAME^}Handler) SetupRoutes(r *gin.RouterGroup) {
r.GET("/${FEATURE_NAME}", h.Get${FEATURE_NAME^})
r.POST("/${FEATURE_NAME}", h.Create${FEATURE_NAME^})
r.PUT("/${FEATURE_NAME}/:id", h.Update${FEATURE_NAME^})
r.DELETE("/${FEATURE_NAME}/:id", h.Delete${FEATURE_NAME^})
}
// Get${FEATURE_NAME^} récupère les données de ${FEATURE_NAME}
func (h *${FEATURE_NAME^}Handler) Get${FEATURE_NAME^}(c *gin.Context) {
// Implémentation
c.JSON(http.StatusOK, gin.H{"message": "Get ${FEATURE_NAME} endpoint"})
}
// Create${FEATURE_NAME^} crée une nouvelle entrée
func (h *${FEATURE_NAME^}Handler) Create${FEATURE_NAME^}(c *gin.Context) {
// Implémentation
c.JSON(http.StatusCreated, gin.H{"message": "Create ${FEATURE_NAME} endpoint"})
}
// Update${FEATURE_NAME^} met à jour une entrée existante
func (h *${FEATURE_NAME^}Handler) Update${FEATURE_NAME^}(c *gin.Context) {
// Implémentation
c.JSON(http.StatusOK, gin.H{"message": "Update ${FEATURE_NAME} endpoint"})
}
// Delete${FEATURE_NAME^} supprime une entrée
func (h *${FEATURE_NAME^}Handler) Delete${FEATURE_NAME^}(c *gin.Context) {
// Implémentation
c.JSON(http.StatusOK, gin.H{"message": "Delete ${FEATURE_NAME} endpoint"})
}
GOEOF
log_success "Code backend généré"
# Génération du frontend (React)
log_info "Génération du code frontend..."
cat > "$FEATURE_DIR/frontend/${FEATURE_NAME^}Page.tsx" << 'REACTEOF'
import React, { useState, useEffect } from 'react';
import { Card, Button, Input, Modal } from '../components/DesignSystem';
interface ${FEATURE_NAME^}Data {
id: string;
name: string;
// Ajoutez vos propriétés ici
}
const ${FEATURE_NAME^}Page: React.FC = () => {
const [data, setData] = useState<${FEATURE_NAME^}Data[]>([]);
const [loading, setLoading] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
useEffect(() => {
fetch${FEATURE_NAME^}Data();
}, []);
const fetch${FEATURE_NAME^}Data = async () => {
setLoading(true);
try {
// Implémentation de la récupération des données
const response = await fetch('/api/${FEATURE_NAME}');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Erreur lors de la récupération des données:', error);
} finally {
setLoading(false);
}
};
const handleCreate = async (formData: any) => {
try {
// Implémentation de la création
const response = await fetch('/api/${FEATURE_NAME}', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (response.ok) {
fetch${FEATURE_NAME^}Data();
setIsModalOpen(false);
}
} catch (error) {
console.error('Erreur lors de la création:', error);
}
};
return (
<div className="p-6">
<div className="flex justify-between items-center mb-6">
<h1 className="text-3xl font-bold text-white">${FEATURE_NAME^}</h1>
<Button onClick={() => setIsModalOpen(true)}>
Créer ${FEATURE_NAME^}
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{data.map((item) => (
<Card key={item.id} className="p-4">
<h3 className="text-lg font-semibold text-white">{item.name}</h3>
{/* Ajoutez vos éléments d'affichage ici */}
</Card>
))}
</div>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="Créer ${FEATURE_NAME^}"
>
{/* Ajoutez votre formulaire ici */}
<form onSubmit={(e) => {
e.preventDefault();
// Implémentation de la soumission
}}>
<Input
type="text"
placeholder="Nom"
required
/>
<Button type="submit" className="mt-4">
Créer
</Button>
</form>
</Modal>
</div>
);
};
export default ${FEATURE_NAME^}Page;
REACTEOF
log_success "Code frontend généré"
# Génération des tests
log_info "Génération des tests..."
cat > "$FEATURE_DIR/tests/${FEATURE_NAME}_test.go" << 'TESTEOF'
package main
import (
"testing"
"context"
"github.com/stretchr/testify/assert"
)
func Test${FEATURE_NAME^}Service(t *testing.T) {
service := New${FEATURE_NAME^}Service()
t.Run("should process ${FEATURE_NAME} successfully", func(t *testing.T) {
ctx := context.Background()
input := "test input"
result, err := service.Process${FEATURE_NAME^}(ctx, input)
assert.NoError(t, err)
assert.Contains(t, result, input)
})
t.Run("should pass health check", func(t *testing.T) {
err := service.HealthCheck()
assert.NoError(t, err)
})
}
TESTEOF
cat > "$FEATURE_DIR/tests/${FEATURE_NAME}_integration_test.go" << 'INTEGEOF'
package main
import (
"testing"
"net/http"
"net/http/httptest"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func Test${FEATURE_NAME^}Endpoints(t *testing.T) {
gin.SetMode(gin.TestMode)
service := New${FEATURE_NAME^}Service()
handler := New${FEATURE_NAME^}Handler(service)
router := gin.New()
handler.SetupRoutes(router.Group("/api"))
t.Run("GET /api/${FEATURE_NAME}", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/${FEATURE_NAME}", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
})
t.Run("POST /api/${FEATURE_NAME}", func(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/${FEATURE_NAME}", nil)
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
})
}
INTEGEOF
log_success "Tests générés"
# Génération de la documentation
log_info "Génération de la documentation..."
cat > "$FEATURE_DIR/docs/README.md" << 'DOCEOF'
# ${FEATURE_NAME^} Feature
## Description
Cette feature implémente la fonctionnalité de ${FEATURE_NAME}.
## Composants
### Backend
- `${FEATURE_NAME}_service.go` - Service principal
- `${FEATURE_NAME}_handler.go` - Handlers HTTP
### Frontend
- `${FEATURE_NAME^}Page.tsx` - Page React
### Tests
- `${FEATURE_NAME}_test.go` - Tests unitaires
- `${FEATURE_NAME}_integration_test.go` - Tests d'intégration
## API Endpoints
### GET /api/${FEATURE_NAME}
Récupère la liste des ${FEATURE_NAME}.
### POST /api/${FEATURE_NAME}
Crée une nouvelle entrée ${FEATURE_NAME}.
### PUT /api/${FEATURE_NAME}/:id
Met à jour une entrée ${FEATURE_NAME} existante.
### DELETE /api/${FEATURE_NAME}/:id
Supprime une entrée ${FEATURE_NAME}.
## Utilisation
1. Implémentez la logique métier dans le service
2. Ajoutez les validations nécessaires
3. Implémentez les tests
4. Intégrez dans l'application principale
## Tests
```bash
# Tests unitaires
go test ./features/feature-$(date +%Y%m%d)-${FEATURE_NAME}/tests/
# Tests d'intégration
go test -tags=integration ./features/feature-$(date +%Y%m%d)-${FEATURE_NAME}/tests/
```
DOCEOF
log_success "Documentation générée"
# Génération du fichier de configuration
cat > "$FEATURE_DIR/feature-config.yaml" << 'CONFIGEOF'
feature:
name: ${FEATURE_NAME}
version: 1.0.0
description: "Feature ${FEATURE_NAME} implementation"
components:
backend:
service: true
handler: true
repository: false
middleware: false
frontend:
page: true
component: false
hook: false
mobile:
screen: false
component: false
tests:
unit: true
integration: true
e2e: false
docs:
readme: true
api: true
user_guide: false
dependencies:
backend:
- gin
- context
frontend:
- react
- typescript
mobile:
- react-native
- expo
CONFIGEOF
log_success "Configuration générée"
# Résumé
echo -e "${GREEN}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ FEATURE GÉNÉRÉE AVEC SUCCÈS ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo -e "${BLUE}📁 Feature créée dans: $FEATURE_DIR${NC}"
echo -e "${BLUE}📋 Prochaines étapes:${NC}"
echo "1. Implémentez la logique métier dans les services"
echo "2. Ajoutez les validations et la gestion d'erreurs"
echo "3. Implémentez les tests"
echo "4. Intégrez dans l'application principale"
echo "5. Mettez à jour la documentation"
log_success "Feature $FEATURE_NAME générée avec succès!"