import functools from datetime import datetime from typing import Any, Callable, List from joint_teapot.config import settings from joint_teapot.utils.logger import logger from joint_teapot.utils.main import first from joint_teapot.workers import Canvas, Git, Gitea def for_all_methods(decorator: Callable[..., Any]) -> Callable[..., Any]: def decorate(cls: Any) -> Any: for attr in cls.__dict__: # there's propably a better way to do this if callable(getattr(cls, attr)): setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate def log_exception_in_loguru(func: Callable[..., Any]) -> Callable[..., Any]: @functools.wraps(func) def decorator(*args: Any, **kwargs: Any) -> Any: try: return func(*args, **kwargs) except Exception as e: logger.exception(e) return decorator @for_all_methods(log_exception_in_loguru) class Teapot: _canvas = None _gitea = None _git = None @property def canvas(self) -> Canvas: if not self._canvas: self._canvas = Canvas() return self._canvas @property def gitea(self) -> Gitea: if not self._gitea: self._gitea = Gitea() return self._gitea @property def git(self) -> Git: if not self._git: self._git = Git() return self._git def __init__(self) -> None: logger.info( f"Settings loaded. Canvas Course ID: {settings.canvas_course_id}, Gitea Organization name: {settings.gitea_org_name}" ) logger.debug("Teapot initialized.") def add_all_canvas_students_to_teams(self, team_names: List[str]) -> None: return self.gitea.add_canvas_students_to_teams(self.canvas.students, team_names) def create_personal_repos_for_all_canvas_students(self) -> List[str]: return self.gitea.create_personal_repos_for_canvas_students( self.canvas.students ) def create_teams_and_repos_by_canvas_groups(self) -> List[str]: def convertor(name: str) -> str: team_name, number_str = name.split(" ") number = int(number_str) return f"{team_name}-{number:02}" return self.gitea.create_teams_and_repos_by_canvas_groups( self.canvas.students, self.canvas.groups, convertor, convertor ) def get_public_key_of_all_canvas_students(self) -> List[str]: return self.gitea.get_public_key_of_canvas_students(self.canvas.students) def clone_all_repos(self) -> List[str]: return [ self.git.repo_clean_and_checkout(repo_name, "master") for repo_name in self.gitea.get_all_repo_names() ] def create_issue_for_repos( self, repo_names: List[str], title: str, body: str ) -> None: for repo_name in repo_names: self.gitea.create_issue(repo_name, title, body) def check_exist_issue_by_title( self, repo_names: List[str], title: str ) -> List[str]: res = [] for repo_name in repo_names: if not self.gitea.check_exist_issue_by_title(repo_name, title): res.append(repo_name) return res def checkout_to_repos_by_release_name( self, repo_names: List[str], release_name: str, due: datetime = datetime(3000, 1, 1), ) -> List[str]: failed_repos = [] repos_releases = self.gitea.get_repos_releases(repo_names) for repo_name, repo_releases in zip(repo_names, repos_releases): release = first(repo_releases, lambda item: item["name"] == release_name) if ( release is None or datetime.strptime(release["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ") >= due ): failed_repos.append(repo_name) continue self.git.repo_clean_and_checkout(repo_name, f"tags/{release['tag_name']}") return failed_repos if __name__ == "__main__": teapot = Teapot()