From 4cbdbf51fa9410f31fd5582d6f0c93062fb3994d Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 17 Jun 2024 23:46:42 -0700 Subject: [PATCH 01/10] apiobject: Add Repository.get_topics() --- gitea/apiobject.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index 209f9fc..480d39b 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -343,6 +343,7 @@ class Repository(ApiObject): REPO_ISSUES = """/repos/{owner}/{repo}/issues""" # REPO_DELETE = """/repos/%s/%s""" # , REPO_TIMES = """/repos/%s/%s/times""" # , + REPO_TOPICS = """/repos/%s/%s/topics""" # REPO_USER_TIME = """/repos/%s/%s/times/%s""" # , , REPO_COMMITS = "/repos/%s/%s/commits" # , REPO_TRANSFER = "/repos/{owner}/{repo}/transfer" @@ -463,7 +464,13 @@ class Repository(ApiObject): Repository.REPO_TIMES % (self.owner.username, self.name) ) return results - + + def get_topics(self): + results = self.gitea.requests_get( + Repository.REPO_TOPICS % (self.owner.username, self.name) + ) + return results + def get_user_time(self, username) -> float: if isinstance(username, User): username = username.username From 2716eef153518dcf3cf44bb28c072392770487df Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 18 Jun 2024 00:45:14 -0700 Subject: [PATCH 02/10] Actually just unwrap the topics --- gitea/apiobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index 480d39b..df92e54 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -469,7 +469,7 @@ class Repository(ApiObject): results = self.gitea.requests_get( Repository.REPO_TOPICS % (self.owner.username, self.name) ) - return results + return results["topics"] def get_user_time(self, username) -> float: if isinstance(username, User): From 6102ca7d30fea302b52fce21d3082f04a64a0308 Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 18 Jun 2024 01:56:36 -0700 Subject: [PATCH 03/10] Method to add a topic to a repository --- gitea/apiobject.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index df92e54..3e533ec 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -344,6 +344,7 @@ class Repository(ApiObject): REPO_DELETE = """/repos/%s/%s""" # , REPO_TIMES = """/repos/%s/%s/times""" # , REPO_TOPICS = """/repos/%s/%s/topics""" # + REPO_TOPIC = """/repos/%s/%s/topics/%s""" # , REPO_USER_TIME = """/repos/%s/%s/times/%s""" # , , REPO_COMMITS = "/repos/%s/%s/commits" # , REPO_TRANSFER = "/repos/{owner}/{repo}/transfer" @@ -470,7 +471,13 @@ class Repository(ApiObject): Repository.REPO_TOPICS % (self.owner.username, self.name) ) return results["topics"] - + + def add_topic(self, topic: str): + """Add a topic to the repository""" + result = self.gitea.requests_put( + Repository.REPO_TOPIC % (self.owner.username, self.name, topic) + ) + def get_user_time(self, username) -> float: if isinstance(username, User): username = username.username From 33137fd185d9f518a0d357de7abba3e8b780cbca Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sat, 27 Jul 2024 16:18:37 +0200 Subject: [PATCH 04/10] format --- gitea/gitea.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gitea/gitea.py b/gitea/gitea.py index 81f7b07..f2b3a66 100644 --- a/gitea/gitea.py +++ b/gitea/gitea.py @@ -22,7 +22,12 @@ class Gitea: CREATE_TEAM = """/orgs/%s/teams""" # def __init__( - self, gitea_url: str, token_text=None, auth=None, verify=True, log_level="INFO" + self, + gitea_url: str, + token_text=None, + auth=None, + verify=True, + log_level="INFO", ): """Initializing Gitea-instance From 1be0b45f262d8568291aa0da7b7130bb3f5de9b9 Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sat, 27 Jul 2024 16:42:00 +0200 Subject: [PATCH 05/10] add proxy support --- gitea/gitea.py | 8 ++++++++ requirements.txt | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gitea/gitea.py b/gitea/gitea.py index f2b3a66..1997efe 100644 --- a/gitea/gitea.py +++ b/gitea/gitea.py @@ -28,6 +28,8 @@ class Gitea: auth=None, verify=True, log_level="INFO", + # example: "socks5h://127.0.0.1:9050" + proxy=None, ): """Initializing Gitea-instance @@ -48,6 +50,12 @@ class Gitea: self.url = gitea_url self.requests = requests.Session() + if proxy: + self.requests.proxies = { + "http": proxy, + "https": proxy, + } + # Manage authentification if not token_text and not auth: raise ValueError("Please provide auth or token_text, but not both") diff --git a/requirements.txt b/requirements.txt index 2b3200e..95c490e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -requests +requests[socks] pytest immutabledict \ No newline at end of file From 22bfab0c434a55cc81f0159fe2204d412064345c Mon Sep 17 00:00:00 2001 From: Enrico Ludwig Date: Thu, 1 Aug 2024 17:40:47 +0200 Subject: [PATCH 06/10] Allowing case-insensitive name in get_team --- gitea/apiobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index 209f9fc..271cf95 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -119,10 +119,10 @@ class Organization(ApiObject): setattr(t, "_organization", self) return teams - def get_team(self, name) -> "Team": + def get_team(self, name, ignore_case : bool = False) -> "Team": teams = self.get_teams() for team in teams: - if team.name == name: + if (not ignore_case and team.name == name) or (ignore_case and team.name.lower() == name.lower()): return team raise NotFoundException("Team not existent in organization.") From 103137686e5c863cb22d8ba08d1006a38f248def Mon Sep 17 00:00:00 2001 From: Enrico Ludwig Date: Thu, 1 Aug 2024 17:44:21 +0200 Subject: [PATCH 07/10] Added units_map to create_team function as it's part of the Gitea API at least for version 1.22.1 --- gitea/gitea.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gitea/gitea.py b/gitea/gitea.py index 81f7b07..ccb419d 100644 --- a/gitea/gitea.py +++ b/gitea/gitea.py @@ -352,6 +352,15 @@ class Gitea: "repo.releases", "repo.ext_wiki", ), + units_map: Dict[str, str] = { + "repo.code": "none", + "repo.issues": "none", + "repo.ext_issues": "none", + "repo.wiki": "none", + "repo.pulls": "none", + "repo.releases": "none", + "repo.ext_wiki": "none", + }, ): """Creates a Team. @@ -370,6 +379,7 @@ class Gitea: "can_create_org_repo": can_create_org_repo, "includes_all_repositories": includes_all_repositories, "units": units, + "units_map": units_map, }, ) if "id" in result: From 5b4650734ce5820da9c10e554e310407df44c3fb Mon Sep 17 00:00:00 2001 From: Langenfeld Date: Thu, 22 Aug 2024 16:06:36 +0200 Subject: [PATCH 08/10] feat: added deleting topics from repositories --- gitea/apiobject.py | 20 +++++++++++++------- tests/test_api.py | 13 +++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index 3e533ec..fdf26ec 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -343,7 +343,7 @@ class Repository(ApiObject): REPO_ISSUES = """/repos/{owner}/{repo}/issues""" # REPO_DELETE = """/repos/%s/%s""" # , REPO_TIMES = """/repos/%s/%s/times""" # , - REPO_TOPICS = """/repos/%s/%s/topics""" # + REPO_TOPICS = """/repos/%s/%s/topics""" # REPO_TOPIC = """/repos/%s/%s/topics/%s""" # , REPO_USER_TIME = """/repos/%s/%s/times/%s""" # , , REPO_COMMITS = "/repos/%s/%s/commits" # , @@ -433,7 +433,7 @@ class Repository(ApiObject): try: results = self.gitea.requests_get_paginated( Repository.REPO_COMMITS % (self.owner.username, self.name), - page_limit= page_limit + page_limit=page_limit, ) except ConflictException as err: logging.warning(err) @@ -465,19 +465,25 @@ class Repository(ApiObject): Repository.REPO_TIMES % (self.owner.username, self.name) ) return results - - def get_topics(self): + + def get_topics(self) -> list[str]: results = self.gitea.requests_get( Repository.REPO_TOPICS % (self.owner.username, self.name) ) return results["topics"] - + def add_topic(self, topic: str): """Add a topic to the repository""" - result = self.gitea.requests_put( + self.gitea.requests_put( Repository.REPO_TOPIC % (self.owner.username, self.name, topic) ) - + + def del_topic(self, topic: str): + """Add a topic to the repository""" + self.gitea.requests_delete( + Repository.REPO_TOPIC % (self.owner.username, self.name, topic) + ) + def get_user_time(self, username) -> float: if isinstance(username, User): username = username.username diff --git a/tests/test_api.py b/tests/test_api.py index 2fa87bd..d2ae8cc 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -348,6 +348,19 @@ def test_team_get_org(instance): assert org.username == teams[0].organization.name +def test_topic_functions(instance): + user = User.request(instance, test_user) + repo = Repository.request(instance, user.username, test_repo) + repo.add_topic("rings") + repo.add_topic("swords") + repo.add_topic("dragons") + assert "swords" in repo.get_topics() + repo.del_topic("swords") + assert "swords" not in repo.get_topics() + assert "dragons" in repo.get_topics() + assert "rings" in repo.get_topics() + + def test_delete_repo_userowned(instance): user = User.request(instance, test_user) repo = Repository.request(instance, user.username, test_repo) From 65c763ae6643d32f86220926d25ce63f9112841b Mon Sep 17 00:00:00 2001 From: Langenfeld Date: Thu, 22 Aug 2024 16:07:40 +0200 Subject: [PATCH 09/10] fix: copy paste comment --- gitea/apiobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index dc8107c..de13d86 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -479,7 +479,7 @@ class Repository(ApiObject): ) def del_topic(self, topic: str): - """Add a topic to the repository""" + """Delete a topic to the repository""" self.gitea.requests_delete( Repository.REPO_TOPIC % (self.owner.username, self.name, topic) ) From ead89d325b14e1680bc6fb9b380087f2fce4eb00 Mon Sep 17 00:00:00 2001 From: Langenfeld Date: Thu, 22 Aug 2024 16:58:59 +0200 Subject: [PATCH 10/10] fix: remove mutable argument in team creation function --- gitea/apiobject.py | 35 +++++++++++++++++++++++++++++++---- gitea/gitea.py | 15 +++------------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/gitea/apiobject.py b/gitea/apiobject.py index de13d86..77e790f 100644 --- a/gitea/apiobject.py +++ b/gitea/apiobject.py @@ -1,11 +1,35 @@ import logging from datetime import datetime from typing import List, Tuple, Dict, Sequence, Optional, Union, Set - +from dataclasses import dataclass, fields from .baseapiobject import ReadonlyApiObject, ApiObject from .exceptions import * +@dataclass(frozen=True) +class RepoUnits: + code: str = "none" + issues: str = "none" + ext_issues: str = "none" + wiki: str = "none" + pulls: str = "none" + releases: str = "none" + ext_wiki: str = "none" + + def to_dict(self) -> dict[str, str]: + """Return the correctly prefixed (added "repo.") representation for gitea Repository runit Rights""" + return { + f"repo.{field.name}": getattr(self, field.name) for field in fields(self) + } + + @classmethod + def from_dict(cls, unit_dict: dict[str, str]) -> "RepoUnits": + """Parse all known repo units from the dictionary returned by the api""" + return RepoUnits( + **{k[5:]: v for k, v in unit_dict.items() if k[5:] in fields(cls)} + ) + + class Organization(ApiObject): """see https://try.gitea.io/api/swagger#/organization/orgGetAll""" @@ -119,10 +143,12 @@ class Organization(ApiObject): setattr(t, "_organization", self) return teams - def get_team(self, name, ignore_case : bool = False) -> "Team": + def get_team(self, name, ignore_case: bool = False) -> "Team": teams = self.get_teams() for team in teams: - if (not ignore_case and team.name == name) or (ignore_case and team.name.lower() == name.lower()): + if (not ignore_case and team.name == name) or ( + ignore_case and team.name.lower() == name.lower() + ): return team raise NotFoundException("Team not existent in organization.") @@ -916,7 +942,8 @@ class Team(ApiObject): return hash(self.organization) ^ hash(self.id) _fields_to_parsers = { - "organization": lambda gitea, o: Organization.parse_response(gitea, o) + "organization": lambda gitea, o: Organization.parse_response(gitea, o), + "units_map": lambda gitea, o: RepoUnits.from_dict(o), } _patchable_fields = { diff --git a/gitea/gitea.py b/gitea/gitea.py index ccb419d..6528ce4 100644 --- a/gitea/gitea.py +++ b/gitea/gitea.py @@ -1,12 +1,11 @@ import logging import json from typing import List, Dict, Union - from immutabledict import immutabledict import requests import urllib3 -from .apiobject import User, Organization, Repository, Team +from .apiobject import User, Organization, Repository, Team, RepoUnits from .exceptions import NotFoundException, ConflictException, AlreadyExistsException @@ -352,15 +351,7 @@ class Gitea: "repo.releases", "repo.ext_wiki", ), - units_map: Dict[str, str] = { - "repo.code": "none", - "repo.issues": "none", - "repo.ext_issues": "none", - "repo.wiki": "none", - "repo.pulls": "none", - "repo.releases": "none", - "repo.ext_wiki": "none", - }, + units_map: "RepoUnits" = RepoUnits(), ): """Creates a Team. @@ -379,7 +370,7 @@ class Gitea: "can_create_org_repo": can_create_org_repo, "includes_all_repositories": includes_all_repositories, "units": units, - "units_map": units_map, + "units_map": units_map.to_dict(), }, ) if "id" in result: