Merge pull request #116 from joe733/workshop
fix: adds lang count option properly
This commit is contained in:
commit
413150be53
14
README.md
14
README.md
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
# Dev Metrics in Readme [](https://github.com/athul/waka-readme/actions/workflows/testing.yml)
|
# Dev Metrics in Readme [](https://github.com/athul/waka-readme/actions/workflows/testing.yml) 
|
||||||
|
|
||||||
<center>
|
|
||||||
|
|
||||||
[WakaTime](https://wakatime.com) weekly metrics on your profile readme.
|
[WakaTime](https://wakatime.com) weekly metrics on your profile readme.
|
||||||
|
|
||||||
@ -14,8 +12,6 @@
|
|||||||
|
|
||||||
:speech_balloon: **Forum** | [GitHub discussions][gh_discuss]
|
:speech_balloon: **Forum** | [GitHub discussions][gh_discuss]
|
||||||
|
|
||||||
</center>
|
|
||||||
|
|
||||||
## New to WakaTime?
|
## New to WakaTime?
|
||||||
|
|
||||||
> Nope? Skip to [prep work](#prep-work).
|
> Nope? Skip to [prep work](#prep-work).
|
||||||
@ -32,15 +28,17 @@ Alternatively, you can also fetch data from WakaTime compatible services like [W
|
|||||||
|
|
||||||
## Prep Work
|
## Prep Work
|
||||||
|
|
||||||
A GitHub repository and a README file is required. We'll be making use of readme in the [profile repository][profile_readme]\*.
|
A GitHub repository and a `README.md` file is required. We'll be making use of readme in the [profile repository][profile_readme]\*.
|
||||||
|
|
||||||
- Save the README file after copy-pasting the following special comments. Your dev-metics will show up in between. `waka` here can be replaced by any string as long as you set the `SECTION_NAME` environment variable [as per the Tweaks section](tweaks).
|
- Save the `README.md` file after copy-pasting the following special comments. Your dev-metics will show up in between.
|
||||||
|
|
||||||
```md
|
```md
|
||||||
<!--START_SECTION:waka-->
|
<!--START_SECTION:waka-->
|
||||||
<!--END_SECTION:waka-->
|
<!--END_SECTION:waka-->
|
||||||
```
|
```
|
||||||
|
|
||||||
|
"`waka`" can be replaced by any alphanumeric string with the `SECTION_NAME` environment variable. See the [#tweaks](#tweaks) section for more.
|
||||||
|
|
||||||
- Navigate to your repo's `Settings > Secrets` and add a new secret _named_ `WAKATIME_API_KEY` with your API key as it's _value_.
|
- Navigate to your repo's `Settings > Secrets` and add a new secret _named_ `WAKATIME_API_KEY` with your API key as it's _value_.
|
||||||
|
|
||||||
> Or use the url <https://github.com/USERNAME/USERNAME/settings/secrets/actions/new> by replacing the `USERNAME` with your own username.
|
> Or use the url <https://github.com/USERNAME/USERNAME/settings/secrets/actions/new> by replacing the `USERNAME` with your own username.
|
||||||
@ -90,6 +88,7 @@ There are many flags that you can tweak to suit your taste!
|
|||||||
| `SHOW_TIME` | `true` | `false`, `true` | Displays the amount of time spent for each language |
|
| `SHOW_TIME` | `true` | `false`, `true` | Displays the amount of time spent for each language |
|
||||||
| `SHOW_TOTAL` | `false` | `false`, `true` | Show total coding time |
|
| `SHOW_TOTAL` | `false` | `false`, `true` | Show total coding time |
|
||||||
| `SHOW_MASKED_TIME` | `false` | `false`, `true` | Adds total coding time including unclassified languages (overrides: `SHOW_TOTAL`) |
|
| `SHOW_MASKED_TIME` | `false` | `false`, `true` | Adds total coding time including unclassified languages (overrides: `SHOW_TOTAL`) |
|
||||||
|
| `LANG_COUNT` | `5` | Any reasonable number | Number of languages to be displayed |
|
||||||
|
|
||||||
# Example
|
# Example
|
||||||
|
|
||||||
@ -117,6 +116,7 @@ jobs:
|
|||||||
TIME_RANGE: all_time
|
TIME_RANGE: all_time
|
||||||
SHOW_TIME: true
|
SHOW_TIME: true
|
||||||
SHOW_MASKED_TIME: true
|
SHOW_MASKED_TIME: true
|
||||||
|
LANG_COUNT: 10
|
||||||
```
|
```
|
||||||
|
|
||||||
**`README.md`**
|
**`README.md`**
|
||||||
|
@ -49,6 +49,11 @@ inputs:
|
|||||||
default: "last_7_days"
|
default: "last_7_days"
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
LANG_COUNT:
|
||||||
|
description: "Maximum number of languages to be shown"
|
||||||
|
default: "5"
|
||||||
|
required: false
|
||||||
|
|
||||||
SHOW_TIME:
|
SHOW_TIME:
|
||||||
description: "Displays the amount of time spent for each language"
|
description: "Displays the amount of time spent for each language"
|
||||||
default: "true"
|
default: "true"
|
||||||
|
51
main.py
51
main.py
@ -154,7 +154,7 @@ class WakaInput:
|
|||||||
show_time: str | bool = os.getenv('INPUT_SHOW_TIME') or False
|
show_time: str | bool = os.getenv('INPUT_SHOW_TIME') or False
|
||||||
show_total_time: str | bool = os.getenv('INPUT_SHOW_TOTAL') or False
|
show_total_time: str | bool = os.getenv('INPUT_SHOW_TOTAL') or False
|
||||||
show_masked_time: str | bool = os.getenv('INPUT_SHOW_MASKED_TIME') or False
|
show_masked_time: str | bool = os.getenv('INPUT_SHOW_MASKED_TIME') or False
|
||||||
language_count: str | bool = os.getenv('INPUT_LANGUAGE_COUNT') or "5"
|
language_count: str | int = os.getenv('INPUT_LANG_COUNT') or 5
|
||||||
|
|
||||||
def validate_input(self) -> bool:
|
def validate_input(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -178,7 +178,7 @@ class WakaInput:
|
|||||||
self.show_time = strtobool(self.show_time)
|
self.show_time = strtobool(self.show_time)
|
||||||
self.show_total_time = strtobool(self.show_total_time)
|
self.show_total_time = strtobool(self.show_total_time)
|
||||||
self.show_masked_time = strtobool(self.show_masked_time)
|
self.show_masked_time = strtobool(self.show_masked_time)
|
||||||
except ValueError as err:
|
except (ValueError, AttributeError) as err:
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -202,6 +202,11 @@ class WakaInput:
|
|||||||
logger.debug('Using default time range: last_7_days')
|
logger.debug('Using default time range: last_7_days')
|
||||||
self.time_range = 'last_7_days'
|
self.time_range = 'last_7_days'
|
||||||
|
|
||||||
|
if not str(self.language_count).isnumeric():
|
||||||
|
logger.warning('Invalid language count')
|
||||||
|
logger.debug('Using default language count: 5')
|
||||||
|
self.language_count = 5
|
||||||
|
|
||||||
logger.debug('Input validation complete\n')
|
logger.debug('Input validation complete\n')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -249,11 +254,11 @@ def make_graph(block_style: str, percent: float, gr_len: int, lg_nm: str = '', /
|
|||||||
graph_bar += block_style[remainder_block] if remainder_block > 0 else ''
|
graph_bar += block_style[remainder_block] if remainder_block > 0 else ''
|
||||||
graph_bar += block_style[0] * (gr_len - len(graph_bar))
|
graph_bar += block_style[0] * (gr_len - len(graph_bar))
|
||||||
|
|
||||||
logger.debug(f'{lg_nm or "..."} graph generated')
|
logger.debug(f'"{lg_nm or "..."}" graph generated')
|
||||||
return graph_bar
|
return graph_bar
|
||||||
|
|
||||||
|
|
||||||
def prep_content(stats: dict[Any, Any], language_count: str = 5, /) -> str:
|
def prep_content(stats: dict[str, Any], language_count: int = 5, /) -> str:
|
||||||
"""
|
"""
|
||||||
WakaReadme Prepare Markdown
|
WakaReadme Prepare Markdown
|
||||||
---------------------------
|
---------------------------
|
||||||
@ -261,14 +266,9 @@ def prep_content(stats: dict[Any, Any], language_count: str = 5, /) -> str:
|
|||||||
Prepared markdown content from the fetched statistics
|
Prepared markdown content from the fetched statistics
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
logger.debug('Making contents')
|
||||||
contents = ''
|
contents = ''
|
||||||
|
|
||||||
# Check if any data exists
|
|
||||||
if not (lang_info := stats.get('languages')):
|
|
||||||
logger.debug('The data seems to be empty, please wait for a day')
|
|
||||||
contents += 'No activity tracked'
|
|
||||||
return contents
|
|
||||||
|
|
||||||
# make title
|
# make title
|
||||||
if wk_i.show_title:
|
if wk_i.show_title:
|
||||||
contents += make_title(stats.get('start'), stats.get('end')) + '\n\n'
|
contents += make_title(stats.get('start'), stats.get('end')) + '\n\n'
|
||||||
@ -284,19 +284,26 @@ def prep_content(stats: dict[Any, Any], language_count: str = 5, /) -> str:
|
|||||||
):
|
):
|
||||||
contents += f'Total Time: {total_time}\n\n'
|
contents += f'Total Time: {total_time}\n\n'
|
||||||
|
|
||||||
# make content
|
lang_info: list[dict[str, int | float | str]] | None = []
|
||||||
logger.debug('Making contents')
|
|
||||||
|
# Check if any language data exists
|
||||||
|
if not (lang_info := stats.get('languages')):
|
||||||
|
logger.debug('The API data seems to be empty, please wait for a day')
|
||||||
|
contents += 'No activity tracked'
|
||||||
|
return contents
|
||||||
|
|
||||||
|
# make lang content
|
||||||
pad_len = len(
|
pad_len = len(
|
||||||
# comment if it feels way computationally expensive
|
# comment if it feels way computationally expensive
|
||||||
max((l.get('name') for l in lang_info), key=len)
|
max((str(lng['name']) for lng in lang_info), key=len)
|
||||||
# and then don't for get to set pad_len to say 13 :)
|
# and then don't for get to set pad_len to say 13 :)
|
||||||
)
|
)
|
||||||
for idx, lang in enumerate(lang_info):
|
for idx, lang in enumerate(lang_info):
|
||||||
lang_name = lang.get('name')
|
lang_name = str(lang['name'])
|
||||||
# >>> add languages to filter here <<<
|
# >>> add languages to filter here <<<
|
||||||
# if lang_name in {...}: continue
|
# if lang_name in {...}: continue
|
||||||
lang_time = lang.get('text') if wk_i.show_time else ''
|
lang_time = str(lang['text']) if wk_i.show_time else ''
|
||||||
lang_ratio = lang.get('percent')
|
lang_ratio = float(lang['percent'])
|
||||||
lang_bar = make_graph(
|
lang_bar = make_graph(
|
||||||
wk_i.block_style, lang_ratio, wk_i.graph_length, lang_name
|
wk_i.block_style, lang_ratio, wk_i.graph_length, lang_name
|
||||||
)
|
)
|
||||||
@ -305,14 +312,14 @@ def prep_content(stats: dict[Any, Any], language_count: str = 5, /) -> str:
|
|||||||
f'{lang_time: <16}{lang_bar} ' +
|
f'{lang_time: <16}{lang_bar} ' +
|
||||||
f'{lang_ratio:.2f}'.zfill(5) + ' %\n'
|
f'{lang_ratio:.2f}'.zfill(5) + ' %\n'
|
||||||
)
|
)
|
||||||
if idx >= int(language_count) or lang_name == 'Other':
|
if idx >= language_count or lang_name == 'Other':
|
||||||
break
|
break
|
||||||
|
|
||||||
logger.debug('Contents were made\n')
|
logger.debug('Contents were made\n')
|
||||||
return contents.rstrip('\n')
|
return contents.rstrip('\n')
|
||||||
|
|
||||||
|
|
||||||
def fetch_stats() -> dict[Any, Any] | None:
|
def fetch_stats() -> dict[str, Any] | None:
|
||||||
"""
|
"""
|
||||||
WakaReadme Fetch Stats
|
WakaReadme Fetch Stats
|
||||||
----------------------
|
----------------------
|
||||||
@ -320,7 +327,7 @@ def fetch_stats() -> dict[Any, Any] | None:
|
|||||||
Returns statistics as JSON string
|
Returns statistics as JSON string
|
||||||
"""
|
"""
|
||||||
attempts = 4
|
attempts = 4
|
||||||
statistic: dict[str, dict[Any, Any]] = {}
|
statistic: dict[str, dict[str, Any]] = {}
|
||||||
encoded_key = str(
|
encoded_key = str(
|
||||||
b64encode(bytes(str(wk_i.waka_key), 'utf-8')), 'utf-8'
|
b64encode(bytes(str(wk_i.waka_key), 'utf-8')), 'utf-8'
|
||||||
)
|
)
|
||||||
@ -341,7 +348,7 @@ def fetch_stats() -> dict[Any, Any] | None:
|
|||||||
timeout=30 * (5 - attempts)
|
timeout=30 * (5 - attempts)
|
||||||
)).status_code != 200:
|
)).status_code != 200:
|
||||||
resp_message += f' • {conn_info}' if (
|
resp_message += f' • {conn_info}' if (
|
||||||
conn_info := resp.json().get("message")
|
conn_info := resp.json().get('message')
|
||||||
) else ''
|
) else ''
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'API response #{5 - attempts}: {resp.status_code} • {resp.reason}{resp_message}'
|
f'API response #{5 - attempts}: {resp.status_code} • {resp.reason}{resp_message}'
|
||||||
@ -374,8 +381,8 @@ def churn(old_readme: str, /) -> str | None:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# processing content
|
# processing content
|
||||||
try:
|
try:
|
||||||
generated_content = prep_content(waka_stats, wk_i.language_count)
|
generated_content = prep_content(waka_stats, int(wk_i.language_count))
|
||||||
except AttributeError as err:
|
except (AttributeError, KeyError, ValueError) as err:
|
||||||
logger.error(f'Unable to read API data | {err}\n')
|
logger.error(f'Unable to read API data | {err}\n')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(generated_content, '\n', sep='')
|
print(generated_content, '\n', sep='')
|
||||||
|
1011
poetry.lock
generated
1011
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "waka-readme"
|
name = "waka-readme"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
description = "Wakatime Weekly Metrics on your Profile Readme."
|
description = "Wakatime Weekly Metrics on your Profile Readme"
|
||||||
authors = ["Athul Cyriac Ajay <athul8720@gmail.com>"]
|
authors = ["Athul Cyriac Ajay <athul8720@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@ -9,14 +9,14 @@ readme = "README.md"
|
|||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.11"
|
python = "^3.11"
|
||||||
requests = "^2.28.1"
|
faker = "^16.6.1"
|
||||||
PyGithub = "^1.57"
|
requests = "^2.28.2"
|
||||||
Faker = "^15.3.3"
|
pygithub = "^1.57"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
autopep8 = "^2.0.0"
|
autopep8 = "^2.0.1"
|
||||||
pylint = "^2.15.7"
|
pylint = "^2.16.1"
|
||||||
python-dotenv = "^0.21.0"
|
python-dotenv = "^0.21.1"
|
||||||
loguru = "^0.6.0"
|
loguru = "^0.6.0"
|
||||||
bandit = "^1.7.4"
|
bandit = "^1.7.4"
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
'''
|
"""
|
||||||
Tests for the main.py
|
Tests for the main.py
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
# standard
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass # , field
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
# from pathlib import Path
|
||||||
# from inspect import cleandoc
|
# from inspect import cleandoc
|
||||||
# from json import loads
|
# from typing import Any
|
||||||
|
# from json import load
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@ -24,7 +27,9 @@ except ImportError as err:
|
|||||||
class TestData:
|
class TestData:
|
||||||
"""Test Data"""
|
"""Test Data"""
|
||||||
# for future tests
|
# for future tests
|
||||||
# waka_json: dict | None = None
|
# waka_json: dict[str, dict[str, Any]] = field(
|
||||||
|
# default_factory=lambda: {}
|
||||||
|
# )
|
||||||
bar_percent: tuple[int | float, ...] | None = None
|
bar_percent: tuple[int | float, ...] | None = None
|
||||||
graph_blocks: tuple[str, ...] | None = None
|
graph_blocks: tuple[str, ...] | None = None
|
||||||
waka_graphs: tuple[list[str], ...] | None = None
|
waka_graphs: tuple[list[str], ...] | None = None
|
||||||
@ -33,8 +38,12 @@ class TestData:
|
|||||||
def populate(self) -> None:
|
def populate(self) -> None:
|
||||||
"""Populate Test Data"""
|
"""Populate Test Data"""
|
||||||
# for future tests
|
# for future tests
|
||||||
# with open(file='tests/sample_data.json', mode='rt', encoding='utf-8') as wkf:
|
# with open(
|
||||||
# self.waka_json = loads(wkf.read())
|
# file=Path(__file__).parent / 'sample_data.json',
|
||||||
|
# encoding='utf-8',
|
||||||
|
# mode='rt',
|
||||||
|
# ) as wkf:
|
||||||
|
# self.waka_json = load(wkf)
|
||||||
|
|
||||||
self.bar_percent = (
|
self.bar_percent = (
|
||||||
0, 100, 49.999, 50, 25, 75, 3.14, 9.901, 87.334, 87.333, 4.666, 4.667
|
0, 100, 49.999, 50, 25, 75, 3.14, 9.901, 87.334, 87.333, 4.666, 4.667
|
||||||
@ -116,11 +125,14 @@ class TestMain(unittest.TestCase):
|
|||||||
r'From: \d{2} \w{3,9} \d{4} - To: \d{2} \w{3,9} \d{4}'
|
r'From: \d{2} \w{3,9} \d{4} - To: \d{2} \w{3,9} \d{4}'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Known test limits
|
def test_strtobool(self) -> None:
|
||||||
# # prep_content() and churn():
|
"""Test string to bool"""
|
||||||
# requires additional modifications such as changing
|
self.assertTrue(prime.strtobool('Yes'))
|
||||||
# globally passed values to parametrically passing them
|
self.assertFalse(prime.strtobool('nO'))
|
||||||
# # fetch_stats(): would required HTTP Authentication
|
self.assertTrue(prime.strtobool(True))
|
||||||
|
self.assertRaises(AttributeError, prime.strtobool, None)
|
||||||
|
self.assertRaises(ValueError, prime.strtobool, 'yo!')
|
||||||
|
self.assertRaises(AttributeError, prime.strtobool, 20.5)
|
||||||
|
|
||||||
|
|
||||||
tds = TestData()
|
tds = TestData()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user