You've already forked wakapi-readme-stats
166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
from base64 import b64decode, b64encode
|
|
from os import environ
|
|
from random import choice
|
|
from re import sub
|
|
from string import ascii_letters
|
|
|
|
from git import Repo
|
|
from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException
|
|
|
|
from manager_environment import EnvironmentManager as EM
|
|
from manager_file import FileManager as FM
|
|
from manager_debug import DebugManager as DBM
|
|
|
|
|
|
def init_github_manager():
|
|
"""
|
|
Initialize GitHub manager.
|
|
Current user, user readme repo and readme file are downloaded.
|
|
"""
|
|
GitHubManager.prepare_github_env()
|
|
DBM.i(f"Current user: {GitHubManager.USER.login}")
|
|
|
|
|
|
class GitHubManager:
|
|
USER: AuthenticatedUser
|
|
REPO: Repo
|
|
REMOTE: Repository
|
|
_README: ContentFile
|
|
_README_CONTENTS: str
|
|
|
|
_REPO_PATH = "repo"
|
|
_START_COMMENT = f"<!--START_SECTION:{EM.SECTION_NAME}-->"
|
|
_END_COMMENT = f"<!--END_SECTION:{EM.SECTION_NAME}-->"
|
|
_README_REGEX = f"{_START_COMMENT}[\\s\\S]+{_END_COMMENT}"
|
|
|
|
@staticmethod
|
|
def prepare_github_env():
|
|
"""
|
|
Download and store for future use:
|
|
- Current GitHub user.
|
|
- Named repo of the user [username]/[username].
|
|
- README.md file of this repo.
|
|
- Parsed contents of the file.
|
|
"""
|
|
github = Github(EM.GH_TOKEN)
|
|
GitHubManager.USER = github.get_user()
|
|
GitHubManager.REMOTE = github.get_repo(f"{GitHubManager.USER.login}/{GitHubManager.USER.login}")
|
|
GitHubManager.REPO = Repo.clone_from(GitHubManager.REMOTE.clone_url, to_path=GitHubManager._REPO_PATH)
|
|
GitHubManager._README = GitHubManager.REMOTE.get_readme()
|
|
GitHubManager._README_CONTENTS = str(b64decode(GitHubManager._README.content), "utf-8")
|
|
|
|
@staticmethod
|
|
def _generate_new_readme(stats: str) -> str:
|
|
"""
|
|
Generates new README.md file, inserts its contents between start and end tags.
|
|
|
|
:param stats: contents to insert.
|
|
:returns: new README.md string.
|
|
"""
|
|
readme_stats = f"{GitHubManager._START_COMMENT}\n{stats}\n{GitHubManager._END_COMMENT}"
|
|
return sub(GitHubManager._README_REGEX, readme_stats, GitHubManager._README_CONTENTS)
|
|
|
|
@staticmethod
|
|
def _get_author() -> InputGitAuthor:
|
|
"""
|
|
Gets GitHub commit author specified by environmental variables.
|
|
It is the user himself or a 'readme-bot'.
|
|
|
|
:returns: Commit author.
|
|
"""
|
|
if EM.COMMIT_BY_ME:
|
|
return InputGitAuthor(GitHubManager.USER.login or EM.COMMIT_USERNAME, GitHubManager.USER.email or EM.COMMIT_EMAIL)
|
|
else:
|
|
return InputGitAuthor(EM.COMMIT_USERNAME or "readme-bot", EM.COMMIT_EMAIL or "41898282+github-actions[bot]@users.noreply.github.com")
|
|
|
|
@staticmethod
|
|
def branch() -> str:
|
|
"""
|
|
Gets name of branch to commit to specified by environmental variables.
|
|
It is the default branch (regularly, 'main' or 'master') or a branch specified by user.
|
|
|
|
:returns: Commit author.
|
|
"""
|
|
return GitHubManager.REMOTE.default_branch if EM.BRANCH_NAME == "" else EM.BRANCH_NAME
|
|
|
|
@staticmethod
|
|
def update_readme(stats: str) -> bool:
|
|
"""
|
|
Updates readme with given data if necessary.
|
|
Uses commit author, commit message and branch name specified by environmental variables.
|
|
|
|
:returns: whether the README.md file was updated or not.
|
|
"""
|
|
DBM.i("Updating README...")
|
|
new_readme = GitHubManager._generate_new_readme(stats)
|
|
if new_readme != GitHubManager._README_CONTENTS:
|
|
GitHubManager.REMOTE.update_file(
|
|
path=GitHubManager._README.path,
|
|
message=EM.COMMIT_MESSAGE,
|
|
content=new_readme,
|
|
sha=GitHubManager._README.sha,
|
|
branch=GitHubManager.branch(),
|
|
committer=GitHubManager._get_author(),
|
|
)
|
|
DBM.g("README updated!")
|
|
return True
|
|
else:
|
|
DBM.w("README update not needed!")
|
|
return False
|
|
|
|
@staticmethod
|
|
def set_github_output(stats: str) -> bool:
|
|
"""
|
|
Outputs readme data as current action output instead of committing it.
|
|
|
|
param stats: Readme stats to be outputted.
|
|
"""
|
|
DBM.i("Setting README contents as action output...")
|
|
if "GITHUB_OUTPUT" not in environ.keys():
|
|
DBM.p("Not in GitHub environment, not setting action output!")
|
|
return False
|
|
|
|
prefix = "README stats current output:"
|
|
eol = "".join(choice(ascii_letters) for _ in range(10))
|
|
FM.write_file(environ["GITHUB_OUTPUT"], f"README_CONTENT<<{eol}\n{prefix}\n\n{stats}\n{eol}\n", append=True)
|
|
|
|
DBM.g("Action output set!")
|
|
return True
|
|
|
|
@staticmethod
|
|
def update_chart(chart_path: str) -> str:
|
|
"""
|
|
Updates lines of code chart.
|
|
Inlines data into readme if in debug mode, commits otherwise.
|
|
Uses commit author, commit message and branch name specified by environmental variables.
|
|
|
|
:param chart_path: path to saved lines of code chart.
|
|
:returns: string to add to README file.
|
|
"""
|
|
DBM.i("Updating lines of code chart...")
|
|
with open(chart_path, "rb") as input_file:
|
|
data = input_file.read()
|
|
|
|
if not EM.DEBUG_RUN:
|
|
DBM.i("Pushing chart to repo...")
|
|
|
|
try:
|
|
contents = GitHubManager.REMOTE.get_contents(chart_path)
|
|
GitHubManager.REMOTE.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author())
|
|
DBM.g("Lines of code chart updated!")
|
|
except UnknownObjectException:
|
|
GitHubManager.REMOTE.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author())
|
|
DBM.g("Lines of code chart created!")
|
|
|
|
chart_path = f"https://raw.githubusercontent.com/{GitHubManager.USER.login}/{GitHubManager.USER.login}/{GitHubManager.branch()}/{chart_path}"
|
|
return f"**{FM.t('Timeline')}**\n\n\n\n"
|
|
|
|
else:
|
|
DBM.i("Inlining chart...")
|
|
hint = "You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated base64 image."
|
|
return f"{hint}\n```\ndata:image/png;base64,{b64encode(data).decode('utf-8')}\n```\n\n"
|
|
|
|
@staticmethod
|
|
def commit_repo():
|
|
pass
|