Merge branch 'master' into CodeQL

This commit is contained in:
Aravind Nair
2023-02-28 02:32:50 +05:30
committed by GitHub
8 changed files with 231 additions and 77 deletions

83
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: CI
on:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
ci:
name: Run Test and Review PR
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
- name: Setup Python 3.8 🐍
uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Install Dependencies 📥
run: pip install -r requirements.txt
- name: Create Assets Folder 📥
run: mkdir assets
- name: Create Previous Comments 🫣
uses: int128/hide-comment-action@v1
with:
starts-with: "README stats current output:"
- name: Run Action Preview on Current Code 🧪
id: make-stats
env:
INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }}
INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
INPUT_SHOW_TIMEZONE: True
INPUT_SHOW_PROJECTS: True
INPUT_SHOW_EDITORS: True
INPUT_SHOW_OS: True
INPUT_SHOW_LANGUAGE: True
INPUT_SYMBOL_VERSION: 1
INPUT_SHOW_LINES_OF_CODE: True
INPUT_SHOW_LOC_CHART: True
INPUT_SHOW_PROFILE_VIEWS: True
INPUT_SHOW_TOTAL_CODE_TIME: True
INPUT_SHOW_SHORT_INFO: True
INPUT_SHOW_COMMIT: True
INPUT_SHOW_DAYS_OF_WEEK: True
INPUT_SHOW_LANGUAGE_PER_REPO: True
INPUT_SHOW_UPDATED_DATE: True
INPUT_COMMIT_BY_ME: True
INPUT_DEBUG_LOGGING: True # Not for prod
DEBUG_RUN: True # Not for prod
run: python3 sources/main.py
- name: Save Branch Name Without Slashes 📛
if: ${{ github.ref != 'refs/heads/master' }}
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
run: |
BRANCH_NAME=${{ env.BRANCH_NAME }}
BRANCH_NAME=${BRANCH_NAME////_}
echo BRANCH_NAME=${BRANCH_NAME} >> $GITHUB_ENV
- name: Upload Artifact 📦
uses: actions/upload-artifact@v3
if: ${{ github.ref != 'refs/heads/master' }}
with:
name: ${{ format('github-pages-for-branch-{0}', env.BRANCH_NAME) }}
path: assets
- name: Create Comment 💬
uses: jungwinter/comment@v1
with:
type: create
body: ${{ steps.make-stats.outputs.README_CONTENT }}
issue_number: ${{ github.event.number }}
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -108,11 +108,11 @@ jobs:
```yml
- uses: anmol098/waka-readme-stats@master
with:
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
SHOW_OS: "False"
SHOW_PROJECTS: "False"
with:
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
SHOW_OS: "False"
SHOW_PROJECTS: "False"
```
### Flags Available
@@ -288,14 +288,15 @@ Contributions are welcome! ♥! Please share any features, and add unit tests! U
# Selected Contributors
1. [Anmol Pratap Singh](https://github.com/anmol098): Maintainer
2. [Prabhat Singh](https://github.com/prabhatdev): For code timeline graph [#18](https://github.com/anmol098/waka-readme-stats/pull/18)
2. [Aravind V. Nair](https://github.com/aravindvnair99): Maintainer and For Pull Request [#188](https://github.com/anmol098/waka-readme-stats/pull/188) And Other improvements
3. [Hedy Li](https://github.com/hedythedev): For Pull Request [#34](https://github.com/anmol098/waka-readme-stats/pull/34) and [#23](https://github.com/anmol098/waka-readme-stats/pull/23)
4. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29)
5. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45)
6. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48)
7. [Daniel Rowe](https://github.com/DanRowe): For Pull Request [#57](https://github.com/anmol098/waka-readme-stats/pull/57)
8. [Ss5h](https://github.com/tlatkdgus1): For adding support for natural sentence writing for translation [#136](https://github.com/anmol098/waka-readme-stats/pull/136)
2. [Alexander Sergeev](https://github.com/pseusys): Maintainer
3. [Aravind V. Nair](https://github.com/aravindvnair99): Maintainer
4. [Prabhat Singh](https://github.com/prabhatdev): For code timeline graph [#18](https://github.com/anmol098/waka-readme-stats/pull/18)
5. [Hedy Li](https://github.com/hedythedev): For Pull Request [#34](https://github.com/anmol098/waka-readme-stats/pull/34) and [#23](https://github.com/anmol098/waka-readme-stats/pull/23)
6. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29)
7. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45)
8. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48)
9. [Daniel Rowe](https://github.com/DanRowe): For Pull Request [#57](https://github.com/anmol098/waka-readme-stats/pull/57)
10. [Ss5h](https://github.com/tlatkdgus1): For adding support for natural sentence writing for translation [#136](https://github.com/anmol098/waka-readme-stats/pull/136)
<details>
<summary>Special mention for those who are currently making their profile readme more awesome :smile: :tada:</summary>
@@ -420,6 +421,10 @@ Contributions are welcome! ♥! Please share any features, and add unit tests! U
- [Muhammad Bilal](https://github.com/BilalJaved15)
- [Wyatt Walsh](https://www.github.com/wyattowalsh)
- [Nithin Balaji](https://github.com/thenithinbalaji)
</details>

View File

@@ -7,7 +7,7 @@ from pytz import timezone, utc
from manager_download import DownloadManager as DM
from manager_environment import EnvironmentManager as EM
from manager_github import GitHubManager as GHM
from manager_localization import LocalizationManager as LM
from manager_file import FileManager as FM
DAY_TIME_EMOJI = ["🌞", "🌆", "🌃", "🌙"] # Emojis, representing different times of day.
@@ -109,17 +109,17 @@ async def make_commit_day_time_list(time_zone: str) -> str:
sum_week = sum(week_days)
day_times = day_times[1:] + day_times[:1]
dt_names = [f"{DAY_TIME_EMOJI[i]} {LM.t(DAY_TIME_NAMES[i])}" for i in range(len(day_times))]
dt_names = [f"{DAY_TIME_EMOJI[i]} {FM.t(DAY_TIME_NAMES[i])}" for i in range(len(day_times))]
dt_texts = [f"{day_time} commits" for day_time in day_times]
dt_percents = [round((day_time / sum_day) * 100, 2) for day_time in day_times]
title = LM.t("I am an Early") if sum(day_times[0:2]) >= sum(day_times[2:4]) else LM.t("I am a Night")
title = FM.t("I am an Early") if sum(day_times[0:2]) >= sum(day_times[2:4]) else FM.t("I am a Night")
stats += f"**{title}** \n\n```text\n{make_list(names=dt_names, texts=dt_texts, percents=dt_percents, top_num=7, sort=False)}\n```\n"
if EM.SHOW_DAYS_OF_WEEK:
wd_names = [LM.t(week_day) for week_day in WEEK_DAY_NAMES]
wd_names = [FM.t(week_day) for week_day in WEEK_DAY_NAMES]
wd_texts = [f"{week_day} commits" for week_day in week_days]
wd_percents = [round((week_day / sum_week) * 100, 2) for week_day in week_days]
title = LM.t("I am Most Productive on") % wd_names[wd_percents.index(max(wd_percents))]
title = FM.t("I am Most Productive on") % wd_names[wd_percents.index(max(wd_percents))]
stats += f"📅 **{title}** \n\n```text\n{make_list(names=wd_names, texts=wd_texts, percents=wd_percents, top_num=7, sort=False)}\n```\n"
return stats
@@ -144,5 +144,5 @@ def make_language_per_repo_list(repositories: Dict) -> str:
percents = [round(language_count[lang]["count"] / len(repos_with_language) * 100, 2) for lang in names]
top_language = max(list(language_count.keys()), key=lambda x: language_count[x]["count"])
title = f"**{LM.t('I Mostly Code in') % top_language}** \n\n" if len(repos_with_language) > 0 else ""
title = f"**{FM.t('I Mostly Code in') % top_language}** \n\n" if len(repos_with_language) > 0 else ""
return f"{title}```text\n{make_list(names=names, texts=texts, percents=percents)}\n```\n\n"

View File

@@ -10,7 +10,7 @@ from humanize import intword, naturalsize, intcomma
from manager_download import init_download_manager, DownloadManager as DM
from manager_environment import EnvironmentManager as EM
from manager_github import init_github_manager, GitHubManager as GHM
from manager_localization import init_localization_manager, LocalizationManager as LM
from manager_file import init_localization_manager, FileManager as FM
from manager_debug import init_debug_manager, DebugManager as DBM
from graphics_chart_drawer import create_loc_graph, GRAPH_PATH
from yearly_commit_calculator import calculate_yearly_commit_data
@@ -33,33 +33,33 @@ async def get_waka_time_stats() -> str:
stats += f"{await make_commit_day_time_list(data['data']['timezone'])}\n\n"
if EM.SHOW_TIMEZONE or EM.SHOW_LANGUAGE or EM.SHOW_EDITORS or EM.SHOW_PROJECTS or EM.SHOW_OS:
no_activity = LM.t("No Activity Tracked This Week")
stats += f"📊 **{LM.t('This Week I Spend My Time On')}** \n\n```text\n"
no_activity = FM.t("No Activity Tracked This Week")
stats += f"📊 **{FM.t('This Week I Spend My Time On')}** \n\n```text\n"
if EM.SHOW_TIMEZONE:
DBM.i("Adding user timezone info...")
time_zone = data["data"]["timezone"]
stats += f"🕑︎ {LM.t('Timezone')}: {time_zone}\n\n"
stats += f"🕑︎ {FM.t('Timezone')}: {time_zone}\n\n"
if EM.SHOW_LANGUAGE:
DBM.i("Adding user top languages info...")
lang_list = no_activity if len(data["data"]["languages"]) == 0 else make_list(data["data"]["languages"])
stats += f"💬 {LM.t('Languages')}: \n{lang_list}\n\n"
stats += f"💬 {FM.t('Languages')}: \n{lang_list}\n\n"
if EM.SHOW_EDITORS:
DBM.i("Adding user editors info...")
edit_list = no_activity if len(data["data"]["editors"]) == 0 else make_list(data["data"]["editors"])
stats += f"🔥 {LM.t('Editors')}: \n{edit_list}\n\n"
stats += f"🔥 {FM.t('Editors')}: \n{edit_list}\n\n"
if EM.SHOW_PROJECTS:
DBM.i("Adding user projects info...")
project_list = no_activity if len(data["data"]["projects"]) == 0 else make_list(data["data"]["projects"])
stats += f"🐱‍💻 {LM.t('Projects')}: \n{project_list}\n\n"
stats += f"🐱‍💻 {FM.t('Projects')}: \n{project_list}\n\n"
if EM.SHOW_OS:
DBM.i("Adding user operating systems info...")
os_list = no_activity if len(data["data"]["operating_systems"]) == 0 else make_list(data["data"]["operating_systems"])
stats += f"💻 {LM.t('operating system')}: \n{os_list}\n\n"
stats += f"💻 {FM.t('operating system')}: \n{os_list}\n\n"
stats = f"{stats[:-1]}```\n\n"
@@ -75,20 +75,20 @@ async def get_short_github_info() -> str:
:returns: String representation of the info.
"""
DBM.i("Adding short GitHub info...")
stats = f"**🐱 {LM.t('My GitHub Data')}** \n\n"
stats = f"**🐱 {FM.t('My GitHub Data')}** \n\n"
DBM.i("Adding user disk usage info...")
if GHM.USER.disk_usage is None:
disk_usage = LM.t("Used in GitHub's Storage") % "?"
disk_usage = FM.t("Used in GitHub's Storage") % "?"
DBM.p("Please add new github personal access token with user permission!")
else:
disk_usage = LM.t("Used in GitHub's Storage") % naturalsize(GHM.USER.disk_usage)
disk_usage = FM.t("Used in GitHub's Storage") % naturalsize(GHM.USER.disk_usage)
stats += f"> 📦 {disk_usage} \n > \n"
data = await DM.get_remote_json("github_stats")
DBM.i("Adding contributions info...")
if len(data["years"]) > 0:
contributions = LM.t("Contributions in the year") % (intcomma(data["years"][0]["total"]), data["years"][0]["year"])
contributions = FM.t("Contributions in the year") % (intcomma(data["years"][0]["total"]), data["years"][0]["year"])
stats += f"> 🏆 {contributions}\n > \n"
else:
DBM.p("GitHub contributions data unavailable!")
@@ -96,23 +96,23 @@ async def get_short_github_info() -> str:
DBM.i("Adding opted for hire info...")
opted_to_hire = GHM.USER.hireable
if opted_to_hire:
stats += f"> 💼 {LM.t('Opted to Hire')}\n > \n"
stats += f"> 💼 {FM.t('Opted to Hire')}\n > \n"
else:
stats += f"> 🚫 {LM.t('Not Opted to Hire')}\n > \n"
stats += f"> 🚫 {FM.t('Not Opted to Hire')}\n > \n"
DBM.i("Adding public repositories info...")
public_repo = GHM.USER.public_repos
if public_repo != 1:
stats += f"> 📜 {LM.t('public repositories') % public_repo} \n > \n"
stats += f"> 📜 {FM.t('public repositories') % public_repo} \n > \n"
else:
stats += f"> 📜 {LM.t('public repository') % public_repo} \n > \n"
stats += f"> 📜 {FM.t('public repository') % public_repo} \n > \n"
DBM.i("Adding private repositories info...")
private_repo = GHM.USER.owned_private_repos if GHM.USER.owned_private_repos is not None else 0
if public_repo != 1:
stats += f"> 🔑 {LM.t('private repositories') % private_repo} \n > \n"
stats += f"> 🔑 {FM.t('private repositories') % private_repo} \n > \n"
else:
stats += f"> 🔑 {LM.t('private repository') % private_repo} \n > \n"
stats += f"> 🔑 {FM.t('private repository') % private_repo} \n > \n"
DBM.g("Short GitHub info added!")
return stats
@@ -144,13 +144,13 @@ async def get_stats() -> str:
if EM.SHOW_PROFILE_VIEWS:
DBM.i("Adding profile views info...")
data = GHM.REPO.get_views_traffic(per="week")
stats += f"![Profile Views](http://img.shields.io/badge/{quote(LM.t('Profile Views'))}-{data['count']}-blue)\n\n"
stats += f"![Profile Views](http://img.shields.io/badge/{quote(FM.t('Profile Views'))}-{data['count']}-blue)\n\n"
if EM.SHOW_LINES_OF_CODE:
DBM.i("Adding lines of code info...")
total_loc = sum([yearly_data[y][q][d] for y in yearly_data.keys() for q in yearly_data[y].keys() for d in yearly_data[y][q].keys()])
data = f"{intword(total_loc)} {LM.t('Lines of code')}"
stats += f"![Lines of code](https://img.shields.io/badge/{quote(LM.t('From Hello World I have written'))}-{quote(data)}-blue)\n\n"
data = f"{intword(total_loc)} {FM.t('Lines of code')}"
stats += f"![Lines of code](https://img.shields.io/badge/{quote(FM.t('From Hello World I have written'))}-{quote(data)}-blue)\n\n"
if EM.SHOW_SHORT_INFO:
stats += await get_short_github_info()
@@ -163,9 +163,7 @@ async def get_stats() -> str:
if EM.SHOW_LOC_CHART:
await create_loc_graph(yearly_data, GRAPH_PATH)
GHM.update_chart(GRAPH_PATH)
chart_path = f"{GHM.USER.login}/{GHM.USER.login}/{GHM.branch()}/{GRAPH_PATH}"
stats += f"**{LM.t('Timeline')}**\n\n![Lines of Code chart](https://raw.githubusercontent.com/{chart_path})\n\n"
stats += GHM.update_chart(GRAPH_PATH)
if EM.SHOW_UPDATED_DATE:
DBM.i("Adding last updated time...")
@@ -181,12 +179,17 @@ async def main():
Initializes all managers, collects user info and updates README.md if necessary.
"""
init_github_manager()
await init_download_manager()
await init_download_manager(GHM.USER.login)
init_localization_manager()
DBM.i("Managers initialized.")
if GHM.update_readme(await get_stats()):
DBM.g("Readme updated!")
stats = await get_stats()
if not EM.DEBUG_RUN:
if GHM.update_readme(stats):
DBM.g("Readme updated!")
else:
GHM.set_github_output(stats)
DBM.g("Debug run, readme not updated. Check the latest comment for the generated stats.")
await DM.close_remote_resources()

View File

@@ -8,10 +8,8 @@ from httpx import AsyncClient
from yaml import safe_load
from manager_environment import EnvironmentManager as EM
from manager_github import GitHubManager as GHM
from manager_debug import DebugManager as DBM
GITHUB_API_QUERIES = {
# Query to collect info about all user repositories, including: is it a fork, name and owner login.
# NB! Query includes information about recent repositories only (apparently, contributed within a year).
@@ -120,24 +118,30 @@ GITHUB_API_QUERIES = {
}
}
}
""",
"hide_outdated_comment": """
mutation {
minimizeComment(input: {classifier:OUTDATED, subjectId: "$id"}) {
clientMutationId
}
}
""",
}
async def init_download_manager():
async def init_download_manager(user_login: str):
"""
Initialize download manager:
- Setup headers for GitHub GraphQL requests.
- Launch static queries in background.
:param user_login: GitHub user login.
"""
await DownloadManager.load_remote_resources(
{
"linguist": "https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml",
"waka_latest": f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}",
"waka_all": f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}",
"github_stats": f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}",
},
{"Authorization": f"Bearer {EM.GH_TOKEN}"},
linguist="https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml",
waka_latest=f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}",
waka_all=f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}",
github_stats=f"https://github-contributions.vercel.app/api/v1/{user_login}",
)
@@ -157,15 +161,13 @@ class DownloadManager:
_REMOTE_RESOURCES_CACHE = dict()
@staticmethod
async def load_remote_resources(resources: Dict[str, str], github_headers: Dict[str, str]):
async def load_remote_resources(**resources: str):
"""
Prepare DownloadManager to launch GitHub API queries and launch all static queries.
:param resources: Dictionary of static queries, "IDENTIFIER": "URL".
:param github_headers: Dictionary of headers for GitHub API queries.
:param resources: Static queries, formatted like "IDENTIFIER"="URL".
"""
for resource, url in resources.items():
DownloadManager._REMOTE_RESOURCES_CACHE[resource] = DownloadManager._client.get(url)
DownloadManager._client.headers = github_headers
@staticmethod
async def close_remote_resources():
@@ -229,10 +231,14 @@ class DownloadManager:
"""
Execute GitHub GraphQL API simple query.
:param query: Dynamic query identifier.
:param use_github_action: Use GitHub actions bot auth token instead of current user.
:param kwargs: Parameters for substitution of variables in dynamic query.
:return: Response JSON dictionary.
"""
res = await DownloadManager._client.post("https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)})
headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"}
res = await DownloadManager._client.post(
"https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers
)
if res.status_code == 200:
return res.json()
else:
@@ -268,13 +274,15 @@ class DownloadManager:
Queries 100 new results each time until no more results are left.
Merges result list into single query, clears pagination-related info.
:param query: Dynamic query identifier.
:param use_github_action: Use GitHub actions bot auth token instead of current user.
:param kwargs: Parameters for substitution of variables in dynamic query.
:return: Response JSON dictionary.
"""
initial_query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination="first: 100")
page_list, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response)
while page_info["hasNextPage"]:
query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination=f'first: 100, after: "{page_info["endCursor"]}"')
pagination = f'first: 100, after: "{page_info["endCursor"]}"'
query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination=pagination)
new_page_list, page_info = DownloadManager._find_pagination_and_data_list(query_response)
page_list += new_page_list
_, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response)

View File

@@ -1,5 +1,5 @@
from json import load
from os.path import join, dirname
from os.path import join
from typing import Dict
from manager_environment import EnvironmentManager as EM
@@ -10,10 +10,10 @@ def init_localization_manager():
Initialize localization manager.
Load GUI translations JSON file.
"""
LocalizationManager.load_localization("translation.json")
FileManager.load_localization("translation.json")
class LocalizationManager:
class FileManager:
"""
Class for handling localization (and maybe other file IO in future).
Stores localization in dictionary.
@@ -28,9 +28,9 @@ class LocalizationManager:
:param file: Localization file path, related to current file (in sources root).
"""
with open(join(dirname(__file__), file), encoding="utf-8") as config_file:
with open(join("sources", file), encoding="utf-8") as config_file:
data = load(config_file)
LocalizationManager._LOCALIZATION = data[EM.LOCALE]
FileManager._LOCALIZATION = data[EM.LOCALE]
@staticmethod
def t(key: str) -> str:
@@ -40,4 +40,18 @@ class LocalizationManager:
:param key: Localization key.
:returns: Translation string.
"""
return LocalizationManager._LOCALIZATION[key]
return FileManager._LOCALIZATION[key]
@staticmethod
def write_file(name: str, content: str, append: bool = False, assets: bool = False):
"""
Save output file.
:param name: File name.
:param content: File content (utf-8 string).
:param append: True for appending to file, false for rewriting.
:param assets: True for saving to 'assets' directory, false otherwise.
"""
name = join("assets", name) if assets else name
with open(name, "a" if append else "w", encoding="utf-8") as file:
file.write(content)

View File

@@ -1,9 +1,13 @@
from base64 import b64decode
from base64 import b64decode, b64encode
from os import environ
from random import choice
from re import sub
from string import ascii_letters
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
@@ -81,6 +85,7 @@ class GitHubManager:
Updates readme with given data if necessary.
Uses commit author, commit message and branch name specified by environmental variables.
:param stats: Readme stats to be pushed.
:returns: whether the README.md file was updated or not.
"""
DBM.i("Updating README...")
@@ -101,20 +106,50 @@ class GitHubManager:
return False
@staticmethod
def update_chart(chart_path: str):
def set_github_output(stats: str):
"""
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():
raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!")
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!")
@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()
try:
contents = GitHubManager.REPO.get_contents(chart_path)
GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author())
DBM.g("Lines of code chart updated!")
except UnknownObjectException:
GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author())
DBM.g("Lines of code chart created!")
if not EM.DEBUG_RUN:
DBM.i("Pushing chart to repo...")
chart_path = f"https://raw.githubusercontent.com/{GitHubManager.USER.login}/{GitHubManager.USER.login}/{GitHubManager.branch()}/{chart_path}"
try:
contents = GitHubManager.REPO.get_contents(chart_path)
GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author())
DBM.g("Lines of code chart updated!")
except UnknownObjectException:
GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author())
DBM.g("Lines of code chart created!")
return f"**{FM.t('Timeline')}**\n\n![Lines of Code chart]({chart_path})\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"

View File

@@ -1,3 +1,4 @@
from json import dumps
from re import search
from datetime import datetime
from typing import Dict
@@ -5,6 +6,7 @@ from typing import Dict
from manager_download import DownloadManager as DM
from manager_environment import EnvironmentManager as EM
from manager_github import GitHubManager as GHM
from manager_file import FileManager as FM
from manager_debug import DebugManager as DBM
@@ -19,12 +21,16 @@ async def calculate_yearly_commit_data(repositories: Dict) -> Dict:
DBM.i("Calculating yearly commit data...")
yearly_data = dict()
total = len(repositories["data"]["user"]["repositories"]["nodes"])
for ind, repo in enumerate(repositories["data"]["user"]["repositories"]["nodes"]):
if repo["name"] not in EM.IGNORED_REPOS:
repo_name = "private" if repo["isPrivate"] else f"{repo['owner']['login']}/{repo['name']}"
DBM.i(f"\t{ind + 1}/{total} Retrieving repo: {repo_name}")
await update_yearly_data_with_commit_stats(repo, yearly_data)
DBM.g("Yearly commit data calculated!")
if EM.DEBUG_RUN:
FM.write_file("yearly_data.json", dumps(yearly_data), assets=True)
return yearly_data