# -*- coding: utf-8 -*-"""Base classes implementing the command pattern for GitHub operations.This module provides foundational classes that follow the command pattern design,where complex operations are encapsulated within objects that contain all the information needed to execute the operation. Each class acts as a self-containedcommand that can be configured with parameters, executed independently, and provides clear interfaces for logging and error handling.The command pattern is particularly well-suited for GitHub API operations because:- It encapsulates API credentials, repository information, and operation parameters- It provides consistent logging and error handling across different operations- It enables easy testing by allowing dependency injection (like custom printers)- It supports caching of expensive resources (like API clients) through properties- It makes complex workflows readable by breaking them into discrete, reusable commandsClasses in this module serve as building blocks for more specialized GitHub operations like release management, tag creation, and repository synchronization."""importtypingasTimportdataclassesfromfunctoolsimportcached_propertyfromfunc_args.apiimportBaseFrozenModel,REQfromgithubimportGithubfrom.typehintimportT_PRINTERifT.TYPE_CHECKING:# pragma: no coverfromgithub.GitRefimportGitReffromgithub.GitTagimportGitTagfromgithub.GitReleaseimportGitRelease
[docs]@dataclasses.dataclass(frozen=True)classBaseLogger(BaseFrozenModel):""" Base logging functionality with configurable output control. Provides simple message logging with optional verbosity control and customizable output destination following the command pattern. :param verbose: Enable or disable message output :param printer: Function to handle message output (defaults to print) """verbose:bool=dataclasses.field(default=True)printer:T_PRINTER=dataclasses.field(default=print)
[docs]definfo(self,msg:str):""" Log an informational message if verbose mode is enabled. This method provides controlled logging output that can be disabled via the verbose flag. It follows specific guidelines for when and how to log messages in workflow methods. **When to Add Logging:** - **Simple API wrappers**: Do NOT add logging to methods that are just wrappers around single API calls (e.g., get_git_tag_and_ref, delete_tag, create_tag_on_commit) - **Complex workflows**: DO add logging to methods that involve multi-step decision-making and perform different actions based on conditions (e.g., put_tag_on_commit, put_release) - **First log pattern**: For complex workflow methods, the first log message should typically follow the pattern: "--- ${description of what this function does}" **Examples:** Complex workflow logging:: self.info("--- Put tag on commit abcd123 ...") self.info("Check if tag exists ...") self.info("Tag exists.") self.info("Check if tag points to the desired commit ...") :param msg: Message to log to the configured printer function .. note:: This approach keeps logs focused on meaningful workflow steps while avoiding noise from simple operations. """ifself.verbose:self.printer(msg)
[docs]defshorten_sha(self,sha:str)->str:""" Shorten a Git SHA to its first 7 characters for display. :param sha: Full Git SHA string :returns: Shortened SHA (first 7 characters) """returnsha[:7]
[docs]@dataclasses.dataclass(frozen=True)classBaseGitHubApiRunner(BaseLogger):""" Base class for GitHub API operations with authentication and logging. Combines logging capabilities with GitHub API client management. Stores GitHub API configuration as attributes and provides a cached GitHub client instance following the command pattern. :param github_kwargs: Configuration parameters for GitHub API client :param data: Additional data storage for derived classes """github_kwargs:dict[str,T.Any]=dataclasses.field(default=REQ)data:dict[str,T.Any]=dataclasses.field(default_factory=dict)@cached_propertydefgh(self)->"Github":""" GitHub API client instance. :returns: Configured GitHub API client using stored credentials """returnGithub(**self.github_kwargs)
[docs]@dataclasses.dataclass(frozen=True)classTagAndRef:""" A container for holding a Git tag and its corresponding reference. :param tag: The Git tag object (or None if it doesn't exist) :param ref: The Git reference object (or None if it doesn't exist) """tag:T.Optional["GitTag"]=dataclasses.field(default=None)ref:T.Optional["GitRef"]=dataclasses.field(default=None)
[docs]defexists(self)->bool:""" Check if the Git tag exists. :returns: True if tag is not None, False otherwise """returnself.tagisnotNone
[docs]@dataclasses.dataclass(frozen=True)classReleaseAndTagAndRef:""" A container for holding a GitHub release, its corresponding tag, and reference. :param release: The GitHub release object (or None if it doesn't exist) :param tag_and_ref: The TagAndRef object containing the tag and reference """release:T.Optional["GitRelease"]=dataclasses.field(default=None)tag_and_ref:"TagAndRef"=dataclasses.field(default=REQ)
[docs]defexists(self)->bool:""" Check if the GitHub release exists. """returnself.releaseisnotNone