Compare commits

..
10 Commits
10 changed files with 141 additions and 35 deletions
+3 -13
View File
@@ -9,11 +9,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v7
with:
- name: Fetch tags fetch-depth: 0
run: |
git fetch --prune --unshallow --tags
- name: Configure git - name: Configure git
run: | run: |
@@ -29,14 +27,6 @@ jobs:
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v8.3.2 uses: astral-sh/setup-uv@v8.3.2
- name: Count commits
run: |
echo "Commit count: $(git rev-list --count main)"
echo "Tags available:"
git tag
echo "Remote tags available:"
git ls-remote --tags
- name: Bump version - name: Bump version
run: | run: |
uv run git-flow tag --token="${{ secrets.GITEA_TOKEN }}" uv run git-flow tag --token="${{ secrets.GITEA_TOKEN }}"
+28
View File
@@ -1,3 +1,31 @@
## 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 ## 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 to v4 and add step to fetch tags [[jteran](mailto:jteran@renatre.org.ar)] (dc79ffa)
+1
View File
@@ -49,6 +49,7 @@ El comando solicitará 2 opciones:
- [x] Bitbucket - [x] Bitbucket
- [x] Github - [x] Github
- [x] Gitea - [x] Gitea
- [x] Gitlab
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" >
+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"
+4
View File
@@ -11,6 +11,7 @@ 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.remote.gitea import GiteaRemoteAPI
from git_flow.remote.gitlab import GitlabRemoteAPI
from git_flow.io import * from git_flow.io import *
from os.path import isfile from os.path import isfile
@@ -123,6 +124,9 @@ def get_remote_api(token: str) -> RemoteAPI:
if remote_type == "gitea": if remote_type == "gitea":
remote_schema = "https://" if schema == "ssh://" else schema remote_schema = "https://" if schema == "ssh://" else schema
return GiteaRemoteAPI(remote_schema + host, repository, token) 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": elif remote_type == "bitbucket":
return BitbucketRemoteAPI(repository, token) return BitbucketRemoteAPI(repository, token)
elif remote_type == "github": elif remote_type == "github":
+1 -1
View File
@@ -101,7 +101,7 @@ uno nuevo.""",
remote = base.io_choice("Remoto", remotes) remote = base.io_choice("Remoto", remotes)
remote_type = base.io_choice( remote_type = base.io_choice(
"Tipo de remoto:", ["bitbucket", "github", "gitea"] "Tipo de remoto:", ["bitbucket", "github", "gitea", "gitlab"]
) )
return (remote, remote_type) return (remote, remote_type)
+29 -17
View File
@@ -1,6 +1,8 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from git_flow import SUPPORTED_REMOTE_APIS, GitFlowError import giturlparse
from git_flow import SUPPORTED_REMOTE_URL_SCHEMAS, GitFlowError
from git_flow.git import Git from git_flow.git import Git
@@ -11,25 +13,35 @@ 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 +50,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
+59
View File
@@ -0,0 +1,59 @@
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,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"