394 lines
14 KiB
Bash
394 lines
14 KiB
Bash
#!/bin/bash
|
||
|
||
# 🛠️ PR Tools - Ferramentas Avançadas para Análise de PRs
|
||
# Autor: Jonas Santos
|
||
# Versão: 1.0
|
||
# Data: Janeiro 2025
|
||
|
||
set -e
|
||
|
||
# Cores
|
||
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'
|
||
|
||
# Função para análise de segurança
|
||
security_analysis() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "${RED}🔒 ANÁLISE DE SEGURANÇA${NC}"
|
||
echo "----------------------------------------"
|
||
|
||
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null)
|
||
|
||
# Padrões sensíveis
|
||
echo -e "${YELLOW}🔍 Verificando padrões sensíveis...${NC}"
|
||
|
||
local security_issues=0
|
||
|
||
# Buscar por padrões perigosos no código
|
||
echo "$modified_files" | while read file; do
|
||
if [ -n "$file" ] && [ -f "$file" ]; then
|
||
# Verificar senhas hardcoded
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -i -E "(password|senha)\s*=\s*['\"][^'\"]+['\"]" > /dev/null; then
|
||
echo -e " 🚨 ${RED}$file: Possível senha hardcoded${NC}"
|
||
security_issues=$((security_issues + 1))
|
||
fi
|
||
|
||
# Verificar API keys
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -i -E "(api_key|apikey|secret_key)\s*=\s*['\"][^'\"]+['\"]" > /dev/null; then
|
||
echo -e " 🚨 ${RED}$file: Possível API key exposta${NC}"
|
||
security_issues=$((security_issues + 1))
|
||
fi
|
||
|
||
# Verificar URLs hardcoded de produção
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -E "https?://[^/]*\.(com|org|net)" > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}$file: URL hardcoded encontrada${NC}"
|
||
fi
|
||
|
||
# Verificar console.log em produção
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep "console\." > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}$file: console.log encontrado${NC}"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if [ $security_issues -eq 0 ]; then
|
||
echo -e " ✅ ${GREEN}Nenhum problema crítico de segurança detectado${NC}"
|
||
fi
|
||
}
|
||
|
||
# Função para análise de performance
|
||
performance_analysis() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "\n${BLUE}⚡ ANÁLISE DE PERFORMANCE${NC}"
|
||
echo "----------------------------------------"
|
||
|
||
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null)
|
||
|
||
echo -e "${YELLOW}🔍 Verificando padrões que afetam performance...${NC}"
|
||
|
||
echo "$modified_files" | while read file; do
|
||
if [ -n "$file" ] && [ -f "$file" ]; then
|
||
# Verificar loops aninhados
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -E "for.*for|while.*while" > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}$file: Loops aninhados detectados${NC}"
|
||
fi
|
||
|
||
# Verificar operações DOM custosas
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -E "querySelector|getElementById" > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}$file: Operações DOM manuais${NC}"
|
||
fi
|
||
|
||
# Verificar imports desnecessários
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep -E "import.*\*.*from" > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}$file: Import de toda biblioteca${NC}"
|
||
fi
|
||
|
||
# Verificar subscribe sem unsubscribe
|
||
if git diff origin/$base_branch origin/$branch -- "$file" | grep "\.subscribe(" > /dev/null; then
|
||
if ! git diff origin/$base_branch origin/$branch -- "$file" | grep -E "(unsubscribe|takeUntil|async)" > /dev/null; then
|
||
echo -e " 🚨 ${RED}$file: Subscribe sem unsubscribe${NC}"
|
||
fi
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Função para análise de dependencies
|
||
dependency_analysis() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "\n${PURPLE}📦 ANÁLISE DE DEPENDÊNCIAS${NC}"
|
||
echo "----------------------------------------"
|
||
|
||
if git diff --name-only origin/$base_branch origin/$branch | grep -q "package.json"; then
|
||
echo -e "${YELLOW}🔍 Mudanças em package.json detectadas...${NC}"
|
||
|
||
# Mostrar diferenças em dependencies
|
||
echo -e "\n${BLUE}Dependências alteradas:${NC}"
|
||
git diff origin/$base_branch origin/$branch -- package.json | grep -E "^\+.*\".*\":" | sed 's/^+/ ✅ ADICIONADO:/' || true
|
||
git diff origin/$base_branch origin/$branch -- package.json | grep -E "^\-.*\".*\":" | sed 's/^-/ ❌ REMOVIDO:/' || true
|
||
|
||
# Verificar dependências perigosas
|
||
echo -e "\n${RED}🚨 Verificando dependências sensíveis:${NC}"
|
||
if git diff origin/$base_branch origin/$branch -- package.json | grep -E "eval|child_process|fs" > /dev/null; then
|
||
echo -e " ⚠️ ${YELLOW}Dependência potencialmente perigosa detectada${NC}"
|
||
else
|
||
echo -e " ✅ ${GREEN}Nenhuma dependência sensível detectada${NC}"
|
||
fi
|
||
else
|
||
echo -e " ℹ️ ${BLUE}Nenhuma mudança em dependências${NC}"
|
||
fi
|
||
}
|
||
|
||
# Função para análise de código duplicado
|
||
duplicate_code_analysis() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "\n${CYAN}🔄 ANÁLISE DE CÓDIGO DUPLICADO${NC}"
|
||
echo "----------------------------------------"
|
||
|
||
local modified_files=$(git diff --name-only origin/$base_branch origin/$branch 2>/dev/null | grep -E "\.(ts|js)$")
|
||
|
||
if [ -z "$modified_files" ]; then
|
||
echo -e " ℹ️ ${BLUE}Nenhum arquivo de código para analisar${NC}"
|
||
return
|
||
fi
|
||
|
||
echo -e "${YELLOW}🔍 Verificando duplicação de código...${NC}"
|
||
|
||
# Verificar funções similares
|
||
echo "$modified_files" | while read file; do
|
||
if [ -n "$file" ] && [ -f "$file" ]; then
|
||
# Contar funções com nomes similares
|
||
local functions=$(git diff origin/$base_branch origin/$branch -- "$file" | grep -E "^\+.*function|^\+.*=>" | wc -l)
|
||
if [ "$functions" -gt 3 ]; then
|
||
echo -e " ⚠️ ${YELLOW}$file: $functions novas funções (verificar se há duplicação)${NC}"
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Função para gerar checklist de PR
|
||
generate_pr_checklist() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "\n${WHITE}📋 CHECKLIST COMPLETO DO PR${NC}"
|
||
echo "========================================"
|
||
|
||
echo -e "${GREEN}🔍 REVISÃO DE CÓDIGO:${NC}"
|
||
echo " [ ] Código segue padrões do projeto"
|
||
echo " [ ] Nomenclatura clara e consistente"
|
||
echo " [ ] Lógica de negócio está correta"
|
||
echo " [ ] Tratamento de erros adequado"
|
||
echo " [ ] Sem código comentado/debug"
|
||
echo " [ ] Imports organizados"
|
||
|
||
echo -e "\n${YELLOW}🧪 TESTES:${NC}"
|
||
echo " [ ] Testes unitários criados/atualizados"
|
||
echo " [ ] Todos os testes passando"
|
||
echo " [ ] Cobertura de código adequada"
|
||
echo " [ ] Testes de integração (se necessário)"
|
||
|
||
echo -e "\n${BLUE}🚀 FUNCIONALIDADE:${NC}"
|
||
echo " [ ] Feature funciona conforme especificado"
|
||
echo " [ ] Casos edge testados"
|
||
echo " [ ] Responsividade verificada"
|
||
echo " [ ] Performance adequada"
|
||
echo " [ ] Acessibilidade considerada"
|
||
|
||
echo -e "\n${RED}🔒 SEGURANÇA:${NC}"
|
||
echo " [ ] Sem credenciais hardcoded"
|
||
echo " [ ] Validação de inputs"
|
||
echo " [ ] Autorização/autenticação OK"
|
||
echo " [ ] Sem vazamentos de dados sensíveis"
|
||
|
||
echo -e "\n${PURPLE}📦 DEPENDÊNCIAS:${NC}"
|
||
echo " [ ] Novas dependências justificadas"
|
||
echo " [ ] Versões compatíveis"
|
||
echo " [ ] Bundle size não aumentou muito"
|
||
|
||
echo -e "\n${CYAN}📚 DOCUMENTAÇÃO:${NC}"
|
||
echo " [ ] README atualizado (se necessário)"
|
||
echo " [ ] Comentários no código (se complexo)"
|
||
echo " [ ] Changelog atualizado"
|
||
echo " [ ] API docs atualizadas"
|
||
}
|
||
|
||
# Função para comparar branches
|
||
compare_branches() {
|
||
local branch1=$1
|
||
local branch2=$2
|
||
|
||
echo -e "${WHITE}🔄 COMPARAÇÃO ENTRE BRANCHES${NC}"
|
||
echo "========================================"
|
||
echo -e "${BLUE}Branch 1:${NC} $branch1"
|
||
echo -e "${BLUE}Branch 2:${NC} $branch2"
|
||
echo ""
|
||
|
||
# Commits únicos em cada branch
|
||
echo -e "${YELLOW}📊 Commits únicos:${NC}"
|
||
echo -e "\n${GREEN}Em $branch1 mas não em $branch2:${NC}"
|
||
git log --oneline $branch2..$branch1 || echo " Nenhum commit único"
|
||
|
||
echo -e "\n${GREEN}Em $branch2 mas não em $branch1:${NC}"
|
||
git log --oneline $branch1..$branch2 || echo " Nenhum commit único"
|
||
|
||
# Diferenças de arquivos
|
||
echo -e "\n${YELLOW}📁 Diferenças de arquivos:${NC}"
|
||
git diff --name-status $branch1 $branch2 | head -20
|
||
}
|
||
|
||
# Função para análise de commit messages
|
||
analyze_commit_messages() {
|
||
local branch=$1
|
||
local base_branch=${2:-main}
|
||
|
||
echo -e "\n${WHITE}💬 ANÁLISE DE MENSAGENS DE COMMIT${NC}"
|
||
echo "========================================"
|
||
|
||
local commits=$(git log --format="%s" origin/$base_branch..origin/$branch 2>/dev/null)
|
||
|
||
if [ -z "$commits" ]; then
|
||
echo -e " ℹ️ ${BLUE}Nenhum commit único encontrado${NC}"
|
||
return
|
||
fi
|
||
|
||
echo -e "${YELLOW}🔍 Verificando padrões de commit...${NC}"
|
||
|
||
local good_commits=0
|
||
local total_commits=0
|
||
|
||
echo "$commits" | while read message; do
|
||
if [ -n "$message" ]; then
|
||
total_commits=$((total_commits + 1))
|
||
|
||
# Verificar se segue conventional commits
|
||
if echo "$message" | grep -E "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: " > /dev/null; then
|
||
echo -e " ✅ ${GREEN}$message${NC}"
|
||
good_commits=$((good_commits + 1))
|
||
else
|
||
echo -e " ⚠️ ${YELLOW}$message${NC}"
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Função principal
|
||
main() {
|
||
local command=""
|
||
local branch1=""
|
||
local branch2="main"
|
||
local show_help=false
|
||
|
||
# Parse dos argumentos
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
security|sec)
|
||
command="security"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
performance|perf)
|
||
command="performance"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
dependencies|deps)
|
||
command="dependencies"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
checklist|check)
|
||
command="checklist"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
compare|comp)
|
||
command="compare"
|
||
branch1="$2"
|
||
branch2="$3"
|
||
shift 3
|
||
;;
|
||
commits|msg)
|
||
command="commits"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
full|all)
|
||
command="full"
|
||
branch1="$2"
|
||
shift 2
|
||
;;
|
||
-h|--help)
|
||
show_help=true
|
||
shift
|
||
;;
|
||
*)
|
||
if [ -z "$command" ]; then
|
||
command="full"
|
||
branch1="$1"
|
||
fi
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Mostrar ajuda
|
||
if [ "$show_help" = true ]; then
|
||
echo "🛠️ PR Tools - Ferramentas Avançadas para Análise de PRs"
|
||
echo ""
|
||
echo "Uso: $0 <comando> [argumentos]"
|
||
echo ""
|
||
echo "Comandos:"
|
||
echo " security <branch> Análise de segurança"
|
||
echo " performance <branch> Análise de performance"
|
||
echo " dependencies <branch> Análise de dependências"
|
||
echo " checklist <branch> Gerar checklist de PR"
|
||
echo " compare <branch1> <branch2> Comparar branches"
|
||
echo " commits <branch> Análise de mensagens de commit"
|
||
echo " full <branch> Análise completa"
|
||
echo ""
|
||
echo "Exemplos:"
|
||
echo " $0 security feature/new-login"
|
||
echo " $0 performance feature/optimization"
|
||
echo " $0 compare feature/a feature/b"
|
||
echo " $0 full feature/checkbox-vehicle"
|
||
exit 0
|
||
fi
|
||
|
||
# Verificar se é repositório git
|
||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||
echo -e "${RED}❌ Erro: Este diretório não é um repositório Git.${NC}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# Executar comando
|
||
case $command in
|
||
security)
|
||
security_analysis "$branch1" "$branch2"
|
||
;;
|
||
performance)
|
||
performance_analysis "$branch1" "$branch2"
|
||
;;
|
||
dependencies)
|
||
dependency_analysis "$branch1" "$branch2"
|
||
;;
|
||
checklist)
|
||
generate_pr_checklist "$branch1" "$branch2"
|
||
;;
|
||
compare)
|
||
compare_branches "$branch1" "$branch2"
|
||
;;
|
||
commits)
|
||
analyze_commit_messages "$branch1" "$branch2"
|
||
;;
|
||
full)
|
||
security_analysis "$branch1" "$branch2"
|
||
performance_analysis "$branch1" "$branch2"
|
||
dependency_analysis "$branch1" "$branch2"
|
||
duplicate_code_analysis "$branch1" "$branch2"
|
||
analyze_commit_messages "$branch1" "$branch2"
|
||
generate_pr_checklist "$branch1" "$branch2"
|
||
;;
|
||
*)
|
||
echo -e "${RED}❌ Comando inválido. Use -h para ajuda.${NC}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Executar função principal
|
||
main "$@" |