🤖 Módulo 5: Automação com PowerShell (listadetarefas-painel.ps1)

Objetivo: Centralizar o gerenciamento do ecossistema com um painel de controle para iniciar e parar todos os serviços de forma rápida e fácil.

📂 Passo 1: Estrutura Final e Configuração

  1. Na pasta raiz que contém todos os 4 projetos, crie o arquivo listadetarefas-painel.ps1.
  2. Habilite a Execução de Scripts: Abra o PowerShell como Administrador e execute (apenas uma vez):
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
    

Estrutura de Pastas Final do Projeto Completo

projeto-todolist/
├── listadetarefas.api/
├── listadetarefas-web/
├── listadetarefas-desktop/
├── listadetarefas-android/
└── listadetarefas-painel.ps1  # <- Script de automação

📜 Passo 2: O Script de Automação

Copie o código abaixo para o seu arquivo listadetarefas-painel.ps1. Ele está corrigido para usar os nomes corretos dos projetos, é portátil e verifica se os projetos precisam ser construídos antes de executar.

#
# SYNOPSIS
#   Painel de controle para gerenciar o projeto To-Do List (API, Web, Desktop, Mobile).
#
# DESCRIPTION
#   Este script PowerShell fornece um menu interativo para iniciar, parar, construir e
#   depurar os diferentes componentes do projeto no Windows.
#
# VERSION
#   4.3 - Versão PowerShell com detecção e seleção dinâmica de emuladores Android.
#

#==============================================================================
# --- CONFIGURAÇÕES GLOBAIS ---
#==============================================================================
$basePath = $PSScriptRoot
$apiPath = "$basePath\listadetarefas.api"
$webPath = "$basePath\listadetarefas-web"
$desktopPath = "$basePath\listadetarefas-desktop"
$androidPath = "$basePath\listadetarefas-android"
$sdkPath = "C:\Users\$env:UserName\AppData\Local\Android\Sdk" # Ajuste se necessário
$emulatorPath = "$sdkPath\emulator"
$platformToolsPath = "$sdkPath\platform-tools"
$emulatorName = "" # Definido dinamicamente
$availableEmulators = @()
$androidPackage = "br.com.curso.listadetarefas.android"
$desktopWindowTitle = "Minha Lista de Tarefas (Desktop)"
$apiJar = "$apiPath\target\listadetarefas.api-0.0.1-SNAPSHOT.jar"
$desktopJar = "$desktopPath\target\listadetarefas-desktop-1.0-SNAPSHOT.jar"
$webUrl = "http://localhost:4200"

#==============================================================================
# --- VERIFICAÇÃO DE PRÉ-REQUISITOS ---
#==============================================================================

function Test-Dependencies {
    $missing = @() if (-not (Get-Command adb.exe -ErrorAction SilentlyContinue) -and -not (Test-Path "$platformToolsPath\adb.exe")) {
        $missing += "adb (Android Platform Tools)" } if (-not (Get-Command java.exe -ErrorAction SilentlyContinue)) {$missing += "java"
    }
    if ($missing.Count -ne 0) { Write-Host "ERRO: Ferramentas necessárias não encontradas:$($missing -join ', ')." -ForegroundColor Red Write-Host "Instale-as e/ou ajuste `$sdkPath no início deste script." -ForegroundColor Yellow
        exit 1
    }
}

#==============================================================================
# --- FUNÇÕES DE SELEÇÃO DE EMULADOR ---
#==============================================================================

function Initialize-EmulatorSelection {
    Write-Host "Detectando emuladores instalados..." -ForegroundColor Cyan
    if (-not (Test-Path "$emulatorPath\emulator.exe")) { Write-Host "AVISO: Executável do emulador não encontrado em '$emulatorPath'." -ForegroundColor Yellow
        Write-Host "Verifique o caminho do SDK do Android no script." -ForegroundColor Yellow
        Start-Sleep -Seconds 2
        return
    }

    $script:availableEmulators = & "$emulatorPath\emulator.exe" -list-avds | Where-Object { $_.Trim() -ne "" }

    if ($availableEmulators.Count -eq 0) { Write-Host "AVISO: Nenhum emulador (AVD) foi encontrado." -ForegroundColor Yellow$script:emulatorName = ""
    }
    elseif ($availableEmulators.Count -eq 1) {$script:emulatorName = $availableEmulators[0] Write-Host "Emulador '$emulatorName' selecionado automaticamente." -ForegroundColor Green
    }
    else {
        $script:emulatorName = $availableEmulators[0]
        Write-Host "Múltiplos emuladores encontrados. '$emulatorName' foi selecionado como padrão." -ForegroundColor Green
        Write-Host "Use a opção 'S' no menu para selecionar outro."
    }
    Start-Sleep -Seconds 2
}

