#!/bin/bash ## # Care API - Coverage Reports Generator # # Gera relatórios de cobertura de código completos com análise de qualidade # # @package Care_API # @author Descomplicar® Crescimento Digital # @version 1.0.0 # @since 2025-09-14 ## set -euo pipefail # Configurações readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly PROJECT_DIR="$(dirname "$SCRIPT_DIR")" readonly COVERAGE_DIR="$PROJECT_DIR/coverage-reports" readonly HTML_DIR="$PROJECT_DIR/coverage-html" readonly MERGED_DIR="$PROJECT_DIR/coverage-merged" # Cores para output readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly NC='\033[0m' # No Color # Função para log colorido log() { local level="$1" shift local message="$*" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') case "$level" in "INFO") echo -e "${GREEN}[INFO]${NC} [$timestamp] $message" ;; "WARN") echo -e "${YELLOW}[WARN]${NC} [$timestamp] $message" ;; "ERROR") echo -e "${RED}[ERROR]${NC} [$timestamp] $message" >&2 ;; "DEBUG") echo -e "${BLUE}[DEBUG]${NC} [$timestamp] $message" ;; esac } # Função para verificar pré-requisitos check_prerequisites() { log "INFO" "Verificando pré-requisitos..." # PHP com extensão coverage if ! php -m | grep -q -E "(xdebug|pcov)"; then log "WARN" "Nenhuma extensão de coverage detectada (Xdebug/PCOV)" log "INFO" "Tentando instalar PCOV automaticamente..." # Instalar PCOV se possível if command -v pecl >/dev/null 2>&1; then pecl install pcov || log "WARN" "Falha ao instalar PCOV automaticamente" fi if ! php -m | grep -q -E "(xdebug|pcov)"; then log "ERROR" "Coverage não disponível. Instale Xdebug ou PCOV:" log "ERROR" " sudo apt-get install php-xdebug" log "ERROR" " ou: pecl install pcov" exit 1 fi fi # PHPUnit if ! command -v phpunit >/dev/null 2>&1; then log "ERROR" "PHPUnit não encontrado" exit 1 fi log "INFO" "Pré-requisitos verificados com sucesso" } # Função para limpar relatórios antigos cleanup_old_reports() { log "INFO" "Limpando relatórios antigos..." local dirs_to_clean=("$COVERAGE_DIR" "$HTML_DIR" "$MERGED_DIR") for dir in "${dirs_to_clean[@]}"; do if [[ -d "$dir" ]]; then rm -rf "$dir" log "DEBUG" "Removido: $dir" fi done # Criar directórios mkdir -p "$COVERAGE_DIR" "$HTML_DIR" "$MERGED_DIR" log "INFO" "Limpeza concluída" } # Função para gerar coverage por test suite generate_suite_coverage() { local suite_name="$1" local suite_key="$2" local output_dir="$COVERAGE_DIR/$suite_key" log "INFO" "Gerando coverage para: $suite_name" mkdir -p "$output_dir" # Executar testes com coverage phpunit \ --testsuite="$suite_name" \ --coverage-html "$output_dir/html" \ --coverage-clover "$output_dir/clover.xml" \ --coverage-php "$output_dir/coverage.php" \ --coverage-text > "$output_dir/coverage.txt" 2>&1 || { log "WARN" "Possíveis falhas em $suite_name - coverage gerado parcialmente" } log "INFO" "Coverage gerado para $suite_name: $output_dir" } # Função para gerar coverage completo generate_full_coverage() { log "INFO" "Gerando coverage completo..." phpunit \ --coverage-html "$HTML_DIR" \ --coverage-clover "$COVERAGE_DIR/clover.xml" \ --coverage-crap4j "$COVERAGE_DIR/crap4j.xml" \ --coverage-php "$COVERAGE_DIR/coverage.php" \ --coverage-xml "$COVERAGE_DIR/xml" \ --coverage-text > "$COVERAGE_DIR/coverage-full.txt" 2>&1 || { log "WARN" "Alguns testes falharam - coverage gerado parcialmente" } log "INFO" "Coverage completo gerado" } # Função para gerar métricas de código generate_code_metrics() { log "INFO" "Gerando métricas de código..." local metrics_dir="$COVERAGE_DIR/metrics" mkdir -p "$metrics_dir" # PHPLOC - Métricas de linhas de código if command -v phploc >/dev/null 2>&1; then phploc --log-xml "$metrics_dir/phploc.xml" "$PROJECT_DIR/src" > "$metrics_dir/phploc.txt" 2>&1 || { log "WARN" "PHPLOC falhou" } fi # PHPCPD - Detector de código duplicado if command -v phpcpd >/dev/null 2>&1; then phpcpd --log-pmd "$metrics_dir/phpcpd.xml" "$PROJECT_DIR/src" > "$metrics_dir/phpcpd.txt" 2>&1 || { log "WARN" "PHPCPD falhou" } fi log "INFO" "Métricas de código geradas" } # Função para gerar relatório dashboard generate_dashboard() { log "INFO" "Gerando dashboard de coverage..." local dashboard_file="$PROJECT_DIR/coverage-dashboard.html" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') cat > "$dashboard_file" << 'EOF' Care API - Coverage Dashboard

