feature: cambio merge y tag para que el changelog se genere al crear un tag nuevo

This commit is contained in:
jt
2025-11-19 20:43:22 -03:00
parent 30c6c36beb
commit be87c2098b
15 changed files with 1036 additions and 233 deletions
+69 -210
View File
@@ -5,14 +5,57 @@ import sys
import datetime
import requests
import locale
from argparse import Namespace, ArgumentParser
from .git import Git
from .io import *
from git_flow import GitFlowError
from git_flow.changelog import Changelog
from git_flow.command.base import Command
from git_flow.command.commit import CommitCommand
from git_flow.command.init import InitCommand
from git_flow.command.merge import MergeCommand
from git_flow.command.new import NewCommand
from git_flow.command.tag import TagCommand
from git_flow.git import BUMP_VERSION, Git
from git_flow.io import *
REPOSITORY_TOKEN_PATH=".repository-token"
LOCALE = 'es_AR.UTF-8'
class GitFlowCommand(Command):
commands: tuple[Command, ...]
def __init__(self, *args: Command) -> None:
self.commands = args
def name(self) -> str:
return "git-flow"
def description(self) -> str:
return """Git flow es un workflow automatizado siguiendo conventional commits, semver, y
deploys aislados a distintos entornos."""
def setup_parser(self, parser: ArgumentParser) -> ArgumentParser:
subparsers = parser.add_subparsers(title="comandos", dest="command", required=True)
for command in self.commands:
subparser = subparsers.add_parser(command.name())
command.setup_parser(subparser)
return parser
def get_parser(self) -> ArgumentParser:
parser = ArgumentParser(self.name(), description=self.description())
return self.setup_parser(parser)
def run(self, args: Namespace = Namespace()):
args = self.get_parser().parse_args()
for command in self.commands:
if command.name() == args.command:
return command.run(args)
def main():
try:
@@ -20,6 +63,22 @@ def main():
except locale.Error as e:
print_warning(f"No se pudo configurar el locale '{LOCALE}': {e}")
command = GitFlowCommand(
InitCommand(),
NewCommand(),
CommitCommand(),
MergeCommand(),
TagCommand(),
)
try:
command.run()
except GitFlowError as e:
command.error(str(e))
except Exception as e:
command.error("Ocurrió un error inesperado: " + str(e))
return
args = sys.argv
if len(args) < 2:
@@ -29,15 +88,7 @@ def main():
command = args[1]
try:
if command == "new":
new_command()
elif command == "init":
init_command()
elif command == "commit":
commit_command()
elif command == "merge":
merge_command()
elif command == "tag":
if command == "tag":
tag_command()
elif command == "release":
release_command()
@@ -89,198 +140,6 @@ COMMIT_TYPES = [
DEFAULT_REMOTE = "origin"
def new_command():
current_branch = ensure_right_branch()
print_info("Se creará una nueva rama de trabajo sobre la rama actual.")
print_info("Seleccione el tipo de cambio a realizar.")
branch_type = choose("Tipos de cambio", BRANCH_TYPES)
branch = get_unique_branch_name(branch_type)
if confirm(f"Crear rama '{branch}' sobre rama '{current_branch}'"):
Git("switch", branch, create=True).exec()
else:
raise RuntimeError("Abortando operación")
def init_command():
if not Git("rev-parse", is_inside_work_tree=True).code() == 0:
print_warning("El directorio actual no es un repositorio.")
if not confirm("¿Desea inicializarlo?"):
raise RuntimeError("Abortando operación")
Git("init").exec()
initialized = Git.flow_config("flow.initialized").without_checking().firstline()
if initialized == "true":
print_error("El repositorio ya fue inicializado")
return
elif initialized != "":
print_error("El valor de 'flow.initialized' ({initialized}) es inválido")
return
print_info("Ingrese las ramas principales del repositorio separadas por espacio.")
branches = input("Ramas [dev main]: ").strip()
branches = branches.split(" ") if len(branches) > 0 else ["dev", "main"]
base = None
if confirm("¿Desea configurar un repositorio remoto?"):
remote = DEFAULT_REMOTE
remotes = Git("remote").lines()
if len(remotes) == 0:
print("El repositorio no tiene ningún remoto.")
url = None
while url is None:
url = input("Ingrese la URL del repositorio (https://github.com/user/repo.git): ").strip()
if len(url) == 0:
print_error("Debe ingresar una URL")
url = None
elif len(remotes) == 1:
remote = remotes[0]
else:
print("Tiene más de un remoto, seleccione el que desea utilizar.")
remote = choose("Remotos: ", remotes)
Git.flow_config("flow.remote", remote).exec()
Git.flow_config("flow.branches", " ".join(branches)).exec()
Git.flow_config("flow.initialized", "true").exec()
Git("add", Git.FLOWCONFIG_FILE).exec()
Git("commit", m="feature: initialize git-flow").exec()
existing_branches = Git.get_branches()
while base is None:
default = Git("rev-parse", "HEAD", abbrev_ref=True).firstline()
base = input(f"Ingrese la rama sobre la que desea crear las ramas principales [{default}]: ")
if not base:
base = default
elif base not in existing_branches:
print_error("Debe ingresar una rama existente.")
base = None
if confirm(f"¿Crear las ramas ingresadas sobre '{base}'?"):
for branch in branches:
if branch in existing_branches:
continue
if base == "HEAD":
Git("branch", branch).exec()
else:
Git("branch", branch, base).exec()
def commit_command():
ensure_initialized()
branch = ensure_right_branch()
status = Git.status()
if not status:
print_error("No hay cambios para commitear.")
return
files_in_index = []
for s in status:
if s.worktree != "?" and s.worktree != " ":
files_in_index.append(s.file)
if not files_in_index:
print_warning("No hay cambios en el indice para commitear.")
if confirm("¿Desea agregar la carpeta actual (`git add .`)?"):
Git("add", ".").exec()
else:
print_error("Debe agregar algún cambio al indice para continuar.")
return
commit_type = choose("Tipo de commit", COMMIT_TYPES)
message = commit_type + ": " + get_commit_message()
if branch.startswith("wip/"):
original_branch = branch.removeprefix("wip/")
Git("commit", m=message).exec()
if commit_type != "wip":
now = datetime.datetime.now()
suffix = now.strftime("%Y-%m-%d_%H.%M.%S")
Git("switch", original_branch).exec()
Git("merge", branch, squash=True).exec()
Git("commit", m=message).exec()
Git("branch", branch, branch + "/" + suffix, move=True).exec()
else:
if commit_type == "wip":
Git("switch", "wip/" + branch, create=True).exec()
Git("commit", m=message).exec()
def merge_command():
ensure_initialized()
branch = ensure_right_branch()
if branch.startswith("wip/"):
print_error("No se pueden mergear ramas de tipo 'wip'")
return
(target, _) = get_branch_env_and_type(branch)
status = Git.status()
remote = Git.flow_config("flow.remote").firstline()
if status:
not_empty = any(map(lambda s: s.index != " " or s.worktree != " ", status))
if not_empty:
print_warning("Existen cambios en tu entorno de trabajo sin commitear.")
if not confirm("¿Desea continuar?", False):
return
if remote:
Git("switch", target).exec()
Git("pull").exec()
Git("switch", "-").exec()
commits = Git("log", target + "..", format="%s").lines()
if not commits:
print_error("No hay cambios a mergear.")
return
print("Cambios a mergear:")
for commit in commits:
if commit != Git.BUMP_VERSION:
print("- " + commit)
merge_conflicts = Git("merge", target, ff=False, commit=False).exec()
if merge_conflicts:
Git("merge", abort=True).exec()
print_error(f"La rama actual tiene conflictos con '{target}'. "
"Se recomienda mergear la rama a la actual, resolver los conflictos, "
"y ejecutar nuevamente este comando.")
return
if remote:
Git("push", remote, branch, set_upstream=True).exec()
url = Git("remote", "get-url", remote).firstline()
if url is not None:
[service, repository] = parse_url(url)
create_pull_request(service, repository, branch, target)
else:
if confirm(f"Mergear rama '{target}' <= '{branch}'?"):
Git("switch", target).exec()
Git("merge", branch, ff=False).exec()
def parse_url(url: str) -> list[str]:
if "@" in url:
@@ -406,8 +265,8 @@ def tag_command():
merged_commit = Git("show", "HEAD^2", patch=False, format="%H").firstline()
if update_changelog(merged_commit, branch):
Git("add", Git.CHANGELOG_FILE).exec()
Git("commit", message=Git.BUMP_VERSION).exec()
Git("add", Changelog.FILENAME).exec()
Git("commit", message=BUMP_VERSION).exec()
Git("push").exec()
else:
Git("tag", new_version, commit).exec()
@@ -524,16 +383,16 @@ def get_unique_branch_name(branch_type):
def update_changelog(branch: str, target: str):
last_commit = Git("show", "HEAD", no_patch=True, format="%s").firstline()
if last_commit == Git.BUMP_VERSION:
if last_commit == BUMP_VERSION:
return False
else:
content = generate_changelog_entry(branch, target)
if os.path.isfile(Git.CHANGELOG_FILE):
with open(Git.CHANGELOG_FILE, "r") as changelog:
if os.path.isfile(Changelog.FILENAME):
with open(Changelog.FILENAME, "r") as changelog:
content = content + changelog.read()
with open(Git.CHANGELOG_FILE, "w") as changelog:
with open(Changelog.FILENAME, "w") as changelog:
changelog.write(content)
@@ -569,7 +428,7 @@ def get_changelog_content_lines(branch: str, target: str):
email = Git("show", commit, patch=False, format="%ae").firstline()
username = email[:email.index('@')]
if message == Git.BUMP_VERSION:
if message == BUMP_VERSION:
continue
index = message.index(":")