425 lines
11 KiB
Bash
425 lines
11 KiB
Bash
#!/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!"
|