Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5ec26529 | ||
|
|
e6386ed252 | ||
|
|
34aba71d32 | ||
|
|
4135a789e3 | ||
|
|
faea8c2d2a | ||
|
|
11e2a9daa9 | ||
|
|
d133c480c5 | ||
|
|
7346cfd1a8 | ||
|
|
37a7c101af | ||
|
|
edf4948719 |
@@ -1,3 +1,17 @@
|
||||
## v1.2.0 - 2025-11-22
|
||||
|
||||
### Commits
|
||||
|
||||
- **bugfix**: deshabilito check en merge --abort al buscar conflictos [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (34aba71)
|
||||
- **feature**: agregando descripcion a ejecucion de comandos importantes en new, tag y merge [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (4135a78)
|
||||
- **feature**: agregando descripcion a ejecucion de comandos importantes en init y commit [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (faea8c2)
|
||||
- **bugfix**: cambiando tipo de print para agregar soporte de titulos [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (11e2a9d)
|
||||
- **bugfix**: descartar output cuando el comando git se ejecuta con _run [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (d133c48)
|
||||
- **feature**: muevo opciones para check y print a metodos para ejecutar git [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (7346cfd)
|
||||
|
||||
---
|
||||
|
||||
|
||||
## v1.1.5 - 2025-11-21
|
||||
|
||||
### Commits
|
||||
|
||||
@@ -31,6 +31,8 @@ TYPE_INFO = 3
|
||||
|
||||
|
||||
class Command(ABC):
|
||||
flowconfig: dict[str, str]
|
||||
|
||||
@abstractmethod
|
||||
def name(self) -> str:
|
||||
pass
|
||||
@@ -43,11 +45,6 @@ class Command(ABC):
|
||||
def run(self, args: Namespace = Namespace()):
|
||||
pass
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.flowconfig = (
|
||||
Git.get_config(FLOWCONFIG_FILE) if isfile(FLOWCONFIG_FILE) else {}
|
||||
)
|
||||
|
||||
def success(self, msg: str):
|
||||
self._print(TYPE_SUCCESS, msg)
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class CommitCommand(Command):
|
||||
|
||||
if not self._has_files_staged():
|
||||
self.warning("No hay cambios en el indice para commitear.")
|
||||
if self.confirm("¿Desea agregar la carpeta actual (`git add .`)?"):
|
||||
Git("add", ".").exec()
|
||||
if self.confirm("¿Desea agregar la carpeta actual?"):
|
||||
Git("add", ".").exec(print="Agregando cambios")
|
||||
else:
|
||||
raise GitFlowError(
|
||||
"Debe agregar algún cambio al indice para continuar."
|
||||
@@ -33,19 +33,19 @@ class CommitCommand(Command):
|
||||
|
||||
if branch.startswith("wip/"):
|
||||
original_branch = branch.removeprefix("wip/")
|
||||
Git("commit", m=message).exec()
|
||||
Git("commit", m=message).exec(print="Creando commit en rama WIP")
|
||||
|
||||
if commit_type != "wip":
|
||||
suffix = datetime.now().strftime("%Y%m%dT%H%M")
|
||||
Git("switch", original_branch).exec()
|
||||
Git("merge", branch, squash=True).exec()
|
||||
Git("commit", m=message).exec()
|
||||
Git("branch", branch, "trash/" + branch + "/" + suffix, move=True).exec()
|
||||
Git("switch", original_branch).exec(print="Volviendo a rama original")
|
||||
Git("merge", branch, squash=True).exec(print="Squasheando commits WIP en uno solo")
|
||||
Git("commit", m=message).exec(print="Creando commit final de rama WIP")
|
||||
Git("branch", branch, "trash/" + branch + "/" + suffix, move=True).exec(print="Backup de rama WIP")
|
||||
else:
|
||||
if commit_type == "wip":
|
||||
Git("switch", "wip/" + branch, create=True).exec()
|
||||
Git("switch", "wip/" + branch, create=True).exec(print="Creando nueva rama WIP")
|
||||
|
||||
Git("commit", m=message).exec()
|
||||
Git("commit", m=message).exec(print="Creando commit")
|
||||
|
||||
def _has_files_staged(self):
|
||||
status = Git.status()
|
||||
|
||||
@@ -45,13 +45,10 @@ class InitCommand(Command):
|
||||
Git("init").exec()
|
||||
|
||||
def _ensure_not_already_initialized(self):
|
||||
if os.path.isfile(FLOWCONFIG_FILE):
|
||||
flowconfig = Git.get_config(FLOWCONFIG_FILE)
|
||||
|
||||
if flowconfig["flow.initialized"] == "true":
|
||||
raise GitFlowError(
|
||||
"El repositorio ya fue inicializado para usar git-flow"
|
||||
)
|
||||
if not self.flowconfig:
|
||||
return
|
||||
elif self.flowconfig.get("flow.initialized") == "true":
|
||||
raise GitFlowError("El repositorio ya fue inicializado para usar git-flow")
|
||||
else:
|
||||
raise GitFlowError("Valor de 'flow.initialized' es inválido")
|
||||
|
||||
@@ -79,7 +76,7 @@ class InitCommand(Command):
|
||||
remote = None
|
||||
|
||||
if self.confirm("¿Configurar repositorio remoto?"):
|
||||
remotes = Git("remote").lines()
|
||||
remotes = Git("remote").lines(print="Listando remotos disponibles")
|
||||
|
||||
if not remotes:
|
||||
self.info("No tiene ningún repositorio remoto, se creará uno.")
|
||||
@@ -89,7 +86,7 @@ class InitCommand(Command):
|
||||
persistent=True,
|
||||
)
|
||||
remote = "origin"
|
||||
Git("remote", "add", remote, url).exec()
|
||||
Git("remote", "add", remote, url).exec(print="Agregando remoto")
|
||||
elif len(remotes) == 1:
|
||||
remote = remotes[0]
|
||||
else:
|
||||
@@ -109,7 +106,11 @@ class InitCommand(Command):
|
||||
|
||||
for branch in branches:
|
||||
if branch not in existing_branches:
|
||||
Git("branch", branch, target_branch).exec()
|
||||
Git("branch", branch, target_branch).exec(
|
||||
print="Creando rama inexistente"
|
||||
)
|
||||
|
||||
if remote:
|
||||
Git("push", remote, branch, set_upstream=True).exec()
|
||||
Git("push", remote, branch, set_upstream=True).exec(
|
||||
print="Creando rama en remoto"
|
||||
)
|
||||
|
||||
@@ -29,14 +29,17 @@ class MergeCommand(Command):
|
||||
def run_remote(self, remote: str, token: str, base: str, branch: str, target: str):
|
||||
self.check_pending_changes(True)
|
||||
|
||||
Git("switch", target).exec()
|
||||
Git("pull").exec()
|
||||
Git("switch", "-").exec()
|
||||
Git("switch", target).exec(print="Cambiando a rama destino")
|
||||
Git("pull").exec(print="Obteniendo ultimos cambios del remoto")
|
||||
Git("switch", "-").exec(print="Volviendo a rama a mergear")
|
||||
|
||||
self.check_merge_conflicts(target)
|
||||
self.show_commits_to_merge(base)
|
||||
|
||||
Git("push", remote, branch, set_upstream=True).exec()
|
||||
if self.confirm(f"¿Crear PR de '{branch}' a '{target}'?"):
|
||||
Git("push", remote, branch, set_upstream=True).exec(
|
||||
print="Subiendo rama al remoto para crear PR"
|
||||
)
|
||||
|
||||
self.create_pull_request(token, base, branch, target)
|
||||
|
||||
@@ -45,9 +48,9 @@ class MergeCommand(Command):
|
||||
self.check_merge_conflicts(target)
|
||||
self.show_commits_to_merge(base)
|
||||
|
||||
if self.confirm(f"Mergear rama '{target}' <= '{branch}'?"):
|
||||
Git("switch", target).exec()
|
||||
Git("merge", branch, ff=False).exec()
|
||||
if self.confirm(f"¿Mergear rama '{branch}' a '{target}'?"):
|
||||
Git("switch", target).exec(print="Cambiando a rama destino")
|
||||
Git("merge", branch, ff=False).exec(print="Mergeando")
|
||||
|
||||
def check_pending_changes(self, has_remote: bool):
|
||||
status = Git.status()
|
||||
@@ -78,10 +81,13 @@ class MergeCommand(Command):
|
||||
print("- " + commit)
|
||||
|
||||
def check_merge_conflicts(self, target: str):
|
||||
merge_conflicts = Git("merge", target, ff=False, commit=False).code() != 0
|
||||
merge_conflicts = Git("merge", target, ff=False, commit=False).code(
|
||||
print="Realizando merge de prueba para verificar conflictos"
|
||||
)
|
||||
|
||||
Git("merge", abort=True).exec(print="Abortando merge de prueba", check=False)
|
||||
|
||||
if merge_conflicts:
|
||||
Git("merge", abort=True).exec()
|
||||
self.error(f"La rama actual tiene conflictos con {target}")
|
||||
self.info(
|
||||
f"""Se recomienda mergear {target} a la rama actual, resolver los conflictos localmente, y ejecutar nuevamente este comando"""
|
||||
|
||||
@@ -22,7 +22,7 @@ class NewCommand(Command):
|
||||
new_branch = self._get_unique_branch_name(branch_type)
|
||||
|
||||
if self.confirm(f"¿Crear rama '{new_branch}' sobre la rama actual?"):
|
||||
Git("switch", new_branch, create=True).exec()
|
||||
Git("switch", new_branch, create=True).exec(print="Creando nueva rama")
|
||||
|
||||
def _get_unique_branch_name(self, branch_type: str) -> str:
|
||||
self.info(
|
||||
|
||||
@@ -43,17 +43,15 @@ class TagCommand(Command):
|
||||
changelog = Changelog()
|
||||
|
||||
changelog.update(next_tag, base, branch)
|
||||
Git("add", Changelog.FILENAME).exec()
|
||||
Git("commit", message=Changelog.COMMIT_MESSAGE).exec()
|
||||
Git("add", Changelog.FILENAME).exec(print="Agregando nuevo CHANGELOG.md")
|
||||
Git("commit", message=Changelog.COMMIT_MESSAGE).exec(print="Creando commit")
|
||||
tag_commit = Git("show", "HEAD", patch=False, format="%h").firstline()
|
||||
|
||||
self.check_not_tagged(tag_commit)
|
||||
|
||||
if ci:
|
||||
Git("push").exec()
|
||||
Git("push").exec(print="Subiendo commit al remoto para taggearlo")
|
||||
self.success(self.get_remote_api(token).create_tag(next_tag, tag_commit))
|
||||
else:
|
||||
Git("tag", next_tag, tag_commit).exec()
|
||||
Git("tag", next_tag, tag_commit).exec(print="Creando tag localmente")
|
||||
|
||||
def get_token_and_ci(self, args: Namespace):
|
||||
try:
|
||||
@@ -77,11 +75,7 @@ class TagCommand(Command):
|
||||
return commit
|
||||
|
||||
def check_not_tagged(self, commit: str):
|
||||
tag = (
|
||||
Git("describe", commit, tags=True, exact_match=True)
|
||||
.without_checking()
|
||||
.firstline()
|
||||
)
|
||||
tag = Git("describe", commit, tags=True, exact_match=True).firstline(check=False)
|
||||
|
||||
if tag:
|
||||
raise GitFlowError("El commit a taggear ya tiene tag: " + tag)
|
||||
|
||||
+30
-26
@@ -22,7 +22,6 @@ class Git:
|
||||
self.file = line[3:].strip("\n")
|
||||
|
||||
command: list[str]
|
||||
check_returncode: bool = True
|
||||
|
||||
@staticmethod
|
||||
def get_config(file: str | None = None):
|
||||
@@ -60,7 +59,7 @@ class Git:
|
||||
|
||||
@staticmethod
|
||||
def get_current_tag():
|
||||
return Git("describe", abbrev="0", tags=True).without_checking().firstline()
|
||||
return Git("describe", abbrev="0", tags=True).firstline(check=False)
|
||||
|
||||
@staticmethod
|
||||
def get_first_fork_point(branch: str, env: str):
|
||||
@@ -115,44 +114,47 @@ class Git:
|
||||
|
||||
self.command += args
|
||||
|
||||
def lines(self, strip: bool = True):
|
||||
process = subprocess.run(self.command, capture_output=True, text=True)
|
||||
|
||||
self.__print_process(process.stdout, process.stderr)
|
||||
|
||||
if self.check_returncode:
|
||||
process.check_returncode()
|
||||
|
||||
def lines(self, strip: bool = True, **kwargs):
|
||||
process = self._get(**kwargs)
|
||||
lines = process.stdout.splitlines()
|
||||
|
||||
return lines if not strip else list(map(lambda l: l.strip(), lines))
|
||||
|
||||
def firstline(self):
|
||||
lines = self.lines()
|
||||
def firstline(self, **kwargs: bool):
|
||||
lines = self.lines(**kwargs)
|
||||
|
||||
return lines[0] if lines else ""
|
||||
|
||||
def exec(self):
|
||||
def code(self, **kwargs):
|
||||
return self._run(check=False, **kwargs).returncode
|
||||
|
||||
def exec(self, **kwargs):
|
||||
self._run(**kwargs)
|
||||
|
||||
def _get(self, print: str|None = None, check: bool = True):
|
||||
process = subprocess.run(self.command, capture_output=True, text=True)
|
||||
|
||||
self.__print_process(process.stdout, process.stderr)
|
||||
if print is not None:
|
||||
self._print_process(process.stdout, process.stderr, print)
|
||||
|
||||
if self.check_returncode:
|
||||
if check:
|
||||
process.check_returncode()
|
||||
|
||||
def code(self):
|
||||
process = subprocess.run(self.command, capture_output=True, text=True)
|
||||
return process
|
||||
|
||||
self.__print_process(process.stdout, process.stderr)
|
||||
|
||||
return process.returncode
|
||||
def _run(self, print: str|None = None, check: bool = True):
|
||||
process = subprocess.run(self.command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
def without_checking(self):
|
||||
self.check_returncode = False
|
||||
if print is not None:
|
||||
self._print_process("", "", title=print)
|
||||
|
||||
return self
|
||||
if check:
|
||||
process.check_returncode()
|
||||
|
||||
def __print_process(self, stdout: str, stderr: str):
|
||||
return process
|
||||
|
||||
def _print_process(self, stdout: str, stderr: str, title: str):
|
||||
command = []
|
||||
|
||||
for arg in self.command:
|
||||
@@ -164,10 +166,12 @@ class Git:
|
||||
|
||||
command.append(arg)
|
||||
|
||||
print(COLOR_YELLOW + "> " + " ".join(command) + COLOR_RESET)
|
||||
title = title or "Ejecutando"
|
||||
print(COLOR_YELLOW + "| " + title + COLOR_RESET)
|
||||
print(COLOR_YELLOW + "| $ " + " ".join(command) + COLOR_RESET)
|
||||
|
||||
for line in stdout.splitlines():
|
||||
print(COLOR_BLUE + "< " + line + COLOR_RESET)
|
||||
print(COLOR_YELLOW + "| " + COLOR_RESET + "[out] " + line)
|
||||
|
||||
for line in stderr.splitlines():
|
||||
print(COLOR_RED + "! " + line + COLOR_RESET)
|
||||
print(COLOR_YELLOW + "| " + COLOR_RED + "[err] " + line + COLOR_RESET)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
from os.path import isfile
|
||||
import sys
|
||||
import datetime
|
||||
import requests
|
||||
@@ -15,7 +16,7 @@ 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.git import BUMP_VERSION, FLOWCONFIG_FILE, Git
|
||||
from git_flow.io import *
|
||||
|
||||
|
||||
@@ -54,6 +55,7 @@ class GitFlowCommand(Command):
|
||||
|
||||
for command in self.commands:
|
||||
if command.name() == args.command:
|
||||
command.flowconfig = Git.get_config(FLOWCONFIG_FILE) if isfile(FLOWCONFIG_FILE) else {}
|
||||
return command.run(args)
|
||||
|
||||
|
||||
@@ -216,7 +218,7 @@ def tag_command():
|
||||
message = output[pos+1:]
|
||||
merged_branch = None
|
||||
|
||||
output = Git("describe", commit, tags=True, exact_match=True).without_checking().firstline()
|
||||
output = Git("describe", commit, tags=True, exact_match=True).firstline(check=False)
|
||||
|
||||
if output:
|
||||
print_error("El ultimo merge ya tiene tag: " + output)
|
||||
|
||||
Reference in New Issue
Block a user