Compare commits

...
35 Commits
Author SHA1 Message Date
gitea-actions 8f1a60cc06 chore: bump version and update CHANGELOG.md [skip ci] 2026-07-29 14:56:49 +00:00
jt fcc8114c8e Merge pull request 'bugfix: change checkout version to v7' (#11) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Successful in 16s
Reviewed-on: #11
2026-07-29 14:56:38 +00:00
Jonathan Teran Carballo c58c4cea96 bugfix: change checkout version to v7 2026-07-29 11:55:54 -03:00
jt 7fbf499278 Merge pull request 'bugfix: move git fetch to separate line' (#10) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 8s
Reviewed-on: #10
2026-07-29 14:49:33 +00:00
Jonathan Teran Carballo 64fc890cb7 bugfix: move git fetch to separate line 2026-07-29 11:49:25 -03:00
gitea-actions 7199249f75 chore: bump version and update CHANGELOG.md [skip ci] 2026-07-29 14:47:56 +00:00
jt 7efaf367e5 Merge pull request 'bugfix: change actions/checkout to v4 and add step to fetch tags' (#9) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 17s
Reviewed-on: #9
2026-07-29 14:47:38 +00:00
Jonathan Teran Carballo dc79ffa399 bugfix: change actions/checkout to v4 and add step to fetch tags 2026-07-29 11:47:00 -03:00
jt 31513a3e3a Merge pull request 'bugfix: change actions/checkout version' (#8) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 19s
Reviewed-on: #8
2026-07-29 14:45:20 +00:00
Jonathan Teran Carballo c45f065e77 bugfix: change actions/checkout version 2026-07-29 11:45:12 -03:00
jt 7f7dd7b538 Merge pull request 'bugfix: add fetch-tags: true' (#7) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 14s
Reviewed-on: #7
2026-07-29 14:41:06 +00:00
Jonathan Teran Carballo adcb53156a bugfix: add fetch-tags: true 2026-07-29 11:40:54 -03:00
jt 5ca817c796 Merge pull request 'bugfix: remove checkout parameters' (#6) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 14s
Reviewed-on: #6
2026-07-29 14:35:04 +00:00
Jonathan Teran Carballo 2be9b50ac4 bugfix: remove checkout parameters 2026-07-29 11:34:43 -03:00
gitea-actions 347b8b9556 chore: bump version and update CHANGELOG.md [skip ci] 2026-07-29 13:57:37 +00:00
jt 9b547bd6a9 Merge pull request 'feature: change flow settings in local config' (#5) from feature/change-flow-settings-in-local-config into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 29s
Reviewed-on: #5
2026-07-29 13:57:06 +00:00
Jonathan Teran Carballo f05582b50f feature: show commit count and list tags on workflow 2026-07-29 10:53:56 -03:00
gitea-actions a1a9a7acac chore: bump version and update CHANGELOG.md [skip ci] 2026-07-18 03:16:04 +00:00
jt 190b4b8408 Merge pull request 'bugfix: add fetch tags to checkout step' (#4) from bugfix/fetch-tags-on-checkout into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 11s
Reviewed-on: #4
2026-07-18 03:15:50 +00:00
jt f9fb5a62d1 bugfix: add fetch tags to checkout step 2026-07-18 00:15:19 -03:00
gitea-actions 09d0de2860 chore: bump version and update CHANGELOG.md [skip ci] 2026-07-18 01:35:18 +00:00
jt f233adfd1d Merge pull request 'feature: print current tag command output' (#3) from feature/log-current-tag-command into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 10s
Reviewed-on: #3
2026-07-18 01:35:03 +00:00
jt 0cdc01291c feature: print current tag command output 2026-07-17 22:34:39 -03:00
gitea-actions 098a4724ca chore: bump version and update CHANGELOG.md [skip ci] 2026-07-18 01:13:08 +00:00
jt 9167390098 Merge pull request 'feature: update I/O methods to use questionary where applicable' (#2) from feature/refactor-use-questionary-package into main
Publish to PyPI / Publish-to-PyPI (push) Failing after 43s
Reviewed-on: #2
2026-07-18 01:12:22 +00:00
jt a08666cac3 style: organize imports 2026-07-17 22:07:37 -03:00
jt 726df217ec style: format and organize imports 2026-07-17 22:04:56 -03:00
jt 07d4ff960e refactor: use base.io_ methods 2026-07-17 22:01:42 -03:00
jt 919e680e75 refactor: use base.io_ methods 2026-07-16 22:26:48 -03:00
jt add4cd2747 refactor: use base.io_ methods 2026-07-16 22:25:20 -03:00
jt e4833c9ed9 style: run black formatter on merge.py 2026-07-16 22:12:30 -03:00
jt 7315681b23 style: run black formatter on commit.py 2026-07-16 22:11:35 -03:00
jt ba1c9bd68d style: run black formatter on new.py 2026-07-16 22:11:07 -03:00
jt 1a7ae338ff style: run black formatter 2026-07-16 22:09:28 -03:00
jt 0120faac9e refactor: use new base.io_ methods 2026-07-16 22:08:46 -03:00
11 changed files with 212 additions and 105 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
Publish-to-PyPI: Publish-to-PyPI:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out repository code - name: Checkout
uses: actions/checkout@v7 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
+65
View File
@@ -1,3 +1,68 @@
## v1.18.0 - 2026-07-29
- **bugfix**: change checkout version to v7 [[jteran](mailto:jteran@renatre.org.ar)] (c58c4ce)
- **bugfix**: move git fetch to separate line [[jteran](mailto:jteran@renatre.org.ar)] (64fc890)
- **bugfix**: change actions/checkout to v4 and add step to fetch tags [[jteran](mailto:jteran@renatre.org.ar)] (dc79ffa)
- **bugfix**: change actions/checkout version [[jteran](mailto:jteran@renatre.org.ar)] (c45f065)
- **bugfix**: add fetch-tags: true [[jteran](mailto:jteran@renatre.org.ar)] (adcb531)
- **bugfix**: remove checkout parameters [[jteran](mailto:jteran@renatre.org.ar)] (2be9b50)
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.1.0-main - 2026-07-29
- **bugfix**: change actions/checkout to v4 and add step to fetch tags [[jteran](mailto:jteran@renatre.org.ar)] (dc79ffa)
- **bugfix**: change actions/checkout version [[jteran](mailto:jteran@renatre.org.ar)] (c45f065)
- **bugfix**: add fetch-tags: true [[jteran](mailto:jteran@renatre.org.ar)] (adcb531)
- **bugfix**: remove checkout parameters [[jteran](mailto:jteran@renatre.org.ar)] (2be9b50)
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.1.0-main - 2026-07-29
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.0.1-main - 2026-07-18
- **bugfix**: add fetch tags to checkout step [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (f9fb5a6)
---
## v0.1.0-main - 2026-07-18
- **feature**: print current tag command output [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (0cdc012)
---
## v0.1.0-main - 2026-07-18
- **style**: organize imports [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (a08666c)
- **style**: format and organize imports [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (726df21)
- **refactor**: use base.io_ methods [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (07d4ff9)
- **refactor**: use base.io_ methods [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (919e680)
- **refactor**: use base.io_ methods [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (add4cd2)
- **style**: run black formatter on merge.py [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (e4833c9)
- **style**: run black formatter on commit.py [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (7315681)
- **style**: run black formatter on new.py [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (ba1c9bd)
- **style**: run black formatter [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (1a7ae33)
- **refactor**: use new base.io_ methods [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (0120faa)
- **refactor**: use unsafe_ask in favor of global error catch [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (febd18c)
- **style**: run black formatter [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (069c33b)
- **refactor**: reword current branch check, move if around so it's better placed [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (1d186e1)
- **feature**: change unicode status icons [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (c0f7642)
---
## v1.17.6 - 2026-07-09 ## v1.17.6 - 2026-07-09
- **bugfix**: actualizo versiones de checkout, setup-python, clonar depth completo [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (4666503) - **bugfix**: actualizo versiones de checkout, setup-python, clonar depth completo [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (4666503)
+11
View File
@@ -3,6 +3,7 @@ from git_flow import (
REPOSITORY_TOKEN_FILENAME, REPOSITORY_TOKEN_FILENAME,
FLOWCONFIG_FILENAME, FLOWCONFIG_FILENAME,
FLOWCONFIG_VERSION, FLOWCONFIG_VERSION,
COMMIT_TYPES,
GitFlowError, GitFlowError,
) )
from git_flow.git import Git from git_flow.git import Git
@@ -147,6 +148,16 @@ def is_valid_ticket(ticket: str) -> bool:
) )
def get_commit_message(commit_types: list[str] = COMMIT_TYPES) -> str:
commit_type = io_choice("Tipo de commit", commit_types)
commit_message = io_prompt(
"Mensaje de commit",
validator=lambda s: 0 < len(s) and len(s) < 100,
instruction="100 caracteres máximo",
)
return commit_type + ": " + commit_message
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)
+20 -14
View File
@@ -1,16 +1,20 @@
from typing import Annotated
import typer
from rich.console import Console
import git_flow.command.base as base
from git_flow import ( from git_flow import (
TRASH_BRANCH_PREFIX, TRASH_BRANCH_PREFIX,
WIP_BRANCH_PREFIX, WIP_BRANCH_PREFIX,
GitFlowError, GitFlowError,
) )
from git_flow.command.base import *
from git_flow.git import Git from git_flow.git import Git
from typing import Annotated
import typer
BRANCH_FORMAT = "%(refname:short)" BRANCH_FORMAT = "%(refname:short)"
app = typer.Typer() app = typer.Typer()
console = Console()
@app.command() @app.command()
@@ -38,28 +42,28 @@ def branch(
] = False, ] = False,
): ):
"""Lista ramas del repositorio, agrupandolas por entorno objetivo""" """Lista ramas del repositorio, agrupandolas por entorno objetivo"""
ensure_initialized() base.ensure_initialized()
current_branch = Git.get_current_branch() current_branch = Git.get_current_branch()
if current_branch in environments: if current_branch in base.environments:
current_environment = current_branch current_environment = current_branch
else: else:
current_environment, _ = get_branch_env_and_type(current_branch) current_environment, _ = base.get_branch_env_and_type(current_branch)
if trash: if trash:
show_branches(TRASH_BRANCH_PREFIX, current_branch) show_branches(TRASH_BRANCH_PREFIX, current_branch)
elif wip: elif wip:
show_branches(WIP_BRANCH_PREFIX, current_branch) show_branches(WIP_BRANCH_PREFIX, current_branch)
elif all: elif all:
show_envs(environments, current_branch) show_envs(base.environments, current_branch)
show_all_branches(environments, current_branch) show_all_branches(base.environments, current_branch)
elif environment is None: elif environment is None:
show_envs(environments, current_branch) show_envs(base.environments, current_branch)
show_env_branches(current_environment, environments, current_branch) show_env_branches(current_environment, base.environments, current_branch)
elif environment in environments: elif environment in base.environments:
show_envs(environments, current_branch) show_envs(base.environments, current_branch)
show_env_branches(environment, environments, current_branch) show_env_branches(environment, base.environments, current_branch)
else: else:
raise GitFlowError(f"'{environment}' no es un entorno válido.") raise GitFlowError(f"'{environment}' no es un entorno válido.")
@@ -78,7 +82,9 @@ def show_branches(branch_prefix: str, current_branch: str):
def get_branches(branch_prefix: str): def get_branches(branch_prefix: str):
return Git("for-each-ref", "refs/heads/" + branch_prefix, format=BRANCH_FORMAT).lines() return Git(
"for-each-ref", "refs/heads/" + branch_prefix, format=BRANCH_FORMAT
).lines()
def show_all_branches(environments: list[str], current_branch: str): def show_all_branches(environments: list[str], current_branch: str):
+7 -10
View File
@@ -1,8 +1,10 @@
import typer
from datetime import datetime from datetime import datetime
from git_flow import COMMIT_TYPES, TRASH_BRANCH_PREFIX, WIP_BRANCH_PREFIX, GitFlowError
from git_flow.git import Git import typer
import git_flow.command.base as base import git_flow.command.base as base
from git_flow import TRASH_BRANCH_PREFIX, WIP_BRANCH_PREFIX, GitFlowError
from git_flow.git import Git
app = typer.Typer() app = typer.Typer()
@@ -20,13 +22,8 @@ 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.")
commit_type = base.io_choice("Tipo de commit", COMMIT_TYPES) message = base.get_commit_message()
commit_message = base.io_prompt( commit_type = message[: message.index(":")]
"Mensaje de commit",
validator=lambda s: 0 < len(s) and len(s) < 100,
instruction="100 caracteres máximo"
)
message = commit_type + ": " + commit_message
if branch.startswith(WIP_BRANCH_PREFIX): if branch.startswith(WIP_BRANCH_PREFIX):
original_branch = branch.removeprefix(WIP_BRANCH_PREFIX) original_branch = branch.removeprefix(WIP_BRANCH_PREFIX)
+27 -21
View File
@@ -1,8 +1,8 @@
import typer import typer
import git_flow.command.base as base
from git_flow import FLOWCONFIG_FILENAME, FLOWCONFIG_VERSION, GitFlowError from git_flow import FLOWCONFIG_FILENAME, FLOWCONFIG_VERSION, GitFlowError
from git_flow.git import Git from git_flow.git import Git
from git_flow.command.base import *
app = typer.Typer() app = typer.Typer()
@@ -15,7 +15,7 @@ def init():
_ensure_not_already_initialized() _ensure_not_already_initialized()
branches = _setup_flow_branches() branches = _setup_flow_branches()
(remote, remote_type) = _setup_flow_remote() remote, remote_type = _setup_flow_remote()
flowconfig = { flowconfig = {
"flow.version": str(FLOWCONFIG_VERSION), "flow.version": str(FLOWCONFIG_VERSION),
@@ -36,32 +36,34 @@ def init():
def _ensure_is_repository(): def _ensure_is_repository():
if not Git.is_repository(): if not Git.is_repository():
warning("El directorio actual no es un repositorio.") base.io_warning("El directorio actual no es un repositorio.")
if not confirm("¿Desea inicializarlo?"): if not base.io_confirm("¿Desea inicializarlo?"):
raise GitFlowError("No se puede continuar sin inicializar el repositorio") raise GitFlowError("No se puede continuar sin inicializar el repositorio")
Git("init").exec() Git("init").exec()
def _ensure_not_already_initialized(): def _ensure_not_already_initialized():
if not flowconfig: if not base.flowconfig:
return return
elif flowconfig.get("flow.initialized") == "true": elif base.flowconfig.get("flow.initialized") == "true":
raise GitFlowError("El repositorio ya fue inicializado para usar git-flow") raise GitFlowError("El repositorio ya fue inicializado para usar git-flow")
else: else:
raise GitFlowError("Valor de 'flow.initialized' es inválido") raise GitFlowError("Valor de 'flow.initialized' es inválido")
def _setup_flow_branches(): def _setup_flow_branches():
panel( base.io_info(
"Configuración de entornos",
"""Ingrese las ramas que representan los entornos de deploy del proyecto """Ingrese las ramas que representan los entornos de deploy del proyecto
en orden creciente de cercanía al entorno productivo, y separados por en orden creciente de cercanía al entorno productivo, y separados por
coma. Por ejemplo: "dev, test, prod".""", coma. Por ejemplo: "dev, test, prod".""",
title="Configuración de entornos",
) )
branches = list(map(lambda b: b.strip(), prompt("Ramas", "main").split(","))) branches = list(
map(lambda b: b.strip(), base.io_prompt("Ramas", "main").split(","))
)
if not all(branches): if not all(branches):
raise GitFlowError("No puede ingresar una rama vacia") raise GitFlowError("No puede ingresar una rama vacia")
@@ -70,21 +72,23 @@ coma. Por ejemplo: "dev, test, prod".""",
def _setup_flow_remote(): def _setup_flow_remote():
panel( base.io_info(
"Configuración de remoto", """Configurar un repositorio remoto le permite generar PRs automáticamente para el
"Puede configurar un repositorio remoto para generar PRs automáticamente", entorno correspondiente. Deberá seleccionar uno de los remotos actuales, o crear
uno nuevo.""",
title="Configuración de remoto",
) )
remote = None remote = None
remote_type = None remote_type = None
if confirm("¿Configurar repositorio remoto?"): if base.io_confirm("¿Configurar repositorio remoto?"):
remotes = Git("remote").lines(print="Listando remotos disponibles") remotes = Git("remote").lines(print="Listando remotos disponibles")
if not remotes: if not remotes:
info("No tiene ningún repositorio remoto, se creará uno.") base.io_info("No tiene ningún repositorio remoto, se creará uno.")
url = prompt( url = base.io_prompt(
"Ingrese la URL del repositorio (e.g. https://github.com/user/repo.git)", "Ingrese la URL del repositorio (e.g. https://github.com/user/repo.git)",
persistent=True, persistent=True,
) )
@@ -93,10 +97,12 @@ def _setup_flow_remote():
elif len(remotes) == 1: elif len(remotes) == 1:
remote = remotes[0] remote = remotes[0]
else: else:
info("Tiene más de un remoto, seleccione el que va a utilizar.") base.io_info("Tiene más de un remoto, seleccione el que va a utilizar.")
remote = choice("Remoto", remotes) remote = base.io_choice("Remoto", remotes)
remote_type = choice("Tipo de remoto:", ["bitbucket", "github", "gitea"]) remote_type = base.io_choice(
"Tipo de remoto:", ["bitbucket", "github", "gitea"]
)
return (remote, remote_type) return (remote, remote_type)
@@ -105,10 +111,10 @@ def _ensure_all_flow_branches_exist(branches: list[str], remote: str | None):
existing_branches = Git.get_branches() existing_branches = Git.get_branches()
if not all(map(lambda b: b in existing_branches, branches)): if not all(map(lambda b: b in existing_branches, branches)):
warning("Algunas de las ramas de entornos expecificadas no existen.") base.io_warning("Algunas de las ramas de entornos expecificadas no existen.")
info("Debe indicar sobre que rama se crearán las ramas de entorno.") base.io_info("Debe indicar sobre que rama se crearán las ramas de entorno.")
target_branch = choice("Rama", existing_branches) target_branch = base.io_choice("Rama", existing_branches)
for branch in branches: for branch in branches:
if branch not in existing_branches: if branch not in existing_branches:
+23 -12
View File
@@ -1,7 +1,8 @@
import typer import typer
import git_flow.command.base as base
from git_flow import GitFlowError from git_flow import GitFlowError
from git_flow.changelog import Changelog from git_flow.changelog import Changelog
import git_flow.command.base as base
from git_flow.git import Git from git_flow.git import Git
app = typer.Typer() app = typer.Typer()
@@ -87,8 +88,12 @@ def check_merge_conflicts(target: str):
Git("merge", abort=True).exec(print="Abortando merge de prueba", check=False) Git("merge", abort=True).exec(print="Abortando merge de prueba", check=False)
if merge_conflicts: if merge_conflicts:
base.io_error(f"La rama actual tiene conflictos con {target}.\n" base.io_error(
f"Se recomienda mergear {target} a la rama actual, resolver los conflictos localmente, y ejecutar nuevamente este comando", "Conflictos de merge") f"La rama actual tiene conflictos con {target}.\n"
f"Se recomienda mergear {target} a la rama actual, resolver los conflictos localmente,\n"
"y ejecutar nuevamente este comando",
title="Conflictos de merge",
)
raise GitFlowError("Ejecución abortada.") raise GitFlowError("Ejecución abortada.")
else: else:
base.io_success("No se detectaron merge conflicts.") base.io_success("No se detectaron merge conflicts.")
@@ -109,7 +114,7 @@ def create_pull_request(token: str, branch: str, target: str):
target, target,
title, title,
changelog.generate_content(target, branch), changelog.generate_content(target, branch),
branch not in base.environments branch not in base.environments,
) )
base.io_success(message, "Rama creada") base.io_success(message, "Rama creada")
@@ -118,12 +123,13 @@ def create_pull_request(token: str, branch: str, target: str):
Git("switch", target).exec(print="Cambiando a rama objetivo") Git("switch", target).exec(print="Cambiando a rama objetivo")
Git("pull").exec(print="Obteniendo cambios") Git("pull").exec(print="Obteniendo cambios")
def _get_pr_title_from_branch(branch: str) -> str: def _get_pr_title_from_branch(branch: str) -> str:
if branch in base.environments: if branch in base.environments:
target = base.environments[base.environments.index(branch) + 1] target = base.environments[base.environments.index(branch) + 1]
return f"Sincronización de entorno {branch} a {target}" return f"Sincronización de entorno {branch} a {target}"
components = branch.split("/") # <type>/<desc> or release/<env>/<type>/<desc> components = branch.split("/") # <type>/<desc> or release/<env>/<type>/<desc>
branch_type = components[-2] branch_type = components[-2]
branch_desc = components[-1] branch_desc = components[-1]
@@ -136,11 +142,16 @@ def _get_pr_title_from_branch(branch: str) -> str:
maybe_ticket = branch_desc[:second_dash] maybe_ticket = branch_desc[:second_dash]
if base.is_valid_ticket(maybe_ticket): if base.is_valid_ticket(maybe_ticket):
branch_ticket = maybe_ticket branch_ticket = maybe_ticket
branch_desc = branch_desc[second_dash+1:] branch_desc = branch_desc[second_dash + 1 :]
return " ".join(filter(None, [ return " ".join(
f"[Pasaje a {components[1]}]" if len(components) == 4 else None, filter(
branch_type + ":", None,
branch_ticket, [
branch_desc.replace("-", " ") f"[Pasaje a {components[1]}]" if len(components) == 4 else None,
])) branch_type + ":",
branch_ticket,
branch_desc.replace("-", " "),
],
)
)
+22 -10
View File
@@ -1,9 +1,11 @@
import typer
from git_flow import BRANCH_TYPES
import git_flow.command.base as base
from git_flow.git import Git
from typing import Optional from typing import Optional
import typer
import git_flow.command.base as base
from git_flow import BRANCH_TYPES
from git_flow.git import Git
app = typer.Typer() app = typer.Typer()
@@ -17,8 +19,11 @@ def new():
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.")
base.io_info("Se creará una nueva rama de trabajo sobre la rama actual.\n" base.io_info(
"Debe seleccionar el tipo de cambio a realizar.", title="Tipo de cambio") "Se creará una nueva rama de trabajo sobre la rama actual.\n"
"Debe seleccionar el tipo de cambio a realizar.",
title="Tipo de cambio",
)
branch_type = base.io_choice("Tipos de cambio", BRANCH_TYPES) branch_type = base.io_choice("Tipos de cambio", BRANCH_TYPES)
ticket = _get_optional_ticket() ticket = _get_optional_ticket()
@@ -30,15 +35,20 @@ def new():
if base.io_confirm(f"¿Crear rama '{new_branch}' sobre la rama actual?"): if base.io_confirm(f"¿Crear rama '{new_branch}' sobre la rama actual?"):
Git("switch", new_branch, create=True).exec(print="Creando nueva rama") Git("switch", new_branch, create=True).exec(print="Creando nueva rama")
def _get_optional_ticket() -> Optional[str]: def _get_optional_ticket() -> Optional[str]:
return base.io_prompt( return base.io_prompt(
"Ticket que respalda el cambio (en formato ABC-123)", "Ticket que respalda el cambio (en formato ABC-123)",
validator=lambda x: len(x.strip()) == 0 or base.is_valid_ticket(x) validator=lambda x: len(x.strip()) == 0 or base.is_valid_ticket(x),
) )
def _get_unique_branch_name(branch_type: str, ticket: Optional[str]) -> str: def _get_unique_branch_name(branch_type: str, ticket: Optional[str]) -> str:
base.io_info(f"Ingrese las palabras clave que describan el cambio de tipo '{branch_type}'.\n" base.io_info(
"Las mismas se utilizaran para generar el nombre de la rama.", title="Nombre de rama") f"Ingrese las palabras clave que describan el cambio de tipo '{branch_type}'.\n"
"Las mismas se utilizaran para generar el nombre de la rama.",
title="Nombre de rama",
)
branch = None branch = None
branches = Git.get_branches() branches = Git.get_branches()
@@ -46,7 +56,9 @@ def _get_unique_branch_name(branch_type: str, ticket: Optional[str]) -> str:
keywords = base.io_prompt("Palabras clave", persistent=True) keywords = base.io_prompt("Palabras clave", persistent=True)
keywords = filter(lambda k: len(k) > 0, keywords.split(" ")) keywords = filter(lambda k: len(k) > 0, keywords.split(" "))
branch = branch_type + "/" + (ticket + "-" if ticket else "") + "-".join(keywords) branch = (
branch_type + "/" + (ticket + "-" if ticket else "") + "-".join(keywords)
)
if branch in branches: if branch in branches:
base.io_error( base.io_error(
+21 -24
View File
@@ -1,38 +1,40 @@
from git_flow import COMMIT_TYPES, GitFlowError
from git_flow.command.base import *
from git_flow.git import Git
from typing import Optional from typing import Optional
import typer import typer
import git_flow.command.base as base
from git_flow import COMMIT_TYPES, GitFlowError
from git_flow.git import Git
app = typer.Typer() app = typer.Typer()
@app.command() @app.command()
def release(group: Optional[str] = None): def release(group: Optional[str] = None):
"""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"""
ensure_initialized() base.ensure_initialized()
branch = ensure_right_branch() branch = base.ensure_right_branch()
env, _ = get_branch_env_and_type(branch) env, _ = base.get_branch_env_and_type(branch)
if env == environments[-1]: if env == base.environments[-1]:
raise GitFlowError( raise GitFlowError(
"No se puede hacer release de una rama en el ultimo entorno." "No se puede hacer release de una rama en el ultimo entorno."
) )
has_remote = "flow.remote" in flowconfig has_remote = "flow.remote" in base.flowconfig
ensure_clean_worktree(has_remote) base.ensure_clean_worktree(has_remote)
next_env = environments[environments.index(env) + 1] next_env = base.environments[base.environments.index(env) + 1]
next_branch = ( next_branch = (
branch.replace(f"/{env}/", f"/{next_env}/") branch.replace(f"/{env}/", f"/{next_env}/")
if branch.startswith("release/") if branch.startswith("release/")
else f"release/{next_env}/{branch}" else f"release/{next_env}/{branch}"
) )
base = Git.get_first_fork_point(branch, env) fork_point = Git.get_first_fork_point(branch, env)
commits = Git("log", base + "..", format="%s").lines() commits = Git("log", fork_point + "..", format="%s").lines()
if not commits: if not commits:
raise GitFlowError("No hay cambios a mergear.") raise GitFlowError("No hay cambios a mergear.")
@@ -45,9 +47,9 @@ def release(group: Optional[str] = None):
grouping = group is not None grouping = group is not None
if not group: if not group:
if confirm("¿Desea agrupar este release con otra rama?", False): if base.io_confirm("¿Desea agrupar este release con otra rama?", False):
grouping = True grouping = True
group = choice( group = base.io_choice(
"Grupo release: ", Git.get_branches("release/" + next_env + "/") "Grupo release: ", Git.get_branches("release/" + next_env + "/")
) )
else: else:
@@ -58,18 +60,13 @@ def release(group: Optional[str] = None):
Git("pull").exec(print="Sincronizando cambios la rama objetivo") Git("pull").exec(print="Sincronizando cambios la rama objetivo")
Git("switch", "-").exec(print="Volviendo a la rama original") Git("switch", "-").exec(print="Volviendo a la rama original")
if len(commits) > 1 and confirm( if len(commits) > 1 and base.io_confirm(
f"¿Desea reemplazar los {len(commits)} commits de la rama por uno solo?", False f"¿Desea reemplazar los {len(commits)} commits de la rama por uno solo?", False
): ):
info("Debe ingresar el mensaje del commit a crear.") base.io_info("Debe ingresar el mensaje del commit a crear.")
message = base.get_commit_message(COMMIT_TYPES[:-1])
commit_type = choice("Tipo de commit", COMMIT_TYPES[:-1]) Git("switch", next_branch, fork_point, create=True).exec(
commit_message = prompt(
"Mensaje (máximo recomendado: 100 caracteres)", persistent=True
)
message = commit_type + ": " + commit_message
Git("switch", next_branch, base, create=True).exec(
print="Creando rama release en base" print="Creando rama release en base"
) )
Git("merge", branch, squash=True).exec(print="Squasheando commits en uno solo") Git("merge", branch, squash=True).exec(print="Squasheando commits en uno solo")
@@ -77,7 +74,7 @@ def release(group: Optional[str] = None):
else: else:
Git("switch", next_branch, create=True).exec(print="Creando rama release") Git("switch", next_branch, create=True).exec(print="Creando rama release")
status = Git("rebase", base, next_branch, onto=group).code( status = Git("rebase", fork_point, next_branch, onto=group).code(
print="Moviendo cambios hacia el siguiente ambiente" print="Moviendo cambios hacia el siguiente ambiente"
) )
+13 -11
View File
@@ -1,3 +1,8 @@
from typing import Optional
import typer
import git_flow.command.base as base
from git_flow import ( from git_flow import (
COMMIT_TYPE_INCREMENT, COMMIT_TYPE_INCREMENT,
SEMVER_MAJOR, SEMVER_MAJOR,
@@ -7,10 +12,7 @@ from git_flow import (
GitFlowError, GitFlowError,
) )
from git_flow.changelog import Changelog from git_flow.changelog import Changelog
from git_flow.command.base import *
from git_flow.git import Git from git_flow.git import Git
from typing import Optional
import typer
app = typer.Typer() app = typer.Typer()
@@ -18,22 +20,22 @@ app = typer.Typer()
@app.command() @app.command()
def tag(token: Optional[str] = None): def tag(token: Optional[str] = None):
"""Crea un nuevo tag para el último merge.""" """Crea un nuevo tag para el último merge."""
ensure_initialized() base.ensure_initialized()
target = Git.get_current_branch() target = Git.get_current_branch()
if target not in environments: if target not in base.environments:
raise GitFlowError("Solo se pueden taggear commits en ramas principales.") raise GitFlowError("Solo se pueden taggear commits en ramas principales.")
branch = Git( branch = Git(
"show", get_last_merge_commit() + "^2", patch=False, format="%h" "show", get_last_merge_commit() + "^2", patch=False, format="%h"
).firstline() ).firstline()
base = Git.get_first_fork_point(branch, target) fork_point = Git.get_first_fork_point(branch, target)
commits = Git("log", base + ".." + branch, format="%s").lines() commits = Git("log", fork_point + ".." + branch, format="%s").lines()
next_tag = get_next_tag_from_commits(commits, target) next_tag = get_next_tag_from_commits(commits, target)
if not next_tag: if not next_tag:
info( base.io_info(
"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."
) )
return return
@@ -45,21 +47,21 @@ def tag(token: Optional[str] = None):
changelog = Changelog() changelog = Changelog()
changelog.update(next_tag, base, branch) changelog.update(next_tag, fork_point, branch)
Git("add", Changelog.FILENAME).exec(print="Agregando nuevo CHANGELOG.md") Git("add", Changelog.FILENAME).exec(print="Agregando nuevo CHANGELOG.md")
Git("commit", message=Changelog.COMMIT_MESSAGE).exec(print="Creando commit") Git("commit", message=Changelog.COMMIT_MESSAGE).exec(print="Creando commit")
tag_commit = Git("show", "HEAD", patch=False, format="%h").firstline() tag_commit = Git("show", "HEAD", patch=False, format="%h").firstline()
if ci: if ci:
Git("push").exec(print="Subiendo commit al remoto para taggearlo") Git("push").exec(print="Subiendo commit al remoto para taggearlo")
success(get_remote_api(token).create_tag(next_tag, tag_commit)) base.io_success(base.get_remote_api(token).create_tag(next_tag, tag_commit))
Git("tag", next_tag, tag_commit).exec(print="Creando tag localmente") Git("tag", next_tag, tag_commit).exec(print="Creando tag localmente")
def get_token_and_ci(token: Optional[str]): def get_token_and_ci(token: Optional[str]):
try: try:
return (ensure_repository_token(), False) return (base.ensure_repository_token(), False)
except GitFlowError: except GitFlowError:
return (token, True) return (token, True)
+2 -2
View File
@@ -53,7 +53,7 @@ class Git:
@staticmethod @staticmethod
def get_current_tag(): def get_current_tag():
return Git("describe", abbrev="0", tags=True).firstline(check=False) return Git("describe", abbrev="0", tags=True).firstline(check=False, print="Obteniendo tag actual")
@staticmethod @staticmethod
def get_first_fork_point(branch: str, env: str): def get_first_fork_point(branch: str, env: str):
@@ -117,7 +117,7 @@ class Git:
return lines if not strip else list(map(lambda l: l.strip(), lines)) return lines if not strip else list(map(lambda l: l.strip(), lines))
def firstline(self, **kwargs: bool): def firstline(self, **kwargs):
lines = self.lines(**kwargs) lines = self.lines(**kwargs)
return lines[0] if lines else "" return lines[0] if lines else ""