git-ez 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
git_ez/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .main import app
2
+
3
+ __version__ = "1.0.0"
4
+ __all__ = ["app", "__version__"]
git_ez/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .main import app
2
+
3
+ if __name__ == "__main__":
4
+ app()
git_ez/main.py ADDED
@@ -0,0 +1,125 @@
1
+ import subprocess
2
+ import re
3
+ import sys
4
+ import typer
5
+ import questionary
6
+ from rich import print
7
+
8
+ app = typer.Typer(help="CLI para generar commits inteligentes y rápidos.")
9
+
10
+
11
+ @app.callback(invoke_without_command=True)
12
+ def main(ctx: typer.Context):
13
+ """Ejecuta `commit` cuando no se indica subcomando (`git ez`)."""
14
+ if ctx.invoked_subcommand is None:
15
+ commit()
16
+
17
+
18
+ def get_git_branch() -> str:
19
+ """Obtiene el nombre de la rama Git actual."""
20
+ try:
21
+ result = subprocess.run(
22
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
23
+ capture_output=True, text=True, check=True
24
+ )
25
+ return result.stdout.strip()
26
+ except subprocess.CalledProcessError:
27
+ return ""
28
+
29
+ def get_staged_files() -> list[str]:
30
+ """Obtiene la lista de archivos actualmente en staging."""
31
+ try:
32
+ result = subprocess.run(
33
+ ["git", "diff", "--cached", "--name-only"],
34
+ capture_output=True, text=True, check=True
35
+ )
36
+ files = [f for f in result.stdout.strip().split("\n") if f]
37
+ return files
38
+ except subprocess.CalledProcessError:
39
+ return []
40
+
41
+ def extract_ticket_from_branch(branch_name: str) -> str:
42
+ """Extrae un ID de ticket (ej. ABC-123 o MELI-88) del nombre de la rama."""
43
+ match = re.search(r"([A-Za-z]+-\d+)", branch_name)
44
+ return match.group(1).upper() if match else ""
45
+
46
+ def generate_suggestions(files: list[str], ticket: str) -> list[str]:
47
+ """Genera opciones de mensajes basados en los archivos en staging."""
48
+ if not files:
49
+ return []
50
+
51
+ ticket_prefix = f"[{ticket}] " if ticket else ""
52
+
53
+ # Analizamos extensiones de archivos para inferir el 'scope'
54
+ has_docs = any(f.endswith(".md") or "docs/" in f for f in files)
55
+ has_tests = any("test" in f or "spec" in f for f in files)
56
+ has_config = any(f in ["package.json", "requirements.txt", "Dockerfile", "pyproject.toml"] for f in files)
57
+
58
+ suggestions = []
59
+
60
+ if has_docs and len(files) == 1:
61
+ suggestions.append(f"docs: {ticket_prefix}actualizar documentación ({files[0]})")
62
+
63
+ if has_tests:
64
+ suggestions.append(f"test: {ticket_prefix}agregar o actualizar pruebas unitarias")
65
+
66
+ if has_config:
67
+ suggestions.append(f"chore: {ticket_prefix}actualizar dependencias y configuración del proyecto")
68
+
69
+ # Opción genérica basada en la cantidad de archivos
70
+ file_summary = ", ".join([f.split("/")[-1] for f in files[:2]])
71
+ if len(files) > 2:
72
+ file_summary += f" y {len(files) - 2} más"
73
+
74
+ suggestions.append(f"feat: {ticket_prefix}actualizar {file_summary}")
75
+ suggestions.append(f"fix: {ticket_prefix}resolver problema en {file_summary}")
76
+
77
+ return suggestions
78
+
79
+ @app.command()
80
+ def commit():
81
+ """Analiza staging y abre el menú para hacer commit."""
82
+ staged_files = get_staged_files()
83
+
84
+ if not staged_files:
85
+ print("[bold yellow]⚠️ No hay archivos en staging.[/bold yellow] Usa [bold cyan]git add[/bold cyan] primero.")
86
+ raise typer.Exit()
87
+
88
+ branch = get_git_branch()
89
+ ticket = extract_ticket_from_branch(branch)
90
+ suggestions = generate_suggestions(staged_files, ticket)
91
+
92
+ # Opción para escribir algo personalizado
93
+ CUSTOM_OPTION = "✏️ Escribir un mensaje personalizado..."
94
+ choices = suggestions + [CUSTOM_OPTION]
95
+
96
+ print(f"[bold green]✓[/bold green] {len(staged_files)} archivo(s) detectado(s) en staging.")
97
+ if ticket:
98
+ print(f"[bold blue]ℹ[/bold blue] Ticket detectado en la rama: [bold]{ticket}[/bold]\n")
99
+
100
+ # Interfaz interactiva en la terminal
101
+ selected_message = questionary.select(
102
+ "Selecciona el mensaje para tu commit:",
103
+ choices=choices
104
+ ).ask()
105
+
106
+ if not selected_message:
107
+ print("[yellow]Operación cancelada.[/yellow]")
108
+ raise typer.Exit(code=1)
109
+
110
+ if selected_message == CUSTOM_OPTION:
111
+ selected_message = questionary.text("Escribe tu mensaje de commit:").ask()
112
+ if not selected_message:
113
+ print("[red]El mensaje no puede estar vacío.[/red]")
114
+ raise typer.Exit(code=1)
115
+
116
+ # Ejecutar el commit
117
+ try:
118
+ subprocess.run(["git", "commit", "-m", selected_message], check=True)
119
+ print(f"\n[bold green]🚀 Commit realizado con éxito:[/bold green] \"{selected_message}\"")
120
+ except subprocess.CalledProcessError:
121
+ print("\n[bold red]❌ Error al ejecutar git commit.[/bold red]")
122
+ raise typer.Exit(code=1)
123
+
124
+ if __name__ == "__main__":
125
+ app()
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.5
2
+ Name: git-ez
3
+ Version: 1.0.0
4
+ Summary: Generador interactivo y local de mensajes de commit bajo Conventional Commits, en español.
5
+ Project-URL: Homepage, https://github.com/AAMoralesC/GitEz
6
+ Project-URL: Repository, https://github.com/AAMoralesC/GitEz
7
+ Project-URL: Issues, https://github.com/AAMoralesC/GitEz/issues
8
+ Author-email: Andrés Morales <andresdremc@gmail.com>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Andrés Morales C
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: cli,commit,conventional-commits,git,typer
32
+ Classifier: Development Status :: 5 - Production/Stable
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Natural Language :: Spanish
37
+ Classifier: Operating System :: OS Independent
38
+ Classifier: Programming Language :: Python :: 3 :: Only
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Topic :: Software Development :: Version Control :: Git
44
+ Requires-Python: >=3.10
45
+ Requires-Dist: questionary>=2.0.0
46
+ Requires-Dist: rich>=13.0.0
47
+ Requires-Dist: typer>=0.9.0
48
+ Description-Content-Type: text/markdown
49
+
50
+ # GitEz 🚀
51
+
52
+ [![tests](https://github.com/AAMoralesC/GitEz/actions/workflows/tests.yml/badge.svg)](https://github.com/AAMoralesC/GitEz/actions/workflows/tests.yml)
53
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
54
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
55
+
56
+ > **Generador interactivo, ultrarrápido y local de mensajes de commit — en español.**
57
+
58
+ `GitEz` analiza los archivos que agregaste a *staging* (`git add .`) y te sugiere mensajes
59
+ estandarizados bajo **Conventional Commits**, redactados en español. Se ejecuta en milisegundos,
60
+ funciona 100% offline y no requiere API keys.
61
+
62
+ ---
63
+
64
+ ## 📸 Demo
65
+
66
+ ![Demo de GitEz en acción](./gitez_demo.png)
67
+
68
+ ---
69
+
70
+ ## ⚡ Características
71
+
72
+ - 🚀 **Ultra rápido:** sin llamadas a servicios externos ni LLMs de pago.
73
+ - 🔒 **100% privado:** todo el análisis ocurre en tu máquina.
74
+ - 🇪🇸 **Mensajes en español:** nativo, no traducciones automáticas.
75
+ - 🎯 **Sugerencias por contexto:** infiere el tipo de commit (`feat`, `fix`, `docs`, `test`, `chore`) según extensiones, documentación, tests y configuración.
76
+ - 🏷️ **Integración con tickets:** detecta el ID en el nombre de la rama (`feature/PROJ-42-login` → `PROJ-42`).
77
+ - ⌨️ **TUI fluida:** flechas y `Enter`, o escribe tu propio mensaje.
78
+
79
+ ---
80
+
81
+ ## 🧠 Sin IA, a propósito
82
+
83
+ GitEz no usa LLMs y es una decisión de diseño, no una limitación:
84
+
85
+ - **Privacidad:** tu código y tus nombres de archivo no salen de tu máquina.
86
+ - **Velocidad:** responde al instante, sin red ni latencia de modelo.
87
+ - **Determinismo:** el mismo staging produce la misma sugerencia, siempre.
88
+
89
+ Para un commit message el contexto útil son las rutas y extensiones de archivo, así que un LLM
90
+ añade costo, latencia y una dependencia externa sin mejorar el resultado.
91
+
92
+ ---
93
+
94
+ ## 📦 Instalación
95
+
96
+ ```bash
97
+ pipx install git-ez
98
+ ```
99
+
100
+ Si el paquete aún no aparece en PyPI, instala directo desde el repositorio:
101
+
102
+ ```bash
103
+ pipx install git+https://github.com/AAMoralesC/GitEz.git
104
+ ```
105
+
106
+ Con `pip` convencional:
107
+
108
+ ```bash
109
+ pip install git+https://github.com/AAMoralesC/GitEz.git
110
+ ```
111
+
112
+ ### Desarrollo local
113
+
114
+ ```bash
115
+ git clone https://github.com/AAMoralesC/GitEz.git
116
+ cd GitEz
117
+ pip install -e .
118
+ python -m unittest discover -s tests
119
+ ```
120
+
121
+ ### Actualización
122
+
123
+ ```bash
124
+ pipx upgrade git-ez
125
+ ```
126
+
127
+ ---
128
+
129
+ ## 💻 Uso
130
+
131
+ 1. Agrega tus cambios al staging como siempre:
132
+
133
+ ```bash
134
+ git add .
135
+ ```
136
+
137
+ 2. Ejecuta GitEz:
138
+
139
+ ```bash
140
+ git ez
141
+ ```
142
+
143
+ También funciona como `git-ez`, como `git ez commit`, o como `python -m git_ez`.
144
+
145
+ 3. Navega con `↑`/`↓`, elige una sugerencia o escribe tu propio mensaje, y presiona `Enter`.
146
+ El commit se ejecuta solo.
147
+
148
+ Ejemplo de mensajes generados:
149
+
150
+ | Tipo | Ejemplo |
151
+ |------|---------|
152
+ | `feat` | `feat: actualizar main.py, utils.py` |
153
+ | `fix` | `fix: resolver problema en auth.py` |
154
+ | `docs` | `docs: actualizar documentación (README.md)` |
155
+ | `test` | `test: agregar o actualizar pruebas unitarias` |
156
+ | `chore` | `chore: actualizar dependencias y configuración del proyecto` |
157
+
158
+ Con ticket en la rama (`feature/PROJ-42-login`):
159
+
160
+ ```
161
+ feat: [PROJ-42] actualizar main.py, utils.py
162
+ ```
163
+
164
+ **Requisitos:** Python 3.10+ y Git en el `PATH`. Probado en 3.10, 3.12 y 3.13.
165
+
166
+ ---
167
+
168
+ ## 🛠️ Stack
169
+
170
+ Python · [Typer](https://typer.tiangolo.com/) · [Questionary](https://questionary.readthedocs.io/) · [Rich](https://rich.readthedocs.io/)
171
+
172
+ ---
173
+
174
+ ## 🤝 Contribuciones
175
+
176
+ Issues y PRs son bienvenidos. Para cambios grandes, abre primero un issue.
177
+
178
+ ```bash
179
+ git checkout -b feature/mi-aporte
180
+ # ...cambios y tests...
181
+ git ez # 😉
182
+ ```
183
+
184
+ ---
185
+
186
+ ## 📄 Licencia
187
+
188
+ MIT — ver [LICENSE](./LICENSE).
@@ -0,0 +1,8 @@
1
+ git_ez/__init__.py,sha256=_AFgLphmHn1D_dXA0FYDOTqUh2rHLlm1LjiRw_YO3-A,78
2
+ git_ez/__main__.py,sha256=RCZmmoCNOWC7rAfIDm_LaymsybXIzE6McYbUEEkf9P8,60
3
+ git_ez/main.py,sha256=2Oou49fTbazOM9NXNjYXT7fHUZFecXYy5Ir1kDhzmH4,4480
4
+ git_ez-1.0.0.dist-info/METADATA,sha256=DOUfL7V4iMgYq-5-ELoh0irGVJQg_am0cb8C6a5UNyo,6134
5
+ git_ez-1.0.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
6
+ git_ez-1.0.0.dist-info/entry_points.txt,sha256=DdS_7kutyKDV7ULUIz8h6heV_o4GN_Ch6gtCRsOYI-4,43
7
+ git_ez-1.0.0.dist-info/licenses/LICENSE,sha256=xrmhxLSpS2jRaNaPlbJBulMlaex6trzAUMKIE7Mw450,1074
8
+ git_ez-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.33.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-ez = git_ez.main:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andrés Morales C
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.