Merge branch 'pull/17'

# Conflicts:
#	main.py
This commit is contained in:
Anmol
2020-07-28 13:11:38 +05:30
9 changed files with 3363 additions and 26 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.env
*.png
node_modules/
__pycache__/

View File

@@ -1,8 +1,12 @@
FROM python:latest
FROM nikolaik/python-nodejs:latest
# Install dependencies.
ADD requirements.txt /requirements.txt
ADD main.py /main.py
ADD loc.py /loc.py
ADD make_bar_graph.py /make_bar_graph.py
ADD colors.json /colors.json
RUN pip install -r requirements.txt
RUN npm install vega-lite vega-cli canvas
CMD ["python", "/main.py"]

1618
colors.json Normal file

File diff suppressed because it is too large Load Diff

0
geckodriver.log Normal file
View File

120
loc.py Normal file
View File

@@ -0,0 +1,120 @@
import re
import os
import base64
import requests
from github import Github
import datetime
from string import Template
import matplotlib.pyplot as plt
from io import StringIO,BytesIO
from dotenv import load_dotenv
import time
from make_bar_graph import BarGraph
class LinesOfCode:
def __init__(self,id,username,ghtoken, repositoryData):
self.id=id
self.username=username
self.g = Github(ghtoken)
self.headers = {"Authorization": "Bearer " + ghtoken}
self.repositoryData=repositoryData
def calculateLoc(self):
result=self.repositoryData
yearly_data={}
for repo in result['data']['user']['repositories']['edges']:
print(repo)
self.getCommitStat(repo['node'],yearly_data)
time.sleep(0.7)
print("\n\n")
print(yearly_data)
graph=BarGraph(yearly_data)
graph_file=graph.build_graph()
self.pushChart()
def run_query_v3(self,nameWithOwner):
endPoint='https://api.github.com/repos/'+nameWithOwner+'/stats/code_frequency'
# print(endPoint)
request = requests.get(endPoint, headers=self.headers)
if request.status_code == 401:
raise Exception("Invalid token {}. {}".format(request.status_code, nameWithOwner))
return request.json()
def getQuarter(self,timeStamp):
month=datetime.datetime.fromtimestamp(timeStamp).month
if month>=1 and month<=4:
return 1
elif month>=5 and month<=8:
return 2
elif month>=9 and month<=12:
return 3
def getCommitStat(self,repoDetails,yearly_data):
result= self.run_query_v3(repoDetails['nameWithOwner'])
this_year=datetime.datetime.utcnow().year
for i in range(len(result)):
curr_year=datetime.datetime.fromtimestamp(result[i][0]).year
# if curr_year != this_year:
quarter=self.getQuarter(result[i][0])
if repoDetails['primaryLanguage'] is not None:
if curr_year not in yearly_data:
yearly_data[curr_year]={}
if quarter not in yearly_data[curr_year]:
yearly_data[curr_year][quarter]={}
if repoDetails['primaryLanguage']['name'] not in yearly_data[curr_year][quarter]:
yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']]=0
yearly_data[curr_year][quarter][repoDetails['primaryLanguage']['name']]+=(result[i][1]+result[i][2])
#to find total
# if 'total' not in yearly_data[curr_year]:
# yearly_data[curr_year]['total']={}
# if repoDetails['primaryLanguage']['name'] not in yearly_data[curr_year]['total']:
# yearly_data[curr_year]['total'][repoDetails['primaryLanguage']['name']]=0
# yearly_data[curr_year]['total'][repoDetails['primaryLanguage']['name']]+=(result[i][1]+result[i][2])
def pushChart(self):
repo = self.g.get_repo(f"{self.username}/{self.username}")
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 Added", data, contents.sha)
except Exception as e:
repo.create_file("charts/bar_graph.png", "Initial Commit",data)
print("pushed")
# if __name__ == '__main__':
# try:
# g = Github(ghtoken)
# headers = {"Authorization": "Bearer " + ghtoken}
# user_data = run_query(userInfoQuery) # Execute the query
# username = user_data["data"]["viewer"]["login"]
# id = user_data["data"]["viewer"]["id"]
# print("user {} id {}".format(username, id))
# getLoc()
# # repo = g.get_repo(f"{username}/{username}")
# # contents = repo.get_readme()
# # waka_stats = get_stats()
# # rdmd = decode_readme(contents.content)
# # new_readme = generate_new_readme(stats=waka_stats, readme=rdmd)
# # print(new_readme)
# # # if new_readme != rdmd:
# # repo.update_file(path=contents.path, message='Updated with Dev Metrics',
# # content=new_readme, sha=contents.sha, branch='master')
# # print("Readme updated")
# except Exception as e:
# print("Exception Occurred" + str(e))

142
main.py
View File

@@ -8,11 +8,16 @@ import base64
import sys
from pytz import timezone
import pytz
import locale
import requests
from github import Github
from github import Github, GithubException
import datetime
from string import Template
import matplotlib.pyplot as plt
from io import StringIO,BytesIO
from dotenv import load_dotenv
from loc import LinesOfCode
load_dotenv()
START_COMMENT = '<!--START_SECTION:waka-->'
END_COMMENT = '<!--END_SECTION:waka-->'
@@ -28,7 +33,9 @@ showOs = os.getenv('INPUT_SHOW_OS')
showCommit = os.getenv('INPUT_SHOW_COMMIT')
showLanguage = os.getenv('INPUT_SHOW_LANGUAGE')
show_loc = os.getenv('INPUT_SHOW_LINES_OF_CODE')
showLanguagePerRepo= os.getenv('INPUT_LANGUAGE_PER_REPO')
showLocChart='y' if (os.getenv('LOC_CHART') is None) else os.getenv('LOC_CHART')
show_waka_stats='n' if waka_key is None else 'y'
# The GraphQL query to get commit data.
userInfoQuery = """
{
@@ -83,6 +90,47 @@ def run_v3_api(query):
raise Exception(
"Query failed to run by returning code of {}. {},... {}".format(request.status_code, query, request.json()))
repositoryListQuery = Template("""
{
user(login: "$username") {
repositories(orderBy: {field: CREATED_AT, direction: ASC}, last: 100, affiliations: [OWNER, COLLABORATOR, ORGANIZATION_MEMBER], isFork: false) {
totalCount
edges {
node {
object(expression:"master") {
... on Commit {
history (author: { id: "$id" }){
totalCount
}
}
}
primaryLanguage {
color
name
id
}
stargazers {
totalCount
}
collaborators {
totalCount
}
createdAt
name
owner {
id
login
}
nameWithOwner
}
}
}
location
createdAt
name
}
}
""")
def run_query(query):
request = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers)
@@ -230,14 +278,11 @@ def generate_commit_list(tz):
string = string + '**' + title + '** \n\n' + '```text\n' + make_commit_list(one_day) + '\n\n```\n'
string = string + '📅 **' + days_title + '** \n\n' + '```text\n' + make_commit_list(dayOfWeek) + '\n\n```\n'
return string
def get_stats():
'''Gets API data and returns markdown progress'''
def get_waka_time_stats():
stats=''
request = requests.get(f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={waka_key}")
try:
request = requests.get(
f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={waka_key}")
if request.status_code != 401:
data = request.json()
@@ -284,6 +329,63 @@ def get_stats():
return stats
def generate_language_per_repo(result):
language_count = {}
total = 0
for repo in result['data']['user']['repositories']['edges']:
if repo['node']['primaryLanguage'] is None:
continue
language = repo['node']['primaryLanguage']['name']
color_code = repo['node']['primaryLanguage']['color']
total += 1
if language not in language_count.keys():
language_count[language] = {}
language_count[language]['count'] = 1
language_count[language]['color'] = color_code
else:
language_count[language]['count'] = language_count[language]['count'] + 1
language_count[language]['color'] = color_code
data = []
sorted_labels = list(language_count.keys())
sorted_labels.sort(key=lambda x: language_count[x]['count'], reverse=True)
most_language_repo = sorted_labels[0]
for label in sorted_labels:
percent = round(language_count[label]['count'] / total * 100, 2)
data.append({
"name": label,
"text": str(language_count[label]['count']) + " repos",
"percent": percent
})
title = 'I mostly code in ' + most_language_repo
return '**' + title + '** \n\n' + '```text\n' + make_commit_list(data) + '\n\n```\n'
def get_stats():
'''Gets API data and returns markdown progress'''
stats = ''
if showCommit.lower() in ['true', '1', 't', 'y', 'yes']:
stats = stats + generate_commit_list() + '\n\n'
repositoryList = run_query(repositoryListQuery.substitute(username=username, id=id))
if showLanguagePerRepo.lower() in ['true', '1', 't', 'y', 'yes']:
stats = stats + generate_language_per_repo(repositoryList) + '\n\n'
if showLocChart.lower() in ['true', '1', 't', 'y', 'yes']:
loc = LinesOfCode(id, username, ghtoken, repositoryList)
loc.calculateLoc()
stats = stats + '**Timeline**\n\n'
stats = stats + '![Chart not found](https://github.com/prabhatdev/prabhatdev/blob/master/charts/bar_graph.png) \n\n'
# stats = stats + generate_language_per_repo(repositoryList) + '\n\n'
if show_waka_stats.lower() in ['true', '1', 't', 'y', 'yes']:
stats = stats + get_waka_time_stats()
return stats
def decode_readme(data: str):
'''Decode the contets of old readme'''
decoded_bytes = base64.b64decode(data)
@@ -297,17 +399,25 @@ def generate_new_readme(stats: str, readme: str):
if __name__ == '__main__':
g = Github(ghtoken)
try:
repo = g.get_repo(f"{user}/{user}")
except GithubException:
print("Authentication Error. Try saving a GitHub Personal Access Token in your Repo Secrets")
sys.exit(1)
contents = repo.get_readme()
if ghtoken is None:
raise Exception('Token not available')
g = Github(ghtoken)
headers = {"Authorization": "Bearer " + ghtoken}
user_data = run_query(userInfoQuery) # Execute the query
username = user_data["data"]["viewer"]["login"]
id = user_data["data"]["viewer"]["id"]
print("user {} id {}".format(username, id))
repo = g.get_repo(f"{username}/{username}")
contents = repo.get_readme()
waka_stats = get_stats()
rdmd = decode_readme(contents.content)
new_readme = generate_new_readme(stats=waka_stats, readme=rdmd)
print(new_readme)
if new_readme != rdmd:
repo.update_file(path=contents.path, message='Updated with Dev Metrics',
content=new_readme, sha=contents.sha, branch='master')
print("Readme updated")
except Exception as e:
print("Exception Occurred" + str(e))

107
make_bar_graph.py Normal file
View File

@@ -0,0 +1,107 @@
import pandas as pd
import numpy as np
import altair as alt
import json
# npm install vega-lite vega-cli canvas
class BarGraph:
def __init__(self, yearly_data):
self.yearly_data=yearly_data
def build_graph(self):
with open('colors.json') as f:
colors = json.load(f)
allColorsValues=[]
#filter data
max_languages=5
top_languages={}
for year in self.yearly_data.keys():
for quarter in self.yearly_data[year].keys():
for language in sorted(list(self.yearly_data[year][quarter].keys()), key=lambda lang:self.yearly_data[year][quarter][lang], reverse=True)[0:max_languages]:
if 'top' not in self.yearly_data[year][quarter]:
self.yearly_data[year][quarter]['top']={}
if self.yearly_data[year][quarter][language]!=0:
self.yearly_data[year][quarter]['top'][language]=self.yearly_data[year][quarter][language]
if language not in top_languages:
top_languages[language] =1
top_languages[language]+=1
# print(self.yearly_data)
all_languages=list(top_languages.keys())
for language in all_languages:
if colors[language]['color'] is not None:
allColorsValues.append(colors[language]['color'])
languages_all_loc={}
for language in all_languages:
language_year=[]
for year in self.yearly_data.keys():
language_quarter=[0,0,0]
for quarter in self.yearly_data[year].keys():
if language in self.yearly_data[year][quarter]['top']:
language_quarter[quarter-1]=self.yearly_data[year][quarter]['top'][language]
else:
language_quarter[quarter-1]=0
language_year.append(language_quarter)
languages_all_loc[language]=language_year
print(languages_all_loc)
language_df={}
def prep_df(df, name):
df = df.stack().reset_index()
df.columns = ['c1', 'c2', 'values']
df['Language'] = name
return df
for language in languages_all_loc.keys():
language_df[language]=pd.DataFrame(languages_all_loc[language],index=list(self.yearly_data.keys()),columns=["Q1","Q2","Q3"])
for language in language_df.keys():
language_df[language]=prep_df(language_df[language], language)
df=pd.concat(list(language_df.values()))
# print(df)
chart=alt.Chart(df).mark_bar().encode(
# tell Altair which field to group columns on
x=alt.X('c2:N', title=None),
# tell Altair which field to use as Y values and how to calculate
y=alt.Y('sum(values):Q',
axis=alt.Axis(
grid=False,
title='LOC added')),
# tell Altair which field to use to use as the set of columns to be represented in each group
column=alt.Column('c1:N', title=None),
# tell Altair which field to use for color segmentation
color=alt.Color('Language:N',
scale=alt.Scale(
domain=all_languages,
# make it look pretty with an enjoyable color pallet
range=allColorsValues,
),
))\
.configure_view(
# remove grid lines around column clusters
strokeOpacity=0
)
chart.save('bar_graph.png')
return 'bar_graph.png'

1344
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,39 @@
altair==4.1.0
altair-data-server==0.4.1
altair-saver==0.5.0
altair-viewer==0.3.0
attrs==19.3.0
certifi==2020.6.20
chardet==3.0.4
cycler==0.10.0
Deprecated==1.2.10
entrypoints==0.3
gitdb==4.0.5
GitPython==3.1.7
idna==2.10
Jinja2==2.11.2
jsonschema==3.2.0
kiwisolver==1.2.0
lizard==1.17.4
MarkupSafe==1.1.1
matplotlib==3.3.0
numpy==1.19.1
pandas==1.0.5
Pillow==7.2.0
portpicker==1.3.1
PyDriller==1.15.2
PyGithub==1.51
PyJWT==1.7.1
pyparsing==2.4.7
pyrsistent==0.16.0
python-dateutil==2.8.1
python-dotenv==0.14.0
pytz==2020.1
requests==2.24.0
selenium==3.141.0
six==1.15.0
smmap==3.0.4
toolz==0.10.0
tornado==6.0.4
urllib3==1.25.9
wrapt==1.12.1
pytz==2020.1