Compare commits

..
16 Commits
Author SHA1 Message Date
jt 14ec438fa1 Merge pull request 'feature: change exit code to 3 when no tag is needed, and skip build / publish in that case' (#71) from feature/no-tag-different-exit-code into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 43s
Reviewed-on: #71
2026-09-29 14:26:22 +00:00
Jonathan Teran 98d5c4ab3d feature: change exit code to 3 when no tag is needed, and skip build / publish in that case 2026-09-29 11:19:46 -03:00
jt 5cff0e4484 Merge pull request 'bugfix: only abort merge when is needed' (#70) from bugfix/abort-merge-when-necessary into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 22s
Reviewed-on: #70
2026-09-28 17:35:38 +00:00
jt 61712b0872 bugfix: only abort merge when is needed 2026-09-28 14:35:10 -03:00
jt 98f71d5481 Merge pull request 'bugfix: commit small improvements' (#69) from bugfix/commit-small-improvements into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 45s
Reviewed-on: #69
2026-09-28 17:27:53 +00:00
jt 76dd177421 refactor: inform instead of confirming current branch 2026-09-28 14:27:28 -03:00
jt e2e1c4b417 feature: change table border style 2026-09-28 14:23:49 -03:00
jt e13beae279 feature: show table with staged changes before comit 2026-09-28 14:22:49 -03:00
jt d54c740748 Merge pull request 'Bugfix/missing click module' (#68) from bugfix/missing-click-module into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 44s
Reviewed-on: #68
2026-09-28 13:04:28 +00:00
jt 86a2768c81 bugfix: remove import click and supress typer errors only 2026-09-28 10:03:39 -03:00
jt 9dee43705a clean: delete test csv 2026-09-28 09:57:30 -03:00
jt aacc5b90e2 bugfix: prevent commits on environments 2026-09-26 21:15:20 -03:00
jt 103eb1137a Merge pull request 'feature: add branch types, commit types, support for breaking changes' (#67) from feature/extend-branch-and-commit-types into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 16s
Reviewed-on: #67
2026-09-26 21:12:39 +00:00
jt e9d88b8113 feature: add branch types, commit types, support for breaking changes 2026-09-26 18:12:14 -03:00
jt 6e760f7866 Merge pull request 'feature: show commit lists in merge and rebase in a table' (#66) from feature/display-commits-in-table into main
Publish to PyPI / Bump-Build-Publish (push) Successful in 18s
Reviewed-on: #66
2026-09-26 20:40:22 +00:00
jt 67eb6fb6d1 feature: show commit lists in merge and rebase in a table 2026-09-26 17:38:05 -03:00
13 changed files with 224 additions and 72 deletions
+11 -1
View File
@@ -22,12 +22,22 @@ jobs:
id: version id: version
run: | run: |
pip install git-flow-envs=="${{ vars.GITFLOWENVS_VERSION }}" pip install git-flow-envs=="${{ vars.GITFLOWENVS_VERSION }}"
git-flow tag --token="${{ secrets.GITEA_TOKEN }}" # El código 3 indica que no hace falta un nuevo tag: se saltea la publicación
status=0
git-flow tag --token="${{ secrets.GITEA_TOKEN }}" || status=$?
if [ "$status" -eq 3 ]; then
echo "skip=true" >> "$GITHUB_OUTPUT"
elif [ "$status" -ne 0 ]; then
exit "$status"
fi
- name: Install uv - name: Install uv
if: steps.version.outputs.skip != 'true'
uses: astral-sh/setup-uv@v8.3.2 uses: astral-sh/setup-uv@v8.3.2
- name: Build and publish - name: Build and publish
if: steps.version.outputs.skip != 'true'
run: | run: |
uv build uv build
uv publish --token="${{ secrets.PYPI_TOKEN }}" uv publish --token="${{ secrets.PYPI_TOKEN }}"
+13 -2
View File
@@ -53,7 +53,7 @@ más información):
- `init`: Inicializa el repositorio para utilizar git-flow (ramas principales y remoto). - `init`: Inicializa el repositorio para utilizar git-flow (ramas principales y remoto).
- `new`: Crea una nueva rama siguiendo CB. - `new`: Crea una nueva rama siguiendo CB.
- `commit`: Crea un commit siguiendo CC. - `commit`: Crea un commit siguiendo CC. No permite commitear directamente sobre un entorno.
- `merge`: Mergea la rama actual a uno de los entornos. - `merge`: Mergea la rama actual a uno de los entornos.
- `tag`: Crea un tag sobre el ultimo merge siguiendo SemVer (ver [Tag](#tag)). - `tag`: Crea un tag sobre el ultimo merge siguiendo SemVer (ver [Tag](#tag)).
- `release`: Prepara la rama actual para pasarse al siguiente entorno configurado. - `release`: Prepara la rama actual para pasarse al siguiente entorno configurado.
@@ -102,7 +102,18 @@ Comportamiento:
- El tag se crea sobre el último merge (first-parent) de la rama. Si ese merge ya tiene un tag, no se - El tag se crea sobre el último merge (first-parent) de la rama. Si ese merge ya tiene un tag, no se
hace nada. hace nada.
- La versión se calcula a partir de los tipos de commit (CC) del último merge. Si ningún commit - La versión se calcula a partir de los tipos de commit (CC) del último merge. Si ningún commit
implica un salto de versión, se avisa y el comando termina con código de salida 1. implica un salto de versión, se avisa y el comando termina con código de salida 1. Se toma el
mayor incremento entre los commits:
| Tipo de commit | Incremento |
| -------------------------------------------------------------- | ---------- |
| cualquier tipo marcado como breaking (`feature!: ...`) | major |
| `feature` (o `feat`) | minor |
| `bugfix` (o `fix`), `hotfix`, `refactor`, `perf`, `revert` | patch |
| `docs`, `style`, `test`, `build`, `ci`, `chore`, `wip` | ninguno |
| personalizado (opción `otro` en `git-flow commit`) | ninguno |
`git-flow commit` pregunta si el commit es un breaking change (salvo en commits `wip`).
- Con más de un entorno configurado, cada rama versiona por separado con el nombre del entorno como - Con más de un entorno configurado, cada rama versiona por separado con el nombre del entorno como
sufijo (por ejemplo, `v1.2.0-prod`). Con un solo entorno no se agrega sufijo. sufijo (por ejemplo, `v1.2.0-prod`). Con un solo entorno no se agrega sufijo.
- Si el merge viene del entorno anterior (por ejemplo, `dev` a `test`), no se calcula una nueva - Si el merge viene del entorno anterior (por ejemplo, `dev` a `test`), no se calcula una nueva
-14
View File
@@ -1,14 +0,0 @@
image: python:3.10
pipelines:
branches:
'main':
- step:
name: "Tag and publish package"
caches:
- pip
script:
- pip install uv
- uv run git-flow tag --token=$BEARER
- uv build
- uv publish --token=$PYPI_TOKEN
-2
View File
@@ -1,2 +0,0 @@
name,commit sha,author,date
worktree-kind-watching-hearth,e8c0c0b777d31fa94cd3f01fbf9c68b165d77015,Jonathan Teran Carballo,2026-09-13T23:18:47-03:00
1 name commit sha author date
2 worktree-kind-watching-hearth e8c0c0b777d31fa94cd3f01fbf9c68b165d77015 Jonathan Teran Carballo 2026-09-13T23:18:47-03:00
+28 -9
View File
@@ -1,15 +1,6 @@
GitFlowError = ValueError GitFlowError = ValueError
BRANCH_TYPES = [ BRANCH_TYPES = [
"feature",
"refactor",
"bugfix",
"hotfix",
"chore",
"docs",
]
COMMIT_TYPES = [
"feature", "feature",
"bugfix", "bugfix",
"hotfix", "hotfix",
@@ -18,6 +9,24 @@ COMMIT_TYPES = [
"docs", "docs",
"style", "style",
"test", "test",
"build",
"ci",
"chore",
]
COMMIT_TYPES = [
"feature",
"bugfix",
"hotfix",
"refactor",
"perf",
"revert",
"docs",
"style",
"test",
"build",
"ci",
"chore",
"wip", "wip",
] ]
@@ -32,15 +41,25 @@ SEMVER_PATCH = 1
# Commits con estos tipos no alteran la versión # Commits con estos tipos no alteran la versión
SEMVER_SKIP = 0 SEMVER_SKIP = 0
# Un commit marcado como breaking change (<tipo>!: <mensaje>) incrementa SEMVER_MAJOR sin importar
# el tipo. Los tipos que no figuran aquí no alteran la versión.
COMMIT_TYPE_INCREMENT = { COMMIT_TYPE_INCREMENT = {
"feature": SEMVER_MINOR, "feature": SEMVER_MINOR,
"bugfix": SEMVER_PATCH, "bugfix": SEMVER_PATCH,
"hotfix": SEMVER_PATCH, "hotfix": SEMVER_PATCH,
"refactor": SEMVER_PATCH, "refactor": SEMVER_PATCH,
"perf": SEMVER_PATCH, "perf": SEMVER_PATCH,
"revert": SEMVER_PATCH,
"docs": SEMVER_SKIP, "docs": SEMVER_SKIP,
"style": SEMVER_SKIP, "style": SEMVER_SKIP,
"test": SEMVER_SKIP, "test": SEMVER_SKIP,
"build": SEMVER_SKIP,
"ci": SEMVER_SKIP,
"chore": SEMVER_SKIP,
"wip": SEMVER_SKIP,
# Alias de Conventional Commits, para commits creados fuera de git-flow
"feat": SEMVER_MINOR,
"fix": SEMVER_PATCH,
} }
SUPPORTED_REMOTE_URL_SCHEMAS = [ SUPPORTED_REMOTE_URL_SCHEMAS = [
+81 -6
View File
@@ -1,11 +1,16 @@
import re
import time
from os.path import isfile from os.path import isfile
import questionary import questionary
import rich import rich
import rich.panel import rich.panel
from rich import box
from rich.table import Table
from git_flow import ( from git_flow import (
BRANCH_TYPES, BRANCH_TYPES,
COMMIT_TYPE_INCREMENT,
COMMIT_TYPES, COMMIT_TYPES,
FLOWCONFIG_FILENAME, FLOWCONFIG_FILENAME,
FLOWCONFIG_VERSION, FLOWCONFIG_VERSION,
@@ -47,15 +52,14 @@ def ensure_initialized():
) )
def ensure_right_branch(): def ensure_on_branch():
branch = Git.get_current_branch() branch = Git.get_current_branch()
if branch == "HEAD": if branch == "HEAD":
raise GitFlowError("No se encuentra parado sobre una rama.") raise GitFlowError("No se encuentra parado sobre una rama.")
elif io_confirm(f"Rama actual: {branch}. ¿Es correcto?"):
return branch io_info(f"Rama actual: {branch}")
else: return branch
raise GitFlowError("Ejecución cancelada.")
def get_branch_env_and_type(branch: str) -> tuple[str, str]: def get_branch_env_and_type(branch: str) -> tuple[str, str]:
@@ -152,8 +156,30 @@ def is_valid_ticket(ticket: str) -> bool:
) )
CUSTOM_COMMIT_TYPE_OPTION = "otro"
def get_commit_message(commit_types: list[str] = COMMIT_TYPES) -> str: def get_commit_message(commit_types: list[str] = COMMIT_TYPES) -> str:
commit_type = io_choice("Tipo de commit", commit_types) commit_type = io_choice("Tipo de commit", commit_types + [CUSTOM_COMMIT_TYPE_OPTION])
if commit_type == CUSTOM_COMMIT_TYPE_OPTION:
commit_type = io_prompt(
"Tipo de commit personalizado",
strip=True,
validator=lambda s: re.fullmatch(r"\w+", s.strip()) is not None,
instruction="letras, números o _",
)
if commit_type not in COMMIT_TYPE_INCREMENT:
io_warning(
f"El tipo '{commit_type}' no produce un salto de versión, "
"salvo que se marque como breaking change."
)
# Los commits WIP se squashean en uno final, que es el que puede marcarse como breaking
if commit_type != "wip" and io_confirm("¿Es un breaking change?", False):
commit_type += "!"
commit_message = io_prompt( commit_message = io_prompt(
"Mensaje de commit", "Mensaje de commit",
validator=lambda s: 0 < len(s) and len(s) < 100, validator=lambda s: 0 < len(s) and len(s) < 100,
@@ -162,6 +188,55 @@ def get_commit_message(commit_types: list[str] = COMMIT_TYPES) -> str:
return commit_type + ": " + commit_message return commit_type + ": " + commit_message
# <tipo>[(alcance)][!]: <mensaje>, para no confundir "Merge pull request 'feature: ...'" con un tipo
COMMIT_SUBJECT_RE = re.compile(r"^(\w+)(?:\([^)]*\))?(!)?:\s*(.*)$")
def show_commits(title: str, revision_range: str):
"""Muestra en una tabla los commits del rango (fecha relativa, tipo y mensaje).
Si no hay commits aborta, ya que no hay nada para mergear."""
# fecha de autor: la de commit cambia al hacer rebase (por ejemplo, en release)
lines = Git("log", revision_range, format="%at%x09%s").lines()
if not lines:
raise GitFlowError("No hay cambios a mergear.")
table = Table(title=title, title_justify="left", title_style="bold", box=box.SQUARE)
table.add_column("Fecha", style="dim", no_wrap=True)
table.add_column("Tipo", style="cyan", no_wrap=True)
table.add_column("Mensaje")
now = time.time()
for line in lines:
timestamp, subject = line.split("\t", 1)
match = COMMIT_SUBJECT_RE.match(subject)
commit_type, breaking, message = match.groups() if match else ("-", None, subject)
commit_type += breaking or ""
table.add_row(format_time_ago(now - int(timestamp)), commit_type, message)
console.print(table)
def format_time_ago(seconds: float) -> str:
units = [
(365 * 24 * 3600, "año", "años"),
(30 * 24 * 3600, "mes", "meses"),
(7 * 24 * 3600, "semana", "semanas"),
(24 * 3600, "día", "días"),
(3600, "hora", "horas"),
(60, "minuto", "minutos"),
]
for size, singular, plural in units:
amount = int(seconds // size)
if amount >= 1:
return f"hace {amount} {singular if amount == 1 else plural}"
return "hace un momento"
def io_error(message: str, title: str | None = None): def io_error(message: str, title: str | None = None):
_io_status(message, "✖ Error: ", "red", title) _io_status(message, "✖ Error: ", "red", title)
+60 -7
View File
@@ -1,10 +1,13 @@
from datetime import datetime from datetime import datetime
import typer import typer
from rich import box
from rich.table import Table
import git_flow.command.base as base
from git_flow import TRASH_BRANCH_PREFIX, WIP_BRANCH_PREFIX, GitFlowError from git_flow import TRASH_BRANCH_PREFIX, WIP_BRANCH_PREFIX, GitFlowError
from git_flow.command import base
from git_flow.git import Git from git_flow.git import Git
from git_flow.io import console
app = typer.Typer() app = typer.Typer()
@@ -13,7 +16,16 @@ app = typer.Typer()
def commit(): def commit():
"""Crea un commit siguiendo el formato de Conventional Commits""" """Crea un commit siguiendo el formato de Conventional Commits"""
base.ensure_initialized() base.ensure_initialized()
branch = base.ensure_right_branch() branch = base.ensure_on_branch()
# Una rama WIP termina squasheando en su rama original, que tampoco puede ser un entorno
target_branch = branch.removeprefix(WIP_BRANCH_PREFIX)
if target_branch in base.environments:
raise GitFlowError(
f"No se puede commitear directamente sobre el entorno '{target_branch}'. "
"Debe crear una rama de trabajo con el comando `new`."
)
if not _has_files_staged(): if not _has_files_staged():
base.io_warning("No hay cambios en el indice para commitear.") base.io_warning("No hay cambios en el indice para commitear.")
@@ -22,6 +34,11 @@ def commit():
else: else:
raise GitFlowError("Debe agregar algún cambio al indice para continuar.") raise GitFlowError("Debe agregar algún cambio al indice para continuar.")
_show_index()
if not base.io_confirm("¿Desea commitear estos cambios?"):
raise GitFlowError("Ejecución cancelada.")
message = base.get_commit_message() message = base.get_commit_message()
commit_type = message[: message.index(":")] commit_type = message[: message.index(":")]
@@ -54,10 +71,46 @@ def _has_files_staged():
if not status: if not status:
raise GitFlowError("No hay cambios para commitear.") raise GitFlowError("No hay cambios para commitear.")
files_in_index = [] return any(_is_staged(s) for s in status)
for s in status:
if s.worktree != "?" and s.worktree != " ":
files_in_index.append(s.file)
return len(files_in_index) > 0 def _is_staged(s: Git.Status) -> bool:
return s.index != "?" and s.index != " "
INDEX_STATES = {
"M": "modificado",
"T": "cambio de tipo",
"A": "agregado",
"D": "eliminado",
"R": "renombrado",
"C": "copiado",
"U": "en conflicto",
}
def _show_index():
"""Muestra en una tabla los archivos del indice (los que entran en el commit), e informa
cuántos archivos quedan con cambios fuera del indice."""
status = Git.status()
staged = [s for s in status if _is_staged(s)]
not_staged = [s for s in status if s.worktree != " "]
table = Table(
title="Cambios a commitear",
title_justify="left",
title_style="bold",
box=box.SQUARE,
)
table.add_column("Estado", style="cyan", no_wrap=True)
table.add_column("Archivo")
for s in staged:
table.add_row(INDEX_STATES.get(s.index, s.index), s.file)
console.print(table)
if not_staged:
base.io_info(
f"{len(not_staged)} archivo(s) con cambios fuera del indice no se incluirán en el commit."
)
+5 -11
View File
@@ -15,7 +15,7 @@ def merge():
"""Realiza el merge de la rama, o crea el PR para hacerlo si tiene un remoto configurado""" """Realiza el merge de la rama, o crea el PR para hacerlo si tiene un remoto configurado"""
base.ensure_initialized() base.ensure_initialized()
branch = base.ensure_right_branch() branch = base.ensure_on_branch()
if branch in base.environments: if branch in base.environments:
if branch == base.environments[-1]: if branch == base.environments[-1]:
@@ -71,15 +71,7 @@ def run_local(branch: str, target: str):
def show_commits_to_merge(target): def show_commits_to_merge(target):
commits = Git("log", target + "..", format="%s").lines() base.show_commits("Cambios a mergear", target + "..")
if not commits:
raise GitFlowError("No hay cambios a mergear.")
print("Cambios a mergear:")
for commit in commits:
print("- " + commit)
def check_merge_conflicts(target: str): def check_merge_conflicts(target: str):
@@ -87,7 +79,9 @@ def check_merge_conflicts(target: str):
print="Realizando merge de prueba para verificar conflictos" print="Realizando merge de prueba para verificar conflictos"
) )
Git("merge", abort=True).exec(print="Abortando merge de prueba", check=False) # Si el merge no llegó a realizarse (por ejemplo, "Already up to date") no hay nada que abortar
if Git.is_merging():
Git("merge", abort=True).exec(print="Abortando merge de prueba")
if merge_conflicts: if merge_conflicts:
base.io_error( base.io_error(
+1 -1
View File
@@ -14,7 +14,7 @@ def new():
"""Crea una nueva rama siguiendo Conventional Branches""" """Crea una nueva rama siguiendo Conventional Branches"""
base.ensure_initialized() base.ensure_initialized()
branch = base.ensure_right_branch() branch = base.ensure_on_branch()
if branch not in base.environments: if branch not in base.environments:
base.io_warning("La rama actual no corresponde a un entorno configurado.") base.io_warning("La rama actual no corresponde a un entorno configurado.")
+2 -10
View File
@@ -12,7 +12,7 @@ def release():
"""Realiza el merge de la rama, o crea el PR para hacerlo si tiene un remoto configurado""" """Realiza el merge de la rama, o crea el PR para hacerlo si tiene un remoto configurado"""
base.ensure_initialized() base.ensure_initialized()
branch = base.ensure_right_branch() branch = base.ensure_on_branch()
env, _ = base.get_branch_env_and_type(branch) env, _ = base.get_branch_env_and_type(branch)
if env == base.environments[-1]: if env == base.environments[-1]:
@@ -32,15 +32,7 @@ def release():
) )
fork_point = Git.get_first_fork_point(branch, env) fork_point = Git.get_first_fork_point(branch, env)
commits = Git("log", fork_point + "..", format="%s").lines() base.show_commits("Cambios a pasar al próximo entorno", fork_point + "..")
if not commits:
raise GitFlowError("No hay cambios a mergear.")
print("Cambios a pasar al proximo entorno:")
for commit in commits:
print("- " + commit)
if has_remote and Git.get_tracking_branch(next_env): if has_remote and Git.get_tracking_branch(next_env):
Git("switch", next_env).exec(print="Cambiando a la rama objetivo") Git("switch", next_env).exec(print="Cambiando a la rama objetivo")
+13 -4
View File
@@ -14,6 +14,9 @@ from git_flow.git import Git
app = typer.Typer() app = typer.Typer()
# Código de salida cuando no hace falta crear un tag, para que el CI pueda saltear la publicación
EXIT_NO_TAG_NEEDED = 3
@app.command() @app.command()
def tag(target: str | None = None, token: str | None = None, update_changelog: bool = False): def tag(target: str | None = None, token: str | None = None, update_changelog: bool = False):
@@ -35,7 +38,7 @@ def tag(target: str | None = None, token: str | None = None, update_changelog: b
merge_commit_tag = Git("tag", "--points-at", merge_commit).firstline() merge_commit_tag = Git("tag", "--points-at", merge_commit).firstline()
if merge_commit_tag: if merge_commit_tag:
base.io_info(f"El último merge ya tiene un tag: {merge_commit_tag}") base.io_info(f"El último merge ya tiene un tag: {merge_commit_tag}")
return raise typer.Exit(code=EXIT_NO_TAG_NEEDED)
token, ci = get_token_and_ci(token) token, ci = get_token_and_ci(token)
@@ -97,7 +100,7 @@ def tag(target: str | None = None, token: str | None = None, update_changelog: b
"Los cambios realizados no implican un salto de versión, se mantiene la anterior." "Los cambios realizados no implican un salto de versión, se mantiene la anterior."
) )
raise typer.Exit(code=1) raise typer.Exit(code=EXIT_NO_TAG_NEEDED)
if update_changelog: if update_changelog:
changelog = Changelog() changelog = Changelog()
@@ -128,8 +131,14 @@ def get_next_tag_from_commits(
) -> str | None: ) -> str | None:
increment = SEMVER_SKIP increment = SEMVER_SKIP
for commit in commits: for commit in commits:
commit_type = commit.partition(":")[0] match = base.COMMIT_SUBJECT_RE.match(commit)
increment = max(increment, COMMIT_TYPE_INCREMENT.get(commit_type, SEMVER_SKIP))
if not match:
continue
commit_type, breaking, _ = match.groups()
commit_increment = SEMVER_MAJOR if breaking else COMMIT_TYPE_INCREMENT.get(commit_type)
increment = max(increment, commit_increment or SEMVER_SKIP)
if increment == SEMVER_SKIP: if increment == SEMVER_SKIP:
return None return None
+9 -3
View File
@@ -26,8 +26,9 @@ class Git:
file: str file: str
def __init__(self, line: str) -> None: def __init__(self, line: str) -> None:
self.worktree = line[0] # Formato porcelain "XY <file>": X es el estado en el indice, Y en el worktree
self.index = line[1] self.index = line[0]
self.worktree = line[1]
self.file = line[3:].strip("\n") self.file = line[3:].strip("\n")
command: list[str] command: list[str]
@@ -62,6 +63,11 @@ class Git:
def get_branches(prefix: str = ""): def get_branches(prefix: str = ""):
return Git._get_references("heads/" + prefix) return Git._get_references("heads/" + prefix)
@staticmethod
def is_merging() -> bool:
"""Indica si hay un merge en curso (existe MERGE_HEAD), con o sin conflictos."""
return Git("rev-parse", "MERGE_HEAD", quiet=True, verify=True).code() == 0
@staticmethod @staticmethod
def status(): def status():
return list(map(Git.Status, Git("status", porcelain=True).lines(False))) return list(map(Git.Status, Git("status", porcelain=True).lines(False)))
@@ -170,7 +176,7 @@ class Git:
process = self._get(**kwargs) process = self._get(**kwargs)
lines = process.stdout.splitlines() lines = process.stdout.splitlines()
return lines if not strip else list(map(lambda l: l.strip(), lines)) return lines if not strip else [l.strip() for l in lines]
def firstline(self, **kwargs): def firstline(self, **kwargs):
lines = self.lines(**kwargs) lines = self.lines(**kwargs)
+1 -2
View File
@@ -3,7 +3,6 @@
from subprocess import CalledProcessError, SubprocessError from subprocess import CalledProcessError, SubprocessError
from typing import Annotated from typing import Annotated
import click
import typer import typer
from rich.markup import escape from rich.markup import escape
from rich.traceback import Traceback from rich.traceback import Traceback
@@ -70,7 +69,7 @@ def _print_error(message: str, title: str, e: BaseException):
base.io_error(message, title=title) base.io_error(message, title=title)
console.print( console.print(
Traceback.from_exception( Traceback.from_exception(
type(e), e, e.__traceback__, suppress=[click, typer] type(e), e, e.__traceback__, suppress=[typer]
) )
) )
else: else: