Merge pull request 'feature: add verbose flag, improve command output, improve error display' (#64) from feature/improve-verbose-output into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 45s
Publish to PyPI / Bump-Build-Publish (push) Successful in 45s
Reviewed-on: #64
This commit was merged in pull request #64.
This commit is contained in:
@@ -62,6 +62,9 @@ más información):
|
||||
`--remote`), dejando un reporte CSV (`branch-clean-report.csv`) con nombre, commit, autor y
|
||||
fecha de cada rama eliminada.
|
||||
|
||||
Por defecto solo se muestra cada paso que se ejecuta. Con `git-flow --verbose <command>` (o `-v`) se
|
||||
muestra además la salida de cada comando git y el traceback completo de los errores.
|
||||
|
||||
El workflow para el cual se penso la herramienta es el siguiente:
|
||||
|
||||
1. Sobre la primer rama principal configurada (por ejemplo, `dev`), se crea una nueva rama con
|
||||
|
||||
+30
-10
@@ -1,6 +1,10 @@
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
|
||||
from rich.markup import escape
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
|
||||
from git_flow import FLOWCONFIG_FILENAME
|
||||
from git_flow.io import *
|
||||
|
||||
@@ -180,10 +184,13 @@ class Git:
|
||||
self._run(**kwargs)
|
||||
|
||||
def _get(self, print: str | None = None, check: bool = True):
|
||||
process = subprocess.run(self.command, capture_output=True, text=True)
|
||||
process = subprocess.run(self.command, capture_output=True, text=True, check=False)
|
||||
|
||||
if print is not None:
|
||||
self._print_process(process.stdout, process.stderr, print)
|
||||
# Sin --verbose solo se muestra el paso; si falla, la salida la muestra main()
|
||||
if print is not None and settings.verbose:
|
||||
self._print_process(process, print)
|
||||
elif print is not None:
|
||||
console.print(Text.assemble(("› ", "cyan"), print))
|
||||
|
||||
if check:
|
||||
process.check_returncode()
|
||||
@@ -193,7 +200,7 @@ class Git:
|
||||
def _run(self, print: str | None = None, check: bool = True):
|
||||
return self._get(print, check)
|
||||
|
||||
def _print_process(self, stdout: str, stderr: str, title: str):
|
||||
def _print_process(self, process: subprocess.CompletedProcess, title: str | None):
|
||||
command = []
|
||||
|
||||
for arg in self.command:
|
||||
@@ -205,12 +212,25 @@ class Git:
|
||||
|
||||
command.append(arg)
|
||||
|
||||
text = f"[green]$ {' '.join(command)}[/green]"
|
||||
ok = process.returncode == 0
|
||||
# git escribe mensajes informativos en stderr, así que solo se resalta si falló
|
||||
stderr_style = "dim" if ok else "red"
|
||||
text = Text.assemble(("$ ", "dim"), (" ".join(command), "bold yellow"))
|
||||
|
||||
for line in stdout.splitlines():
|
||||
text += "\n" + line
|
||||
for line in process.stdout.splitlines():
|
||||
text.append("\n" + line)
|
||||
|
||||
for line in stderr.splitlines():
|
||||
text += "\n[red]" + line + "[/red]"
|
||||
for line in process.stderr.splitlines():
|
||||
text.append("\n" + line, stderr_style)
|
||||
|
||||
panel(title or "Ejecutando", text)
|
||||
console.print(
|
||||
Panel(
|
||||
text,
|
||||
title=f"[bold]{escape(title or 'Ejecutando')}[/bold]",
|
||||
title_align="left",
|
||||
subtitle=None if ok else f"código de salida {process.returncode}",
|
||||
subtitle_align="right",
|
||||
border_style="bright_black" if ok else "red",
|
||||
expand=False,
|
||||
)
|
||||
)
|
||||
|
||||
+10
-1
@@ -1,10 +1,19 @@
|
||||
from rich.console import Console
|
||||
from rich.prompt import Prompt, Confirm
|
||||
from rich.panel import Panel
|
||||
from rich.prompt import Confirm, Prompt
|
||||
|
||||
console = Console(highlight=False)
|
||||
|
||||
|
||||
class Settings:
|
||||
"""Opciones globales de ejecución, configuradas desde la línea de comandos."""
|
||||
|
||||
verbose: bool = False
|
||||
|
||||
|
||||
settings = Settings()
|
||||
|
||||
|
||||
def success(msg: str):
|
||||
console.print(f":white_check_mark: [green]{msg}[/green]")
|
||||
|
||||
|
||||
+50
-6
@@ -1,12 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import traceback
|
||||
from subprocess import SubprocessError
|
||||
from subprocess import CalledProcessError, SubprocessError
|
||||
from typing import Annotated
|
||||
|
||||
import click
|
||||
import typer
|
||||
from rich.markup import escape
|
||||
from rich.traceback import Traceback
|
||||
|
||||
from git_flow import GitFlowError
|
||||
from git_flow.command import base, branch, commit, init, merge, new, release, tag
|
||||
from git_flow.io import console, settings
|
||||
|
||||
REPOSITORY_TOKEN_PATH = ".repository-token"
|
||||
LOCALE = "es_AR.UTF-8"
|
||||
@@ -22,15 +26,55 @@ app.add_typer(release.app)
|
||||
app.add_typer(branch.app)
|
||||
|
||||
|
||||
@app.callback()
|
||||
def options(
|
||||
verbose: Annotated[
|
||||
bool,
|
||||
typer.Option(
|
||||
"--verbose",
|
||||
"-v",
|
||||
help="Muestra la salida de los comandos git y el traceback de los errores",
|
||||
),
|
||||
] = False,
|
||||
):
|
||||
settings.verbose = verbose
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
app()
|
||||
print()
|
||||
except GitFlowError as e:
|
||||
lines = [str(e), ""]
|
||||
lines += traceback.format_exception(e)
|
||||
base.io_error("".join(lines), title="Git Flow")
|
||||
_print_error(escape(str(e)), "Git Flow", e)
|
||||
except CalledProcessError as e:
|
||||
_print_error(_format_process_error(e), "Comando", e)
|
||||
except SubprocessError as e:
|
||||
base.io_error(str(e), title="Comando")
|
||||
_print_error(escape(str(e)), "Comando", e)
|
||||
except KeyboardInterrupt:
|
||||
base.io_error("Ejecución abortada")
|
||||
|
||||
|
||||
def _format_process_error(e: CalledProcessError) -> str:
|
||||
command = " ".join(e.cmd) if isinstance(e.cmd, list) else str(e.cmd)
|
||||
message = f"[bold]$ {escape(command)}[/bold]\nTerminó con código de salida {e.returncode}"
|
||||
|
||||
for output in (e.stdout, e.stderr):
|
||||
if isinstance(output, str) and output.strip():
|
||||
message += "\n\n" + escape(output.strip())
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def _print_error(message: str, title: str, e: BaseException):
|
||||
if settings.verbose:
|
||||
base.io_error(message, title=title)
|
||||
console.print(
|
||||
Traceback.from_exception(
|
||||
type(e), e, e.__traceback__, suppress=[click, typer]
|
||||
)
|
||||
)
|
||||
else:
|
||||
base.io_error(
|
||||
message + "\n\n[dim]Ejecutar con `git-flow --verbose <comando>` para ver el detalle[/dim]",
|
||||
title=title,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user