diff --git a/git-flow b/git-flow index ca72cde..413d3e7 100755 --- a/git-flow +++ b/git-flow @@ -40,6 +40,8 @@ def main(): merge_command() elif command == "tag": tag_command() + elif command == "release": + release_command() elif command == "help": help_command() else: @@ -83,7 +85,7 @@ COMMIT_TYPES = [ "typo", "testing", "ignore", - "WIP" + "wip" ] DEFAULT_REMOTE = "origin" @@ -229,7 +231,7 @@ def merge_command(): print_error("No se pueden mergear ramas de tipo 'wip'") return - target = get_base_branch(branch) + (target, _) = get_branch_env_and_type(branch) status = Git.status() remote = Git.flow_config("flow.remote").firstline() @@ -312,6 +314,37 @@ def parse_url(url: str) -> list[str]: return [service, repository] +def get_branch_env_and_type(branch: str) -> tuple[str, str]: + components = branch.split("/") + target_branches = ( + Git.flow_config("flow.branches") + .firstline() # dev test main + .split(" ") # [dev, test, main] + [1:] # [test, main] (dev no deberia ser un release) + ) + + + if len(components) == 2: + if components[0] not in BRANCH_TYPES: + raise ValueError(f"Branch inválida, el tipo '{components[0]}' no es válido.") + + return (target_branches[0], components[0]) + elif len(components) == 4: + if ( + components[0] != "release" + or components[1] not in target_branches + or components[2] not in BRANCH_TYPES + ): + raise ValueError( + "Branch release inválido, debe tener el siguiente formato: " + "release///, pero es: " + branch + ) + + return (components[1], components[2]) + else: + raise ValueError("Branch inválido: " + branch) + + def tag_command(): ensure_initialized() ci = len(sys.argv) == 3 # ./git-flow tag @@ -357,16 +390,8 @@ def tag_command(): until_dash = last_version.index("-") if "-" in last_version else None [major, minor, patch] = map(int, last_version[from_major:until_dash].split(".")) - components = merged_branch.split("/") - - if len(components) not in [2, 4]: - raise RuntimeError("Branch mergeado es inválido: " + merged_branch) - elif len(components) == 4 and components[0] != "release": - raise RuntimeError("Release branch mergeado es inválido: " + merged_branch) - elif components[-2] not in BRANCH_TYPES: - raise RuntimeError("Tipo de rama mergeado es inválido: " + components[-2]) - - increment = BRANCH_TYPES_INCREMENT[components[-2]] + (_, merged_branch_type) = get_branch_env_and_type(merged_branch) + increment = BRANCH_TYPES_INCREMENT[merged_branch_type] if increment == "major": major = major + 1 @@ -390,6 +415,39 @@ def tag_command(): Git("tag", new_version, commit).exec() +def release_command(): + ensure_initialized() + + branch = ensure_right_branch() + env_branches = Git.flow_config("flow.branches").firstline().split(" ") + (env, _) = get_branch_env_and_type(branch) + + if env == env_branches[-1]: + raise RuntimeError("No se puede hacer release de una rama en el ultimo entorno.") + + next_env = env_branches[env_branches.index(env) + 1] + boundary_commits = list(filter( + lambda c: c.startswith("-"), # boundary commits + Git("rev-list", env + "..." + branch, topo_order=True, boundary=True).lines() + )) + + if not boundary_commits: + raise RuntimeError("No se encontro un commit base para realizar el rebase.") + + base = boundary_commits[-1].removeprefix("-") + next_branch = branch.replace(f"/{env}/", f"/{next_env}/") if branch.startswith("release/") else f"release/{next_env}/{branch}" + + Git("switch", next_branch, create=True).exec() + commits = int(Git("rev-list", base + ".." + next_branch, count=True).firstline()) + + if commits > 1 and confirm(f"Desea reemplazar los {commits} commits de la rama por uno solo?"): + Git("reset", base, soft=True).exec() + commit_type = choose("Tipo de commit", COMMIT_TYPES[:-1]) # Solo permitir commits NO wip + Git("commit", m=commit_type + ": " + get_commit_message()).exec() + + Git("rebase", base, next_branch, onto=next_env).exec() + + def help_command(name: str|None = None): if name is not None: print_error(f"Comando inválido: {name}") @@ -405,6 +463,7 @@ COMANDOS: commit crea un commit siguiendo el formato de Conventional Commit merge actualiza el changelog y crea un nuevo PR para mergear la rama tag crea un nuevo tag para el ultimo merge + release crea una nueva rama release para pasar la rama actual al siguiente entorno help muestra este texto de ayuda""", file=sys.stderr)