Compare commits
47
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4968667dad | ||
|
|
79ae88b012 | ||
|
|
4666503f32 | ||
|
|
4c089eb8da | ||
|
|
dc858d026f | ||
|
|
5989699f08 | ||
|
|
ecfe058f8d | ||
|
|
ffe813bf06 | ||
|
|
6cd6771241 | ||
|
|
1cc2de0b75 | ||
|
|
0e669019f4 | ||
|
|
d456565b2f | ||
|
|
74a78d30a1 | ||
|
|
ad8984cb28 | ||
|
|
53b02f1f8f | ||
|
|
bf6a0e8443 | ||
|
|
12351e64ba | ||
|
|
cb742425c1 | ||
|
|
bd47b40aff | ||
|
|
e94ee2ccc7 | ||
|
|
069c62b697 | ||
|
|
c18ca454c0 | ||
|
|
0fcf53bcb5 | ||
|
|
f9dddbc4d6 | ||
|
|
c7888c74f1 | ||
|
|
87c5ba81c4 | ||
|
|
a10e9fe4fe | ||
|
|
c93833769b | ||
|
|
c536deb54d | ||
|
|
3ff9f76a6c | ||
|
|
1c319beff4 | ||
|
|
f885c27e08 | ||
|
|
094bc1a698 | ||
|
|
9b0d7d6166 | ||
|
|
f52edf03e0 | ||
|
|
8ee01290ef | ||
|
|
9c89f4d638 | ||
|
|
8d35610c00 | ||
|
|
de124baf1a | ||
|
|
2676f41def | ||
|
|
22fd68c5b6 | ||
|
|
04c9a4b449 | ||
|
|
417021b36e | ||
|
|
be245114d5 | ||
|
|
184b135886 | ||
|
|
acc0e8666a | ||
|
|
5806aeab27 |
@@ -2,3 +2,5 @@
|
|||||||
remote = origin
|
remote = origin
|
||||||
branches = main
|
branches = main
|
||||||
initialized = true
|
initialized = true
|
||||||
|
version = 2
|
||||||
|
remote-type = gitea
|
||||||
|
|||||||
@@ -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 }}"
|
||||||
@@ -1,3 +1,78 @@
|
|||||||
|
## 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
|
## 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)
|
- **bugfix**: arreglo split de branch para armar correctamente el titulo del PR [[jteran](mailto:jteran@renatre.org.ar)] (a0d3028)
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ El comando solicitará 2 opciones:
|
|||||||
automáticamente. Por el momento, se soportan los siguientes remotos:
|
automáticamente. Por el momento, se soportan los siguientes remotos:
|
||||||
|
|
||||||
- [x] Bitbucket
|
- [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.
|
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" >
|
El mismo se puede crear desde el repositorio al que se quiere dar acceso: *"Repository settings" >
|
||||||
|
|||||||
@@ -51,3 +51,5 @@ SUPPORTED_REMOTE_APIS = [
|
|||||||
REPOSITORY_TOKEN_FILENAME = ".repository-token"
|
REPOSITORY_TOKEN_FILENAME = ".repository-token"
|
||||||
|
|
||||||
FLOWCONFIG_FILENAME = ".flowconfig"
|
FLOWCONFIG_FILENAME = ".flowconfig"
|
||||||
|
|
||||||
|
FLOWCONFIG_VERSION = 2
|
||||||
|
|||||||
@@ -28,11 +28,15 @@ class Changelog:
|
|||||||
message = Git("show", commit, patch=False, format="%s").firstline()
|
message = Git("show", commit, patch=False, format="%s").firstline()
|
||||||
email = Git("show", commit, patch=False, format="%ae").firstline()
|
email = Git("show", commit, patch=False, format="%ae").firstline()
|
||||||
username = email[: email.index("@")]
|
username = email[: email.index("@")]
|
||||||
|
description = message
|
||||||
|
|
||||||
|
if ":" in message:
|
||||||
index = message.index(":")
|
index = message.index(":")
|
||||||
commit_type = message[:index]
|
commit_type = message[:index]
|
||||||
commit_message = message[index + 1 :]
|
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
|
return content
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ from git_flow import (
|
|||||||
BRANCH_TYPES,
|
BRANCH_TYPES,
|
||||||
REPOSITORY_TOKEN_FILENAME,
|
REPOSITORY_TOKEN_FILENAME,
|
||||||
FLOWCONFIG_FILENAME,
|
FLOWCONFIG_FILENAME,
|
||||||
|
FLOWCONFIG_VERSION,
|
||||||
GitFlowError,
|
GitFlowError,
|
||||||
)
|
)
|
||||||
from git_flow.git import Git
|
from git_flow.git import Git
|
||||||
from git_flow.remote.base import RemoteAPI
|
from git_flow.remote.base import RemoteAPI
|
||||||
from git_flow.remote.bitbucket import BitbucketRemoteAPI
|
from git_flow.remote.bitbucket import BitbucketRemoteAPI
|
||||||
from git_flow.remote.github import GithubRemoteAPI
|
from git_flow.remote.github import GithubRemoteAPI
|
||||||
|
from git_flow.remote.gitea import GiteaRemoteAPI
|
||||||
from git_flow.io import *
|
from git_flow.io import *
|
||||||
from os.path import isfile
|
from os.path import isfile
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ TYPE_INFO = 3
|
|||||||
|
|
||||||
|
|
||||||
flowconfig = Git.get_config(FLOWCONFIG_FILENAME) if isfile(FLOWCONFIG_FILENAME) 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():
|
def ensure_initialized():
|
||||||
initialized = flowconfig["flow.initialized"] if flowconfig else None
|
initialized = flowconfig["flow.initialized"] if flowconfig else None
|
||||||
@@ -32,6 +34,14 @@ def ensure_initialized():
|
|||||||
f"El valor de `flow.initialized` ({initialized}) es inválido."
|
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():
|
def ensure_right_branch():
|
||||||
branch = Git.get_current_branch()
|
branch = Git.get_current_branch()
|
||||||
@@ -46,7 +56,6 @@ def ensure_right_branch():
|
|||||||
|
|
||||||
def get_branch_env_and_type(branch: str) -> tuple[str, str]:
|
def get_branch_env_and_type(branch: str) -> tuple[str, str]:
|
||||||
components = branch.split("/")
|
components = branch.split("/")
|
||||||
target_branches = flowconfig["flow.branches"].split(",")
|
|
||||||
|
|
||||||
if len(components) == 2:
|
if len(components) == 2:
|
||||||
if components[0] not in BRANCH_TYPES:
|
if components[0] not in BRANCH_TYPES:
|
||||||
@@ -54,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."
|
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:
|
elif len(components) == 4:
|
||||||
target_branches = target_branches[1:]
|
valid_environments = environments[1:]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
components[0] != "release"
|
components[0] != "release"
|
||||||
or components[1] not in target_branches
|
or components[1] not in valid_environments
|
||||||
or components[2] not in BRANCH_TYPES
|
or components[2] not in BRANCH_TYPES
|
||||||
):
|
):
|
||||||
raise GitFlowError(
|
raise GitFlowError(
|
||||||
@@ -105,14 +114,18 @@ def get_remote_api(token: str) -> RemoteAPI:
|
|||||||
if "flow.remote" not in flowconfig:
|
if "flow.remote" not in flowconfig:
|
||||||
raise GitFlowError("El repositorio no tiene configurado un remoto.")
|
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)
|
return BitbucketRemoteAPI(repository, token)
|
||||||
elif host == "github.com":
|
elif remote_type == "github":
|
||||||
return GithubRemoteAPI(repository, token)
|
return GithubRemoteAPI(repository, token)
|
||||||
else:
|
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:
|
def is_valid_ticket(ticket: str) -> bool:
|
||||||
"""Check if the specified string is a valid ticket number (ABC-123)"""
|
"""Check if the specified string is a valid ticket number (ABC-123)"""
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ def branch(
|
|||||||
ensure_initialized()
|
ensure_initialized()
|
||||||
|
|
||||||
current_branch = Git.get_current_branch()
|
current_branch = Git.get_current_branch()
|
||||||
environments = flowconfig["flow.branches"].split(",")
|
|
||||||
|
|
||||||
if current_branch in environments:
|
if current_branch in environments:
|
||||||
current_environment = current_branch
|
current_environment = current_branch
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import typer
|
import typer
|
||||||
|
|
||||||
from git_flow import FLOWCONFIG_FILENAME, 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 *
|
from git_flow.command.base import *
|
||||||
|
|
||||||
@@ -15,15 +15,17 @@ def init():
|
|||||||
_ensure_not_already_initialized()
|
_ensure_not_already_initialized()
|
||||||
|
|
||||||
branches = _setup_flow_branches()
|
branches = _setup_flow_branches()
|
||||||
remote = _setup_flow_remote()
|
(remote, remote_type) = _setup_flow_remote()
|
||||||
|
|
||||||
flowconfig = {
|
flowconfig = {
|
||||||
|
"flow.version": str(FLOWCONFIG_VERSION),
|
||||||
"flow.initialized": "true",
|
"flow.initialized": "true",
|
||||||
"flow.branches": ",".join(branches),
|
"flow.branches": ",".join(branches),
|
||||||
}
|
}
|
||||||
|
|
||||||
if remote:
|
if remote and remote_type:
|
||||||
flowconfig["flow.remote"] = remote
|
flowconfig["flow.remote"] = remote
|
||||||
|
flowconfig["flow.remote-type"] = remote_type
|
||||||
|
|
||||||
Git.set_config(flowconfig, FLOWCONFIG_FILENAME)
|
Git.set_config(flowconfig, FLOWCONFIG_FILENAME)
|
||||||
Git("add", FLOWCONFIG_FILENAME).exec()
|
Git("add", FLOWCONFIG_FILENAME).exec()
|
||||||
@@ -74,6 +76,7 @@ def _setup_flow_remote():
|
|||||||
)
|
)
|
||||||
|
|
||||||
remote = None
|
remote = None
|
||||||
|
remote_type = None
|
||||||
|
|
||||||
if confirm("¿Configurar repositorio remoto?"):
|
if confirm("¿Configurar repositorio remoto?"):
|
||||||
remotes = Git("remote").lines(print="Listando remotos disponibles")
|
remotes = Git("remote").lines(print="Listando remotos disponibles")
|
||||||
@@ -93,7 +96,9 @@ def _setup_flow_remote():
|
|||||||
info("Tiene más de un remoto, seleccione el que va a utilizar.")
|
info("Tiene más de un remoto, seleccione el que va a utilizar.")
|
||||||
remote = choice("Remoto", remotes)
|
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):
|
def _ensure_all_flow_branches_exist(branches: list[str], remote: str | None):
|
||||||
|
|||||||
@@ -13,6 +13,21 @@ def merge():
|
|||||||
ensure_initialized()
|
ensure_initialized()
|
||||||
|
|
||||||
branch = ensure_right_branch()
|
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)
|
target, _ = get_branch_env_and_type(branch)
|
||||||
|
|
||||||
if "flow.remote" in flowconfig:
|
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)
|
show_commits_to_merge(target)
|
||||||
|
|
||||||
if confirm(f"¿Crear PR de '{branch}' a '{target}'?"):
|
if confirm(f"¿Crear PR de '{branch}' a '{target}'?"):
|
||||||
|
if branch not in environments:
|
||||||
Git("push", remote, branch, set_upstream=True).exec(
|
Git("push", remote, branch, set_upstream=True).exec(
|
||||||
print="Subiendo rama al remoto para crear PR"
|
print="Subiendo rama al remoto para crear PR"
|
||||||
)
|
)
|
||||||
@@ -95,6 +111,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 environments
|
||||||
)
|
)
|
||||||
|
|
||||||
success(message)
|
success(message)
|
||||||
@@ -104,6 +121,10 @@ def create_pull_request(token: str, branch: str, target: str):
|
|||||||
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 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>
|
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]
|
||||||
@@ -117,7 +138,7 @@ def _get_pr_title_from_branch(branch: str) -> str:
|
|||||||
maybe_ticket = branch_desc[:second_dash]
|
maybe_ticket = branch_desc[:second_dash]
|
||||||
if is_valid_ticket(maybe_ticket):
|
if 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(filter(None, [
|
||||||
f"[Pasaje a {components[1]}]" if len(components) == 4 else None,
|
f"[Pasaje a {components[1]}]" if len(components) == 4 else None,
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ def new():
|
|||||||
|
|
||||||
ensure_initialized()
|
ensure_initialized()
|
||||||
branch = ensure_right_branch()
|
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.")
|
warning("La rama actual no corresponde a un entorno configurado.")
|
||||||
|
|
||||||
info("Se creará una nueva rama de trabajo sobre la rama actual.")
|
info("Se creará una nueva rama de trabajo sobre la rama actual.")
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ def release(group: Optional[str] = None):
|
|||||||
ensure_initialized()
|
ensure_initialized()
|
||||||
|
|
||||||
branch = ensure_right_branch()
|
branch = ensure_right_branch()
|
||||||
envs = flowconfig["flow.branches"].split(",")
|
|
||||||
env, _ = get_branch_env_and_type(branch)
|
env, _ = get_branch_env_and_type(branch)
|
||||||
|
|
||||||
if env == envs[-1]:
|
if env == 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."
|
||||||
)
|
)
|
||||||
@@ -25,7 +24,7 @@ def release(group: Optional[str] = None):
|
|||||||
|
|
||||||
ensure_clean_worktree(has_remote)
|
ensure_clean_worktree(has_remote)
|
||||||
|
|
||||||
next_env = envs[envs.index(env) + 1]
|
next_env = environments[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/")
|
||||||
|
|||||||
@@ -20,10 +20,9 @@ def tag(token: Optional[str] = None):
|
|||||||
"""Crea un nuevo tag para el último merge."""
|
"""Crea un nuevo tag para el último merge."""
|
||||||
ensure_initialized()
|
ensure_initialized()
|
||||||
|
|
||||||
envs = flowconfig["flow.branches"].split(",")
|
|
||||||
target = Git.get_current_branch()
|
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.")
|
raise GitFlowError("Solo se pueden taggear commits en ramas principales.")
|
||||||
|
|
||||||
branch = Git(
|
branch = Git(
|
||||||
|
|||||||
+11
-28
@@ -12,42 +12,24 @@ class RemoteAPI(ABC):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(remote: str):
|
def parse(remote: str):
|
||||||
url = Git("remote", "get-url", remote).firstline()
|
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@"):
|
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("@")
|
at_pos = url.index("@")
|
||||||
colon_pos = url.index(":")
|
colon_pos = url.index(":")
|
||||||
|
schema = "ssh://"
|
||||||
host = url[at_pos+1:colon_pos]
|
host = url[at_pos+1:colon_pos]
|
||||||
repository = url[colon_pos+1:]
|
repository = url[colon_pos+1:]
|
||||||
else:
|
elif url.startswith("http://") or url.startswith("https://"):
|
||||||
# https://host/user/repo[.git]
|
start_pos = url.index("://") + 3
|
||||||
host_start = url.index("://") + 3
|
uri_start = url.index("/", start_pos)
|
||||||
uri_start = url.index("/", host_start)
|
schema = url[:start_pos]
|
||||||
host = url[host_start:uri_start]
|
host = url[start_pos:uri_start]
|
||||||
repository = url[uri_start+1:]
|
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
|
repository = repository.removesuffix(".git")
|
||||||
if host.endswith(".bitbucket.org"):
|
return [schema, host, repository]
|
||||||
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]
|
|
||||||
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_pull_request(
|
def create_pull_request(
|
||||||
@@ -56,6 +38,7 @@ class RemoteAPI(ABC):
|
|||||||
destination: str,
|
destination: str,
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
close_source_branch: bool = True
|
||||||
) -> str:
|
) -> str:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class BitbucketRemoteAPI(RemoteAPI):
|
|||||||
destination: str,
|
destination: str,
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
close_source_branch: bool = True
|
||||||
):
|
):
|
||||||
request = requests.post(
|
request = requests.post(
|
||||||
self.get_endpoint("/pullrequests"),
|
self.get_endpoint("/pullrequests"),
|
||||||
@@ -21,7 +22,7 @@ class BitbucketRemoteAPI(RemoteAPI):
|
|||||||
"description": description,
|
"description": description,
|
||||||
"source": {"branch": {"name": source}},
|
"source": {"branch": {"name": source}},
|
||||||
"destination": {"branch": {"name": destination}},
|
"destination": {"branch": {"name": destination}},
|
||||||
"close_source_branch": True,
|
"close_source_branch": close_source_branch,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import requests
|
||||||
from git_flow import GitFlowError
|
from git_flow import GitFlowError
|
||||||
from git_flow.remote.base import RemoteAPI
|
from git_flow.remote.base import RemoteAPI
|
||||||
|
|
||||||
|
|
||||||
class GithubRemoteAPI(RemoteAPI):
|
class GithubRemoteAPI(RemoteAPI):
|
||||||
API_ENDPOINT = "https://github.com"
|
API_ENDPOINT = "https://api.github.com/repos"
|
||||||
|
|
||||||
def create_pull_request(
|
def create_pull_request(
|
||||||
self,
|
self,
|
||||||
@@ -11,11 +12,35 @@ class GithubRemoteAPI(RemoteAPI):
|
|||||||
destination: str,
|
destination: str,
|
||||||
title: str | None = None,
|
title: str | None = None,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
close_source_branch: bool = True
|
||||||
) -> str:
|
) -> 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:
|
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:
|
def get_endpoint(self, resource: str) -> str:
|
||||||
return GithubRemoteAPI.API_ENDPOINT
|
return f"{GithubRemoteAPI.API_ENDPOINT}/{self.repository}{resource}"
|
||||||
|
|||||||
Reference in New Issue
Block a user