merged with master

This commit is contained in:
pseusys
2023-02-16 22:19:30 +01:00
13 changed files with 675 additions and 621 deletions

View File

@@ -1,22 +1,22 @@
INPUT_WAKATIME_API_KEY="" INPUT_WAKATIME_API_KEY=YOUR_WAKATIME_API_KEY
INPUT_PUSH_BRANCH_NAME="main" INPUT_PUSH_BRANCH_NAME=main
INPUT_SECTION_NAME="waka" INPUT_SECTION_NAME=waka
INPUT_SHOW_TIMEZONE="True" INPUT_SHOW_TIMEZONE=True
INPUT_SHOW_PROJECTS="False" INPUT_SHOW_PROJECTS=True
INPUT_SHOW_EDITORS="False" INPUT_SHOW_EDITORS=True
INPUT_SHOW_OS="False" INPUT_SHOW_OS=True
INPUT_SHOW_LANGUAGE="False" INPUT_SHOW_LANGUAGE=True
INPUT_GH_TOKEN="" INPUT_GH_TOKEN=YOUR_GITHUB_TOKEN_KEY
INPUT_SYMBOL_VERSION="1" INPUT_SYMBOL_VERSION=1
INPUT_SHOW_LINES_OF_CODE="False" INPUT_SHOW_LINES_OF_CODE=True
INPUT_SHOW_LOC_CHART="False" INPUT_SHOW_LOC_CHART=True
INPUT_SHOW_PROFILE_VIEWS="False" INPUT_SHOW_PROFILE_VIEWS=True
INPUT_SHOW_TOTAL_CODE_TIME="True" INPUT_SHOW_TOTAL_CODE_TIME=True
INPUT_SHOW_SHORT_INFO="False" INPUT_SHOW_SHORT_INFO=True
INPUT_SHOW_COMMIT="False" INPUT_SHOW_COMMIT=True
INPUT_SHOW_DAYS_OF_WEEK="True" INPUT_SHOW_DAYS_OF_WEEK=True
INPUT_SHOW_LANGUAGE_PER_REPO="True" INPUT_SHOW_LANGUAGE_PER_REPO=True
INPUT_SHOW_UPDATED_DATE="True" INPUT_SHOW_UPDATED_DATE=True
INPUT_UPDATED_DATE_FORMAT="%d/%m/%Y %H:%M:%S" INPUT_UPDATED_DATE_FORMAT=%d/%m/%Y %H:%M:%S
INPUT_COMMIT_BY_ME="False" INPUT_COMMIT_BY_ME=False
INPUT_COMMIT_MESSAGE="Updated with Dev Metrics" INPUT_COMMIT_MESSAGE=Updated with Dev Metrics

37
.github/workflows/build_image.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: PUBLISH_IMAGE
on:
push:
jobs:
publish-server-image:
name: Publish 'waka-readme-stats' image
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
- name: Log in to the container registry 🚪
uses: docker/login-action@v2
with:
username: wakareadmestats
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker 🏋️
id: meta
uses: docker/metadata-action@v4
with:
images: wakareadmestats/waka-readme-stats
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push Docker image 🏗️
uses: docker/build-push-action@v3
with:
push: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/releases') }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

14
.gitignore vendored
View File

@@ -1,6 +1,20 @@
# Environment files:
*.env *.env
# Generated graph images:
*.png *.png
# Library roots:
node_modules/ node_modules/
venv/
# Python caches:
__pycache__/ __pycache__/
# Package manager configuration files:
package.json
package-lock.json
# IDE configuration files:
.vscode .vscode
.idea

View File

