Skip to content

Commit

Permalink
Add base support for forgejo
Browse files Browse the repository at this point in the history
  • Loading branch information
majamassarini committed Feb 12, 2025
1 parent 4a3d53f commit 0f0c118
Show file tree
Hide file tree
Showing 16 changed files with 1,611 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ogr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
get_service_class,
get_service_class_or_none,
)
from ogr.services.forgejo import ForgejoService
from ogr.services.github import GithubService
from ogr.services.gitlab import GitlabService
from ogr.services.pagure import PagureService
Expand All @@ -26,6 +27,7 @@
GithubService.__name__,
PagureService.__name__,
GitlabService.__name__,
ForgejoService.__name__,
AuthMethod.__name__,
get_project.__name__,
get_service_class.__name__,
Expand Down
15 changes: 13 additions & 2 deletions ogr/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@

import github
import gitlab
import pyforgejo
import requests

from ogr.deprecation import deprecate_and_set_removal
from ogr.exceptions import (
APIException,
ForgejoAPIException,
GitForgeInternalError,
GithubAPIException,
GitlabAPIException,
Expand Down Expand Up @@ -59,7 +61,11 @@ def __check_for_internal_failure(ex: APIException):


def __wrap_exception(
ex: Union[github.GithubException, gitlab.GitlabError],
ex: Union[
github.GithubException,
gitlab.GitlabError,
pyforgejo.core.api_error.ApiError,
],
) -> APIException:
"""
Wraps uncaught exception in one of ogr exceptions.
Expand All @@ -76,6 +82,7 @@ def __wrap_exception(
MAPPING = {
github.GithubException: GithubAPIException,
gitlab.GitlabError: GitlabAPIException,
pyforgejo.core.api_error.ApiError: ForgejoAPIException,
}

for caught_exception, ogr_exception in MAPPING.items():
Expand Down Expand Up @@ -114,7 +121,11 @@ def wrapper(*args, **kwargs):
) from ex
except APIException as ex:
__check_for_internal_failure(ex)
except (github.GithubException, gitlab.GitlabError) as ex:
except (
github.GithubException,
gitlab.GitlabError,
pyforgejo.core.api_error.ApiError,
) as ex:
__check_for_internal_failure(__wrap_exception(ex))

return wrapper
Expand Down
14 changes: 14 additions & 0 deletions ogr/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import github
import gitlab
import pyforgejo


class OgrException(Exception):
Expand Down Expand Up @@ -66,6 +67,19 @@ def response_code(self):
return self.__cause__.response_code


class ForgejoAPIException(APIException):
"""Exception related to Forgejo API."""

@property
def response_code(self):
if self.__cause__ is None or not isinstance(
self.__cause__,
pyforgejo.core.api_error.ApiError,
):
return None
return self.__cause__.status_code


class OperationNotSupported(OgrException):
"""Raise when the operation is not supported by the backend."""

Expand Down
14 changes: 14 additions & 0 deletions ogr/services/forgejo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT

from ogr.services.forgejo.issue import ForgejoIssue
from ogr.services.forgejo.project import ForgejoProject
from ogr.services.forgejo.pull_request import ForgejoPullRequest
from ogr.services.forgejo.service import ForgejoService

__all__ = [
ForgejoPullRequest.__name__,
ForgejoIssue.__name__,
ForgejoProject.__name__,
ForgejoService.__name__,
]
10 changes: 10 additions & 0 deletions ogr/services/forgejo/issue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT

from ogr.services import forgejo
from ogr.services.base import BaseIssue


class ForgejoIssue(BaseIssue):
def __init__(self, raw_issue, project: "forgejo.ForgejoProject"):
super().__init__(raw_issue, project)
35 changes: 35 additions & 0 deletions ogr/services/forgejo/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT


from ogr.services import forgejo
from ogr.services.base import BaseGitProject


class ForgejoProject(BaseGitProject):
service: "forgejo.ForgejoService"

def __init__(
self,
repo: str,
service: "forgejo.ForgejoService",
namespace: str,
**kwargs,
):
super().__init__(repo, service, namespace)
self._forgejo_repo = None

@property
def forgejo_repo(self):
if not self._forgejo_repo:
if self.namespace:
self._forgejo_repo = self.service.api.repository.repo_get(
owner=self.namespace,
repo=self.repo,
)
else:
self._forgejo_repo = self.service.api.repository.repo_get(
owner=self.service.user.get_username(),
repo=self.repo,
)
return self._forgejo_repo
16 changes: 16 additions & 0 deletions ogr/services/forgejo/pull_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT

from typing import Any

from ogr.services import forgejo
from ogr.services.base import BasePullRequest


class ForgejoPullRequest(BasePullRequest):
def __init__(
self,
raw_pr: Any,
project: "forgejo.ForgejoProject",
):
super().__init__(raw_pr, project)
89 changes: 89 additions & 0 deletions ogr/services/forgejo/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT

from typing import Optional
from urllib.parse import urlparse

from pyforgejo import PyforgejoApi

from ogr.abstract import GitUser
from ogr.exceptions import OgrException
from ogr.factory import use_for_service
from ogr.services.base import BaseGitService
from ogr.services.forgejo.project import ForgejoProject
from ogr.services.forgejo.user import ForgejoUser


@use_for_service("forgejo")
class ForgejoService(BaseGitService):
version = "/api/v1"

def __init__(
self,
instance_url: str = "https://forgejo.org",
api_key: Optional[str] = None,
**kwargs,
):
super().__init__()
self.instance_url = instance_url + self.version
self._token = f"token {api_key}"
self._api = None

@property
def api(self):
if not self._api:
self._api = PyforgejoApi(base_url=self.instance_url, api_key=self._token)
return self._api

def get_project( # type: ignore[override]
self,
repo: str,
namespace: str,
**kwargs,
) -> "ForgejoProject":
return ForgejoProject(
repo=repo,
namespace=namespace,
service=self,
**kwargs,
)

@property
def user(self) -> GitUser:
return ForgejoUser(self)

def project_create(
self,
repo: str,
namespace: Optional[str] = None,
description: Optional[str] = None,
) -> "ForgejoProject":
if namespace:
new_repo = self.api.organization.create_org_repo(
org=namespace,
name=repo,
description=description,
)
else:
new_repo = self.api.repository.create_current_user_repo(
name=repo,
description=description,
)
return ForgejoProject(
repo=repo,
namespace=namespace,
service=self,
github_repo=new_repo,
)

def get_project_from_url(self, url: str) -> "ForgejoProject":
parsed_url = urlparse(url)
path_parts = parsed_url.path.strip("/").split("/")

if len(path_parts) < 2:
raise OgrException(f"Invalid Forgejo URL: {url}")

namespace = path_parts[0]
repo = path_parts[1]

return self.get_project(repo=repo, namespace=namespace)
26 changes: 26 additions & 0 deletions ogr/services/forgejo/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright Contributors to the Packit project.
# SPDX-License-Identifier: MIT


from ogr.services import forgejo
from ogr.services.base import BaseGitUser


class ForgejoUser(BaseGitUser):
service: "forgejo.ForgejoService"

def __init__(self, service: "forgejo.ForgejoService") -> None:
super().__init__(service=service)
self._forgejo_user = None

def __str__(self) -> str:
return f'ForgejoUser(username="{self.get_username()}")'

@property
def forgejo_user(self):
if not self._forgejo_user:
self._forgejo_user = self.service.api.user.get_current()
return self._forgejo_user

def get_username(self) -> str:
return self.forgejo_user.login
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies = [
"PyYAML",
"requests",
"urllib3",
"pyforgejo",
]

[project.urls]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
_requre:
DataTypes: 1
key_strategy: StorageKeysInspectSimple
version_storage_file: 3
pyforgejo.core.http_client:
request:
- metadata:
guess_type: ObjectStorage
latency: 0.4872744083404541
module_call_list:
- unittest.case
- requre.record_and_replace
- tests.integration.factory.test_factory
- ogr.services.forgejo.project
- pyforgejo.repository.client
- requre.objects
- requre.cassette
- pyforgejo.core.http_client
- request
output: !!binary |
gASVgw0AAAAAAACMBWh0dHB4lIwIUmVzcG9uc2WUk5QpgZR9lCiMC3N0YXR1c19jb2RllEvIjAdo
ZWFkZXJzlGgAjAdIZWFkZXJzlJOUKYGUfZQojAVfbGlzdJRdlChDDUNhY2hlLUNvbnRyb2yUQw1j
YWNoZS1jb250cm9slEMxbWF4LWFnZT0wLCBwcml2YXRlLCBtdXN0LXJldmFsaWRhdGUsIG5vLXRy
YW5zZm9ybZSHlEMMQ29udGVudC1UeXBllEMMY29udGVudC10eXBllEMeYXBwbGljYXRpb24vanNv
bjtjaGFyc2V0PXV0Zi04lIeUQwREYXRllEMEZGF0ZZRDHVdlZCwgMTIgRmViIDIwMjUgMTA6MDk6
MjYgR01UlIeUQwRWYXJ5lEMEdmFyeZRDBk9yaWdpbpSHlEMWWC1Db250ZW50LVR5cGUtT3B0aW9u
c5RDFngtY29udGVudC10eXBlLW9wdGlvbnOUQwdub3NuaWZmlIeUQw9YLUZyYW1lLU9wdGlvbnOU
Qw94LWZyYW1lLW9wdGlvbnOUQwpTQU1FT1JJR0lOlIeUQxFUcmFuc2Zlci1FbmNvZGluZ5RDEXRy
YW5zZmVyLWVuY29kaW5nlEMHY2h1bmtlZJSHlGWMCV9lbmNvZGluZ5SMBWFzY2lplHVijAhfcmVx
dWVzdJRoAIwHUmVxdWVzdJSTlCmBlH2UKIwGbWV0aG9klIwDR0VUlIwDdXJslGgAjANVUkyUk5Qp
gZR9lIwOX3VyaV9yZWZlcmVuY2WUjA9odHRweC5fdXJscGFyc2WUjAtQYXJzZVJlc3VsdJSTlCiM
BWh0dHBzlIwAlIwUdjEwLm5leHQuZm9yZ2Vqby5vcmeUTowZL2FwaS92MS9yZXBvcy9wYWNraXQv
dGVzdJROTnSUgZRzYmgGaAgpgZR9lChoC12UKEMESG9zdJRDBGhvc3SUQxR2MTAubmV4dC5mb3Jn
ZWpvLm9yZ5SHlEMGQWNjZXB0lEMGYWNjZXB0lEMDKi8qlIeUQw9BY2NlcHQtRW5jb2RpbmeUQw9h
Y2NlcHQtZW5jb2RpbmeUQxdnemlwLCBkZWZsYXRlLCBiciwgenN0ZJSHlEMKQ29ubmVjdGlvbpRD
CmNvbm5lY3Rpb26UQwprZWVwLWFsaXZllIeUQwpVc2VyLUFnZW50lEMKdXNlci1hZ2VudJRDE3B5
dGhvbi1odHRweC8wLjI4LjGUh5RDD1gtRmVybi1MYW5ndWFnZZRDD3gtZmVybi1sYW5ndWFnZZRD
BlB5dGhvbpSHlEMNQXV0aG9yaXphdGlvbpRDDWF1dGhvcml6YXRpb26UQy50b2tlbiAyYjIzNzFi
M2ZlMjZiMjUxODhmYjg5NzM2MjE5YmQ3YzY2YjE5ZjI5lIeUZWgpaCp1YowIX2NvbnRlbnSUQwCU
dWKMDG5leHRfcmVxdWVzdJROjAdoaXN0b3J5lF2UjBJpc19zdHJlYW1fY29uc3VtZWSUiIwQZGVm
YXVsdF9lbmNvZGluZ5SMBXV0Zi04lIwVX251bV9ieXRlc19kb3dubG9hZGVklE2tCIwIX2VsYXBz
ZWSUjAhkYXRldGltZZSMCXRpbWVkZWx0YZSTlEsASwBKvm0HAIeUUpRoYEKtCAAAeyJpZCI6Mjc1
LCJvd25lciI6eyJpZCI6NDUwLCJsb2dpbiI6InBhY2tpdCIsImxvZ2luX25hbWUiOiIiLCJzb3Vy
Y2VfaWQiOjAsImZ1bGxfbmFtZSI6IiIsImVtYWlsIjoiIiwiYXZhdGFyX3VybCI6Imh0dHBzOi8v
djEwLm5leHQuZm9yZ2Vqby5vcmcvYXZhdGFycy9jY2VmMTlkZTVkMjgxNDg5NDVkY2NhNWFhMjI0
OWMwMCIsImh0bWxfdXJsIjoiaHR0cHM6Ly92MTAubmV4dC5mb3JnZWpvLm9yZy9wYWNraXQiLCJs
YW5ndWFnZSI6IiIsImlzX2FkbWluIjpmYWxzZSwibGFzdF9sb2dpbiI6IjAwMDEtMDEtMDFUMDA6
MDA6MDBaIiwiY3JlYXRlZCI6IjIwMjUtMDEtMjlUMDk6MjU6NDRaIiwicmVzdHJpY3RlZCI6ZmFs
c2UsImFjdGl2ZSI6ZmFsc2UsInByb2hpYml0X2xvZ2luIjpmYWxzZSwibG9jYXRpb24iOiIiLCJw
cm9ub3VucyI6IiIsIndlYnNpdGUiOiIiLCJkZXNjcmlwdGlvbiI6IiIsInZpc2liaWxpdHkiOiJw
dWJsaWMiLCJmb2xsb3dlcnNfY291bnQiOjAsImZvbGxvd2luZ19jb3VudCI6MCwic3RhcnJlZF9y
ZXBvc19jb3VudCI6MCwidXNlcm5hbWUiOiJwYWNraXQifSwibmFtZSI6InRlc3QiLCJmdWxsX25h
bWUiOiJwYWNraXQvdGVzdCIsImRlc2NyaXB0aW9uIjoiIiwiZW1wdHkiOnRydWUsInByaXZhdGUi
OmZhbHNlLCJmb3JrIjpmYWxzZSwidGVtcGxhdGUiOmZhbHNlLCJwYXJlbnQiOm51bGwsIm1pcnJv
ciI6ZmFsc2UsInNpemUiOjIyLCJsYW5ndWFnZSI6IiIsImxhbmd1YWdlc191cmwiOiJodHRwczov
L3YxMC5uZXh0LmZvcmdlam8ub3JnL2FwaS92MS9yZXBvcy9wYWNraXQvdGVzdC9sYW5ndWFnZXMi
LCJodG1sX3VybCI6Imh0dHBzOi8vdjEwLm5leHQuZm9yZ2Vqby5vcmcvcGFja2l0L3Rlc3QiLCJ1
cmwiOiJodHRwczovL3YxMC5uZXh0LmZvcmdlam8ub3JnL2FwaS92MS9yZXBvcy9wYWNraXQvdGVz
dCIsImxpbmsiOiIiLCJzc2hfdXJsIjoic3NoOi8vZ2l0QHYxMC5uZXh0LmZvcmdlam8ub3JnOjIx
MDAvcGFja2l0L3Rlc3QuZ2l0IiwiY2xvbmVfdXJsIjoiaHR0cHM6Ly92MTAubmV4dC5mb3JnZWpv
Lm9yZy9wYWNraXQvdGVzdC5naXQiLCJvcmlnaW5hbF91cmwiOiIiLCJ3ZWJzaXRlIjoiIiwic3Rh
cnNfY291bnQiOjAsImZvcmtzX2NvdW50IjowLCJ3YXRjaGVyc19jb3VudCI6MSwib3Blbl9pc3N1
ZXNfY291bnQiOjAsIm9wZW5fcHJfY291bnRlciI6MCwicmVsZWFzZV9jb3VudGVyIjowLCJkZWZh
dWx0X2JyYW5jaCI6Im1haW4iLCJhcmNoaXZlZCI6ZmFsc2UsImNyZWF0ZWRfYXQiOiIyMDI1LTAy
LTEyVDA5OjU3OjMyWiIsInVwZGF0ZWRfYXQiOiIyMDI1LTAyLTEyVDA5OjU3OjMyWiIsImFyY2hp
dmVkX2F0IjoiMTk3MC0wMS0wMVQwMDowMDowMFoiLCJwZXJtaXNzaW9ucyI6eyJhZG1pbiI6dHJ1
ZSwicHVzaCI6dHJ1ZSwicHVsbCI6dHJ1ZX0sImhhc19pc3N1ZXMiOnRydWUsImludGVybmFsX3Ry
YWNrZXIiOnsiZW5hYmxlX3RpbWVfdHJhY2tlciI6dHJ1ZSwiYWxsb3dfb25seV9jb250cmlidXRv
cnNfdG9fdHJhY2tfdGltZSI6dHJ1ZSwiZW5hYmxlX2lzc3VlX2RlcGVuZGVuY2llcyI6dHJ1ZX0s
Imhhc193aWtpIjp0cnVlLCJ3aWtpX2JyYW5jaCI6Im1haW4iLCJnbG9iYWxseV9lZGl0YWJsZV93
aWtpIjpmYWxzZSwiaGFzX3B1bGxfcmVxdWVzdHMiOnRydWUsImhhc19wcm9qZWN0cyI6dHJ1ZSwi
aGFzX3JlbGVhc2VzIjp0cnVlLCJoYXNfcGFja2FnZXMiOnRydWUsImhhc19hY3Rpb25zIjp0cnVl
LCJpZ25vcmVfd2hpdGVzcGFjZV9jb25mbGljdHMiOmZhbHNlLCJhbGxvd19tZXJnZV9jb21taXRz
Ijp0cnVlLCJhbGxvd19yZWJhc2UiOnRydWUsImFsbG93X3JlYmFzZV9leHBsaWNpdCI6dHJ1ZSwi
YWxsb3dfc3F1YXNoX21lcmdlIjp0cnVlLCJhbGxvd19mYXN0X2ZvcndhcmRfb25seV9tZXJnZSI6
dHJ1ZSwiYWxsb3dfcmViYXNlX3VwZGF0ZSI6dHJ1ZSwiZGVmYXVsdF9kZWxldGVfYnJhbmNoX2Fm
dGVyX21lcmdlIjpmYWxzZSwiZGVmYXVsdF9tZXJnZV9zdHlsZSI6Im1lcmdlIiwiZGVmYXVsdF9h
bGxvd19tYWludGFpbmVyX2VkaXQiOmZhbHNlLCJkZWZhdWx0X3VwZGF0ZV9zdHlsZSI6Im1lcmdl
IiwiYXZhdGFyX3VybCI6IiIsImludGVybmFsIjpmYWxzZSwibWlycm9yX2ludGVydmFsIjoiIiwi
b2JqZWN0X2Zvcm1hdF9uYW1lIjoic2hhMSIsIm1pcnJvcl91cGRhdGVkIjoiMDAwMS0wMS0wMVQw
MDowMDowMFoiLCJyZXBvX3RyYW5zZmVyIjpudWxsLCJ0b3BpY3MiOm51bGx9CpR1Yi4=
Loading

0 comments on commit 0f0c118

Please sign in to comment.