🏥 Care API - Coverage Dashboard

Relatório de Cobertura de Código Gerado em TIMESTAMP_PLACEHOLDER

📊 Resumo de Cobertura

Cobertura Global --%
Classes Cobertas --
Métodos Cobertos --
Linhas Cobertas --

🧪 Suites de Teste

Testes Unitários --%
Testes Integração --%
Testes Contrato --%
Testes Performance --%

📈 Métricas de Qualidade

Complexidade CRAP --
Código Duplicado --%
Linhas de Código --
Densidade Comentários --%

🔗 Relatórios Detalhados

EOF # Substituir timestamp sed -i "s/TIMESTAMP_PLACEHOLDER/$timestamp/g" "$dashboard_file" log "INFO" "Dashboard gerado: $dashboard_file" } # Função para extrair métricas do coverage extract_coverage_metrics() { log "INFO" "Extraindo métricas de coverage..." local summary_file="$COVERAGE_DIR/coverage-summary.json" # Verificar se clover.xml existe if [[ -f "$COVERAGE_DIR/clover.xml" ]]; then # Extrair métricas do XML usando PHP php << 'PHP_SCRIPT' > "$summary_file" 'Clover file not found']); exit(1); } $xml = simplexml_load_file($cloverFile); if ($xml === false) { echo json_encode(['error' => 'Invalid XML file']); exit(1); } $metrics = [ 'timestamp' => date('Y-m-d H:i:s'), 'files' => (int) $xml->project->metrics['files'] ?? 0, 'classes' => (int) $xml->project->metrics['classes'] ?? 0, 'methods' => (int) $xml->project->metrics['methods'] ?? 0, 'coveredmethods' => (int) $xml->project->metrics['coveredmethods'] ?? 0, 'statements' => (int) $xml->project->metrics['statements'] ?? 0, 'coveredstatements' => (int) $xml->project->metrics['coveredstatements'] ?? 0, 'elements' => (int) $xml->project->metrics['elements'] ?? 0, 'coveredelements' => (int) $xml->project->metrics['coveredelements'] ?? 0 ]; // Calcular percentagens $metrics['method_coverage'] = $metrics['methods'] > 0 ? round(($metrics['coveredmethods'] / $metrics['methods']) * 100, 2) : 0; $metrics['statement_coverage'] = $metrics['statements'] > 0 ? round(($metrics['coveredstatements'] / $metrics['statements']) * 100, 2) : 0; $metrics['overall_coverage'] = $metrics['elements'] > 0 ? round(($metrics['coveredelements'] / $metrics['elements']) * 100, 2) : 0; echo json_encode($metrics, JSON_PRETTY_PRINT); ?> PHP_SCRIPT export COVERAGE_DIR log "INFO" "Métricas extraídas para: $summary_file" else log "WARN" "Arquivo clover.xml não encontrado - métricas não extraídas" fi } # Função principal main() { log "INFO" "🏥 Care API - Iniciando geração de coverage reports" cd "$PROJECT_DIR" # Verificar argumentos local mode="${1:-full}" case "$mode" in "clean") cleanup_old_reports log "INFO" "Limpeza concluída" exit 0 ;; "quick") log "INFO" "Modo rápido: apenas coverage HTML" cleanup_old_reports check_prerequisites generate_full_coverage ;; "suites") log "INFO" "Modo suites: coverage por test suite" cleanup_old_reports check_prerequisites generate_suite_coverage "KiviCare API Unit Tests" "unit" generate_suite_coverage "KiviCare API Integration Tests" "integration" generate_suite_coverage "KiviCare API Contract Tests" "contract" generate_suite_coverage "KiviCare API Performance Tests" "performance" ;; "full"|*) log "INFO" "Modo completo: todos os relatórios" cleanup_old_reports check_prerequisites generate_full_coverage generate_code_metrics extract_coverage_metrics generate_dashboard ;; esac log "INFO" "✅ Coverage reports gerados com sucesso!" # Mostrar localização dos relatórios echo "" log "INFO" "📊 Relatórios disponíveis:" [[ -f "$PROJECT_DIR/coverage-dashboard.html" ]] && log "INFO" " Dashboard: coverage-dashboard.html" [[ -d "$HTML_DIR" ]] && log "INFO" " HTML: coverage-html/index.html" [[ -f "$COVERAGE_DIR/coverage-full.txt" ]] && log "INFO" " Texto: coverage-reports/coverage-full.txt" [[ -f "$COVERAGE_DIR/clover.xml" ]] && log "INFO" " Clover: coverage-reports/clover.xml" echo "" log "INFO" "🚀 Para ver o dashboard execute: open coverage-dashboard.html" } # Executar se chamado directamente if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi