Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
aaff45b1d4 | ||
|
b37bede506 | ||
|
215367a2ad | ||
|
d827cb172d | ||
|
73c1050f48 | ||
|
d0c740a1a1 | ||
|
6f4f9c9933 | ||
|
442c0dae4d | ||
|
fa74a6bca2 | ||
|
55aaf85a2f | ||
|
59c5854cd1 | ||
|
21e5b9c804 | ||
|
67a3568c75 | ||
|
580f6d4639 | ||
|
fd7a6214c1 | ||
|
c487876563 | ||
|
744bf5ae56 | ||
|
0edb69508c | ||
|
5f04a7c728 | ||
|
610c67b096 | ||
|
15c5dbcc49 | ||
|
96f680b05f | ||
|
49b64c7be8 | ||
|
0cf0773d1c | ||
|
d0c5208665 | ||
|
b1a69733c8 | ||
|
02b84ff4ca |
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
ko_fi: athulcyriac
|
||||
custom: https://www.buymeacoffee.com/JeVlc7T
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#generated when running the tests
|
||||
__pycache__/
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
language: python
|
||||
python:
|
||||
- "3.7"
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
script:
|
||||
- python -m unittest discover
|
100
README.md
100
README.md
@@ -1,4 +1,4 @@
|
||||
# Dev Metrics in Readme
|
||||
# Dev Metrics in Readme [](https://travis-ci.com/athul/waka-readme)
|
||||
|
||||

|
||||
|
||||
@@ -48,28 +48,43 @@ WakaTime gives you an idea of the time you really spent on coding. This helps yo
|
||||
|
||||
> You wouldn't need an GitHub Access Token since GitHub Actions already makes one for you.
|
||||
|
||||
Here is a sample workflow file for you to get started:
|
||||
Please follow the steps below:
|
||||
|
||||
```yml
|
||||
name: Waka Readme
|
||||
1. Go to your `<username>/<username>/actions`, hit `New workflow`, `set up a workflow yourself`, delete all the default content github made for you.
|
||||
2. Copy the following code and paste it to your new workflow you created at step 1:
|
||||
```yml
|
||||
name: Waka Readme
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Runs at 12am UTC
|
||||
- cron: '0 0 * * *'
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Runs at 12am UTC
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
update-readme:
|
||||
name: Update this repo's README
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: athul/waka-readme@master
|
||||
with:
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
```
|
||||
jobs:
|
||||
update-readme:
|
||||
name: Update this repo's README
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: athul/waka-readme@master
|
||||
with:
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
```
|
||||
3. Go to your repo secrets by hitting `Settings => Secrets` tab in your profile repo. You can also enter the url https://github.com/USERNAME/USERNAME/settings/secrets . Please replace the `USERNAME` with your own username.
|
||||
4. Create a new `Secret`. `Name`: `WAKATIME_API_KEY`, `Value`: Paste the Wakatime API key here. If you don't know what is the key, please go to [Account Settings in WakaTime](https://wakatime.com/settings/account) to find your API Key there.
|
||||
5. Add a comment to your `README.md` like this:
|
||||
|
||||
```md
|
||||
<!--START_SECTION:waka-->
|
||||
<!--END_SECTION:waka-->
|
||||
```
|
||||
6. Go to Workflows menu (mentioned in step 1), click `Waka Readme`, click `Run workflow`.
|
||||
7. Go to your profile page. you will be able to see it.
|
||||
|
||||
### Other Repository (not Profile)
|
||||
|
||||
|
||||
|
||||
*If you're executing the workflow on another repo other than `<username>/<username>`*
|
||||
|
||||
You'll need to get a [GitHub Access Token](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token) with a `repo` scope and save it in the Repo Secrets `GH_TOKEN = <Your GitHub Access Token>`
|
||||
@@ -95,3 +110,54 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
USERNAME: <username> # optional, it will automatically use the username of the owner of the repository who's executing the workflow.
|
||||
```
|
||||
|
||||
## Tests
|
||||
### Running Tests
|
||||
To run tests simply execute the following in the directory containing main.py:
|
||||
```python
|
||||
python -m unittest discover
|
||||
```
|
||||
### Contributing Tests
|
||||
These tests uses the python Unit testing framework, [unittest](https://docs.python.org/3/library/unittest.html)
|
||||
|
||||
Since this project is contained all within one file, 'main.py'. You can simply add a function to the TestMain class in tests/test_main.py, similar to the test_graph function.
|
||||
|
||||
## Extras
|
||||
|
||||
1. If you want to add the week in the Header of your stats, you can add `HEAD_FLAG: true` in your workflow file like this
|
||||
|
||||
```yml
|
||||
- uses: athul/waka-readme@master
|
||||
with:
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
USERNAME: <username>
|
||||
SHOW_TITLE: true
|
||||
```
|
||||
|
||||
`SHOW_TITLE` flag can be set to true if you want to display the week number and days in the readme, by default it will be false. Here is an example output with `SHOW_TITLE` set to true.
|
||||
|
||||
```text
|
||||
Week: 10 July, 2020 - 17 July, 2020
|
||||
Python 8 hrs 52 mins ███████████████████░░░░░░ 75.87 %
|
||||
Go 1 hr 15 mins ██░░░░░░░░░░░░░░░░░░░░░░░ 10.79 %
|
||||
Markdown 52 mins █░░░░░░░░░░░░░░░░░░░░░░░░ 07.43 %
|
||||
Docker 16 mins ░░░░░░░░░░░░░░░░░░░░░░░░░ 02.32 %
|
||||
YAML 7 mins ░░░░░░░░░░░░░░░░░░░░░░░░░ 01.07 %
|
||||
```
|
||||
|
||||
2. You can specify a commit message to overrdie the default _"Updated the Graph with new Metrics"_. Here is how you do it
|
||||
|
||||
```yml
|
||||
- uses: athul/waka-readme@master
|
||||
with:
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
USERNAME: <username>
|
||||
COMMIT_MESSAGE: Updated the Readme
|
||||
```
|
||||
|
||||
If no commit message is specified in the `yml` file, it defaults to _"Updated the Graph with new Metrics"_
|
||||
|
||||
## Why only the language stats and not other data from the API?
|
||||
I am a fan of minimal designs and the profile readme is a great way to show off your skills and interests. The WakaTime API, gets us a **lot of data** about a person's **coding activity including the editors and Operating Systems you used and the projects you worked on**. Some of these projects maybe secretive and should not be shown out to the public. Using up more data via the Wakatime API will clutter the profile readme and hinder your chances on displaying what you provide **value to the community** like the pinned Repositories. I believe that **Coding Stats is nerdiest of all** since you can tell the community that you are *__exercising these languages or learning a new language__*, this will also show that you spend some amount of time to learn and exercise your development skills. That's what matters in the end :heart:
|
||||
|
11
action.yml
11
action.yml
@@ -15,6 +15,17 @@ inputs:
|
||||
USERNAME:
|
||||
description: 'Your GitHub username'
|
||||
default: ${{ github.repository_owner }}
|
||||
required: false
|
||||
|
||||
SHOW_TITLE:
|
||||
description: "Displays the week number and days in Readme as title"
|
||||
default: false
|
||||
required: false
|
||||
|
||||
COMMIT_MESSAGE:
|
||||
description: "Add a commit message of your choice"
|
||||
default: "Updated the Graph with new Metrics"
|
||||
required: false
|
||||
|
||||
|
||||
runs:
|
||||
|
84
main.py
84
main.py
@@ -5,10 +5,10 @@ WakaTime progress visualizer
|
||||
import re
|
||||
import os
|
||||
import base64
|
||||
import sys
|
||||
import datetime
|
||||
import requests
|
||||
from github import Github
|
||||
|
||||
from github import Github, GithubException
|
||||
|
||||
START_COMMENT = '<!--START_SECTION:waka-->'
|
||||
END_COMMENT = '<!--END_SECTION:waka-->'
|
||||
@@ -17,45 +17,69 @@ listReg = f"{START_COMMENT}[\\s\\S]+{END_COMMENT}"
|
||||
user = os.getenv('INPUT_USERNAME')
|
||||
waka_key = os.getenv('INPUT_WAKATIME_API_KEY')
|
||||
ghtoken = os.getenv('INPUT_GH_TOKEN')
|
||||
show_title = os.getenv("INPUT_SHOW_TITLE")
|
||||
commit_message = os.getenv("INPUT_COMMIT_MESSAGE")
|
||||
|
||||
def this_week():
|
||||
'''Returns current week span'''
|
||||
week_number = datetime.date.today().isocalendar()[1]
|
||||
month = datetime.date.today().strftime('%B')
|
||||
week_start = datetime.datetime.today().day - datetime.datetime.today().weekday()
|
||||
week_end = week_start + 5
|
||||
return f"Week #{week_number} : {month} {week_start} - {week_end}"
|
||||
|
||||
def make_graph(percent: float):
|
||||
def this_week() -> str:
|
||||
'''Returns a week streak'''
|
||||
week_end = datetime.datetime.today() - datetime.timedelta(days=1)
|
||||
week_start = week_end - datetime.timedelta(days=7)
|
||||
print("Week header created")
|
||||
return f"Week: {week_start.strftime('%d %B, %Y')} - {week_end.strftime('%d %B, %Y')}"
|
||||
|
||||
|
||||
def make_graph(percent: float) -> str:
|
||||
'''Make progress graph from API graph'''
|
||||
done_block = '█'
|
||||
empty_block = '░'
|
||||
pc_rnd = round(percent)
|
||||
return f"{done_block*int(pc_rnd/4)}{empty_block*int(25-int(pc_rnd/4))}"
|
||||
blocks = "░▒▓█"
|
||||
graph = blocks[3] * int(percent / 4 + 1 / 6)
|
||||
remainder_block = int((percent + 2 / 3) % 4 * 3 / 4)
|
||||
if remainder_block > 0:
|
||||
graph += blocks[remainder_block]
|
||||
graph += blocks[0] * (25 - len(graph))
|
||||
return graph
|
||||
|
||||
|
||||
def get_stats():
|
||||
def get_stats() -> str:
|
||||
'''Gets API data and returns markdown progress'''
|
||||
data = requests.get(
|
||||
f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={waka_key}").json()
|
||||
lang_data = data['data']['languages']
|
||||
try:
|
||||
lang_data = data['data']['languages']
|
||||
except KeyError:
|
||||
print("Please Add your WakaTime API Key to the Repository Secrets")
|
||||
sys.exit(1)
|
||||
|
||||
data_list = []
|
||||
for l in lang_data[:5]:
|
||||
ln = len(l['name'])
|
||||
ln_text = len(l['text'])
|
||||
op = f"{l['name']}{' '*(12-ln)}{l['text']}{' '*(20-ln_text)}{make_graph(l['percent'])} {l['percent']}%"
|
||||
data_list.append(op)
|
||||
data = ' \n'.join(data_list)
|
||||
return '```text\n'+this_week()+'\n\n'+data+'\n```'
|
||||
try:
|
||||
pad = len(max([l['name'] for l in lang_data[:5]], key=len))
|
||||
except ValueError:
|
||||
print("The Data seems to be empty. Please wait for a day for the data to be filled in.")
|
||||
return '```text\nNo Activity tracked this Week\n```'
|
||||
for lang in lang_data[:5]:
|
||||
lth = len(lang['name'])
|
||||
ln_text = len(lang['text'])
|
||||
# following line provides a neat finish
|
||||
fmt_percent = format(lang['percent'], '0.2f').zfill(5)
|
||||
data_list.append(
|
||||
f"{lang['name']}{' '*(pad + 3 - lth)}{lang['text']}{' '*(16 - ln_text)}{make_graph(lang['percent'])} {fmt_percent} % ")
|
||||
print("Graph Generated")
|
||||
data = '\n'.join(data_list)
|
||||
if show_title == 'true':
|
||||
print("Stats with Weeks in Title Generated")
|
||||
return '```text\n'+this_week()+'\n\n'+data+'\n```'
|
||||
else:
|
||||
print("Usual Stats Generated")
|
||||
return '```text\n'+data+'\n```'
|
||||
|
||||
|
||||
def decode_readme(data: str):
|
||||
'''Decode the contets of old readme'''
|
||||
def decode_readme(data: str) -> str:
|
||||
'''Decode the contents of old readme'''
|
||||
decoded_bytes = base64.b64decode(data)
|
||||
return str(decoded_bytes, 'utf-8')
|
||||
|
||||
|
||||
def generate_new_readme(stats: str, readme: str):
|
||||
def generate_new_readme(stats: str, readme: str) -> str:
|
||||
'''Generate a new Readme.md'''
|
||||
stats_in_readme = f"{START_COMMENT}\n{stats}\n{END_COMMENT}"
|
||||
return re.sub(listReg, stats_in_readme, readme)
|
||||
@@ -63,11 +87,15 @@ def generate_new_readme(stats: str, readme: str):
|
||||
|
||||
if __name__ == '__main__':
|
||||
g = Github(ghtoken)
|
||||
repo = g.get_repo(f"{user}/{user}")
|
||||
try:
|
||||
repo = g.get_repo(f"{user}/{user}")
|
||||
except GithubException:
|
||||
print("Authentication Error. Try saving a GitHub Token in your Repo Secrets or Use the GitHub Actions Token, which is automatically used by the action.")
|
||||
sys.exit(1)
|
||||
contents = repo.get_readme()
|
||||
waka_stats = get_stats()
|
||||
rdmd = decode_readme(contents.content)
|
||||
new_readme = generate_new_readme(stats=waka_stats, readme=rdmd)
|
||||
if new_readme != rdmd:
|
||||
repo.update_file(path=contents.path, message='Updated with Dev Metrics',
|
||||
repo.update_file(path=contents.path, message=commit_message,
|
||||
content=new_readme, sha=contents.sha, branch='master')
|
||||
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
29
tests/test_main.py
Normal file
29
tests/test_main.py
Normal file
@@ -0,0 +1,29 @@
|
||||
'''
|
||||
Tests for the main.py
|
||||
'''
|
||||
from main import make_graph
|
||||
import unittest
|
||||
|
||||
|
||||
class TestMain(unittest.TestCase):
|
||||
|
||||
def test_make_graph(self):
|
||||
'''Tests the make_graph function'''
|
||||
def test(percent: float, result: str):
|
||||
self.assertEqual(make_graph(percent), result, f"{percent}% should return {result}")
|
||||
test(0, "░░░░░░░░░░░░░░░░░░░░░░░░░")
|
||||
test(100, "█████████████████████████")
|
||||
test(50, "████████████▒░░░░░░░░░░░░")
|
||||
test(50.001, "████████████▓░░░░░░░░░░░░")
|
||||
test(25, "██████▒░░░░░░░░░░░░░░░░░░")
|
||||
test(75, "██████████████████▓░░░░░░")
|
||||
test(3.14, "▓░░░░░░░░░░░░░░░░░░░░░░░░")
|
||||
test(9.901, "██▒░░░░░░░░░░░░░░░░░░░░░░")
|
||||
test(87.334, "██████████████████████░░░")
|
||||
test(87.333, "█████████████████████▓░░░")
|
||||
test(4.666, "█░░░░░░░░░░░░░░░░░░░░░░░░")
|
||||
test(4.667, "█▒░░░░░░░░░░░░░░░░░░░░░░░")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Reference in New Issue
Block a user