function Select-Emulator {
    Clear-Host
    Write-Host "--- SELECIONAR EMULADOR ANDROID ---" -ForegroundColor Yellow
    if ($availableEmulators.Count -eq 0) {
        Read-Host "Nenhum emulador foi detectado. Pressione Enter"
        return
    }

    Write-Host "`nEmuladores disponíveis:"
    for ($i = 0; $i -lt $availableEmulators.Count; $i++) {
        $indicator = "" if ($availableEmulators[$i] -eq $emulatorName) { $indicator = " [SELECIONADO]" } Write-Host "$($i + 1). $($availableEmulators[$i])$indicator"
    }

    $choice = Read-Host "`nDigite o número do emulador que deseja usar e pressione Enter (ou Enter para cancelar)" if ([string]::IsNullOrWhiteSpace($choice)) { return }

    if ($choice -match '^\d+$' -and [int]$choice -ge 1 -and [int]$choice -le $availableEmulators.Count) {$script:emulatorName = $availableEmulators[[int]$choice - 1]
        Write-Host "Emulador '$emulatorName' selecionado." -ForegroundColor Green
    }
    else {
        Write-Host "Seleção inválida. Nenhuma alteração foi feita." -ForegroundColor Red
    }
    Start-Sleep -Seconds 2
}

#==============================================================================
# --- FUNÇÕES AUXILIARES ---
#==============================================================================

function Get-ServiceStatus {
    param([string]$Service) switch ($Service) {
        'api' { if (Get-NetTCPConnection -LocalPort 8080 -State Listen -ErrorAction SilentlyContinue) { "RUNNING" } else { "STOPPED" } }
        'web' { if (Get-NetTCPConnection -LocalPort 4200 -State Listen -ErrorAction SilentlyContinue) { "RUNNING" } else { "STOPPED" } }
        'desktop' { if (Get-Process | Where-Object { $_.MainWindowTitle -like "*$desktopWindowTitle*" }) { "RUNNING" } else { "STOPPED" } }
        'android' {
            $running = & "$platformToolsPath\adb.exe" shell ps 2>$null | Select-String $androidPackage
            if ($running) { "RUNNING" } else { "STOPPED" } } 'emulator' {$devices = & "$platformToolsPath\adb.exe" devices 2>$null | Select-String "device$" if ($devices) { "RUNNING" } else { "STOPPED" }
        }
    }
}

function Wait-ForAdbDevice {
    $timeout = 90 if ((Get-ServiceStatus 'emulator') -eq "RUNNING") { return$true }
    Write-Host "Aguardando o emulador/dispositivo ficar online..." -ForegroundColor Cyan -NoNewline
    $elapsed = 0 while ($elapsed -lt $timeout) { if ((Get-ServiceStatus 'emulator') -eq "RUNNING") { Write-Host "`nDispositivo detectado." -ForegroundColor Green Start-Sleep -Seconds 1 return$true
        }
        Write-Host "." -NoNewline
        Start-Sleep -Seconds 2
        $elapsed += 2 } Write-Host "`nTempo esgotado!" -ForegroundColor Red return$false
}

function Confirm-BuildArtifact {
    param([string]$ArtifactPath, [string]$ProjectPath)
    if (-not (Test-Path $ArtifactPath)) {$choice = Read-Host "Artefato de build não encontrado em '$ArtifactPath'. Deseja construir agora? (s/n)" if ($choice -eq "s") {
            Push-Location $ProjectPath & .\mvnw.cmd clean package$exitCode = $LASTEXITCODE Pop-Location if ($exitCode -ne 0) {
                Write-Host "ERRO DE BUILD." -ForegroundColor Red
                Start-Sleep -Seconds 2
                return $false } } else { Write-Host "Início cancelado." -ForegroundColor Red Start-Sleep -Seconds 2 return$false
        }
    }
    return $true
}

#==============================================================================
# --- FUNÇÕES DE GERENCIAMENTO ---
#==============================================================================

