You've already forked wakapi-readme-stats
Merge branch 'master' into dependabot
This commit is contained in:
83
.github/workflows/ci.yml
vendored
Normal file
83
.github/workflows/ci.yml
vendored
Normal 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 }}
|
||||||
21
README.md
21
README.md
@@ -288,14 +288,15 @@ Contributions are welcome! ♥! Please share any features, and add unit tests! U
|
|||||||
# Selected Contributors
|
# Selected Contributors
|
||||||
|
|
||||||
1. [Anmol Pratap Singh](https://github.com/anmol098): Maintainer
|
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. [Alexander Sergeev](https://github.com/pseusys): Maintainer
|
||||||
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. [Aravind V. Nair](https://github.com/aravindvnair99): Maintainer
|
||||||
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. [Prabhat Singh](https://github.com/prabhatdev): For code timeline graph [#18](https://github.com/anmol098/waka-readme-stats/pull/18)
|
||||||
4. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29)
|
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)
|
||||||
5. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45)
|
6. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29)
|
||||||
6. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48)
|
7. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45)
|
||||||
7. [Daniel Rowe](https://github.com/DanRowe): For Pull Request [#57](https://github.com/anmol098/waka-readme-stats/pull/57)
|
8. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48)
|
||||||
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)
|
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>
|
<details>
|
||||||
<summary>Special mention for those who are currently making their profile readme more awesome :smile: :tada:</summary>
|
<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)
|
- [Muhammad Bilal](https://github.com/BilalJaved15)
|
||||||
|
|
||||||
|
- [Wyatt Walsh](https://www.github.com/wyattowalsh)
|
||||||
|
|
||||||
|
- [Nithin Balaji](https://github.com/thenithinbalaji)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from pytz import timezone, utc
|
|||||||
from manager_download import DownloadManager as DM
|
from manager_download import DownloadManager as DM
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
from manager_github import GitHubManager as GHM
|
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.
|
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)
|
sum_week = sum(week_days)
|
||||||
day_times = day_times[1:] + day_times[:1]
|
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_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]
|
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"
|
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:
|
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_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]
|
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"
|
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
|
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]
|
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"])
|
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"
|
return f"{title}```text\n{make_list(names=names, texts=texts, percents=percents)}\n```\n\n"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from humanize import intword, naturalsize, intcomma
|
|||||||
from manager_download import init_download_manager, DownloadManager as DM
|
from manager_download import init_download_manager, DownloadManager as DM
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
from manager_github import init_github_manager, GitHubManager as GHM
|
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 manager_debug import init_debug_manager, DebugManager as DBM
|
||||||
from graphics_chart_drawer import create_loc_graph, GRAPH_PATH
|
from graphics_chart_drawer import create_loc_graph, GRAPH_PATH
|
||||||
from yearly_commit_calculator import calculate_yearly_commit_data
|
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"
|
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:
|
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")
|
no_activity = FM.t("No Activity Tracked This Week")
|
||||||
stats += f"📊 **{LM.t('This Week I Spend My Time On')}** \n\n```text\n"
|
stats += f"📊 **{FM.t('This Week I Spend My Time On')}** \n\n```text\n"
|
||||||
|
|
||||||
if EM.SHOW_TIMEZONE:
|
if EM.SHOW_TIMEZONE:
|
||||||
DBM.i("Adding user timezone info...")
|
DBM.i("Adding user timezone info...")
|
||||||
time_zone = data["data"]["timezone"]
|
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:
|
if EM.SHOW_LANGUAGE:
|
||||||
DBM.i("Adding user top languages info...")
|
DBM.i("Adding user top languages info...")
|
||||||
lang_list = no_activity if len(data["data"]["languages"]) == 0 else make_list(data["data"]["languages"])
|
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:
|
if EM.SHOW_EDITORS:
|
||||||
DBM.i("Adding user editors info...")
|
DBM.i("Adding user editors info...")
|
||||||
edit_list = no_activity if len(data["data"]["editors"]) == 0 else make_list(data["data"]["editors"])
|
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:
|
if EM.SHOW_PROJECTS:
|
||||||
DBM.i("Adding user projects info...")
|
DBM.i("Adding user projects info...")
|
||||||
project_list = no_activity if len(data["data"]["projects"]) == 0 else make_list(data["data"]["projects"])
|
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:
|
if EM.SHOW_OS:
|
||||||
DBM.i("Adding user operating systems info...")
|
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"])
|
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"
|
stats = f"{stats[:-1]}```\n\n"
|
||||||
|
|
||||||
@@ -75,20 +75,20 @@ async def get_short_github_info() -> str:
|
|||||||
:returns: String representation of the info.
|
:returns: String representation of the info.
|
||||||
"""
|
"""
|
||||||
DBM.i("Adding short GitHub 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...")
|
DBM.i("Adding user disk usage info...")
|
||||||
if GHM.USER.disk_usage is None:
|
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!")
|
DBM.p("Please add new github personal access token with user permission!")
|
||||||
else:
|
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"
|
stats += f"> 📦 {disk_usage} \n > \n"
|
||||||
|
|
||||||
data = await DM.get_remote_json("github_stats")
|
data = await DM.get_remote_json("github_stats")
|
||||||
DBM.i("Adding contributions info...")
|
DBM.i("Adding contributions info...")
|
||||||
if len(data["years"]) > 0:
|
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"
|
stats += f"> 🏆 {contributions}\n > \n"
|
||||||
else:
|
else:
|
||||||
DBM.p("GitHub contributions data unavailable!")
|
DBM.p("GitHub contributions data unavailable!")
|
||||||
@@ -96,23 +96,23 @@ async def get_short_github_info() -> str:
|
|||||||
DBM.i("Adding opted for hire info...")
|
DBM.i("Adding opted for hire info...")
|
||||||
opted_to_hire = GHM.USER.hireable
|
opted_to_hire = GHM.USER.hireable
|
||||||
if opted_to_hire:
|
if opted_to_hire:
|
||||||
stats += f"> 💼 {LM.t('Opted to Hire')}\n > \n"
|
stats += f"> 💼 {FM.t('Opted to Hire')}\n > \n"
|
||||||
else:
|
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...")
|
DBM.i("Adding public repositories info...")
|
||||||
public_repo = GHM.USER.public_repos
|
public_repo = GHM.USER.public_repos
|
||||||
if public_repo != 1:
|
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:
|
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...")
|
DBM.i("Adding private repositories info...")
|
||||||
private_repo = GHM.USER.owned_private_repos if GHM.USER.owned_private_repos is not None else 0
|
private_repo = GHM.USER.owned_private_repos if GHM.USER.owned_private_repos is not None else 0
|
||||||
if public_repo != 1:
|
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:
|
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!")
|
DBM.g("Short GitHub info added!")
|
||||||
return stats
|
return stats
|
||||||
@@ -144,13 +144,13 @@ async def get_stats() -> str:
|
|||||||
if EM.SHOW_PROFILE_VIEWS:
|
if EM.SHOW_PROFILE_VIEWS:
|
||||||
DBM.i("Adding profile views info...")
|
DBM.i("Adding profile views info...")
|
||||||
data = GHM.REPO.get_views_traffic(per="week")
|
data = GHM.REPO.get_views_traffic(per="week")
|
||||||
stats += f")}-{data['count']}-blue)\n\n"
|
stats += f")}-{data['count']}-blue)\n\n"
|
||||||
|
|
||||||
if EM.SHOW_LINES_OF_CODE:
|
if EM.SHOW_LINES_OF_CODE:
|
||||||
DBM.i("Adding lines of code info...")
|
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()])
|
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')}"
|
data = f"{intword(total_loc)} {FM.t('Lines of code')}"
|
||||||
stats += f")}-{quote(data)}-blue)\n\n"
|
stats += f")}-{quote(data)}-blue)\n\n"
|
||||||
|
|
||||||
if EM.SHOW_SHORT_INFO:
|
if EM.SHOW_SHORT_INFO:
|
||||||
stats += await get_short_github_info()
|
stats += await get_short_github_info()
|
||||||
@@ -163,9 +163,7 @@ async def get_stats() -> str:
|
|||||||
|
|
||||||
if EM.SHOW_LOC_CHART:
|
if EM.SHOW_LOC_CHART:
|
||||||
await create_loc_graph(yearly_data, GRAPH_PATH)
|
await create_loc_graph(yearly_data, GRAPH_PATH)
|
||||||
GHM.update_chart(GRAPH_PATH)
|
stats += 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\n\n"
|
|
||||||
|
|
||||||
if EM.SHOW_UPDATED_DATE:
|
if EM.SHOW_UPDATED_DATE:
|
||||||
DBM.i("Adding last updated time...")
|
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.
|
Initializes all managers, collects user info and updates README.md if necessary.
|
||||||
"""
|
"""
|
||||||
init_github_manager()
|
init_github_manager()
|
||||||
await init_download_manager()
|
await init_download_manager(GHM.USER.login)
|
||||||
init_localization_manager()
|
init_localization_manager()
|
||||||
DBM.i("Managers initialized.")
|
DBM.i("Managers initialized.")
|
||||||
|
|
||||||
if GHM.update_readme(await get_stats()):
|
stats = await get_stats()
|
||||||
|
if not EM.DEBUG_RUN:
|
||||||
|
if GHM.update_readme(stats):
|
||||||
DBM.g("Readme updated!")
|
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()
|
await DM.close_remote_resources()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ from httpx import AsyncClient
|
|||||||
from yaml import safe_load
|
from yaml import safe_load
|
||||||
|
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
from manager_github import GitHubManager as GHM
|
|
||||||
from manager_debug import DebugManager as DBM
|
from manager_debug import DebugManager as DBM
|
||||||
|
|
||||||
|
|
||||||
GITHUB_API_QUERIES = {
|
GITHUB_API_QUERIES = {
|
||||||
# Query to collect info about all user repositories, including: is it a fork, name and owner login.
|
# 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).
|
# 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:
|
Initialize download manager:
|
||||||
- Setup headers for GitHub GraphQL requests.
|
- Setup headers for GitHub GraphQL requests.
|
||||||
- Launch static queries in background.
|
- Launch static queries in background.
|
||||||
|
|
||||||
|
:param user_login: GitHub user login.
|
||||||
"""
|
"""
|
||||||
await DownloadManager.load_remote_resources(
|
await DownloadManager.load_remote_resources(
|
||||||
{
|
linguist="https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml",
|
||||||
"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_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}",
|
||||||
"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}",
|
||||||
"github_stats": f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}",
|
|
||||||
},
|
|
||||||
{"Authorization": f"Bearer {EM.GH_TOKEN}"},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -157,15 +161,13 @@ class DownloadManager:
|
|||||||
_REMOTE_RESOURCES_CACHE = dict()
|
_REMOTE_RESOURCES_CACHE = dict()
|
||||||
|
|
||||||
@staticmethod
|
@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.
|
Prepare DownloadManager to launch GitHub API queries and launch all static queries.
|
||||||
:param resources: Dictionary of static queries, "IDENTIFIER": "URL".
|
:param resources: Static queries, formatted like "IDENTIFIER"="URL".
|
||||||
:param github_headers: Dictionary of headers for GitHub API queries.
|
|
||||||
"""
|
"""
|
||||||
for resource, url in resources.items():
|
for resource, url in resources.items():
|
||||||
DownloadManager._REMOTE_RESOURCES_CACHE[resource] = DownloadManager._client.get(url)
|
DownloadManager._REMOTE_RESOURCES_CACHE[resource] = DownloadManager._client.get(url)
|
||||||
DownloadManager._client.headers = github_headers
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def close_remote_resources():
|
async def close_remote_resources():
|
||||||
@@ -229,10 +231,14 @@ class DownloadManager:
|
|||||||
"""
|
"""
|
||||||
Execute GitHub GraphQL API simple query.
|
Execute GitHub GraphQL API simple query.
|
||||||
:param query: Dynamic query identifier.
|
: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.
|
:param kwargs: Parameters for substitution of variables in dynamic query.
|
||||||
:return: Response JSON dictionary.
|
: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:
|
if res.status_code == 200:
|
||||||
return res.json()
|
return res.json()
|
||||||
else:
|
else:
|
||||||
@@ -268,13 +274,15 @@ class DownloadManager:
|
|||||||
Queries 100 new results each time until no more results are left.
|
Queries 100 new results each time until no more results are left.
|
||||||
Merges result list into single query, clears pagination-related info.
|
Merges result list into single query, clears pagination-related info.
|
||||||
:param query: Dynamic query identifier.
|
: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.
|
:param kwargs: Parameters for substitution of variables in dynamic query.
|
||||||
:return: Response JSON dictionary.
|
:return: Response JSON dictionary.
|
||||||
"""
|
"""
|
||||||
initial_query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination="first: 100")
|
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)
|
page_list, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response)
|
||||||
while page_info["hasNextPage"]:
|
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)
|
new_page_list, page_info = DownloadManager._find_pagination_and_data_list(query_response)
|
||||||
page_list += new_page_list
|
page_list += new_page_list
|
||||||
_, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response)
|
_, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from json import load
|
from json import load
|
||||||
from os.path import join, dirname
|
from os.path import join
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
@@ -10,10 +10,10 @@ def init_localization_manager():
|
|||||||
Initialize localization manager.
|
Initialize localization manager.
|
||||||
Load GUI translations JSON file.
|
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).
|
Class for handling localization (and maybe other file IO in future).
|
||||||
Stores localization in dictionary.
|
Stores localization in dictionary.
|
||||||
@@ -28,9 +28,9 @@ class LocalizationManager:
|
|||||||
|
|
||||||
:param file: Localization file path, related to current file (in sources root).
|
: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)
|
data = load(config_file)
|
||||||
LocalizationManager._LOCALIZATION = data[EM.LOCALE]
|
FileManager._LOCALIZATION = data[EM.LOCALE]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def t(key: str) -> str:
|
def t(key: str) -> str:
|
||||||
@@ -40,4 +40,18 @@ class LocalizationManager:
|
|||||||
:param key: Localization key.
|
:param key: Localization key.
|
||||||
:returns: Translation string.
|
: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)
|
||||||
@@ -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 re import sub
|
||||||
|
from string import ascii_letters
|
||||||
|
|
||||||
from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException
|
from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException
|
||||||
|
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
|
from manager_file import FileManager as FM
|
||||||
from manager_debug import DebugManager as DBM
|
from manager_debug import DebugManager as DBM
|
||||||
|
|
||||||
|
|
||||||
@@ -81,6 +85,7 @@ class GitHubManager:
|
|||||||
Updates readme with given data if necessary.
|
Updates readme with given data if necessary.
|
||||||
Uses commit author, commit message and branch name specified by environmental variables.
|
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.
|
:returns: whether the README.md file was updated or not.
|
||||||
"""
|
"""
|
||||||
DBM.i("Updating README...")
|
DBM.i("Updating README...")
|
||||||
@@ -101,16 +106,40 @@ class GitHubManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@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.
|
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.
|
Uses commit author, commit message and branch name specified by environmental variables.
|
||||||
|
|
||||||
:param chart_path: path to saved lines of code chart.
|
:param chart_path: path to saved lines of code chart.
|
||||||
|
:returns: string to add to README file.
|
||||||
"""
|
"""
|
||||||
DBM.i("Updating lines of code chart...")
|
DBM.i("Updating lines of code chart...")
|
||||||
with open(chart_path, "rb") as input_file:
|
with open(chart_path, "rb") as input_file:
|
||||||
data = input_file.read()
|
data = input_file.read()
|
||||||
|
|
||||||
|
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:
|
try:
|
||||||
contents = GitHubManager.REPO.get_contents(chart_path)
|
contents = GitHubManager.REPO.get_contents(chart_path)
|
||||||
GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author())
|
GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author())
|
||||||
@@ -118,3 +147,9 @@ class GitHubManager:
|
|||||||
except UnknownObjectException:
|
except UnknownObjectException:
|
||||||
GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author())
|
GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author())
|
||||||
DBM.g("Lines of code chart created!")
|
DBM.g("Lines of code chart created!")
|
||||||
|
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"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from json import dumps
|
||||||
from re import search
|
from re import search
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
@@ -5,6 +6,7 @@ from typing import Dict
|
|||||||
from manager_download import DownloadManager as DM
|
from manager_download import DownloadManager as DM
|
||||||
from manager_environment import EnvironmentManager as EM
|
from manager_environment import EnvironmentManager as EM
|
||||||
from manager_github import GitHubManager as GHM
|
from manager_github import GitHubManager as GHM
|
||||||
|
from manager_file import FileManager as FM
|
||||||
from manager_debug import DebugManager as DBM
|
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...")
|
DBM.i("Calculating yearly commit data...")
|
||||||
yearly_data = dict()
|
yearly_data = dict()
|
||||||
total = len(repositories["data"]["user"]["repositories"]["nodes"])
|
total = len(repositories["data"]["user"]["repositories"]["nodes"])
|
||||||
|
|
||||||
for ind, repo in enumerate(repositories["data"]["user"]["repositories"]["nodes"]):
|
for ind, repo in enumerate(repositories["data"]["user"]["repositories"]["nodes"]):
|
||||||
if repo["name"] not in EM.IGNORED_REPOS:
|
if repo["name"] not in EM.IGNORED_REPOS:
|
||||||
repo_name = "private" if repo["isPrivate"] else f"{repo['owner']['login']}/{repo['name']}"
|
repo_name = "private" if repo["isPrivate"] else f"{repo['owner']['login']}/{repo['name']}"
|
||||||
DBM.i(f"\t{ind + 1}/{total} Retrieving repo: {repo_name}")
|
DBM.i(f"\t{ind + 1}/{total} Retrieving repo: {repo_name}")
|
||||||
await update_yearly_data_with_commit_stats(repo, yearly_data)
|
await update_yearly_data_with_commit_stats(repo, yearly_data)
|
||||||
DBM.g("Yearly commit data calculated!")
|
DBM.g("Yearly commit data calculated!")
|
||||||
|
|
||||||
|
if EM.DEBUG_RUN:
|
||||||
|
FM.write_file("yearly_data.json", dumps(yearly_data), assets=True)
|
||||||
return yearly_data
|
return yearly_data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user