Compare commits

..
55 Commits
Author SHA1 Message Date
gitea-actions 4968667dad chore: bump version and update CHANGELOG.md [skip ci] 2026-07-09 21:15:32 +00:00
jt 79ae88b012 Merge pull request 'bugfix: actualizo versiones de checkout, setup-python, clonar depth completo' (#10) from bugfix/publish-pypi-workflow into main
Reviewed-on: #10
2026-07-09 21:15:00 +00:00
jt 4666503f32 bugfix: actualizo versiones de checkout, setup-python, clonar depth completo 2026-07-09 18:14:38 -03:00
gitea-actions 4c089eb8da chore: bump version and update CHANGELOG.md [skip ci] 2026-07-09 21:05:19 +00:00
jt dc858d026f Merge pull request 'feature: add publish pypi package workflow' (#9) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #9
2026-07-09 21:05:03 +00:00
jt 5989699f08 bugfix: usar https por defecto como esquema si se detecta ssh 2026-07-09 18:04:40 -03:00
jt ecfe058f8d feature: usar esquema de remoto para host de api gitea 2026-07-09 18:00:39 -03:00
gitea-actions ffe813bf06 chore: bump version and update CHANGELOG.md [skip ci] 2026-07-09 01:21:44 +00:00
jt 6cd6771241 Merge pull request 'bugfix: agregar setup previo a ejecucion de git tag' (#8) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #8
2026-07-09 01:21:35 +00:00
jt 1cc2de0b75 bugfix: agregar setup previo a ejecucion de git tag 2026-07-08 22:21:17 -03:00
jt 0e669019f4 Merge pull request 'bugfix: arreglo acceso a secretos' (#7) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #7
2026-07-09 01:11:06 +00:00
jt d456565b2f bugfix: arreglo acceso a secretos 2026-07-08 22:10:35 -03:00
jt 74a78d30a1 Merge pull request 'bugfix: agrego fetch-depth a checkout' (#6) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #6
2026-07-09 01:08:20 +00:00
jt ad8984cb28 bugfix: agrego fetch-depth a checkout 2026-07-08 22:08:02 -03:00
jt 53b02f1f8f Merge pull request 'bugfix: agrego log de git luego del checkout' (#5) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #5
2026-07-09 01:06:41 +00:00
jt bf6a0e8443 bugfix: agrego log de git luego del checkout 2026-07-08 22:06:24 -03:00
jt 12351e64ba Merge pull request 'bugfix: cambio version de action setup-uv' (#4) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #4
2026-07-09 00:59:09 +00:00
jt cb742425c1 bugfix: cambio version de action setup-uv 2026-07-08 21:58:52 -03:00
jt bd47b40aff Merge pull request 'feature: agrego workflow para subir paquete a pypi' (#3) from feature/add-publish-pypi-package-workflow into main
Reviewed-on: #3
2026-07-09 00:55:53 +00:00
jt e94ee2ccc7 feature: agrego workflow para subir paquete a pypi 2026-07-08 21:55:16 -03:00
jt 069c62b697 Merge pull request 'feature: agrego implementacion de github remote api' (#2) from feature/add-github-remote-api into main
Reviewed-on: #2
2026-07-09 00:28:52 +00:00
jt c18ca454c0 feature: agrego implementacion de github remote api 2026-07-08 21:27:42 -03:00
jt 0fcf53bcb5 Merge pull request 'feature: add gitea remote api' (#1) from feature/add-gitea-remote-api into main
Reviewed-on: #1
2026-07-09 00:22:34 +00:00
jt f9dddbc4d6 bugfix: agregar schema a host de gitea api 2026-07-08 21:20:43 -03:00
jt c7888c74f1 bugfix: corregir headers de gitea 2026-07-08 21:19:24 -03:00
jt 87c5ba81c4 feature: agrego soporte para apis gitea 2026-07-08 21:12:06 -03:00
jt a10e9fe4fe Add .gitea/workflows/demo.yaml 2026-07-08 02:56:08 +00:00
bitbucket-pipelines c93833769b chore: bump version and update CHANGELOG.md [skip ci] 2026-06-03 00:40:26 +00:00
JonathanGitFlowandjt c536deb54d Merged in bugfix/allow-commit-messages-non-conventional (pull request #77)
bugfix: allow commits not compliant with conventional commits in changelog generation

Approved-by: Jonathan Teran
2026-06-03 00:39:43 +00:00
jt 3ff9f76a6c bugfix: allow commits not compliant with conventional commits in changelog generation 2026-06-02 21:38:18 -03:00
bitbucket-pipelines 1c319beff4 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-24 05:42:13 +00:00
JonathanGitFlowandjt f885c27e08 Merged in bugfix/pr-title-with-ticket (pull request #76)
bugfix: use rest of branch name instead of ticket for pr title generation

Approved-by: Jonathan Teran
2026-05-24 05:41:05 +00:00
jt 094bc1a698 bugfix: use rest of branch name instead of ticket for pr title generation 2026-05-24 02:40:33 -03:00
bitbucket-pipelines 9b0d7d6166 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-22 19:20:02 +00:00
JonathanGitFlowandjt f52edf03e0 Merged in bugfix/prevent-close-branch-on-environment-merges (pull request #75)
bugfix: dont close branches on merges between environments

Approved-by: Jonathan Teran
2026-05-22 19:19:30 +00:00
Jonathan Teran 8ee01290ef bugfix: dont close branches on merges between environments 2026-05-22 16:18:56 -03:00
bitbucket-pipelines 9c89f4d638 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-22 19:14:59 +00:00
JonathanGitFlowandjt 8d35610c00 Merged in bugfix/customize-pr-title-on-environment-merges (pull request #74)
bugfix: change pr title on merges between environments

Approved-by: Jonathan Teran
2026-05-22 19:14:19 +00:00
Jonathan Teran de124baf1a bugfix: change pr title on merges between environments 2026-05-22 16:13:39 -03:00
bitbucket-pipelines 2676f41def chore: bump version and update CHANGELOG.md [skip ci] 2026-05-20 20:14:50 +00:00
JonathanGitFlowandjt 22fd68c5b6 Merged in bugfix/dont-push-environment-branches-on-merge (pull request #73)
bugfix: dont push environment branches since they are already created on remote

Approved-by: Jonathan Teran
2026-05-20 20:14:08 +00:00
jt 04c9a4b449 bugfix: dont push environment branches since they are already created on remote 2026-05-20 17:13:34 -03:00
JonathanGitFlowandjt 417021b36e Merged in refactor/unify-flow-environments-usage (pull request #72)
refactor: unify flow branches usage

Approved-by: Jonathan Teran
2026-05-20 20:12:26 +00:00
jt be245114d5 refactor: unify flow branches usage 2026-05-20 17:10:58 -03:00
bitbucket-pipelines 184b135886 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-20 20:01:41 +00:00
JonathanGitFlowandjt acc0e8666a Merged in feature/allow-environment-merges (pull request #71)
feature: allow merges between environments

Approved-by: Jonathan Teran
2026-05-20 20:00:57 +00:00
jt 5806aeab27 feature: allow merges between environments 2026-05-20 17:00:20 -03:00
bitbucket-pipelines 23eb9df482 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-20 12:20:37 +00:00
JonathanGitFlowandjt 538c9130dc Merged in bugfix/pr-title-getter (pull request #70)
bugfix: arreglo split de branch para armar correctamente el titulo del PR

Approved-by: Jonathan Teran
2026-05-20 12:19:58 +00:00
Jonathan Teran Carballo a0d3028904 bugfix: arreglo split de branch para armar correctamente el titulo del PR 2026-05-20 09:19:24 -03:00
bitbucket-pipelines 59b9e1c419 chore: bump version and update CHANGELOG.md [skip ci] 2026-05-20 02:30:52 +00:00
JonathanGitFlowandjt 8793248dbe Merged in feature/add-ticket-support (pull request #69)
feature: agrego soporte para especificar tickets en nombre e rama

Approved-by: Jonathan Teran
2026-05-20 02:30:18 +00:00
jt f389118515 feature: agrego soporte para especificar tickets en nombre e rama 2026-05-19 23:29:22 -03:00
JonathanGitFlowandjt 5a7ed03801 Merged in refactor/move-constants-to-git_flow (pull request #68)
refactor: move constants to git_flow module

Approved-by: Jonathan Teran
2026-05-17 14:48:46 +00:00
Jonathan Teran Carballo 5f7db6cf5d refactor: move constants to git_flow module 2026-05-17 11:48:02 -03:00
18 changed files with 361 additions and 92 deletions
+2
View File
@@ -2,3 +2,5 @@
remote = origin
branches = main
initialized = true
version = 2
remote-type = gitea
+37
View File
@@ -0,0 +1,37 @@
name: Publish to PyPI
on:
push:
branches:
- main
jobs:
Publish-to-PyPI:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Configure git
run: |
git config --global user.name "gitea-actions"
git config --global user.email "actions@git.jonathanteran.dev"
git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: "Set up Python"
uses: actions/setup-python@v6
with:
python-version-file: ".python-version"
- name: Install uv
uses: astral-sh/setup-uv@v8.3.2
- name: Bump version
run: |
uv run git-flow tag --token="${{ secrets.GITEA_TOKEN }}"
- name: Build and publish
run: |
uv build
uv publish --token="${{ secrets.PYPI_TOKEN }}"
+89
View File
@@ -1,3 +1,92 @@
## v1.17.6 - 2026-07-09
- **bugfix**: actualizo versiones de checkout, setup-python, clonar depth completo [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (4666503)
---
## v0.1.0-main - 2026-07-09
- **bugfix**: usar https por defecto como esquema si se detecta ssh [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (5989699)
- **feature**: usar esquema de remoto para host de api gitea [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (ecfe058)
- **bugfix**: agregar setup previo a ejecucion de git tag [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (1cc2de0)
- **bugfix**: arreglo acceso a secretos [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (d456565)
- **bugfix**: agrego fetch-depth a checkout [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (ad8984c)
- **bugfix**: agrego log de git luego del checkout [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (bf6a0e8)
- **bugfix**: cambio version de action setup-uv [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (cb74242)
- **feature**: agrego workflow para subir paquete a pypi [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (e94ee2c)
---
## v0.1.0-main - 2026-07-09
- **bugfix**: agregar setup previo a ejecucion de git tag [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (1cc2de0)
- **bugfix**: arreglo acceso a secretos [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (d456565)
- **bugfix**: agrego fetch-depth a checkout [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (ad8984c)
- **bugfix**: agrego log de git luego del checkout [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (bf6a0e8)
- **bugfix**: cambio version de action setup-uv [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (cb74242)
- **feature**: agrego workflow para subir paquete a pypi [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (e94ee2c)
---
## v1.17.5 - 2026-06-03
- **bugfix**: allow commits not compliant with conventional commits in changelog generation [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (3ff9f76)
---
## v1.17.4 - 2026-05-24
- **bugfix**: use rest of branch name instead of ticket for pr title generation [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (094bc1a)
---
## v1.17.3 - 2026-05-22
- **bugfix**: dont close branches on merges between environments [[jteran](mailto:jteran@renatre.org.ar)] (8ee0129)
---
## v1.17.2 - 2026-05-22
- **bugfix**: change pr title on merges between environments [[jteran](mailto:jteran@renatre.org.ar)] (de124ba)
---
## v1.17.1 - 2026-05-20
- **bugfix**: dont push environment branches since they are already created on remote [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (04c9a4b)
---
## v1.17.0 - 2026-05-20
- **feature**: allow merges between environments [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (5806aea)
---
## v1.16.1 - 2026-05-20
- **bugfix**: arreglo split de branch para armar correctamente el titulo del PR [[jteran](mailto:jteran@renatre.org.ar)] (a0d3028)
---
## v1.16.0 - 2026-05-20
- **feature**: agrego soporte para especificar tickets en nombre e rama [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (f389118)
---
## v1.15.0 - 2026-05-17
- **feature**: include revlist count in version tag when skipping bump [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (d275ac0)
+2 -1
View File
@@ -47,7 +47,8 @@ El comando solicitará 2 opciones:
automáticamente. Por el momento, se soportan los siguientes remotos:
- [x] Bitbucket
- [ ] Github: planeado
- [x] Github
- [x] Gitea
La configuración del remoto requiere tener un Access Token para poder crear los PRs automáticamente.
El mismo se puede crear desde el repositorio al que se quiere dar acceso: *"Repository settings" >
+4
View File
@@ -49,3 +49,7 @@ SUPPORTED_REMOTE_APIS = [
]
REPOSITORY_TOKEN_FILENAME = ".repository-token"
FLOWCONFIG_FILENAME = ".flowconfig"
FLOWCONFIG_VERSION = 2
+5 -1
View File
@@ -28,11 +28,15 @@ class Changelog:
message = Git("show", commit, patch=False, format="%s").firstline()
email = Git("show", commit, patch=False, format="%ae").firstline()
username = email[: email.index("@")]
description = message
if ":" in message:
index = message.index(":")
commit_type = message[:index]
commit_message = message[index + 1 :]
description = f"**{commit_type}**: {commit_message}"
content += f"- **{commit_type}**: {commit_message} [[{username}](mailto:{email})] ({commit})\n"
content += f"- {description} [[{username}](mailto:{email})] ({commit})\n"
return content
+37 -11
View File
@@ -1,12 +1,15 @@
from git_flow import (
BRANCH_TYPES,
REPOSITORY_TOKEN_FILENAME,
FLOWCONFIG_FILENAME,
FLOWCONFIG_VERSION,
GitFlowError,
)
from git_flow.git import FLOWCONFIG_FILE, Git
from git_flow.git import Git
from git_flow.remote.base import RemoteAPI
from git_flow.remote.bitbucket import BitbucketRemoteAPI
from git_flow.remote.github import GithubRemoteAPI
from git_flow.remote.gitea import GiteaRemoteAPI
from git_flow.io import *
from os.path import isfile
@@ -16,8 +19,8 @@ TYPE_ERROR = 2
TYPE_INFO = 3
flowconfig = Git.get_config(FLOWCONFIG_FILE) if isfile(FLOWCONFIG_FILE) else {}
flowconfig = Git.get_config(FLOWCONFIG_FILENAME) if isfile(FLOWCONFIG_FILENAME) else {}
environments = flowconfig["flow.branches"].split(",") if "flow.branches" in flowconfig else []
def ensure_initialized():
initialized = flowconfig["flow.initialized"] if flowconfig else None
@@ -31,6 +34,14 @@ def ensure_initialized():
f"El valor de `flow.initialized` ({initialized}) es inválido."
)
version = int(flowconfig.get("flow.version", "1"))
if version != FLOWCONFIG_VERSION:
raise GitFlowError(
f"La versión del flowconfig ({version}) no es compatible con esta versión de git-flow ({FLOWCONFIG_VERSION}). "
f"Debe reinicializar el repositorio."
)
def ensure_right_branch():
branch = Git.get_current_branch()
@@ -45,7 +56,6 @@ def ensure_right_branch():
def get_branch_env_and_type(branch: str) -> tuple[str, str]:
components = branch.split("/")
target_branches = flowconfig["flow.branches"].split(",")
if len(components) == 2:
if components[0] not in BRANCH_TYPES:
@@ -53,13 +63,13 @@ def get_branch_env_and_type(branch: str) -> tuple[str, str]:
f"Branch inválida, el tipo '{components[0]}' no es válido."
)
return (target_branches[0], components[0])
return (environments[0], components[0])
elif len(components) == 4:
target_branches = target_branches[1:]
valid_environments = environments[1:]
if (
components[0] != "release"
or components[1] not in target_branches
or components[1] not in valid_environments
or components[2] not in BRANCH_TYPES
):
raise GitFlowError(
@@ -104,11 +114,27 @@ def get_remote_api(token: str) -> RemoteAPI:
if "flow.remote" not in flowconfig:
raise GitFlowError("El repositorio no tiene configurado un remoto.")
[host, repository] = RemoteAPI.parse(flowconfig["flow.remote"])
remote_type = flowconfig.get("flow.remote-type", "").lower()
[schema, host, repository] = RemoteAPI.parse(flowconfig["flow.remote"])
if host == "bitbucket.org":
if remote_type == "gitea":
return GiteaRemoteAPI(("https://" if schema == "ssh://" else schema) + host, repository, token)
elif remote_type == "bitbucket":
return BitbucketRemoteAPI(repository, token)
elif host == "github.com":
elif remote_type == "github":
return GithubRemoteAPI(repository, token)
else:
raise GitFlowError("El host del repositorio remoto es inválido")
raise GitFlowError("El tipo del remoto es inválido")
def is_valid_ticket(ticket: str) -> bool:
"""Check if the specified string is a valid ticket number (ABC-123)"""
components = ticket.split("-")
if len(components) != 2:
return False
ticket_project = components[0]
ticket_number = components[1]
return ticket_project.isalpha() and ticket_project.isupper() and ticket_number.isnumeric()
-1
View File
@@ -41,7 +41,6 @@ def branch(
ensure_initialized()
current_branch = Git.get_current_branch()
environments = flowconfig["flow.branches"].split(",")
if current_branch in environments:
current_environment = current_branch
+12 -8
View File
@@ -1,7 +1,7 @@
import typer
from git_flow import GitFlowError
from git_flow.git import FLOWCONFIG_FILE, Git
from git_flow import FLOWCONFIG_FILENAME, FLOWCONFIG_VERSION, GitFlowError
from git_flow.git import Git
from git_flow.command.base import *
app = typer.Typer()
@@ -15,18 +15,20 @@ def init():
_ensure_not_already_initialized()
branches = _setup_flow_branches()
remote = _setup_flow_remote()
(remote, remote_type) = _setup_flow_remote()
flowconfig = {
"flow.version": str(FLOWCONFIG_VERSION),
"flow.initialized": "true",
"flow.branches": ",".join(branches),
}
if remote:
if remote and remote_type:
flowconfig["flow.remote"] = remote
flowconfig["flow.remote-type"] = remote_type
Git.set_config(flowconfig, FLOWCONFIG_FILE)
Git("add", FLOWCONFIG_FILE).exec()
Git.set_config(flowconfig, FLOWCONFIG_FILENAME)
Git("add", FLOWCONFIG_FILENAME).exec()
Git("commit", message="feature: initialize git-flow").exec()
_ensure_all_flow_branches_exist(branches, remote)
@@ -43,7 +45,6 @@ def _ensure_is_repository():
def _ensure_not_already_initialized():
flowconfig = get_config()
if not flowconfig:
return
elif flowconfig.get("flow.initialized") == "true":
@@ -75,6 +76,7 @@ def _setup_flow_remote():
)
remote = None
remote_type = None
if confirm("¿Configurar repositorio remoto?"):
remotes = Git("remote").lines(print="Listando remotos disponibles")
@@ -94,7 +96,9 @@ def _setup_flow_remote():
info("Tiene más de un remoto, seleccione el que va a utilizar.")
remote = choice("Remoto", remotes)
return remote
remote_type = choice("Tipo de remoto:", ["bitbucket", "github", "gitea"])
return (remote, remote_type)
def _ensure_all_flow_branches_exist(branches: list[str], remote: str | None):
+48 -13
View File
@@ -13,6 +13,21 @@ def merge():
ensure_initialized()
branch = ensure_right_branch()
if branch in environments:
if branch == environments[-1]:
raise GitFlowError("No se puede hacer un merge del último entorno.")
panel(
"Merge de entornos",
"""Está por hacer un merge de 2 entornos que puede implicar muchos cambios en el proyecto.""",
)
if not confirm("¿Desea continuar?"):
raise GitFlowError("Ejecución abortada")
target = environments[environments.index(branch) + 1]
else:
target, _ = get_branch_env_and_type(branch)
if "flow.remote" in flowconfig:
@@ -34,6 +49,7 @@ def run_remote(remote: str, token: str, branch: str, target: str):
show_commits_to_merge(target)
if confirm(f"¿Crear PR de '{branch}' a '{target}'?"):
if branch not in environments:
Git("push", remote, branch, set_upstream=True).exec(
print="Subiendo rama al remoto para crear PR"
)
@@ -83,27 +99,19 @@ def check_merge_conflicts(target: str):
def create_pull_request(token: str, branch: str, target: str):
changelog = Changelog()
commits = Git("log", target + "..", format="%s").lines()
title = commits[0] if len(commits) == 1 else _get_pr_title_from_branch(branch)
if len(commits) == 1:
title = commits[0]
else:
title = branch.replace("/", ": ").replace("-", " ")
panel("Título del PR", title)
if title.startswith("release: "):
title = title[title.index(" ", title.index(" ") + 1) + 1 :]
info("Título del PR por defecto: " + title)
opt_title = prompt("[Opcional] Ingrese otro titulo para el PR")
if opt_title:
title = opt_title
if confirm("¿Desea cambiar el título del PR?", False):
title = prompt("Título del PR")
message = get_remote_api(token).create_pull_request(
branch,
target,
title,
changelog.generate_content(target, branch),
branch not in environments
)
success(message)
@@ -111,3 +119,30 @@ def create_pull_request(token: str, branch: str, target: str):
if confirm("¿Desea cambiar a la rama objetivo y bajar los cambios?"):
Git("switch", target).exec(print="Cambiando a rama objetivo")
Git("pull").exec(print="Obteniendo cambios")
def _get_pr_title_from_branch(branch: str) -> str:
if branch in environments:
target = environments[environments.index(branch) + 1]
return f"Sincronización de entorno {branch} a {target}"
components = branch.split("/") # <type>/<desc> or release/<env>/<type>/<desc>
branch_type = components[-2]
branch_desc = components[-1]
# detect if branch description has ticket as prefix: <desc> = ABC-123-my-branch-name
branch_ticket = None
first_dash = branch_desc.find("-")
second_dash = branch_desc.find("-", first_dash + 1)
if first_dash >= 0 and second_dash >= 0:
maybe_ticket = branch_desc[:second_dash]
if is_valid_ticket(maybe_ticket):
branch_ticket = maybe_ticket
branch_desc = branch_desc[second_dash+1:]
return " ".join(filter(None, [
f"[Pasaje a {components[1]}]" if len(components) == 4 else None,
branch_type + ":",
branch_ticket,
branch_desc.replace("-", " ")
]))
+16 -5
View File
@@ -2,6 +2,7 @@ import typer
from git_flow import BRANCH_TYPES
from git_flow.command.base import *
from git_flow.git import Git
from typing import Optional
app = typer.Typer()
@@ -12,16 +13,16 @@ def new():
ensure_initialized()
branch = ensure_right_branch()
envs = flowconfig["flow.branches"].split(",")
if branch not in envs:
if branch not in environments:
warning("La rama actual no corresponde a un entorno configurado.")
info("Se creará una nueva rama de trabajo sobre la rama actual.")
info("Debe seleccionar el tipo de cambio a realizar.")
branch_type = choice("Tipos de cambio", BRANCH_TYPES)
new_branch = _get_unique_branch_name(branch_type)
ticket = _get_optional_ticket()
new_branch = _get_unique_branch_name(branch_type, ticket)
if "flow.remote" in flowconfig and Git.get_tracking_branch(branch):
Git("pull").exec(print="Actualizando rama actual")
@@ -29,8 +30,18 @@ def new():
if confirm(f"¿Crear rama '{new_branch}' sobre la rama actual?"):
Git("switch", new_branch, create=True).exec(print="Creando nueva rama")
def _get_optional_ticket() -> Optional[str]:
ticket = prompt("[Opcional] Ticket que respalda el cambio (en formato ABC-123)")
def _get_unique_branch_name(branch_type: str) -> str:
if not ticket:
return None
if not is_valid_ticket(ticket):
warning("Formato de ticket inválido, ignorando.")
return None
return ticket
def _get_unique_branch_name(branch_type: str, ticket: Optional[str]) -> str:
info(f"Ingrese las palabras clave que describan el cambio de tipo '{branch_type}'.")
branch = None
branches = Git.get_branches()
@@ -42,7 +53,7 @@ def _get_unique_branch_name(branch_type: str) -> str:
)
keywords = filter(lambda k: len(k) > 0, keywords.split(" "))
branch = branch_type + "/" + "-".join(keywords)
branch = branch_type + "/" + (ticket + "-" if ticket else "") + "-".join(keywords)
if branch in branches:
error(
+2 -3
View File
@@ -13,10 +13,9 @@ def release(group: Optional[str] = None):
ensure_initialized()
branch = ensure_right_branch()
envs = flowconfig["flow.branches"].split(",")
env, _ = get_branch_env_and_type(branch)
if env == envs[-1]:
if env == environments[-1]:
raise GitFlowError(
"No se puede hacer release de una rama en el ultimo entorno."
)
@@ -25,7 +24,7 @@ def release(group: Optional[str] = None):
ensure_clean_worktree(has_remote)
next_env = envs[envs.index(env) + 1]
next_env = environments[environments.index(env) + 1]
next_branch = (
branch.replace(f"/{env}/", f"/{next_env}/")
if branch.startswith("release/")
+1 -2
View File
@@ -20,10 +20,9 @@ def tag(token: Optional[str] = None):
"""Crea un nuevo tag para el último merge."""
ensure_initialized()
envs = flowconfig["flow.branches"].split(",")
target = Git.get_current_branch()
if target not in envs:
if target not in environments:
raise GitFlowError("Solo se pueden taggear commits en ramas principales.")
branch = Git(
+2 -7
View File
@@ -1,13 +1,8 @@
import subprocess
from git_flow import FLOWCONFIG_FILENAME
from git_flow.io import *
FLOWCONFIG_FILE = ".flowconfig"
CHANGELOG_FILE = "CHANGELOG.md"
BUMP_VERSION = "chore: bump version and update CHANGELOG.md [skip ci]"
class Git:
class Status:
@@ -42,7 +37,7 @@ class Git:
@staticmethod
def flow_config(*args, **kwargs):
return Git("config", *args, file=FLOWCONFIG_FILE, **kwargs)
return Git("config", *args, file=FLOWCONFIG_FILENAME, **kwargs)
@staticmethod
def get_current_branch():
+11 -28
View File
@@ -12,42 +12,24 @@ class RemoteAPI(ABC):
@staticmethod
def parse(remote: str):
url = Git("remote", "get-url", remote).firstline()
invalid_url_error = GitFlowError(f"La URL del remoto {remote} es inválida: {url}")
url_type = None
if url.startswith("git@"):
url_type = "ssh"
elif url.startswith("http://") or url.startswith("https://"):
url_type = "https"
else:
raise invalid_url_error
if url_type == "ssh":
# git@host:user/repo[.git]
at_pos = url.index("@")
colon_pos = url.index(":")
schema = "ssh://"
host = url[at_pos+1:colon_pos]
repository = url[colon_pos+1:]
else:
# https://host/user/repo[.git]
host_start = url.index("://") + 3
uri_start = url.index("/", host_start)
host = url[host_start:uri_start]
elif url.startswith("http://") or url.startswith("https://"):
start_pos = url.index("://") + 3
uri_start = url.index("/", start_pos)
schema = url[:start_pos]
host = url[start_pos:uri_start]
repository = url[uri_start+1:]
else:
raise GitFlowError(f"La URL del remoto {remote} es inválida: {url}")
# Esto permite configurar hosts "imaginarios" para permitir el uso de multiples claves ssh
if host.endswith(".bitbucket.org"):
host = "bitbucket.org"
elif host.endswith(".github.com"):
host = "github.com"
if host not in SUPPORTED_REMOTE_APIS:
raise GitFlowError("El host del repositorio remoto es inválido")
repository.removesuffix(".git")
return [host, repository]
repository = repository.removesuffix(".git")
return [schema, host, repository]
@abstractmethod
def create_pull_request(
@@ -56,6 +38,7 @@ class RemoteAPI(ABC):
destination: str,
title: str | None = None,
description: str | None = None,
close_source_branch: bool = True
) -> str:
pass
+2 -1
View File
@@ -12,6 +12,7 @@ class BitbucketRemoteAPI(RemoteAPI):
destination: str,
title: str | None = None,
description: str | None = None,
close_source_branch: bool = True
):
request = requests.post(
self.get_endpoint("/pullrequests"),
@@ -21,7 +22,7 @@ class BitbucketRemoteAPI(RemoteAPI):
"description": description,
"source": {"branch": {"name": source}},
"destination": {"branch": {"name": destination}},
"close_source_branch": True,
"close_source_branch": close_source_branch,
},
)
+55
View File
@@ -0,0 +1,55 @@
import requests
from git_flow import GitFlowError
from git_flow.remote.base import RemoteAPI
class GiteaRemoteAPI(RemoteAPI):
def __init__(self, base_url: str, repository: str, token: str) -> None:
super().__init__(repository, token)
self.base_url = base_url
def create_pull_request(
self,
source: str,
destination: str,
title: str | None = None,
description: str | None = None,
close_source_branch: bool = True
) -> str:
response = requests.post(
self.get_endpoint("/pulls"),
headers=self.get_headers(),
json={
"title": title,
"body": description,
"head": source,
"base": destination,
},
)
if response.ok:
return "PR creado exitosamente: " + response.json()["html_url"]
else:
raise GitFlowError("Ocurrió un error al crear el PR: " + response.text)
def create_tag(self, tag: str, commit: str) -> str:
response = requests.post(
self.get_endpoint("/tags"),
headers=self.get_headers(),
json={"tag_name": tag, "target": commit},
)
if response.ok:
return "Tag creado exitosamente: " + tag
else:
raise GitFlowError("Ocurrió un error al crear el tag: " + response.text)
def get_endpoint(self, resource: str) -> str:
return f"{self.base_url}/api/v1/repos/{self.repository}{resource}"
def get_headers(self):
return {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "token " + self.token,
}
+29 -4
View File
@@ -1,9 +1,10 @@
import requests
from git_flow import GitFlowError
from git_flow.remote.base import RemoteAPI
class GithubRemoteAPI(RemoteAPI):
API_ENDPOINT = "https://github.com"
API_ENDPOINT = "https://api.github.com/repos"
def create_pull_request(
self,
@@ -11,11 +12,35 @@ class GithubRemoteAPI(RemoteAPI):
destination: str,
title: str | None = None,
description: str | None = None,
close_source_branch: bool = True
) -> str:
raise GitFlowError("not implemented yet!")
response = requests.post(
self.get_endpoint("/pulls"),
headers=self.get_headers(),
json={
"title": title,
"body": description,
"head": source,
"base": destination,
},
)
if response.ok:
return "PR creado exitosamente: " + response.json()["html_url"]
else:
raise GitFlowError("Ocurrió un error al crear el PR: " + response.text)
def create_tag(self, tag: str, commit: str) -> str:
raise GitFlowError("not implemented yet!")
response = requests.post(
self.get_endpoint("/git/refs"),
headers=self.get_headers(),
json={"ref": f"refs/tags/{tag}", "sha": commit},
)
if response.ok:
return "Tag creado exitosamente: " + tag
else:
raise GitFlowError("Ocurrió un error al crear el tag: " + response.text)
def get_endpoint(self, resource: str) -> str:
return GithubRemoteAPI.API_ENDPOINT
return f"{GithubRemoteAPI.API_ENDPOINT}/{self.repository}{resource}"