function Start-AppService {
    param([string]$Service, [string]$ColdBoot)

    if ($Service -in @('web', 'desktop', 'android') -and (Get-ServiceStatus 'api') -eq "STOPPED") {$confirm = Read-Host "AVISO: A API está parada. Deseja iniciá-la primeiro? (s/n)"
        if ($confirm -eq "s") { if (-not (Start-AppService 'api')) { Write-Host "Falha ao iniciar API." -ForegroundColor Red Start-Sleep -Seconds 2 return$false
            }
        }
    }

    Write-Host "`nTentando iniciar serviço: $Service..." -ForegroundColor Yellow switch ($Service) {
        'api' {
            if (-not (Confirm-BuildArtifact $apiJar $apiPath)) { return $false } Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$apiPath'; java -jar '$apiJar'" } 'web' { Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$webPath'; ng serve --open"
        }
        'desktop' {
            if (-not (Confirm-BuildArtifact $desktopJar $desktopPath)) { return $false } Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd '$desktopPath'; java -jar '$desktopJar'" } 'android' { if (-not (Wait-ForAdbDevice)) { Write-Host "Nenhum emulador/dispositivo detectado." -ForegroundColor Red Start-Sleep -Seconds 2 return$false
            }
            Write-Host "Criando túnel de rede (adb reverse)..." -ForegroundColor Cyan
            & "$platformToolsPath\adb.exe" reverse tcp:8080 tcp:8080 Write-Host "Iniciando App Mobile..." & "$platformToolsPath\adb.exe" shell am start -n "$androidPackage/$androidPackage.MainActivity"
        }
        'emulator' {
            if ([string]::IsNullOrWhiteSpace($emulatorName)) { Write-Host "Nenhum emulador está selecionado." -ForegroundColor Yellow Select-Emulator if ([string]::IsNullOrWhiteSpace($emulatorName)) {
                    Read-Host "Operação cancelada. Pressione Enter"
                    return $false } } if ((Get-ServiceStatus 'emulator') -eq "RUNNING") { Write-Host "Emulador já parece estar rodando." -ForegroundColor Green return$true
            }
            $emuArgs = @("-avd", $emulatorName)
            if ($ColdBoot -eq "-ColdBoot") {$emuArgs += "-no-snapshot-load"
                Write-Host "Iniciando emulador em modo Cold Boot..." -ForegroundColor Yellow
            }
            Start-Process -FilePath "$emulatorPath\emulator.exe" -ArgumentList $emuArgs -WindowStyle Hidden
            if (-not (Wait-ForAdbDevice)) { return $false } } } return$true
}

function Stop-AppService {
    param([string]$Service) Write-Host "`nParando serviço:$Service..." -ForegroundColor Yellow
    switch ($Service) { 'api' { Get-NetTCPConnection -LocalPort 8080 -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object { Stop-Process -Id$_ -Force -ErrorAction SilentlyContinue }
        }
        'web' {
            Get-NetTCPConnection -LocalPort 4200 -State Listen -ErrorAction SilentlyContinue |
                Select-Object -ExpandProperty OwningProcess -Unique |
                ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue } } 'desktop' { Get-Process | Where-Object {$_.MainWindowTitle -like "*$desktopWindowTitle*" } | Stop-Process -Force -ErrorAction SilentlyContinue } 'android' { & "$platformToolsPath\adb.exe" shell am force-stop $androidPackage } 'emulator' { & "$platformToolsPath\adb.exe" emu kill }
    }
    Write-Host "Comando de parada enviado." -ForegroundColor Green
    Start-Sleep -Seconds 1
}

function Clear-ProjectCaches {
    Clear-Host
    Write-Host "--- LIMPANDO CACHES E BUILDS ---" -ForegroundColor Yellow
    Write-Host "`nLimpando API..." -ForegroundColor Cyan
    Push-Location $apiPath; & .\mvnw.cmd clean; Pop-Location Write-Host "`nLimpando Desktop..." -ForegroundColor Cyan Push-Location$desktopPath; & .\mvnw.cmd clean; Pop-Location
    Write-Host "`nLimpando Web..." -ForegroundColor Cyan
    Remove-Item -Recurse -Force "$webPath\.angular", "$webPath\dist" -ErrorAction SilentlyContinue
    Write-Host "`n--- LIMPEZA CONCLUÍDA ---" -ForegroundColor Green
    Read-Host "Pressione Enter"
}

function Invoke-AdbTool {
    param([string]$Tool) if (-not (Wait-ForAdbDevice)) { Read-Host "Operação ADB cancelada. Pressione Enter" return } Clear-Host Write-Host "--- Ferramenta Mobile (ADB):$Tool ---" -ForegroundColor Yellow
    switch ($Tool) { 'reset' { & "$platformToolsPath\adb.exe" kill-server; & "$platformToolsPath\adb.exe" start-server } 'devices' { & "$platformToolsPath\adb.exe" devices }
        'logcat' {
            Start-Process powershell -ArgumentList "-NoExit", "-Command", "& '$platformToolsPath\adb.exe' logcat '*:S' '$androidPackage:V'"
            return
        }
        'reverse' {
            & "$platformToolsPath\adb.exe" reverse tcp:8080 tcp:8080 Write-Host "Verificando túneis:" & "$platformToolsPath\adb.exe" reverse --list
        }
    }
    Read-Host "`nPressione Enter para voltar ao menu"
}

#==============================================================================
# --- INTERFACE DO USUÁRIO (MENU) ---
#==============================================================================

