feature: parse git remote url with giturlparse

This commit is contained in:
Jonathan Teran
2026-07-31 12:22:14 -03:00
parent 8f1a60cc06
commit f4adb431db
4 changed files with 38 additions and 21 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ description = "Git workflow automation to follow best practices when working wit
dynamic = ["version"] dynamic = ["version"]
requires-python = ">= 3.14" requires-python = ">= 3.14"
dependencies = [ dependencies = [
"requests", "typer", "rich", "questionary" "requests", "typer", "rich", "questionary", "giturlparse"
] ]
authors = [ authors = [
{name = "Alan Facundo Biglieri", email = "abiglieri@renatre.org.ar"}, {name = "Alan Facundo Biglieri", email = "abiglieri@renatre.org.ar"},
+4 -3
View File
@@ -43,9 +43,10 @@ COMMIT_TYPE_INCREMENT = {
"test": SEMVER_SKIP, "test": SEMVER_SKIP,
} }
SUPPORTED_REMOTE_APIS = [ SUPPORTED_REMOTE_URL_SCHEMAS = [
"bitbucket.org", "ssh",
"github.com", "http",
"https"
] ]
REPOSITORY_TOKEN_FILENAME = ".repository-token" REPOSITORY_TOKEN_FILENAME = ".repository-token"
+22 -17
View File
@@ -1,6 +1,7 @@
import giturlparse
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from git_flow import SUPPORTED_REMOTE_APIS, GitFlowError from git_flow import SUPPORTED_REMOTE_URL_SCHEMAS, GitFlowError
from git_flow.git import Git from git_flow.git import Git
@@ -11,25 +12,29 @@ class RemoteAPI(ABC):
@staticmethod @staticmethod
def parse(remote: str): def parse(remote: str):
"""Soportamos 3 tipos de URL: http, https y ssh. Si no se especifica el esquema, asumimos ssh:
Ejemplos:
- http://gitea/user/repo
- https://gitea.com/user/repo.git
- git@bitbucket.org:user/repo
- git.mygiteainstance.com:user/repo.git
- ssh://git@git.mygiteainstance.com:1234/user/repo.git
"""
url = Git("remote", "get-url", remote).firstline() url = Git("remote", "get-url", remote).firstline()
if url.startswith("git@"): parsed_url = giturlparse.parse(url) # Validamos que la URL sea válida
at_pos = url.index("@")
colon_pos = url.index(":") if not parsed_url.valid:
schema = "ssh://"
host = url[at_pos+1:colon_pos]
repository = url[colon_pos+1:]
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}") raise GitFlowError(f"La URL del remoto {remote} es inválida: {url}")
repository = repository.removesuffix(".git") if not parsed_url.protocol in SUPPORTED_REMOTE_URL_SCHEMAS:
return [schema, host, repository] raise GitFlowError(f"La URL del remoto {remote} no tiene un esquema soportado: {url}")
# Cuando el host es seteado por pipeline puede ser "http://gitea/OWNER/REPO", en ese caso
# la libreria parsea OWNER="" y REPO="OWNER/REPO"
repository = "/".join(filter(None, [parsed_url.owner, parsed_url.repo])).removeprefix("/").removesuffix(".git")
return [parsed_url.protocol + "://", parsed_url.host, repository]
@abstractmethod @abstractmethod
def create_pull_request( def create_pull_request(
@@ -38,7 +43,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 close_source_branch: bool = True,
) -> str: ) -> str:
pass pass
Generated
+11
View File
@@ -70,6 +70,7 @@ wheels = [
name = "git-flow-envs" name = "git-flow-envs"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "giturlparse" },
{ name = "questionary" }, { name = "questionary" },
{ name = "requests" }, { name = "requests" },
{ name = "rich" }, { name = "rich" },
@@ -78,12 +79,22 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "giturlparse" },
{ name = "questionary" }, { name = "questionary" },
{ name = "requests" }, { name = "requests" },
{ name = "rich" }, { name = "rich" },
{ name = "typer" }, { name = "typer" },
] ]
[[package]]
name = "giturlparse"
version = "0.15.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8c/8a/b70b84cc78f9059d627f09560c81a11e8f046570d220a24e169489cad6c9/giturlparse-0.15.0.tar.gz", hash = "sha256:9af3f1fd5c4a0cac94ddb283593635005646393ee0debbe330d1bdff8866bf2c", size = 16138, upload-time = "2026-06-16T07:28:56.021Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/96/147a2771ab655b9353781fb2f95c94eaf1d8576dccc991c1a61d0d355067/giturlparse-0.15.0-py2.py3-none-any.whl", hash = "sha256:76d2e6983b037356ab99b30683e533ac3db96409b68e2163a20fc3aff6446f10", size = 16683, upload-time = "2026-06-16T07:28:55.184Z" },
]
[[package]] [[package]]
name = "idna" name = "idna"
version = "3.11" version = "3.11"