testes/Modulos Angular/scripts/analyze-branch.sh

494 lines
18 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# 🔍 Branch Analyzer - Análise Completa de Branches e PRs
# Autor: Jonas Santos
# Versão: 1.0
# Data: Janeiro 2025
set -e
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
NC='\033[0m' # No Color
# Emojis
ROCKET="🚀"
CHECK="✅"
WARNING="⚠️"
INFO=""
FIRE="🔥"
EYES="👀"
CHART="📊"
FILES="📁"
COMMIT="💻"
MERGE="🔀"
TEST="🧪"
SECURITY="🔒"
PERFORMANCE="⚡"
DOCS="📚"
# Função para exibir cabeçalho
print_header() {
echo -e "${WHITE}================================================================${NC}"
echo -e "${CYAN}${ROCKET} BRANCH ANALYZER - Análise Completa de Branch/PR${NC}"
echo -e "${WHITE}================================================================${NC}"
}
# Função para exibir seção
print_section() {
echo ""
echo -e "${YELLOW}$1${NC}"
echo -e "${WHITE}$(printf '%.0s-' {1..50})${NC}"
}
# Função para exibir erro e sair
error_exit() {
echo -e "${RED}❌ Erro: $1${NC}" >&2
exit 1
}
# Função para verificar se é um repositório git
check_git_repo() {
if ! git rev-parse --git-dir > /dev/null 2>&1; then
error_exit "Este diretório não é um repositório Git."
fi
}
# Função para verificar se a branch existe
check_branch_exists() {
local branch=$1
if ! git show-ref --verify --quiet refs/remotes/origin/$branch; then
if ! git show-ref --verify --quiet refs/heads/$branch; then
error_exit "Branch '$branch' não encontrada localmente nem no remoto."
fi
fi
}
# Função para obter informações básicas da branch
get_branch_info() {
local branch=$1
local base_branch=${2:-main}
print_section "${INFO} INFORMAÇÕES BÁSICAS"
# Último commit
local last_commit=$(git log --format="%H" -n 1 origin/$branch 2>/dev/null || git log --format="%H" -n 1 $branch)
local last_commit_short=$(git log --format="%h" -n 1 origin/$branch 2>/dev/null || git log --format="%h" -n 1 $branch)
local author=$(git log --format="%an" -n 1 $last_commit)
local date=$(git log --format="%ad" --date=format:'%d/%m/%Y %H:%M' -n 1 $last_commit)
local message=$(git log --format="%s" -n 1 $last_commit)
echo -e "${CHECK} ${GREEN}Branch:${NC} $branch"
echo -e "${CHECK} ${GREEN}Último commit:${NC} $last_commit_short"
echo -e "${CHECK} ${GREEN}Autor:${NC} $author"
echo -e "${CHECK} ${GREEN}Data:${NC} $date"
echo -e "${CHECK} ${GREEN}Mensagem:${NC} $message"
# Status da branch
local ahead_behind=$(git rev-list --left-right --count origin/$base_branch...origin/$branch 2>/dev/null || echo "0 0")
local behind=$(echo $ahead_behind | cut -f1)
local ahead=$(echo $ahead_behind | cut -f2)
echo -e "${CHECK} ${GREEN}Commits à frente de $base_branch:${NC} $ahead"
echo -e "${CHECK} ${GREEN}Commits atrás de $base_branch:${NC} $behind"
if [ "$behind" -gt 0 ]; then
echo -e "${WARNING} ${YELLOW}Branch está desatualizada! Considere fazer rebase.${NC}"
fi
}
# Função para análise de commits
analyze_commits() {
local branch=$1
local base_branch=${2:-main}
print_section "${COMMIT} ANÁLISE DE COMMITS"
# Últimos commits da branch
echo -e "${EYES} ${BLUE}Últimos 10 commits:${NC}"
git log --oneline origin/$branch -10 2>/dev/null || git log --oneline $branch -10
# Commits únicos da branch
local unique_commits=$(git rev-list --count origin/$base_branch..origin/$branch 2>/dev/null || git rev-list --count $base_branch..$branch)
echo -e "\n${CHART} ${GREEN}Commits únicos nesta branch:${NC} $unique_commits"
if [ "$unique_commits" -gt 0 ]; then
echo -e "\n${EYES} ${BLUE}Commits únicos da branch:${NC}"
git log --oneline origin/$base_branch..origin/$branch 2>/dev/null || git log --oneline $base_branch..$branch
fi
}
# Função para análise de arquivos modificados
analyze_files() {
local branch=$1
local base_branch=${2:-main}
print_section "${FILES} ANÁLISE DE ARQUIVOS"
# Arquivos modificados
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null || git diff --name-only $base_branch $branch)
local total_files=$(echo "$modified_files" | wc -l)
if [ -z "$modified_files" ]; then
echo -e "${INFO} ${BLUE}Nenhum arquivo modificado encontrado.${NC}"
return
fi
echo -e "${CHART} ${GREEN}Total de arquivos modificados:${NC} $total_files"
echo ""
echo -e "${EYES} ${BLUE}Arquivos modificados:${NC}"
echo "$modified_files" | while read file; do
if [ -n "$file" ]; then
echo " 📄 $file"
fi
done
# Estatísticas detalhadas
echo ""
echo -e "${CHART} ${GREEN}Estatísticas de mudanças:${NC}"
git diff --stat origin/$base_branch origin/$branch 2>/dev/null || git diff --stat $base_branch $branch
}
# Função para análise de tipos de arquivo
analyze_file_types() {
local branch=$1
local base_branch=${2:-main}
print_section "${CHART} ANÁLISE POR TIPO DE ARQUIVO"
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null || git diff --name-only $base_branch $branch)
if [ -z "$modified_files" ]; then
return
fi
# Contar por extensão
echo -e "${EYES} ${BLUE}Distribuição por tipo:${NC}"
echo "$modified_files" | grep -E '\.' | sed 's/.*\.//' | sort | uniq -c | sort -nr | while read count ext; do
echo " 📋 .$ext: $count arquivo(s)"
done
# Arquivos críticos
echo ""
echo -e "${SECURITY} ${RED}Arquivos críticos detectados:${NC}"
local critical_found=false
echo "$modified_files" | while read file; do
if [ -n "$file" ]; then
case "$file" in
package.json|package-lock.json|yarn.lock)
echo " 🔴 $file (Dependências)"
critical_found=true
;;
*.config.js|*.config.ts|angular.json|tsconfig*.json)
echo " 🟡 $file (Configuração)"
critical_found=true
;;
*.env*|*secret*|*key*|*password*)
echo " 🔴 $file (Segurança - ATENÇÃO!)"
critical_found=true
;;
*test*|*spec*|*.test.ts|*.spec.ts)
echo " 🟢 $file (Testes)"
;;
*.md|docs/*|documentation/*)
echo " 📘 $file (Documentação)"
;;
esac
fi
done
}
# Função para análise de complexidade
analyze_complexity() {
local branch=$1
local base_branch=${2:-main}
print_section "${PERFORMANCE} ANÁLISE DE COMPLEXIDADE"
# Linhas adicionadas/removidas
local stats=$(git diff --numstat origin/$base_branch origin/$branch 2>/dev/null || git diff --numstat $base_branch $branch)
if [ -z "$stats" ]; then
echo -e "${INFO} ${BLUE}Nenhuma mudança detectada.${NC}"
return
fi
local total_added=0
local total_removed=0
local files_count=0
while read added removed file; do
if [ "$added" != "-" ] && [ "$removed" != "-" ]; then
total_added=$((total_added + added))
total_removed=$((total_removed + removed))
files_count=$((files_count + 1))
fi
done <<< "$stats"
echo -e "${CHART} ${GREEN}Linhas adicionadas:${NC} +$total_added"
echo -e "${CHART} ${RED}Linhas removidas:${NC} -$total_removed"
echo -e "${CHART} ${BLUE}Total de mudanças:${NC} $((total_added + total_removed))"
echo -e "${CHART} ${PURPLE}Arquivos afetados:${NC} $files_count"
# Classificação de complexidade
local total_changes=$((total_added + total_removed))
if [ $total_changes -lt 50 ]; then
echo -e "${CHECK} ${GREEN}Complexidade: BAIXA (< 50 linhas)${NC}"
elif [ $total_changes -lt 200 ]; then
echo -e "${WARNING} ${YELLOW}Complexidade: MÉDIA (50-200 linhas)${NC}"
elif [ $total_changes -lt 500 ]; then
echo -e "${WARNING} ${YELLOW}Complexidade: ALTA (200-500 linhas)${NC}"
else
echo -e "${FIRE} ${RED}Complexidade: MUITO ALTA (> 500 linhas)${NC}"
fi
# Arquivos com mais mudanças
echo ""
echo -e "${EYES} ${BLUE}Top 5 arquivos com mais mudanças:${NC}"
echo "$stats" | awk '$1 != "-" && $2 != "-" {print ($1+$2)" "$3}' | sort -nr | head -5 | while read changes file; do
echo " 📊 $file: $changes mudanças"
done
}
# Função para verificar conflitos potenciais
check_potential_conflicts() {
local branch=$1
local base_branch=${2:-main}
print_section "${MERGE} VERIFICAÇÃO DE CONFLITOS"
# Tentar fazer um merge dry-run
echo -e "${INFO} ${BLUE}Verificando possíveis conflitos...${NC}"
# Backup da branch atual
local current_branch=$(git branch --show-current)
# Criar uma branch temporária para teste
local temp_branch="temp-merge-test-$(date +%s)"
if git checkout -b $temp_branch origin/$base_branch >/dev/null 2>&1; then
if git merge --no-commit --no-ff origin/$branch >/dev/null 2>&1; then
echo -e "${CHECK} ${GREEN}Nenhum conflito detectado! Merge será limpo.${NC}"
git merge --abort >/dev/null 2>&1
else
echo -e "${WARNING} ${RED}Conflitos potenciais detectados!${NC}"
echo -e "${INFO} ${YELLOW}Arquivos com possíveis conflitos:${NC}"
git status --porcelain | grep "^UU\|^AA\|^DD" | while read status file; do
echo " ⚠️ $file"
done
git merge --abort >/dev/null 2>&1
fi
# Voltar para a branch original e limpar
git checkout $current_branch >/dev/null 2>&1
git branch -D $temp_branch >/dev/null 2>&1
else
echo -e "${WARNING} ${YELLOW}Não foi possível verificar conflitos automaticamente.${NC}"
fi
}
# Função para análise de testes
analyze_tests() {
local branch=$1
local base_branch=${2:-main}
print_section "${TEST} ANÁLISE DE TESTES"
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null || git diff --name-only $base_branch $branch)
if [ -z "$modified_files" ]; then
return
fi
# Arquivos de teste modificados
local test_files=$(echo "$modified_files" | grep -E "\.(test|spec)\.(ts|js)$" || true)
local test_count=$(echo "$test_files" | grep -v '^$' | wc -l || echo 0)
echo -e "${CHART} ${GREEN}Arquivos de teste modificados:${NC} $test_count"
if [ "$test_count" -gt 0 ]; then
echo -e "${EYES} ${BLUE}Testes afetados:${NC}"
echo "$test_files" | while read file; do
if [ -n "$file" ]; then
echo " 🧪 $file"
fi
done
fi
# Arquivos de código sem testes correspondentes
echo ""
echo -e "${WARNING} ${YELLOW}Verificando cobertura de testes:${NC}"
local code_files=$(echo "$modified_files" | grep -E "\.(ts|js)$" | grep -v -E "\.(test|spec|config|d)\.(ts|js)$" || true)
echo "$code_files" | while read file; do
if [ -n "$file" ]; then
local test_file1="${file%.ts}.spec.ts"
local test_file2="${file%.ts}.test.ts"
local test_file3="${file%.js}.spec.js"
local test_file4="${file%.js}.test.js"
if [ ! -f "$test_file1" ] && [ ! -f "$test_file2" ] && [ ! -f "$test_file3" ] && [ ! -f "$test_file4" ]; then
echo " ⚠️ $file (sem teste correspondente)"
fi
fi
done
}
# Função para sugestões de revisão
review_suggestions() {
local branch=$1
local base_branch=${2:-main}
print_section "${DOCS} SUGESTÕES PARA REVISÃO"
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null || git diff --name-only $base_branch $branch)
local total_changes=$(git diff --numstat origin/$base_branch origin/$branch 2>/dev/null | awk '{added+=$1; removed+=$2} END {print added+removed}' || echo 0)
echo -e "${EYES} ${BLUE}Pontos importantes para revisar:${NC}"
# Checklist baseado na análise
echo ""
echo -e "${CHECK} ${GREEN}CHECKLIST DE REVISÃO:${NC}"
echo " 📋 Verificar se os commits têm mensagens claras"
echo " 📋 Validar se as mudanças atendem aos requisitos"
echo " 📋 Revisar lógica de negócio implementada"
echo " 📋 Verificar padrões de código e nomenclatura"
echo " 📋 Validar tratamento de erros"
echo " 📋 Checar performance das mudanças"
if echo "$modified_files" | grep -q -E "\.(test|spec)\.(ts|js)$"; then
echo " 📋 Executar testes automatizados"
echo " 📋 Verificar cobertura de testes"
else
echo -e " ${WARNING} Considerar adicionar testes"
fi
if echo "$modified_files" | grep -q "package.json"; then
echo -e " ${WARNING} Revisar mudanças em dependências"
echo " 📋 Verificar compatibilidade de versões"
fi
if echo "$modified_files" | grep -q -E "\.config\.(ts|js)$|angular\.json"; then
echo -e " ${WARNING} Revisar mudanças de configuração"
echo " 📋 Testar em diferentes ambientes"
fi
if [ "$total_changes" -gt 300 ]; then
echo -e " ${WARNING} PR grande - considerar quebrar em partes menores"
echo " 📋 Revisar com mais cuidado devido ao tamanho"
fi
echo ""
echo -e "${PERFORMANCE} ${PURPLE}COMANDOS ÚTEIS PARA REVISÃO:${NC}"
echo " git checkout $branch"
echo " git diff origin/$base_branch..origin/$branch"
echo " git log origin/$base_branch..origin/$branch --oneline"
echo " npm test (para executar testes)"
echo " npm run build (para verificar build)"
}
# Função para gerar relatório resumido
generate_summary() {
local branch=$1
local base_branch=${2:-main}
print_section "${ROCKET} RESUMO EXECUTIVO"
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null || git diff --name-only $base_branch $branch)
local total_files=$(echo "$modified_files" | grep -v '^$' | wc -l || echo 0)
local total_commits=$(git rev-list --count origin/$base_branch..origin/$branch 2>/dev/null || git rev-list --count $base_branch..$branch)
local stats=$(git diff --numstat origin/$base_branch origin/$branch 2>/dev/null || git diff --numstat $base_branch $branch)
local total_added=$(echo "$stats" | awk '$1 != "-" {added+=$1} END {print added+0}')
local total_removed=$(echo "$stats" | awk '$2 != "-" {removed+=$2} END {print removed+0}')
local author=$(git log --format="%an" -n 1 origin/$branch 2>/dev/null || git log --format="%an" -n 1 $branch)
echo "┌─────────────────────────────────────────────────┐"
echo "│ RESUMO │"
echo "├─────────────────────────────────────────────────┤"
echo "│ Branch: $branch"
echo "│ Autor: $author"
echo "│ Base: $base_branch"
echo "│ Commits: $total_commits"
echo "│ Arquivos: $total_files"
echo "│ Linhas: +$total_added/-$total_removed"
echo "└─────────────────────────────────────────────────┘"
}
# Função principal
main() {
local branch_name=""
local base_branch="main"
local show_help=false
# Parse dos argumentos
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help=true
shift
;;
-b|--base)
base_branch="$2"
shift 2
;;
*)
if [ -z "$branch_name" ]; then
branch_name="$1"
fi
shift
;;
esac
done
# Mostrar ajuda
if [ "$show_help" = true ]; then
echo "🔍 Branch Analyzer - Análise Completa de Branches e PRs"
echo ""
echo "Uso: $0 [OPÇÕES] <nome-da-branch>"
echo ""
echo "Opções:"
echo " -h, --help Mostra esta ajuda"
echo " -b, --base BRANCH Define a branch base para comparação (padrão: main)"
echo ""
echo "Exemplos:"
echo " $0 feature/checkbox-vehicle"
echo " $0 feature/new-feature -b develop"
echo " $0 --help"
exit 0
fi
# Verificar se branch foi fornecida
if [ -z "$branch_name" ]; then
error_exit "Nome da branch é obrigatório. Use -h para ajuda."
fi
# Verificações iniciais
check_git_repo
check_branch_exists "$branch_name"
# Executar análises
print_header
get_branch_info "$branch_name" "$base_branch"
analyze_commits "$branch_name" "$base_branch"
analyze_files "$branch_name" "$base_branch"
analyze_file_types "$branch_name" "$base_branch"
analyze_complexity "$branch_name" "$base_branch"
check_potential_conflicts "$branch_name" "$base_branch"
analyze_tests "$branch_name" "$base_branch"
review_suggestions "$branch_name" "$base_branch"
generate_summary "$branch_name" "$base_branch"
echo ""
echo -e "${GREEN}${CHECK} Análise concluída com sucesso!${NC}"
echo ""
}
# Executar função principal com todos os argumentos
main "$@"