function Show-Menu {
    Clear-Host
    Write-Host "=================================================" -ForegroundColor Cyan
    Write-Host "      PAINEL DE CONTROLE - PROJETO TO-DO LIST      " -ForegroundColor White
    Write-Host "=================================================" -ForegroundColor Cyan

    $emulatorDisplayName = if ($emulatorName) { $emulatorName } else { "Nenhum Selecionado" }$statuses = [ordered]@{
        "Emulador ($emulatorDisplayName)" = Get-ServiceStatus 'emulator'
        "API Backend"                     = Get-ServiceStatus 'api'
        "Frontend Web"                    = Get-ServiceStatus 'web'
        "App Desktop"                     = Get-ServiceStatus 'desktop'
        "App Mobile"                      = if ((Get-ServiceStatus 'emulator') -eq "RUNNING") { Get-ServiceStatus 'android' } else { "OFFLINE" }
    }

    Write-Host "`nSTATUS ATUAL:" -ForegroundColor White
    foreach ($key in $statuses.Keys) {
        $color = if ($statuses[$key] -eq "RUNNING") { "Green" } else { "Red" } Write-Host (" {0,-30} " -f$key) -NoNewline
        Write-Host $statuses[$key] -ForegroundColor $color
    }

    Write-Host "`n--- OPÇÕES ---" -ForegroundColor Yellow
    Write-Host " GERAL                     SERVIÇOS INDIVIDUAIS"
    Write-Host "  9) Iniciar TUDO          1) Iniciar API          5) Iniciar Desktop"
    Write-Host "  10) Parar TUDO           2) Parar API            6) Parar Desktop"
    Write-Host "  L) Limpar Caches         3) Iniciar Web          7) Iniciar App Mobile"
    Write-Host "                           4) Parar Web            8) Parar App Mobile"
    Write-Host "-----------------------------------------------------------------"
    Write-Host " FERRAMENTAS MOBILE (ANDROID)                      NAVEGAÇÃO"
    Write-Host "  A) Iniciar Emulador      D) Resetar Servidor ADB R) Atualizar Status"
    Write-Host "  B) Parar Emulador        E) Listar Dispositivos  Q) Sair"
    Write-Host "  H) Ligar (Cold Boot)     F) Ver Logs (logcat)"
    Write-Host "  S) Selecionar Emulador   G) Criar Túnel de Rede"
    Write-Host ""
}

#==============================================================================
# --- LÓGICA PRINCIPAL (LOOP DO MENU) ---
#==============================================================================

Test-Dependencies
Initialize-EmulatorSelection

while ($true) { Show-Menu$choice = (Read-Host "Digite sua opção e pressione Enter").ToLower()

    switch ($choice) { '1' { Start-AppService 'api' | Out-Null } '2' { Stop-AppService 'api' } '3' { Start-AppService 'web' | Out-Null } '4' { Stop-AppService 'web' } '5' { Start-AppService 'desktop' | Out-Null } '6' { Stop-AppService 'desktop' } '7' { Start-AppService 'android' | Out-Null } '8' { Stop-AppService 'android' } '9' { if (-not (Start-AppService 'emulator')) { Read-Host "Falha ao iniciar Emulador"; continue } if (-not (Start-AppService 'api')) { Read-Host "Falha ao iniciar API"; continue } Start-AppService 'web' | Out-Null Start-AppService 'desktop' | Out-Null Start-AppService 'android' | Out-Null Read-Host "`n--- SEQUÊNCIA CONCLUÍDA ---`nPressione Enter" } '10' { Stop-AppService 'android'; Stop-AppService 'desktop'; Stop-AppService 'web'; Stop-AppService 'api' if ((Get-ServiceStatus 'emulator') -eq "RUNNING") {$confirm = Read-Host "Deseja parar o Emulador também? (s/n)"
                if ($confirm -eq "s") { Stop-AppService 'emulator' } } } 'a' { Start-AppService 'emulator' | Out-Null } 'b' { Stop-AppService 'emulator' } 'h' { Start-AppService 'emulator' '-ColdBoot' | Out-Null } 's' { Select-Emulator } 'c' { Start-Process$webUrl }
        'd' { Invoke-AdbTool 'reset' }
        'e' { Invoke-AdbTool 'devices' }
        'f' { Invoke-AdbTool 'logcat' }
        'g' { Invoke-AdbTool 'reverse' }
        'l' { Clear-ProjectCaches }
        'r' { }
        'q' { break }
        default { Write-Host "Opção inválida!" -ForegroundColor Red; Start-Sleep -Seconds 2 }
    }
}

✅ Passo 3: Teste do Painel de Controle

  1. Abra o terminal na pasta raiz do projeto.
  2. Execute o script: .\listadetarefas-painel.ps1
  3. Teste as opções do menu (Iniciar API, Parar API, Iniciar TUDO, etc.) para garantir que o painel está gerenciando todos os componentes do ecossistema corretamente.