feature: update I/O methods to use questionary where applicable #2

Merged
jt merged 14 commits from feature/refactor-use-questionary-package into main 2026-07-18 01:12:23 +00:00
2 changed files with 53 additions and 13 deletions
Showing only changes of commit 069c33bc17 - Show all commits
+50 -12
View File
@@ -18,9 +18,11 @@ import rich
import rich.panel import rich.panel
import questionary import questionary
flowconfig = Git.get_config(FLOWCONFIG_FILENAME) if isfile(FLOWCONFIG_FILENAME) else {} flowconfig = Git.get_config(FLOWCONFIG_FILENAME) if isfile(FLOWCONFIG_FILENAME) else {}
environments = flowconfig["flow.branches"].split(",") if "flow.branches" in flowconfig else [] environments = (
flowconfig["flow.branches"].split(",") if "flow.branches" in flowconfig else []
)
def ensure_initialized(): def ensure_initialized():
initialized = flowconfig["flow.initialized"] if flowconfig else None initialized = flowconfig["flow.initialized"] if flowconfig else None
@@ -118,7 +120,8 @@ def get_remote_api(token: str) -> RemoteAPI:
[schema, host, repository] = RemoteAPI.parse(flowconfig["flow.remote"]) [schema, host, repository] = RemoteAPI.parse(flowconfig["flow.remote"])
if remote_type == "gitea": if remote_type == "gitea":
return GiteaRemoteAPI(("https://" if schema == "ssh://" else schema) + host, repository, token) remote_schema = "https://" if schema == "ssh://" else schema
return GiteaRemoteAPI(remote_schema + host, repository, token)
elif remote_type == "bitbucket": elif remote_type == "bitbucket":
return BitbucketRemoteAPI(repository, token) return BitbucketRemoteAPI(repository, token)
elif remote_type == "github": elif remote_type == "github":
@@ -133,40 +136,75 @@ def is_valid_ticket(ticket: str) -> bool:
if len(components) != 2: if len(components) != 2:
return False return False
ticket_project = components[0] ticket_project = components[0]
ticket_number = components[1] ticket_number = components[1]
return ticket_project.isalpha() and ticket_project.isupper() and ticket_number.isnumeric() return (
ticket_project.isalpha()
and ticket_project.isupper()
and ticket_number.isnumeric()
)
def io_error(message: str, title: Optional[str] = None): def io_error(message: str, title: Optional[str] = None):
_io_status(message, "✖ Error: ", "red", title) _io_status(message, "✖ Error: ", "red", title)
def io_warning(message: str, title: Optional[str] = None): def io_warning(message: str, title: Optional[str] = None):
_io_status(message, "⚠ Warning: ", "yellow", title) _io_status(message, "⚠ Warning: ", "yellow", title)
def io_info(message: str, title: Optional[str] = None): def io_info(message: str, title: Optional[str] = None):
_io_status(message, " Info: ", "blue", title) _io_status(message, " Info: ", "blue", title)
def io_success(message: str, title: Optional[str] = None): def io_success(message: str, title: Optional[str] = None):
_io_status(message, "✔ Success: ", "green", title) _io_status(message, "✔ Success: ", "green", title)
def _io_status(message: str, prefix: str, style: str, title: Optional[str] = None): def _io_status(message: str, prefix: str, style: str, title: Optional[str] = None):
if title: if title:
rich.print(rich.panel.Panel(message, title=prefix + title, style=style, expand=False, title_align="left")) rich.print(
rich.panel.Panel(
message,
title=prefix + title,
style=style,
expand=False,
title_align="left",
)
)
else: else:
rich.print(f"[{style}]{prefix}{message}[/{style}]") rich.print(f"[{style}]{prefix}{message}[/{style}]")
def io_confirm(question: str, default: bool = True) -> bool: def io_confirm(question: str, default: bool = True) -> bool:
return questionary.confirm(question, default=default, auto_enter=False).ask() return questionary.confirm(question, default=default, auto_enter=False).ask()
def io_choice(prompt: str, options: list[str]) -> str:
return questionary.select(prompt, options, use_search_filter=True, use_jk_keys=False, instruction="Tipear o usar flechas").ask()
def io_prompt(message: str, default: str = "", persistent: bool = False, strip: bool = False, validator = None, instruction: str | None = None) -> str: def io_choice(prompt: str, options: list[str]) -> str:
return questionary.select(
prompt,
options,
use_search_filter=True,
use_jk_keys=False,
instruction="Tipear o usar flechas",
).ask()
def io_prompt(
message: str,
default: str = "",
persistent: bool = False,
strip: bool = False,
validator=None,
instruction: str | None = None,
) -> str:
if persistent and not validator: if persistent and not validator:
validator = lambda s: len(s.strip()) > 0 validator = lambda s: len(s.strip()) > 0
value = questionary.text(message, default, validate=validator, instruction=instruction).ask() value = questionary.text(
message, default, validate=validator, instruction=instruction
).ask()
return value.strip() if strip else value return value.strip() if strip else value
+3 -1
View File
@@ -22,7 +22,9 @@ def commit():
commit_type = base.io_choice("Tipo de commit", COMMIT_TYPES) commit_type = base.io_choice("Tipo de commit", COMMIT_TYPES)
commit_message = base.io_prompt( commit_message = base.io_prompt(
"Mensaje (máximo recomendado: 100 caracteres)", persistent=True "Mensaje de commit",
validator=lambda s: 0 < len(s) and len(s) < 100,
instruction="100 caracteres máximo"
) )
message = commit_type + ": " + commit_message message = commit_type + ": " + commit_message