@@ -1,18 +1,14 @@
FROM nikolaik/python-nodejs:python3.9-nodejs16 FROM nikolaik/python-nodejs:python3.9-nodejs16
ADD requirements.txt /requirements.txt ENV PYTHONUNBUFFERED 1
ADD main.py /main.py ENV PYTHONDONTWRITEBYTECODE 1
ADD loc.py /loc.py
ADD make_bar_graph.py /make_bar_graph.py
ADD translation.json /translation.json
ADD download_manager.py /download_manager.py
ENV PATH "$PATH:/home/root/.npm-global/bin" WORKDIR /waka-readme-stats
RUN python -m pip install --upgrade pip wheel setuptools ADD requirements.txt ./requirements.txt
RUN pip install -r requirements.txt RUN pip install --upgrade pip && pip install -r requirements.txt
RUN npm -g config set user root RUN npm i npm@next-8 && npm i vega vega-lite vega-cli canvas
RUN npm i -g npm@next-8
RUN npm i -g vega vega-lite vega-cli canvas
ENTRYPOINT ["python", "/main.py"] ADD sources/* ./
ENTRYPOINT python3 /waka-readme-stats/main.py

49
Makefile Normal file
View File

@@ -0,0 +1,49 @@
.ONESHELL:
.DEFAULT_GOAL = help
SHELL = /bin/bash
PATH := venv/bin:node_modules/.bin:$(PATH)
help:
@ # Print help commands
echo "Welcome to 'waka-readme-stats' GitHub Actions!"
echo "The action can be tested locally with: 'make run'."
echo "NB! For local testing Python version 3.6+ and NodeJS version between 14 and 16 are required."
echo "The action image can be built locally with: 'make container'."
echo "NB! For local container building Docker version 20+ is required."
echo "The action directory and image can be cleaned with: 'make clean'."
.PHONY: help
venv:
@ # Install Python virtual environment and dependencies
python3 -m venv venv
pip install --upgrade pip
pip install -r requirements.txt
node_modules:
@ # Install NodeJS dependencies
npm i npm@next-8
npm i vega vega-lite vega-cli canvas
run-locally: venv node_modules
@ # Run action locally
source <(cat .env.example | sed 's/=/=/' | sed 's/^/export /') && python3 ./sources/main.py
.PHONY: run-locally
run-container:
@ # Run action in container
docker build -t waka-readme-stats -f Dockerfile .
docker run --env-file .env.example waka-readme-stats
.PHONY: run-container
clean:
@ # Clean all build files, including: libraries, package manager configs, docker images and containers
rm -rf venv
rm -rf node_modules
rm -f package*.json
docker rm -f waka-readme-stats 2>/dev/null || true
docker rmi $(docker images | grep "waka-readme-stats") 2> /dev/null || true
.PHONY: clean

View File

@@ -11,7 +11,7 @@ inputs:
WAKATIME_API_KEY: WAKATIME_API_KEY:
description: 'Your Wakatime API Key' description: 'Your Wakatime API Key'
required: true required: true
SECTION_NAME: SECTION_NAME:
description: 'Name used in readme to scope the updated section' description: 'Name used in readme to scope the updated section'
required: false required: false
@@ -134,7 +134,7 @@ inputs:
runs: runs:
using: 'docker' using: 'docker'
image: 'Dockerfile' image: 'docker://wakareadmestats/waka-readme-stats:master'
branding: branding:
icon: 'activity' icon: 'activity'

View File

@@ -1,35 +1,11 @@
altair==4.1.0
altair-data-server==0.4.1
altair-saver==0.5.0
altair-viewer==0.3.0
attrs==20.3.0
certifi==2020.12.5
cycler==0.10.0
Deprecated==1.2.12
entrypoints==0.3
httpx==0.23.3
humanize==3.3.0
idna==2.10
Jinja2==2.11.3
jsonschema==3.2.0
kiwisolver==1.3.1
MarkupSafe==1.1.1
matplotlib==3.4.1
numpy==1.20.2
pandas==1.2.3
Pillow==8.2.0
portpicker==1.3.1
PyGithub==1.54.1 PyGithub==1.54.1
PyJWT==1.7.1 matplotlib==3.4.1
PyYAML==6.0
pyparsing==2.4.7
pyrsistent==0.17.3
python-dateutil==2.8.1
python-dotenv==0.17.0 python-dotenv==0.17.0
numpy==1.24.1
pandas==1.2.3
altair==4.1.0
altair-saver==0.5.0
pytz==2021.1 pytz==2021.1
selenium==3.141.0 humanize==3.3.0
six==1.15.0 httpx==0.23.3
toolz==0.11.1 PyYAML==6.0
tornado==6.1
urllib3==1.26.5
wrapt==1.12.1

0
sources/colors.json Normal file
View File

View File

@@ -1,84 +1,77 @@
import re import re
import os from asyncio import sleep
import base64
from asyncio import sleep from github import Github, InputGitAuthor, AuthenticatedUser
import datetime
from github import Github, InputGitAuthor, AuthenticatedUser
import datetime from download_manager import DownloadManager
from string import Template from make_bar_graph import BarGraph
import matplotlib.pyplot as plt
from io import StringIO, BytesIO
from dotenv import load_dotenv class LinesOfCode:
import time
def __init__(self, user: AuthenticatedUser, ghtoken, repositoryData, ignored_repos):
from download_manager import DownloadManager self.g = Github(ghtoken)
from make_bar_graph import BarGraph self.user = user
self.repositoryData = repositoryData
self.ignored_repos = ignored_repos
class LinesOfCode:
async def calculateLoc(self):
def __init__(self, user: AuthenticatedUser, ghtoken, repositoryData, ignored_repos): result = self.repositoryData
self.g = Github(ghtoken) yearly_data = {}
self.user = user total = len(result['data']['user']['repositories']['edges'])
self.repositoryData = repositoryData for ind, repo in enumerate(result['data']['user']['repositories']['edges']):
self.ignored_repos = ignored_repos if repo['node']['name'] not in self.ignored_repos:
print(f"{ind}/{total}", "Retrieving repo:", repo['node']["owner"]["login"], repo['node']['name'])
async def calculateLoc(self): await self.getCommitStat(repo['node'], yearly_data)
result = self.repositoryData await sleep(0.7)
yearly_data = {} return yearly_data
total = len(result['data']['user']['repositories']['edges'])
for ind, repo in enumerate(result['data']['user']['repositories']['edges']): async def plotLoc(self, yearly_data):
if repo['node']['name'] not in self.ignored_repos: graph = BarGraph(yearly_data)
print(f"{ind}/{total}", "Retrieving repo:", repo['node']["owner"]["login"], repo['node']['name']) await graph.build_graph()
await self.getCommitStat(repo['node'], yearly_data) self.pushChart()
await sleep(0.7)
return yearly_data def getQuarter(self, timeStamp):
month = datetime.datetime.fromisoformat(timeStamp).month
async def plotLoc(self, yearly_data): if month >= 1 and month <= 3:
graph = BarGraph(yearly_data) return 1
await graph.build_graph() elif month >= 4 and month <= 6:
self.pushChart() return 2
elif month >= 7 and month <= 9:
def getQuarter(self, timeStamp): return 3
month = datetime.datetime.fromisoformat(timeStamp).month elif month >= 10 and month <= 12:
if month >= 1 and month <= 3: return 4
return 1
elif month >= 4 and month <= 6: async def getCommitStat(self, repoDetails, yearly_data):
return 2 commit_data = await DownloadManager.get_remote_graphql("repository_commit_list", owner=repoDetails["owner"]["login"], name=repoDetails['name'], id=self.user.node_id)
elif month >= 7 and month <= 9:
return 3 if commit_data["data"]["repository"] is None:
elif month >= 10 and month <= 12: print("\tSkipping:", repoDetails['name'])
return 4 return
async def getCommitStat(self, repoDetails, yearly_data): for commit in [commit["node"] for branch in commit_data["data"]["repository"]["refs"]["edges"] for commit in branch["node"]["target"]["history"]["edges"]]:
commit_data = await DownloadManager.get_remote_graphql("repository_commit_list", owner=repoDetails["owner"]["login"], name=repoDetails['name'], id=self.user.node_id) date = re.search(r'\d+-\d+-\d+', commit["committedDate"]).group(0)
curr_year = datetime.datetime.fromisoformat(date).year
if commit_data["data"]["repository"] is None: quarter = self.getQuarter(date)
print("\tSkipping:", repoDetails['name'])
return if repoDetails['primaryLanguage'] is not None:
if curr_year not in yearly_data:
for commit in [commit["node"] for branch in commit_data["data"]["repository"]["refs"]["edges"] for commit in branch["node"]["target"]["history"]["edges"]]: yearly_data[curr_year] = {}
date = re.search(r'\d+-\d+-\d+', commit["committedDate"]).group(0) if quarter not in yearly_data[curr_year]:
curr_year = datetime.datetime.fromisoformat(date).year yearly_data[curr_year][quarter] = {}
quarter = self.getQuarter(date) if repoDetails['primaryLanguage']['name'] not in yearly_data[curr_year][quarter]:
yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']] = 0
if repoDetails['primaryLanguage'] is not None: yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']] += (commit["additions"] - commit["deletions"])
if curr_year not in yearly_data:
yearly_data[curr_year] = {}
if quarter not in yearly_data[curr_year]: def pushChart(self):
yearly_data[curr_year][quarter] = {} repo = self.g.get_repo(f"{self.user.login}/{self.user.login}")
if repoDetails['primaryLanguage']['name'] not in yearly_data[curr_year][quarter]: committer = InputGitAuthor('readme-bot', '41898282+github-actions[bot]@users.noreply.github.com')
yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']] = 0 with open('bar_graph.png', 'rb') as input_file:
yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']] += (commit["additions"] - commit["deletions"]) data = input_file.read()
try:
contents = repo.get_contents("charts/bar_graph.png")
def pushChart(self): repo.update_file(contents.path, "Charts Updated", data, contents.sha, committer=committer)
repo = self.g.get_repo(f"{self.user.login}/{self.user.login}") except Exception as e:
committer = InputGitAuthor('readme-bot', '41898282+github-actions[bot]@users.noreply.github.com') repo.create_file("charts/bar_graph.png", "Charts Added", data, committer=committer)
with open('bar_graph.png', 'rb') as input_file:
data = input_file.read()
try:
contents = repo.get_contents("charts/bar_graph.png")
repo.update_file(contents.path, "Charts Updated", data, contents.sha, committer=committer)
except Exception as e:
repo.create_file("charts/bar_graph.png", "Charts Added", data, committer=committer)

View File

@@ -1,462 +1,457 @@
''' '''
Readme Development Metrics With waka time progress Readme Development Metrics With waka time progress
''' '''
import re import re
import os import os
import base64 import base64
from asyncio import run from asyncio import run
from typing import Dict from typing import Dict
from pytz import timezone from pytz import timezone
import pytz import pytz
from github import Github, GithubException, InputGitAuthor, AuthenticatedUser from github import Github, InputGitAuthor, AuthenticatedUser
import datetime import datetime
from string import Template
from download_manager import init_download_manager, DownloadManager
from download_manager import init_download_manager, DownloadManager from loc import LinesOfCode
from loc import LinesOfCode import humanize
import time from urllib.parse import quote
import traceback import json
import humanize import math
from urllib.parse import quote
import json from dotenv import load_dotenv
import sys
from datetime import date load_dotenv()
import math
START_COMMENT = f'<!--START_SECTION:{os.getenv("INPUT_SECTION_NAME")}-->'
from dotenv import load_dotenv END_COMMENT = f'<!--END_SECTION:{os.getenv("INPUT_SECTION_NAME")}-->'
listReg = f"{START_COMMENT}[\\s\\S]+{END_COMMENT}"
load_dotenv()
waka_key = os.getenv('INPUT_WAKATIME_API_KEY')
START_COMMENT = f'<!--START_SECTION:{os.getenv("INPUT_SECTION_NAME")}-->' ghtoken = os.getenv('INPUT_GH_TOKEN')
END_COMMENT = f'<!--END_SECTION:{os.getenv("INPUT_SECTION_NAME")}-->' branchName = os.getenv('INPUT_PUSH_BRANCH_NAME')
listReg = f"{START_COMMENT}[\\s\\S]+{END_COMMENT}" showTimeZone = os.getenv('INPUT_SHOW_TIMEZONE')
showProjects = os.getenv('INPUT_SHOW_PROJECTS')
waka_key = os.getenv('INPUT_WAKATIME_API_KEY') showEditors = os.getenv('INPUT_SHOW_EDITORS')
ghtoken = os.getenv('INPUT_GH_TOKEN') showOs = os.getenv('INPUT_SHOW_OS')
branchName = os.getenv('INPUT_PUSH_BRANCH_NAME') showCommit = os.getenv('INPUT_SHOW_COMMIT')
showTimeZone = os.getenv('INPUT_SHOW_TIMEZONE') showLanguage = os.getenv('INPUT_SHOW_LANGUAGE')
showProjects = os.getenv('INPUT_SHOW_PROJECTS') show_loc = os.getenv('INPUT_SHOW_LINES_OF_CODE')
showEditors = os.getenv('INPUT_SHOW_EDITORS') show_days_of_week = os.getenv('INPUT_SHOW_DAYS_OF_WEEK')
showOs = os.getenv('INPUT_SHOW_OS') showLanguagePerRepo = os.getenv('INPUT_SHOW_LANGUAGE_PER_REPO')
showCommit = os.getenv('INPUT_SHOW_COMMIT') showLocChart = os.getenv('INPUT_SHOW_LOC_CHART')
showLanguage = os.getenv('INPUT_SHOW_LANGUAGE') show_profile_view = os.getenv('INPUT_SHOW_PROFILE_VIEWS')
show_loc = os.getenv('INPUT_SHOW_LINES_OF_CODE') show_short_info = os.getenv('INPUT_SHOW_SHORT_INFO')
show_days_of_week = os.getenv('INPUT_SHOW_DAYS_OF_WEEK') locale = os.getenv('INPUT_LOCALE')
showLanguagePerRepo = os.getenv('INPUT_SHOW_LANGUAGE_PER_REPO') commit_by_me = os.getenv('INPUT_COMMIT_BY_ME')
showLocChart = os.getenv('INPUT_SHOW_LOC_CHART') ignored_repos_name = str(os.getenv('INPUT_IGNORED_REPOS') or '').replace(' ', '').split(',')
show_profile_view = os.getenv('INPUT_SHOW_PROFILE_VIEWS') show_updated_date = os.getenv('INPUT_SHOW_UPDATED_DATE')
show_short_info = os.getenv('INPUT_SHOW_SHORT_INFO') updated_date_format = os.getenv('INPUT_UPDATED_DATE_FORMAT')
locale = os.getenv('INPUT_LOCALE') commit_message = os.getenv('INPUT_COMMIT_MESSAGE')
commit_by_me = os.getenv('INPUT_COMMIT_BY_ME') commit_username = os.getenv('INPUT_COMMIT_USERNAME')
ignored_repos_name = str(os.getenv('INPUT_IGNORED_REPOS') or '').replace(' ', '').split(',') commit_email = os.getenv('INPUT_COMMIT_EMAIL')
show_updated_date = os.getenv('INPUT_SHOW_UPDATED_DATE') show_total_code_time = os.getenv('INPUT_SHOW_TOTAL_CODE_TIME')
updated_date_format = os.getenv('INPUT_UPDATED_DATE_FORMAT') symbol_version = os.getenv('INPUT_SYMBOL_VERSION').strip()
commit_message = os.getenv('INPUT_COMMIT_MESSAGE') show_waka_stats = 'y'
commit_username = os.getenv('INPUT_COMMIT_USERNAME')
commit_email = os.getenv('INPUT_COMMIT_EMAIL') truthy = ['true', '1', 't', 'y', 'yes']
show_total_code_time = os.getenv('INPUT_SHOW_TOTAL_CODE_TIME')
symbol_version = os.getenv('INPUT_SYMBOL_VERSION').strip() translate: Dict[str, str]
show_waka_stats = 'y' user: AuthenticatedUser
truthy = ['true', '1', 't', 'y', 'yes']
def millify(n):
translate: Dict[str, str] millnames = ['', ' Thousand', ' Million', ' Billion', ' Trillion']
user: AuthenticatedUser n = float(n)
millidx = max(0, min(len(millnames) - 1,
int(math.floor(0
def millify(n): if n == 0
millnames = ['', ' Thousand', ' Million', ' Billion', ' Trillion'] else math.log10(abs(n)) / 3))))
n = float(n)
millidx = max(0, min(len(millnames) - 1, return '{:.0f}{}'.format(n / 10 ** (3 * millidx), millnames[millidx])
int(math.floor(0
if n == 0
else math.log10(abs(n)) / 3)))) def make_graph(percent: float):
'''Make progress graph from API graph'''
return '{:.0f}{}'.format(n / 10 ** (3 * millidx), millnames[millidx]) if (symbol_version == '1'): # version 1
done_block = ''
empty_block = ''
def make_graph(percent: float): elif (symbol_version == '2'): # version 2
'''Make progress graph from API graph''' done_block = ''
if (symbol_version == '1'): # version 1 empty_block = ''
done_block = '' elif (symbol_version == '3'): # version 3
empty_block = '' done_block = ''
elif (symbol_version == '2'): # version 2 empty_block = ''
done_block = '' else:
empty_block = '' done_block = '' # default is version 1
elif (symbol_version == '3'): # version 3 empty_block = ''
done_block = ''
empty_block = '' pc_rnd = round(percent)
else: return f"{done_block * int(pc_rnd / 4)}{empty_block * int(25 - int(pc_rnd / 4))}"
done_block = '' # default is version 1
empty_block = ''
def make_list(data: list):
pc_rnd = round(percent) '''Make List'''
return f"{done_block * int(pc_rnd / 4)}{empty_block * int(25 - int(pc_rnd / 4))}" data_list = []
for l in data[:5]:
ln = len(l['name'])
def make_list(data: list): ln_text = len(l['text'])
'''Make List''' percent = "{:05.2f}".format(float(l['percent']))
data_list = [] op = f"{l['name'][:25]}{' ' * (25 - ln)}{l['text']}{' ' * (20 - ln_text)}{make_graph(l['percent'])} {percent} % "
for l in data[:5]: data_list.append(op)
ln = len(l['name']) return '\n'.join(data_list)
ln_text = len(l['text'])
percent = "{:05.2f}".format(float(l['percent']))
op = f"{l['name'][:25]}{' ' * (25 - ln)}{l['text']}{' ' * (20 - ln_text)}{make_graph(l['percent'])} {percent} % " def make_commit_list(data: list):
data_list.append(op) '''Make List'''
return '\n'.join(data_list) data_list = []
for l in data[:7]:
ln = len(l['name'])
def make_commit_list(data: list): ln_text = len(l['text'])
'''Make List''' percent = "{:05.2f}".format(float(l['percent']))
data_list = [] op = f"{l['name']}{' ' * ((15 - ln) + (11 - ln_text))}{l['text']}{' ' * (7)}{make_graph(l['percent'])} {percent} % "
for l in data[:7]: data_list.append(op)
ln = len(l['name']) return '\n'.join(data_list)
ln_text = len(l['text'])
percent = "{:05.2f}".format(float(l['percent']))
op = f"{l['name']}{' ' * ((15 - ln) + (11 - ln_text))}{l['text']}{' ' * (7)}{make_graph(l['percent'])} {percent} % " async def generate_commit_list(tz):
data_list.append(op) string = ''
return '\n'.join(data_list)
result = await DownloadManager.get_remote_graphql("repositories_contributed_to", username=user.login)
nodes = result["data"]["user"]["repositoriesContributedTo"]["nodes"]
async def generate_commit_list(tz): repos = [d for d in nodes if d['isFork'] is False]
string = ''
morning = 0 # 6 - 12
result = await DownloadManager.get_remote_graphql("repositories_contributed_to", username=user.login) daytime = 0 # 12 - 18
nodes = result["data"]["user"]["repositoriesContributedTo"]["nodes"] evening = 0 # 18 - 24
repos = [d for d in nodes if d['isFork'] is False] night = 0 # 0 - 6
morning = 0 # 6 - 12 Monday = 0
daytime = 0 # 12 - 18 Tuesday = 0
evening = 0 # 18 - 24 Wednesday = 0
night = 0 # 0 - 6 Thursday = 0
Friday = 0
Monday = 0 Saturday = 0
Tuesday = 0 Sunday = 0
Wednesday = 0
Thursday = 0 for repository in repos:
Friday = 0 result = await DownloadManager.get_remote_graphql("repository_committed_dates", owner=repository["owner"]["login"], name=repository["name"], id=user.node_id)
Saturday = 0 committed_dates = result["data"]["repository"]["defaultBranchRef"]["target"]["history"]["edges"]
Sunday = 0 for committedDate in committed_dates:
date = datetime.datetime.strptime(committedDate["node"]["committedDate"], "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.utc).astimezone(timezone(tz))
for repository in repos: hour = date.hour
result = await DownloadManager.get_remote_graphql("repository_committed_dates", owner=repository["owner"]["login"], name=repository["name"], id=user.node_id) weekday = date.strftime('%A')
committed_dates = result["data"]["repository"]["defaultBranchRef"]["target"]["history"]["edges"] if 6 <= hour < 12:
for committedDate in committed_dates: morning += 1
date = datetime.datetime.strptime(committedDate["node"]["committedDate"], "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.utc).astimezone(timezone(tz)) if 12 <= hour < 18:
hour = date.hour daytime += 1
weekday = date.strftime('%A') if 18 <= hour < 24:
if 6 <= hour < 12: evening += 1
morning += 1 if 0 <= hour < 6:
if 12 <= hour < 18: night += 1
daytime += 1
if 18 <= hour < 24: if weekday == "Monday":
evening += 1 Monday += 1
if 0 <= hour < 6: if weekday == "Tuesday":
night += 1 Tuesday += 1
if weekday == "Wednesday":
if weekday == "Monday": Wednesday += 1
Monday += 1 if weekday == "Thursday":
if weekday == "Tuesday": Thursday += 1
Tuesday += 1 if weekday == "Friday":
if weekday == "Wednesday": Friday += 1
Wednesday += 1 if weekday == "Saturday":
if weekday == "Thursday": Saturday += 1
Thursday += 1 if weekday == "Sunday":
if weekday == "Friday": Sunday += 1
Friday += 1
if weekday == "Saturday": sumAll = morning + daytime + evening + night
Saturday += 1 sum_week = Sunday + Monday + Tuesday + Friday + Saturday + Wednesday + Thursday
if weekday == "Sunday": title = translate['I am an Early'] if morning + daytime >= evening + night else translate['I am a Night']
Sunday += 1 one_day = [
{"name": "🌞 " + translate['Morning'], "text": str(morning) + " commits",
sumAll = morning + daytime + evening + night "percent": round((morning / sumAll) * 100, 2)},
sum_week = Sunday + Monday + Tuesday + Friday + Saturday + Wednesday + Thursday {"name": "🌆 " + translate['Daytime'], "text": str(daytime) + " commits",
title = translate['I am an Early'] if morning + daytime >= evening + night else translate['I am a Night'] "percent": round((daytime / sumAll) * 100, 2)},
one_day = [ {"name": "🌃 " + translate['Evening'], "text": str(evening) + " commits",
{"name": "🌞 " + translate['Morning'], "text": str(morning) + " commits", "percent": round((evening / sumAll) * 100, 2)},
"percent": round((morning / sumAll) * 100, 2)}, {"name": "🌙 " + translate['Night'], "text": str(night) + " commits",
{"name": "🌆 " + translate['Daytime'], "text": str(daytime) + " commits", "percent": round((night / sumAll) * 100, 2)},
"percent": round((daytime / sumAll) * 100, 2)}, ]
{"name": "🌃 " + translate['Evening'], "text": str(evening) + " commits", dayOfWeek = [
"percent": round((evening / sumAll) * 100, 2)}, {"name": translate['Monday'], "text": str(Monday) + " commits", "percent": round((Monday / sum_week) * 100, 2)},
{"name": "🌙 " + translate['Night'], "text": str(night) + " commits", {"name": translate['Tuesday'], "text": str(Tuesday) + " commits",
"percent": round((night / sumAll) * 100, 2)}, "percent": round((Tuesday / sum_week) * 100, 2)},
] {"name": translate['Wednesday'], "text": str(Wednesday) + " commits",
dayOfWeek = [ "percent": round((Wednesday / sum_week) * 100, 2)},
{"name": translate['Monday'], "text": str(Monday) + " commits", "percent": round((Monday / sum_week) * 100, 2)}, {"name": translate['Thursday'], "text": str(Thursday) + " commits",
{"name": translate['Tuesday'], "text": str(Tuesday) + " commits", "percent": round((Thursday / sum_week) * 100, 2)},
"percent": round((Tuesday / sum_week) * 100, 2)}, {"name": translate['Friday'], "text": str(Friday) + " commits", "percent": round((Friday / sum_week) * 100, 2)},
{"name": translate['Wednesday'], "text": str(Wednesday) + " commits", {"name": translate['Saturday'], "text": str(Saturday) + " commits",
"percent": round((Wednesday / sum_week) * 100, 2)}, "percent": round((Saturday / sum_week) * 100, 2)},
{"name": translate['Thursday'], "text": str(Thursday) + " commits", {"name": translate['Sunday'], "text": str(Sunday) + " commits", "percent": round((Sunday / sum_week) * 100, 2)},
"percent": round((Thursday / sum_week) * 100, 2)}, ]
{"name": translate['Friday'], "text": str(Friday) + " commits", "percent": round((Friday / sum_week) * 100, 2)},
{"name": translate['Saturday'], "text": str(Saturday) + " commits", string = string + '**' + title + '** \n\n' + '```text\n' + make_commit_list(one_day) + '\n\n```\n'
"percent": round((Saturday / sum_week) * 100, 2)},
{"name": translate['Sunday'], "text": str(Sunday) + " commits", "percent": round((Sunday / sum_week) * 100, 2)}, if show_days_of_week.lower() in truthy:
] max_element = {
'percent': 0
string = string + '**' + title + '** \n\n' + '```text\n' + make_commit_list(one_day) + '\n\n```\n' }
if show_days_of_week.lower() in truthy: for day in dayOfWeek:
max_element = { if day['percent'] > max_element['percent']:
'percent': 0 max_element = day
} days_title = translate['I am Most Productive on'] % max_element['name']
string = string + '📅 **' + days_title + '** \n\n' + '```text\n' + make_commit_list(dayOfWeek) + '\n\n```\n'
for day in dayOfWeek:
if day['percent'] > max_element['percent']: return string
max_element = day
days_title = translate['I am Most Productive on'] % max_element['name']
string = string + '📅 **' + days_title + '** \n\n' + '```text\n' + make_commit_list(dayOfWeek) + '\n\n```\n' async def get_waka_time_stats():
stats = ''
return string no_activity = translate["No Activity Tracked This Week"]
data = await DownloadManager.get_remote_json("waka_latest")
async def get_waka_time_stats(): if showCommit.lower() in truthy:
stats = '' stats = stats + await generate_commit_list(data['data']['timezone']) + '\n\n'
no_activity = translate["No Activity Tracked This Week"]
if showTimeZone.lower() in truthy or showLanguage.lower() in truthy or showEditors.lower() in truthy or showProjects.lower() in truthy or showOs.lower() in truthy:
data = await DownloadManager.get_remote_json("waka_latest") stats += '📊 **' + translate['This Week I Spend My Time On'] + '** \n\n'
if showCommit.lower() in truthy: stats += '```text\n'
stats = stats + await generate_commit_list(data['data']['timezone']) + '\n\n'
if showTimeZone.lower() in truthy:
if showTimeZone.lower() in truthy or showLanguage.lower() in truthy or showEditors.lower() in truthy or showProjects.lower() in truthy or showOs.lower() in truthy: tzone = data['data']['timezone']
stats += '📊 **' + translate['This Week I Spend My Time On'] + '** \n\n' stats = stats + '⌚︎ ' + translate['Timezone'] + ': ' + tzone + '\n\n'
stats += '```text\n'
if showLanguage.lower() in truthy:
if showTimeZone.lower() in truthy: if len(data['data']['languages']) == 0:
tzone = data['data']['timezone'] lang_list = no_activity
stats = stats + '⌚︎ ' + translate['Timezone'] + ': ' + tzone + '\n\n' else:
lang_list = make_list(data['data']['languages'])
if showLanguage.lower() in truthy: stats = stats + '💬 ' + translate['Languages'] + ': \n' + lang_list + '\n\n'
if len(data['data']['languages']) == 0:
lang_list = no_activity if showEditors.lower() in truthy:
else: if len(data['data']['editors']) == 0:
lang_list = make_list(data['data']['languages']) edit_list = no_activity
stats = stats + '💬 ' + translate['Languages'] + ': \n' + lang_list + '\n\n' else:
edit_list = make_list(data['data']['editors'])
if showEditors.lower() in truthy: stats = stats + '🔥 ' + translate['Editors'] + ': \n' + edit_list + '\n\n'
if len(data['data']['editors']) == 0:
edit_list = no_activity if showProjects.lower() in truthy:
else: if len(data['data']['projects']) == 0:
edit_list = make_list(data['data']['editors']) project_list = no_activity
stats = stats + '🔥 ' + translate['Editors'] + ': \n' + edit_list + '\n\n' else:
# Re-order the project list by percentage
if showProjects.lower() in truthy: data['data']['projects'] = sorted(data['data']['projects'], key=lambda x: x["percent"],
if len(data['data']['projects']) == 0: reverse=True)
project_list = no_activity project_list = make_list(data['data']['projects'])
else: stats = stats + '🐱‍💻 ' + translate['Projects'] + ': \n' + project_list + '\n\n'
# Re-order the project list by percentage
data['data']['projects'] = sorted(data['data']['projects'], key=lambda x: x["percent"], if showOs.lower() in truthy:
reverse=True) if len(data['data']['operating_systems']) == 0:
project_list = make_list(data['data']['projects']) os_list = no_activity
stats = stats + '🐱‍💻 ' + translate['Projects'] + ': \n' + project_list + '\n\n' else:
os_list = make_list(data['data']['operating_systems'])
if showOs.lower() in truthy: stats = stats + '💻 ' + translate['operating system'] + ': \n' + os_list + '\n\n'
if len(data['data']['operating_systems']) == 0:
os_list = no_activity stats += '```\n\n'
else:
os_list = make_list(data['data']['operating_systems']) return stats
stats = stats + '💻 ' + translate['operating system'] + ': \n' + os_list + '\n\n'
stats += '```\n\n' def generate_language_per_repo(result):
language_count = {}
return stats total = 0
for repo in result['data']['user']['repositories']['edges']:
if repo['node']['primaryLanguage'] is None:
def generate_language_per_repo(result): continue
language_count = {} language = repo['node']['primaryLanguage']['name']
total = 0 total += 1
for repo in result['data']['user']['repositories']['edges']: if language not in language_count.keys():
if repo['node']['primaryLanguage'] is None: language_count[language] = {}
continue language_count[language]['count'] = 1
language = repo['node']['primaryLanguage']['name'] else:
total += 1 language_count[language]['count'] = language_count[language]['count'] + 1
if language not in language_count.keys(): data = []
language_count[language] = {} sorted_labels = list(language_count.keys())
language_count[language]['count'] = 1 sorted_labels.sort(key=lambda x: language_count[x]['count'], reverse=True)
else: most_language_repo = sorted_labels[0]
language_count[language]['count'] = language_count[language]['count'] + 1 for label in sorted_labels:
data = [] percent = round(language_count[label]['count'] / total * 100, 2)
sorted_labels = list(language_count.keys()) extension = " repos"
sorted_labels.sort(key=lambda x: language_count[x]['count'], reverse=True) if language_count[label]['count'] == 1:
most_language_repo = sorted_labels[0] extension = " repo"
for label in sorted_labels: data.append({
percent = round(language_count[label]['count'] / total * 100, 2) "name": label,
extension = " repos" "text": str(language_count[label]['count']) + extension,
if language_count[label]['count'] == 1: "percent": percent
extension = " repo" })
data.append({
"name": label, title = translate['I Mostly Code in'] % most_language_repo
"text": str(language_count[label]['count']) + extension, return '**' + title + '** \n\n' + '```text\n' + make_list(data) + '\n\n```\n'
"percent": percent
})
async def get_yearly_data():
title = translate['I Mostly Code in'] % most_language_repo repository_list = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id)
return '**' + title + '** \n\n' + '```text\n' + make_list(data) + '\n\n```\n' loc = LinesOfCode(user, ghtoken, repository_list, ignored_repos_name)
yearly_data = await loc.calculateLoc()
if showLocChart.lower() in truthy:
async def get_yearly_data(): await loc.plotLoc(yearly_data)
repository_list = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id) return yearly_data
loc = LinesOfCode(user, ghtoken, repository_list, ignored_repos_name)
yearly_data = await loc.calculateLoc()
if showLocChart.lower() in truthy: async def get_line_of_code() -> str:
await loc.plotLoc(yearly_data) repositoryList = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id)
return yearly_data loc = LinesOfCode(user, ghtoken, repositoryList, ignored_repos_name)
yearly_data = await loc.calculateLoc()
total_loc = sum(
async def get_line_of_code() -> str: [yearly_data[year][quarter][lang] for year in yearly_data for quarter in yearly_data[year] for lang in
repositoryList = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id) yearly_data[year][quarter]])
loc = LinesOfCode(user, ghtoken, repositoryList, ignored_repos_name) return millify(int(total_loc))
yearly_data = await loc.calculateLoc()
total_loc = sum(
[yearly_data[year][quarter][lang] for year in yearly_data for quarter in yearly_data[year] for lang in async def get_short_info():
yearly_data[year][quarter]]) string = '**🐱 ' + translate['My GitHub Data'] + '** \n\n'
return millify(int(total_loc)) if user.disk_usage is None:
disk_usage = humanize.naturalsize(0)
print("Please add new github personal access token with user permission")
async def get_short_info(): else:
string = '**🐱 ' + translate['My GitHub Data'] + '** \n\n' disk_usage = humanize.naturalsize(user.disk_usage)
if user.disk_usage is None: data = await DownloadManager.get_remote_json("github_stats")
disk_usage = humanize.naturalsize(0) if len(data['years']) > 0:
print("Please add new github personal access token with user permission") this_year_data = data['years'][0]
else: total = this_year_data['total']
disk_usage = humanize.naturalsize(user.disk_usage) year = this_year_data['year']
data = await DownloadManager.get_remote_json("github_stats") string += '> 🏆 ' + translate['Contributions in the year'] % (humanize.intcomma(total), year) + '\n > \n'
if len(data['years']) > 0:
this_year_data = data['years'][0] string += '> 📦 ' + translate["Used in GitHub's Storage"] % disk_usage + ' \n > \n'
total = this_year_data['total'] is_hireable = user.hireable
year = this_year_data['year'] public_repo = user.public_repos
string += '> 🏆 ' + translate['Contributions in the year'] % (humanize.intcomma(total), year) + '\n > \n' private_repo = user.owned_private_repos
if private_repo is None:
string += '> 📦 ' + translate["Used in GitHub's Storage"] % disk_usage + ' \n > \n' private_repo = 0
is_hireable = user.hireable if is_hireable:
public_repo = user.public_repos string += "> 💼 " + translate["Opted to Hire"] + "\n > \n"
private_repo = user.owned_private_repos else:
if private_repo is None: string += "> 🚫 " + translate["Not Opted to Hire"] + "\n > \n"
private_repo = 0
if is_hireable: string += '> 📜 '
string += "> 💼 " + translate["Opted to Hire"] + "\n > \n" string += translate['public repositories'] % public_repo + " " + '\n > \n' if public_repo != 1 else translate[
else: 'public repository'] % public_repo + " " + '\n > \n'
string += "> 🚫 " + translate["Not Opted to Hire"] + "\n > \n" string += '> 🔑 '
string += translate['private repositories'] % private_repo + " " + ' \n > \n' if private_repo != 1 else translate[
string += '> 📜 ' 'private repository'] % private_repo + " " + '\n > \n'
string += translate['public repositories'] % public_repo + " " + '\n > \n' if public_repo != 1 else translate[
'public repository'] % public_repo + " " + '\n > \n' return string
string += '> 🔑 '
string += translate['private repositories'] % private_repo + " " + ' \n > \n' if private_repo != 1 else translate[
'private repository'] % private_repo + " " + '\n > \n' async def get_stats(github) -> str:
'''Gets API data and returns markdown progress'''
return string
stats = ''
repositoryList = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id)
async def get_stats(github) -> str:
'''Gets API data and returns markdown progress''' if show_loc.lower() in truthy or showLocChart.lower() in truthy:
# This condition is written to calculate the lines of code because it is heavy process soo needs to be calculate once this will reduce the execution time
stats = '' await get_yearly_data()
repositoryList = await DownloadManager.get_remote_graphql("user_repository_list", username=user.login, id=user.node_id)
if show_total_code_time.lower() in truthy:
if show_loc.lower() in truthy or showLocChart.lower() in truthy: data = await DownloadManager.get_remote_json("waka_all")
# This condition is written to calculate the lines of code because it is heavy process soo needs to be calculate once this will reduce the execution time stats += '![Code Time](http://img.shields.io/badge/' + quote(
await get_yearly_data() str("Code Time")) + '-' + quote(str(
data['data']['text'])) + '-blue)\n\n'
if show_total_code_time.lower() in truthy:
data = await DownloadManager.get_remote_json("waka_all") if show_profile_view.lower() in truthy:
stats += '![Code Time](http://img.shields.io/badge/' + quote( data = github.get_repo(f"{user.login}/{user.login}").get_views_traffic(per="week")
str("Code Time")) + '-' + quote(str( stats += '![Profile Views](http://img.shields.io/badge/' + quote(str(translate['Profile Views'])) + '-' + str(
data['data']['text'])) + '-blue)\n\n' data['count']) + '-blue)\n\n'
if show_profile_view.lower() in truthy: if show_loc.lower() in truthy:
data = github.get_repo(f"{user.login}/{user.login}").get_views_traffic(per="week") stats += '![Lines of code](https://img.shields.io/badge/' + quote(
stats += '![Profile Views](http://img.shields.io/badge/' + quote(str(translate['Profile Views'])) + '-' + str( str(translate['From Hello World I have written'])) + '-' + quote(
data['count']) + '-blue)\n\n' str(await get_line_of_code())) + '%20' + quote(str(translate['Lines of code'])) + '-blue)\n\n'
if show_loc.lower() in truthy: if show_short_info.lower() in truthy:
stats += '![Lines of code](https://img.shields.io/badge/' + quote( stats += await get_short_info()
str(translate['From Hello World I have written'])) + '-' + quote(
str(await get_line_of_code())) + '%20' + quote(str(translate['Lines of code'])) + '-blue)\n\n' if show_waka_stats.lower() in truthy:
stats += await get_waka_time_stats()
if show_short_info.lower() in truthy:
stats += await get_short_info() if showLanguagePerRepo.lower() in truthy:
stats = stats + generate_language_per_repo(repositoryList) + '\n\n'
if show_waka_stats.lower() in truthy:
stats += await get_waka_time_stats() if showLocChart.lower() in truthy:
stats += '**' + translate['Timeline'] + '**\n\n'
if showLanguagePerRepo.lower() in truthy: branch_name = github.get_repo(f'{user.login}/{user.login}').default_branch
stats = stats + generate_language_per_repo(repositoryList) + '\n\n' stats = stats + '![Chart not found](https://raw.githubusercontent.com/' + user.login + '/' + user.login + '/' + branch_name + '/charts/bar_graph.png) \n\n'
if showLocChart.lower() in truthy: if show_updated_date.lower() in truthy:
stats += '**' + translate['Timeline'] + '**\n\n' now = datetime.datetime.utcnow()
branch_name = github.get_repo(f'{user.login}/{user.login}').default_branch d1 = now.strftime(updated_date_format)
stats = stats + '![Chart not found](https://raw.githubusercontent.com/' + user.login + '/' + user.login + '/' + branch_name + '/charts/bar_graph.png) \n\n' stats = stats + "\n Last Updated on " + d1 + " UTC"
if show_updated_date.lower() in truthy: return stats
now = datetime.datetime.utcnow()
d1 = now.strftime(updated_date_format)
stats = stats + "\n Last Updated on " + d1 + " UTC" def decode_readme(data: str):
'''Decode the contents of old readme'''
return stats decoded_bytes = base64.b64decode(data)
return str(decoded_bytes, 'utf-8')
def decode_readme(data: str):
'''Decode the contents of old readme''' def generate_new_readme(stats: str, readme: str):
decoded_bytes = base64.b64decode(data) '''Generate a new Readme.md'''
return str(decoded_bytes, 'utf-8') stats_in_readme = f"{START_COMMENT}\n{stats}\n{END_COMMENT}"
return re.sub(listReg, stats_in_readme, readme)
def generate_new_readme(stats: str, readme: str):
'''Generate a new Readme.md''' async def main():
stats_in_readme = f"{START_COMMENT}\n{stats}\n{END_COMMENT}" global translate, user
return re.sub(listReg, stats_in_readme, readme)
if ghtoken is None:
raise Exception('Token not available')
async def main(): user = Github(ghtoken).get_user()
global translate, user print(f"Current user: {user.login}")
await init_download_manager(waka_key, ghtoken, user)
if ghtoken is None:
raise Exception('Token not available') try:
user = Github(ghtoken).get_user() with open(os.path.join(os.path.dirname(__file__), 'translation.json'), encoding='utf-8') as config_file:
print(f"Current user: {user.login}") data = json.load(config_file)
await init_download_manager(waka_key, ghtoken, user) translate = data[locale]
except Exception as e:
try: print("Cannot find the Locale choosing default to english")
with open(os.path.join(os.path.dirname(__file__), 'translation.json'), encoding='utf-8') as config_file: translate = data['en']
data = json.load(config_file)
translate = data[locale] g = Github(ghtoken)
except Exception as e: waka_stats = await get_stats(g)
print("Cannot find the Locale choosing default to english")
translate = data['en'] repo = g.get_repo(f"{user.login}/{user.login}")
contents = repo.get_readme()
g = Github(ghtoken) rdmd = decode_readme(contents.content)
waka_stats = await get_stats(g) new_readme = generate_new_readme(stats=waka_stats, readme=rdmd)
repo = g.get_repo(f"{user.login}/{user.login}") if commit_by_me.lower() in truthy:
contents = repo.get_readme() committer = InputGitAuthor(user.login or commit_username, user.email or commit_email)
rdmd = decode_readme(contents.content) else:
new_readme = generate_new_readme(stats=waka_stats, readme=rdmd) committer = InputGitAuthor(
commit_username or 'readme-bot',
if commit_by_me.lower() in truthy: commit_email or '41898282+github-actions[bot]@users.noreply.github.com'
committer = InputGitAuthor(user.login or commit_username, user.email or commit_email) )
else: if new_readme != rdmd:
committer = InputGitAuthor( try:
commit_username or 'readme-bot', repo.update_file(path=contents.path, message=commit_message,
commit_email or '41898282+github-actions[bot]@users.noreply.github.com' content=new_readme, sha=contents.sha, branch=branchName,
) committer=committer)
if new_readme != rdmd: except:
try: repo.update_file(path=contents.path, message=commit_message,
repo.update_file(path=contents.path, message=commit_message, content=new_readme, sha=contents.sha, branch='main',
content=new_readme, sha=contents.sha, branch=branchName, committer=committer)
committer=committer) print("Readme updated")
except:
repo.update_file(path=contents.path, message=commit_message,
content=new_readme, sha=contents.sha, branch='main', if __name__ == '__main__':
committer=committer) start_time = datetime.datetime.now().timestamp() * 1000
print("Readme updated") run(main())
end_time = datetime.datetime.now().timestamp() * 1000
print(f"Program processed in {round(end_time - start_time, 0)} miliseconds.")
if __name__ == '__main__':
start_time = datetime.datetime.now().timestamp() * 1000
run(main())
end_time = datetime.datetime.now().timestamp() * 1000
print(f"Program processed in {round(end_time - start_time, 0)} miliseconds.")

View File

@@ -1,11 +1,5 @@
import os
from asyncio import run
import pandas as pd import pandas as pd
import numpy as np
import altair as alt import altair as alt
import json
import os
from download_manager import DownloadManager from download_manager import DownloadManager