Compare commits

..
2 Commits
11 changed files with 28 additions and 171 deletions
+2 -1
View File
@@ -8,10 +8,11 @@ jobs:
Publish-to-PyPI:
runs-on: ubuntu-latest
steps:
- name: Checkout
- name: Check out repository code
uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Configure git
run: |
-46
View File
@@ -1,49 +1,3 @@
## v1.20.0 - 2026-09-13
- **feature**: add gitlab remote support [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (748d420)
---
## v1.19.0 - 2026-07-31
- **style**: format with ruff [[jteran](mailto:jteran@renatre.org.ar)] (11a48a9)
- **feature**: parse git remote url with giturlparse [[jteran](mailto:jteran@renatre.org.ar)] (f4adb43)
---
## v1.18.0 - 2026-07-29
- **bugfix**: change checkout version to v7 [[jteran](mailto:jteran@renatre.org.ar)] (c58c4ce)
- **bugfix**: move git fetch to separate line [[jteran](mailto:jteran@renatre.org.ar)] (64fc890)
- **bugfix**: change actions/checkout to v4 and add step to fetch tags [[jteran](mailto:jteran@renatre.org.ar)] (dc79ffa)
- **bugfix**: change actions/checkout version [[jteran](mailto:jteran@renatre.org.ar)] (c45f065)
- **bugfix**: add fetch-tags: true [[jteran](mailto:jteran@renatre.org.ar)] (adcb531)
- **bugfix**: remove checkout parameters [[jteran](mailto:jteran@renatre.org.ar)] (2be9b50)
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.1.0-main - 2026-07-29
- **bugfix**: change actions/checkout to v4 and add step to fetch tags [[jteran](mailto:jteran@renatre.org.ar)] (dc79ffa)
- **bugfix**: change actions/checkout version [[jteran](mailto:jteran@renatre.org.ar)] (c45f065)
- **bugfix**: add fetch-tags: true [[jteran](mailto:jteran@renatre.org.ar)] (adcb531)
- **bugfix**: remove checkout parameters [[jteran](mailto:jteran@renatre.org.ar)] (2be9b50)
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.1.0-main - 2026-07-29
- **feature**: show commit count and list tags on workflow [[jteran](mailto:jteran@renatre.org.ar)] (f05582b)
---
## v0.0.1-main - 2026-07-18
- **bugfix**: add fetch tags to checkout step [[jonathan.nerat](mailto:jonathan.nerat@gmail.com)] (f9fb5a6)
-1
View File
@@ -49,7 +49,6 @@ El comando solicitará 2 opciones:
- [x] Bitbucket
- [x] Github
- [x] Gitea
- [x] Gitlab
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" >
+1 -1
View File
@@ -8,7 +8,7 @@ description = "Git workflow automation to follow best practices when working wit
dynamic = ["version"]
requires-python = ">= 3.14"
dependencies = [
"requests", "typer", "rich", "questionary", "giturlparse"
"requests", "typer", "rich", "questionary"
]
authors = [
{name = "Alan Facundo Biglieri", email = "abiglieri@renatre.org.ar"},
+3 -6
View File
@@ -43,14 +43,11 @@ COMMIT_TYPE_INCREMENT = {
"test": SEMVER_SKIP,
}
SUPPORTED_REMOTE_URL_SCHEMAS = [
"ssh",
"http",
"https"
SUPPORTED_REMOTE_APIS = [
"bitbucket.org",
"github.com",
]
REPOSITORY_TOKEN_FILENAME = ".repository-token"
FLOWCONFIG_FILENAME = ".flowconfig"
FLOWCONFIG_VERSION = 2
+1 -6
View File
@@ -1,7 +1,6 @@
from git_flow import (
BRANCH_TYPES,
REPOSITORY_TOKEN_FILENAME,
FLOWCONFIG_FILENAME,
FLOWCONFIG_VERSION,
COMMIT_TYPES,
GitFlowError,
@@ -11,7 +10,6 @@ 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.remote.gitlab import GitlabRemoteAPI
from git_flow.io import *
from os.path import isfile
@@ -20,7 +18,7 @@ import rich
import rich.panel
import questionary
flowconfig = Git.get_config(FLOWCONFIG_FILENAME) if isfile(FLOWCONFIG_FILENAME) else {}
flowconfig = Git.get_config()
environments = (
flowconfig["flow.branches"].split(",") if "flow.branches" in flowconfig else []
)
@@ -124,9 +122,6 @@ def get_remote_api(token: str) -> RemoteAPI:
if remote_type == "gitea":
remote_schema = "https://" if schema == "ssh://" else schema
return GiteaRemoteAPI(remote_schema + host, repository, token)
elif remote_type == "gitlab":
remote_schema = "https://" if schema == "ssh://" else schema
return GitlabRemoteAPI(remote_schema + host, repository, token)
elif remote_type == "bitbucket":
return BitbucketRemoteAPI(repository, token)
elif remote_type == "github":
+3 -5
View File
@@ -1,7 +1,7 @@
import typer
import git_flow.command.base as base
from git_flow import FLOWCONFIG_FILENAME, FLOWCONFIG_VERSION, GitFlowError
from git_flow import FLOWCONFIG_VERSION, GitFlowError
from git_flow.git import Git
app = typer.Typer()
@@ -27,9 +27,7 @@ def init():
flowconfig["flow.remote"] = remote
flowconfig["flow.remote-type"] = remote_type
Git.set_config(flowconfig, FLOWCONFIG_FILENAME)
Git("add", FLOWCONFIG_FILENAME).exec()
Git("commit", message="feature: initialize git-flow").exec()
Git.set_config(flowconfig)
_ensure_all_flow_branches_exist(branches, remote)
@@ -101,7 +99,7 @@ uno nuevo.""",
remote = base.io_choice("Remoto", remotes)
remote_type = base.io_choice(
"Tipo de remoto:", ["bitbucket", "github", "gitea", "gitlab"]
"Tipo de remoto:", ["bitbucket", "github", "gitea"]
)
return (remote, remote_type)
+1 -6
View File
@@ -1,6 +1,5 @@
import subprocess
from git_flow import FLOWCONFIG_FILENAME
from git_flow.io import *
@@ -33,11 +32,7 @@ class Git:
@staticmethod
def set_config(config: dict[str, str], file: str | None = None):
for key, value in config.items():
Git("config", key, value, file=file).exec()
@staticmethod
def flow_config(*args, **kwargs):
return Git("config", *args, file=FLOWCONFIG_FILENAME, **kwargs)
Git("config", key, value, file=file).exec(print="Updating config")
@staticmethod
def get_current_branch():
+17 -29
View File
@@ -1,8 +1,6 @@
from abc import ABC, abstractmethod
import giturlparse
from git_flow import SUPPORTED_REMOTE_URL_SCHEMAS, GitFlowError
from git_flow import SUPPORTED_REMOTE_APIS, GitFlowError
from git_flow.git import Git
@@ -13,35 +11,25 @@ class RemoteAPI(ABC):
@staticmethod
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()
parsed_url = giturlparse.parse(url) # Validamos que la URL sea válida
if not parsed_url.valid:
if url.startswith("git@"):
at_pos = url.index("@")
colon_pos = url.index(":")
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}")
if not parsed_url.protocol in SUPPORTED_REMOTE_URL_SCHEMAS:
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]
repository = repository.removesuffix(".git")
return [schema, host, repository]
@abstractmethod
def create_pull_request(
@@ -50,7 +38,7 @@ class RemoteAPI(ABC):
destination: str,
title: str | None = None,
description: str | None = None,
close_source_branch: bool = True,
close_source_branch: bool = True
) -> str:
pass
-59
View File
@@ -1,59 +0,0 @@
from urllib.parse import quote
import requests
from git_flow import GitFlowError
from git_flow.remote.base import RemoteAPI
class GitlabRemoteAPI(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("/merge_requests"),
headers=self.get_headers(),
json={
"title": title,
"description": description,
"source_branch": source,
"target_branch": destination,
"remove_source_branch": close_source_branch,
},
)
if response.ok:
return "PR creado exitosamente: " + response.json()["web_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("/repository/tags"),
headers=self.get_headers(),
json={"tag_name": tag, "ref": 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:
project_id = quote(self.repository, safe="")
return f"{self.base_url}/api/v4/projects/{project_id}{resource}"
def get_headers(self):
return {
"Accept": "application/json",
"Content-Type": "application/json",
"PRIVATE-TOKEN": self.token,
}
Generated
-11
View File
@@ -70,7 +70,6 @@ wheels = [
name = "git-flow-envs"
source = { editable = "." }
dependencies = [
{ name = "giturlparse" },
{ name = "questionary" },
{ name = "requests" },
{ name = "rich" },
@@ -79,22 +78,12 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "giturlparse" },
{ name = "questionary" },
{ name = "requests" },
{ name = "rich" },
{ 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]]
name = "idna"
version = "3.11"