diff --git a/.coverage b/.coverage deleted file mode 100644 index 733ee02..0000000 Binary files a/.coverage and /dev/null differ diff --git a/.gitignore b/.gitignore index ceb1016..acb54dd 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,9 @@ venv.bak/ .pytest_cache/ tests/repo/ tests/repo_windows/ -~/.gitauditor_ai_cache.json -*.json +.gitauditor_ai_cache.json +.coverage +htmlcov/ # IDEs and Editors .vscode/ diff --git a/BLUEPRINT.md b/BLUEPRINT.md deleted file mode 100644 index 5ca762b..0000000 --- a/BLUEPRINT.md +++ /dev/null @@ -1,104 +0,0 @@ -# GitAuditor Blueprint - V3: O Catálogo Inteligente - -Este documento consolida a evolução do **GitAuditor** de um simples scanner de repositórios para um **Catálogo Local Inteligente**. O foco agora não é apenas escanear, mas gerenciar, normalizar e auditar a saúde completa da infraestrutura de código local do usuário. - -## 1. Visão Canônica e Metadados Enriquecidos (O "Cérebro") -A base de toda a reestruturação é o abandono do "scan toda hora" para a introdução de um banco de dados local (`SQLite` ou `JSON` persistente). -Cada repositório não será mais apenas um "caminho de pasta", mas uma entidade rica: - -- **Host/Owner/Repo** (Ex: `github.com/refernandes/gitauditor`) -- **Tags de Categoria:** `work`, `study`, `archive`, `lab`, `client` -- **Tamanho no Disco** (Megabytes/Gigabytes) -- **Status de Saúde** (Up-to-date, Stale, Broken Remote, Orphans) -- **Última Atividade** (Data do último commit local vs remoto) - -Isso desbloqueia consultas ricas e instantâneas: -`gitauditor list --tag work --stale --remote broken` - -## 2. Fluxos de Normalização (O "Arrumador") -Ferramentas como o `ghq` provam que caminhos previsíveis salvam vidas. -O GitAuditor será capaz de detectar repositórios espalhados e sugerir uma padronização: -- De: `~/Desktop/projetos-antigos/api` -- Para: `~/Code/github.com/owner/api` - -### Comandos-chave propostos: -- `gitauditor repos organize --root ~/Code` (Move e organiza em estrutura canônica) -- `gitauditor repos dedupe --plan` (Mostra quais projetos lógicos estão clonados mais de uma vez) - -## 3. Backlog de Implantação Priorizado - -### P0 (Missão Crítica) -- **Catálogo Local com Tags/Categorias:** Criação do banco de dados local (`~/.gitauditor.db`) e comandos de sincronização (`gitauditor catalog sync`). Isso transforma o projeto num produto de organização, não apenas num script. -- **Normalização de Paths e Detecção de Duplicatas Lógicas:** O algoritmo que agrupa chaves HTTPS e SSH sob a mesma URL canônica e permite a reorganização sem dor (`--dry-run` para segurança extrema). - -### P1 (Valor Imediato) -- **Dashboard de Saúde do Repo:** Detectar remotes quebrados, diretórios `.git` inflados que precisam de um `git gc`, e repositórios abandonados ("stale"). -- **Cleanup Seguro com Preview:** Interface para deleção ou arquivamento em massa de repositórios podres ou órfãos, sempre mostrando o ganho de disco. -- **Busca Rápida e Abertura:** Achar repos e abri-los direto no editor padrão (`gitauditor open `). - -### P2 (Funcionalidades Avançadas de Fluxo) -- **Worktree Manager:** Em vez de clonar de novo para testar a branch X, sugerir e criar `git worktrees` (`gitauditor worktree create repo-x feature/teste`). Isso poupa muito espaço de HD e mantém as coisas higienizadas. -- **Templates e Bootstrap:** Ajudar na padronização de novos projetos locais. -- **Suporte a Sparse-Checkout:** Para monorepos que destroem a máquina local, facilitando a vida para baixar só as peças necessárias. - -## 4. Arquitetura de Comandos (Typer) - -A fundação recém construída com o **Typer** permite fatiarmos o CLI de maneira muito elegante. O blueprint de comandos será: - -```bash -# Sincroniza e populo o banco de dados -gitauditor catalog sync - -# Relatórios rápidos e filtragem -gitauditor repos list --tag work --stale -gitauditor catalog health - -# Ações de Limpeza e Organização -gitauditor catalog dedupe --plan -gitauditor repos organize --root ~/Code --dry-run -gitauditor repos prune - -# Agilidade e Fluxo -gitauditor catalog open backend-api -gitauditor worktree create api feature/teste -``` - -## 5. Backlog Futuro: Phase 3 (Semantic AI Layer) - -A próxima grande evolução do GitAuditor foca em integrar Inteligência Artificial (LLMs Locais via Ollama ou APIs Externas plugáveis) não apenas como geradores de mensagens, mas como uma **Camada Semântica Confiável** sobre o inventário Git. - -### Princípios de Design e Governança -Para que a IA adicione valor real sem transformar o produto em uma caixa de surpresas, as seguintes regras guiarão a arquitetura P3: - -1. **Multi-Provider API:** A camada de LLM deve ser agnóstica, permitindo o uso do Ollama local por padrão, mas com portas abertas para provedores externos via chaves de API. -2. **Governança no Catálogo:** O banco de dados (`Repo`) não guardará apenas as respostas. Ele rastreará a proveniência: `ai_model`, `ai_prompt_version`, `ai_updated_at`, `ai_confidence`, `ai_error` e `ai_source_hash`. -3. **Estratégia de Cache e Hash:** A IA só será chamada se o contexto base do repositório mudar. Se o hash do README + manifestos + árvore for o mesmo, lemos do banco. -4. **Validação Estruturada (Pydantic) + Retry:** As saídas da IA deverão seguir schemas JSON estritos e separados por feature, com lógica de retry caso a estrutura venha inválida. -5. **Heurística Antes da IA (Fallback Determinístico):** A classificação (`tag`) começará sempre por regras rígidas e determinísticas (ex: detectar `package.json`). O LLM entra como enriquecedor. Se o LLM falhar, a heurística garante a funcionalidade. -6. **Limites do LLM:** No *repo review*, a IA não substituirá scanners de segurança (como gitleaks). Ela focará em smells qualitativos, arquitetura e dicas humanas. -7. **Contexto Hierárquico Inteligente:** O extrator não vai só cuspir a pasta inteira para o LLM. Ele enviará metadados do Git, a árvore resumida por profundidade, o README truncado, manifestos chaves (`pyproject.toml`, `package.json`, etc) e excluirá arquivos nocivos (`.venv`, `node_modules`). - -### Roadmap Fatiado da Fase P3 - -Para evitar complexidade monstruosa, a implementação será feita em 4 entregas atômicas: - -- **P3.1 | Summarize & Foundation:** - - Adição dos campos semânticos e de governança no banco SQLite. - - Implementação do "Extrator de Contexto" hierárquico com cálculo de Hash. - - Implementação do motor Multi-Provider de IA com Structured Outputs (JSON) usando Pydantic. - - Comando: `gitauditor catalog summarize`. - -- **P3.2 | Auto-Tagging Híbrido:** - - Comando: `gitauditor catalog tag --auto`. - - Inferência primeiro determinística, depois refinada pela IA para categorizar projetos (`work`, `api`, `lab`, `archive`). - -- **P3.3 | Local Review (Code Quality):** - - Comando: `gitauditor repo review`. - - Foco restrito em analisar diffs curtos ou *staged* para apontar falhas qualitativas de design antes do commit. - -- **P3.4 | Rascunho de Documentação:** - - Comando: `gitauditor repo readme-draft`. - - Geração estruturada de READMEs a partir da stack detectada para reativar repositórios "mortos". - ---- -*Status: P0, P1, P2 Concluídos na Versão 3. Fase P3 em estágio de arquitetura e aprovação.* diff --git a/repomix-output.xml b/repomix-output.xml deleted file mode 100644 index ee5cdfb..0000000 --- a/repomix-output.xml +++ /dev/null @@ -1,113 +0,0 @@ -This file is a merged representation of the entire codebase, combined into a single document by Repomix. -The content has been processed where content has been compressed (code blocks are separated by ⋮---- delimiter). - - -This section contains a summary of this file. - - -This file contains a packed representation of the entire repository's contents. -It is designed to be easily consumable by AI systems for analysis, code review, -or other automated processes. - - - -The content is organized as follows: -1. This summary section -2. Repository information -3. Directory structure -4. Repository files (if enabled) -5. Multiple file entries, each consisting of: - - File path as an attribute - - Full contents of the file - - - -- This file should be treated as read-only. Any changes should be made to the - original repository files, not this packed version. -- When processing this file, use the file path to distinguish - between different files in the repository. -- Be aware that this file may contain sensitive information. Handle it with - the same level of security as you would the original repository. - - - -- Some files may have been excluded based on .gitignore rules and Repomix's configuration -- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files -- Files matching patterns in .gitignore are excluded -- Files matching default ignore patterns are excluded -- Content has been compressed - code blocks are separated by ⋮---- delimiter -- Files are sorted by Git change count (files with more changes are at the bottom) - - - - - -.github/ - workflows/ - ci.yml -src/ - gitauditor/ - commands/ - __init__.py - amend_cmd.py - audit_cmd.py - catalog_cmd.py - changelog_cmd.py - config_cmd.py - policy_cmd.py - repo_app.py - repo_cmd.py - review_cmd.py - ssh_cmd.py - worktree_cmd.py - core/ - ai_api.py - audit_log.py - catalog.py - config.py - enricher.py - git_ops.py - heuristics.py - models.py - policy_engine.py - scanner.py - semantic.py - ssh_audit.py - locales/ - en_US/ - LC_MESSAGES/ - gitauditor.mo - gitauditor.po - messages.mo - messages.po - pt_BR/ - LC_MESSAGES/ - gitauditor.mo - gitauditor.po - messages.mo - messages.po - gitauditor.pot - __main__.py - cli.py - gitauditor.egg-info/ - dependency_links.txt - entry_points.txt - PKG-INFO - requires.txt - SOURCES.txt - top_level.txt -tests/ - test_enricher.py - test_point1_rebase_merges.py - test_point2_async_audit.py - test_point3_windows_rebase.py - test_point5_duplicates.py -.gitignore -BLUEPRINT.md -pyproject.toml -README_pt.md -README.md -requirements.txt -test_azure_key.py -test_azure.py - diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5afc8d5..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -textual>=0.86.0 -GitPython>=3.1.43 -httpx>=0.27.0 -rich>=13.7.1 -pyyaml>=6.0.1 -tenacity>=8.0.0 -azure-identity>=1.15.0 diff --git a/src/gitauditor/cli.py b/src/gitauditor/cli.py index 84b9f05..30c86a6 100644 --- a/src/gitauditor/cli.py +++ b/src/gitauditor/cli.py @@ -18,15 +18,18 @@ with open(config_path) as f: cfg = json.load(f) lang_to_use = cfg.get("lang", "pt_BR") -except Exception: - pass +except Exception as e: + import sys + print(f"Aviso: Erro ao carregar config i18n: {e}", file=sys.stderr) localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locales') try: translate = gettext.translation('gitauditor', localedir, languages=[lang_to_use], fallback=True) translate.install() _ = translate.gettext -except Exception: +except Exception as e: + import sys + print(f"Aviso: Não foi possível carregar a tradução: {e}", file=sys.stderr) import builtins builtins.__dict__['_'] = lambda x: x # ---------------------------------------------------- @@ -457,17 +460,24 @@ def _action_filter_table(self): app.add_typer(worktree_app, name="wt", hidden=True) app.command(name="config", help=_("Configurações do GitAuditor"))(config_command) -cli_state = GitAuditorCLI() + +_cli_state = None + +def get_cli_state() -> GitAuditorCLI: + global _cli_state + if _cli_state is None: + _cli_state = GitAuditorCLI() + return _cli_state @app.callback(invoke_without_command=True) def main_callback(ctx: typer.Context): if ctx.invoked_subcommand is None: - cli_state.run() + get_cli_state().run() @app.command() def ui(): """Modo Interativo (UI/Launcher Clássico).""" - cli_state.run() + get_cli_state().run() @app.command(name="sync", hidden=True) def sync_shortcut(): @@ -507,7 +517,7 @@ def review_shortcut(path: str = ".", staged: bool = False): @app.command(name="ssh", help=_("Gerenciar Chaves e Identidades SSH.")) def ssh_cmd(): - handle_manage_ssh(cli_state) + handle_manage_ssh(get_cli_state()) if __name__ == "__main__": diff --git a/tests/test_cli_commands.py b/tests/test_cli_commands.py index c1bfcaf..07ef61d 100644 --- a/tests/test_cli_commands.py +++ b/tests/test_cli_commands.py @@ -1,21 +1,72 @@ from typer.testing import CliRunner +from unittest.mock import patch from gitauditor.cli import app runner = CliRunner() + def test_cli_help(): """Testa se o comando principal da CLI responde com o menu de ajuda.""" result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 - assert "Manage, audit, and organize Git repositories locally" in result.stdout or "Usage:" in result.stdout - -def test_catalog_dashboard_command_help(): - """Testa a ajuda do comando dashboard no catalog.""" - # Assuming there's a command structure or just testing the main help - result = runner.invoke(app, ["dashboard", "--help"]) - if result.exit_code == 0: - assert "dashboard" in result.stdout.lower() - else: - # Some commands might be invoked differently - pass + assert "GitAuditor" in result.stdout + assert "catalog" in result.stdout + assert "policy" in result.stdout + + +def test_invalid_command_fails(): + """Testa se um comando inexistente falha corretamente.""" + result = runner.invoke(app, ["comando-inexistente"]) + assert result.exit_code != 0 + + +@patch("gitauditor.commands.catalog_cmd.init_db") +@patch("gitauditor.commands.catalog_cmd.Session") +def test_catalog_sync_command(mock_session, mock_init_db): + """Testa o roteamento e a execução base do catalog sync, com mock do banco de dados.""" + # Como não temos um DB de teste configurado, verificamos apenas o help do subcomando. + result = runner.invoke(app, ["catalog", "sync", "--help"]) + assert result.exit_code == 0 + assert "Sincroniza" in result.stdout or "sync" in result.stdout + + +@patch("gitauditor.commands.policy_cmd.PolicyEngine") +@patch("gitauditor.commands.policy_cmd.find_repo_or_exit") +def test_policy_check_command(mock_find, mock_engine): + """Testa se o comando policy check é chamado adequadamente.""" + mock_find.return_value = "/tmp/dummy/repo" + mock_engine.return_value.check_repository.return_value = { + "status": "ok", + "score": 100, + "critical": [], + "warnings": [], + "checks": { + "readme": True, + "license": True, + "gitignore": True, + "ci_cd": True, + "codeowners": True, + "contributing": True, + "security": True, + "env_exposed": False, + }, + } + + result = runner.invoke(app, ["policy", "check", "."]) + assert result.exit_code == 0 + + +def test_repo_amend_help(): + """Testa o help do comando de inteligência artificial de repositório.""" + result = runner.invoke(app, ["repo", "amend", "--help"]) + assert result.exit_code == 0 + assert "amend" in result.stdout.lower() + + +@patch("gitauditor.commands.catalog_cmd.health_dashboard") +def test_hidden_health_shortcut(mock_health): + """Testa se os atalhos escondidos do CLI estão roteando corretamente.""" + result = runner.invoke(app, ["health"]) + assert result.exit_code == 0 + mock_health.assert_called_once()