Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
c1b28d7f43 | |||
512d27739c | |||
ad3a3b38e6 | |||
1d9eeae447 | |||
c0345cb5d9 | |||
632b13121d | |||
e9ab3581aa | |||
8b0ab3bd76 | |||
7a6d95d436 | |||
fd26197e70 | |||
99b6b3f887 | |||
c2f0b9de48 | |||
95c7f84451 | |||
d1558ad6db | |||
76d3c7249a | |||
450ba61d22 | |||
3d3239a2e3 | |||
830c76c07a | |||
6125862010 | |||
b88da2af7d | |||
b55e75a74d | |||
3bc9d82ee4 | |||
980f869999 | |||
108a90abce | |||
|
5dc349128a | ||
|
d2e7ba7208 | ||
|
2dd14d3fd8 | ||
|
e644272268 |
4
.github/workflows/testing.yml
vendored
4
.github/workflows/testing.yml
vendored
@@ -2,9 +2,9 @@ name: WakaReadme CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -163,8 +163,9 @@ cython_debug/
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# asdf
|
||||
# asdf/rtx
|
||||
.tool-versions
|
||||
.rtx.toml
|
||||
|
||||
# ruff
|
||||
.ruff_cache
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Contributing
|
||||
|
||||

|
||||

|
||||
|
||||
> First off, thank you! Please follow along.
|
||||
|
||||
@@ -47,17 +47,18 @@ $ podman-compose -p waka-readme -f ./docker-compose.yml down
|
||||
|
||||
1. Inside the cloned folder run the following commands to install dependencies
|
||||
|
||||
```console
|
||||
```sh
|
||||
$ python -m venv .venv
|
||||
$ . ./.venv/bin/activate
|
||||
$ python -m pip install .
|
||||
# ... install decencies ...
|
||||
```
|
||||
|
||||
to activate virtual environment & install dependencies.
|
||||
|
||||
2. To test or execute the program in development, run:
|
||||
|
||||
```console
|
||||
```sh
|
||||
(.venv)$ python -m unittest discover # run tests
|
||||
(.venv)$ python -m main --dev # execute program in dev mode
|
||||
```
|
||||
|
59
README.md
59
README.md
@@ -1,27 +1,10 @@
|
||||
<p align="center">
|
||||
<img
|
||||
src="https://socialify.git.ci/athul/waka-readme/image?description=1&font=Source%20Code%20Pro&forks=1&issues=1&name=1&owner=1&pulls=1&stargazers=1&theme=Auto"
|
||||
alt="waka-readme"
|
||||
width="640"
|
||||
height="320"
|
||||
/>
|
||||
</p>
|
||||
# Dev Metrics in Readme
|
||||
|
||||
# Dev Metrics in Readme [](https://github.com/athul/waka-readme/actions/workflows/testing.yml)
|
||||
fork from [waka-readme](https://github/athul/waka-readme)
|
||||
edit for Gitea use.
|
||||
|
||||
[WakaTime](https://wakatime.com) coding metrics on your profile readme.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<picture>
|
||||
<source srcset="https://github.com/athul/waka-readme/assets/38415384/60a6bcd0-01f8-421a-8730-7e872d216e09"
|
||||
media="(prefers-color-scheme: dark)" />
|
||||
<img src="https://github.com/athul/waka-readme/assets/38415384/29541cbc-0e39-47c4-93c2-514032b47276"
|
||||
alt="new_secrets_actions" />
|
||||
</picture>
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
:speech_balloon: **Forum** | [GitHub discussions][gh_discuss]
|
||||
|
||||
## New to WakaTime?
|
||||
|
||||
> Nope? Skip to [#Prep work](#prep-work).
|
||||
@@ -39,7 +22,7 @@ Alternatively, you can fetch data from WakaTime compatible services such as [Wak
|
||||
|
||||
## Prep Work
|
||||
|
||||
A GitHub repository and a `README.md` file is required. We'll be making use of readme in the [profile repository][profile_readme].
|
||||
A Gitea repository and a `README.md` file is required. We'll be making use of readme in the [profile repository][profile_readme].
|
||||
|
||||
- Save the `README.md` file after copy-pasting the following special comments. Your dev-metics will show up in between.
|
||||
|
||||
@@ -51,31 +34,9 @@ A GitHub repository and a `README.md` file is required. We'll be making use of r
|
||||
`<!--START_SECTION: -->` and `<!--END_SECTION: -->` are placeholders and must be retained as is. Whereas "`waka`" can be replaced by any alphanumeric string. See [#Tweaks](#tweaks) section for more.
|
||||
|
||||
- Navigate to your repo's `Settings`:
|
||||
- Go to `Secrets` (at `https://github.com/USERNAME/USERNAME/settings/secrets/actions/new` by replacing the `USERNAME` with your own username) and add a new secret "_Named_" `WAKATIME_API_KEY` with your API key as it's "_Secret_".
|
||||
- Go to `Secrets` (at `https://your_gitea_url/username/.profile/settings/actions/secrets` by replacing the `USERNAME` with your own username) and add a new secret "_Named_" `WAKATIME_API_KEY` with your API key as it's "_Secret_".
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<picture>
|
||||
<source srcset="https://github.com/athul/waka-readme/assets/38415384/04dee9dc-65a1-43f9-9df4-7545646b9a72"
|
||||
media="(prefers-color-scheme: dark)" />
|
||||
<img src="https://github.com/athul/waka-readme/assets/38415384/9110cc3e-66cc-46ed-89d4-36644aa258e1"
|
||||
alt="new_secrets_actions" />
|
||||
</picture>
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
> If you're not using [profile repository][profile_readme], add another secret "_Named_" `GH_TOKEN` and in place of "_Secret_" insert your [GitHub token][gh_access_token].
|
||||
|
||||
- Go to `Workflow permissions` under `Actions` (at `https://github.com/USERNAME/USERNAME/settings/actions` by replacing the `USERNAME` with your own username) and set `Read and write permissions`.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<picture>
|
||||
<source srcset="https://github.com/athul/waka-readme/assets/38415384/a1b86a0b-4065-4ff1-847b-b52e681bf247"
|
||||
media="(prefers-color-scheme: dark)" />
|
||||
<img src="https://github.com/athul/waka-readme/assets/38415384/de9cb7d0-fd40-43cf-8fed-7c6f57207788"
|
||||
alt="new_secrets_actions" />
|
||||
</picture>
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
- Create a new workflow file named `waka-readme.yml` inside `.github/workflows/` folder of your repository.
|
||||
- Create a new workflow file named `waka-readme.yml` inside `.gitea/workflows/` folder of your profile repository.
|
||||
- Clear all existing contents, add following lines and save the file.
|
||||
|
||||
```yml
|
||||
@@ -93,7 +54,7 @@ A GitHub repository and a `README.md` file is required. We'll be making use of r
|
||||
name: WakaReadme DevMetrics
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: athul/waka-readme@master # this action name
|
||||
- uses: https://git.mamahaha.work/sangge/waka-readme@master # this action name
|
||||
with:
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
```
|
||||
@@ -161,13 +122,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# this action name
|
||||
- uses: athul/waka-readme@master # do NOT replace with anything else
|
||||
- uses: https://git.mamahaha.work/sangge/waka-readme@master # do NOT replace with anything else
|
||||
with:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }} # optional if on profile readme
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} # required
|
||||
### meta
|
||||
API_BASE_URL: https://wakatime.com/api # optional
|
||||
REPOSITORY: YOUR_GITHUB_USERNAME/YOUR_REPOSITORY_NAME # optional
|
||||
REPOSITORY: YOUR_GITEA_USERNAME/YOUR_REPOSITORY_NAME # optional
|
||||
### content
|
||||
SHOW_TITLE: true # optional
|
||||
SECTION_NAME: waka # optional
|
||||
@@ -228,5 +189,3 @@ I am a fan of minimal designs and the profile readme is a great way to show off
|
||||
[waka_plugins]: https://wakatime.com/plugins
|
||||
[waka_help]: https://wakatime.com/help/editors
|
||||
[profile_readme]: https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme
|
||||
[gh_access_token]: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
|
||||
[gh_discuss]: https://github.com/athul/waka-readme/discussions
|
||||
|
@@ -3,7 +3,7 @@ author: "Athul Cyriac Ajay"
|
||||
description: "WakaTime coding activity graph in your profile readme"
|
||||
|
||||
inputs:
|
||||
GH_TOKEN:
|
||||
GITEA_TOKEN:
|
||||
description: "GitHub access token with Repo scope"
|
||||
default: ${{ github.token }}
|
||||
required: true
|
||||
|
@@ -1,6 +1,6 @@
|
||||
FROM docker.io/python:3-slim
|
||||
|
||||
ENV INPUT_GH_TOKEN \
|
||||
ENV INPUT_GITEA_TOKEN \
|
||||
INPUT_WAKATIME_API_KEY \
|
||||
# meta
|
||||
INPUT_API_BASE_URL \
|
||||
@@ -39,10 +39,10 @@ ENV PATH="${PATH}:/root/.local/bin" \
|
||||
PIP_DEFAULT_TIMEOUT=100
|
||||
|
||||
# copy project files
|
||||
COPY --chown=root:root pyproject.toml main.py /app/
|
||||
COPY --chown=root:root pyproject.toml main.py /app/
|
||||
|
||||
# install dependencies
|
||||
RUN python -m pip install /app/
|
||||
RUN python -m pip install /app/ -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# copy tests
|
||||
COPY --chown=root:root tests /app/tests/
|
||||
|
@@ -42,7 +42,7 @@ ENV PATH="${PATH}:/root/.local/bin" \
|
||||
COPY --chown=root:root pyproject.toml main.py /app/
|
||||
|
||||
# install dependencies
|
||||
RUN python -m pip install /app/
|
||||
RUN python -m pip install /app/ -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
|
||||
# execute program
|
||||
CMD python /app/main.py
|
||||
|
130
main.py
130
main.py
@@ -28,7 +28,7 @@ Contents := Title + Byline + Body
|
||||
"""
|
||||
|
||||
# standard
|
||||
from base64 import b64encode
|
||||
from base64 import b64encode, b64decode
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from functools import partial
|
||||
@@ -42,13 +42,14 @@ from typing import Any
|
||||
|
||||
# external
|
||||
from faker import Faker
|
||||
from github import ContentFile, Github, GithubException, InputGitAuthor, Repository
|
||||
|
||||
# from github import ContentFile, Github, GithubException, InputGitAuthor, Repository
|
||||
import gitea
|
||||
from requests import get as rq_get
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
################### setup ###################
|
||||
|
||||
|
||||
print()
|
||||
# hush existing loggers
|
||||
for lgr_name in logger.root.manager.loggerDict:
|
||||
@@ -70,8 +71,12 @@ try:
|
||||
# comment this out to disable colored logging
|
||||
from loguru import logger
|
||||
|
||||
logger.debug("loguru loaded")
|
||||
|
||||
# load from .env before class def gets parsed
|
||||
load_dotenv()
|
||||
logger.debug("dotenv loaded")
|
||||
waka_key: str | None = os.getenv("INPUT_WAKATIME_API_KEY")
|
||||
except ImportError as im_err:
|
||||
logger.warning(im_err)
|
||||
|
||||
@@ -127,10 +132,11 @@ class WakaInput:
|
||||
|
||||
# mapped environment variables
|
||||
# # required
|
||||
gh_token: str | None = os.getenv("INPUT_GH_TOKEN")
|
||||
gitea_token: str | None = os.getenv("INPUT_GITEA_TOKEN")
|
||||
gitea_url: str | None = os.getenv("GITHUB_SERVER_URL", "https://gitea.com")
|
||||
waka_key: str | None = os.getenv("INPUT_WAKATIME_API_KEY")
|
||||
api_base_url: str | None = os.getenv("INPUT_API_BASE_URL", "https://wakatime.com/api")
|
||||
repository: str | None = os.getenv("INPUT_REPOSITORY")
|
||||
repository: str | None = os.getenv("INPUT_REPOSITORY", ".profile")
|
||||
# # depends
|
||||
commit_message: str = os.getenv(
|
||||
"INPUT_COMMIT_MESSAGE", "Updated WakaReadme graph with new metrics"
|
||||
@@ -161,7 +167,12 @@ class WakaInput:
|
||||
def validate_input(self):
|
||||
"""Validate Input Env Variables."""
|
||||
logger.debug("Validating input variables")
|
||||
if not self.gh_token or not self.waka_key or not self.api_base_url or not self.repository:
|
||||
if (
|
||||
not self.gitea_token
|
||||
or not self.waka_key
|
||||
or not self.api_base_url
|
||||
or not self.repository
|
||||
):
|
||||
logger.error("Invalid inputs")
|
||||
logger.info("Refer https://github.com/athul/waka-readme")
|
||||
return False
|
||||
@@ -407,54 +418,63 @@ def churn(old_readme: str, /):
|
||||
repl=f"{wk_i.start_comment}\n\n```{wk_i.code_lang}\n{generated_content}\n```\n\n{wk_i.end_comment}",
|
||||
string=old_readme,
|
||||
)
|
||||
logger.debug(new_readme)
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "--dev":
|
||||
logger.debug("Detected run in `dev` mode.")
|
||||
# to avoid accidentally writing back to Github
|
||||
# when developing or testing waka-readme
|
||||
return None
|
||||
|
||||
return None if new_readme == old_readme else new_readme
|
||||
|
||||
|
||||
def qualify_target(gh_repo: Repository.Repository):
|
||||
# def qualify_target(gitea_repo: Repository.Repository):
|
||||
def qualify_target(gitea_repo: gitea.Repository, gitea_connect: gitea.Gitea):
|
||||
"""Qualify target repository defaults."""
|
||||
|
||||
@dataclass
|
||||
class TargetRepository:
|
||||
this: ContentFile.ContentFile
|
||||
# this: ContentFile.ContentFile
|
||||
this: gitea.Content
|
||||
path: str
|
||||
commit_message: str
|
||||
sha: str
|
||||
branch: str
|
||||
committer: InputGitAuthor | None
|
||||
author: InputGitAuthor | None
|
||||
# committer: InputGitAuthor | None
|
||||
# author: InputGitAuthor | None
|
||||
committer: None
|
||||
author: None
|
||||
|
||||
gh_branch = gh_repo.default_branch
|
||||
if wk_i.target_branch != "NOT_SET":
|
||||
gh_branch = gh_repo.get_branch(wk_i.target_branch)
|
||||
gitea_branch = gitea_repo.get_branches()[0].name
|
||||
# if wk_i.target_branch != "NOT_SET":
|
||||
# gitea_branch = gitea_repo.get_branch(wk_i.target_branch)
|
||||
|
||||
target = gh_repo.get_readme()
|
||||
if wk_i.target_path != "NOT_SET":
|
||||
target = gh_repo.get_contents(
|
||||
path=wk_i.target_path,
|
||||
ref=gh_branch if isinstance(gh_branch, str) else gh_branch.commit.sha,
|
||||
)
|
||||
readme_content = gitea.Content(gitea_connect)
|
||||
readme_content.path = "README.md"
|
||||
readme_content.type = gitea.Content.FILE
|
||||
target = gitea_repo.get_file_content(readme_content) # base64 encoded
|
||||
# target = gitea_repo.get_readme()
|
||||
|
||||
# if wk_i.target_path != "NOT_SET":
|
||||
# target = gitea_repo.get_contents(
|
||||
# path=wk_i.target_path,
|
||||
# ref=gitea_branch if isinstance(gitea_branch, str) else gitea_branch.commit.sha,
|
||||
# )
|
||||
if isinstance(target, list):
|
||||
raise RuntimeError("Cannot handle multiple files.")
|
||||
|
||||
committer, author = None, None
|
||||
if wk_i.committer_name != "NOT_SET" and wk_i.committer_email != "NOT_SET":
|
||||
committer = InputGitAuthor(name=wk_i.committer_name, email=wk_i.committer_email)
|
||||
if wk_i.author_name != "NOT_SET" and wk_i.author_email != "NOT_SET":
|
||||
author = InputGitAuthor(name=wk_i.author_name, email=wk_i.author_email)
|
||||
# if wk_i.committer_name != "NOT_SET" and wk_i.committer_email != "NOT_SET":
|
||||
# committer = InputGitAuthor(name=wk_i.committer_name, email=wk_i.committer_email)
|
||||
# if wk_i.author_name != "NOT_SET" and wk_i.author_email != "NOT_SET":
|
||||
# author = InputGitAuthor(name=wk_i.author_name, email=wk_i.author_email)
|
||||
sha = ""
|
||||
|
||||
return TargetRepository(
|
||||
this=target,
|
||||
path=target.path,
|
||||
path="README.md",
|
||||
commit_message=wk_i.commit_message,
|
||||
sha=target.sha,
|
||||
branch=gh_branch if isinstance(gh_branch, str) else gh_branch.name,
|
||||
sha=sha,
|
||||
branch=gitea_branch if isinstance(gitea_branch, str) else gitea_branch.name,
|
||||
committer=committer,
|
||||
author=author,
|
||||
)
|
||||
@@ -462,34 +482,48 @@ def qualify_target(gh_repo: Repository.Repository):
|
||||
|
||||
def genesis():
|
||||
"""Run Program."""
|
||||
logger.debug("Connecting to GitHub")
|
||||
gh_connect = Github(wk_i.gh_token)
|
||||
logger.debug("Connecting to Gitea")
|
||||
gitea_connect = gitea.Gitea(wk_i.gitea_url, wk_i.gitea_token)
|
||||
logger.debug("logged into gitea\n")
|
||||
|
||||
# since a validator is being used earlier, casting
|
||||
# `wk_i.ENV_VARIABLE` to a string here, is okay
|
||||
gh_repo = gh_connect.get_repo(str(wk_i.repository))
|
||||
target = qualify_target(gh_repo)
|
||||
# gitea_repo = gitea_connect.get_repo(str(wk_i.repository))
|
||||
|
||||
owner = "sangge"
|
||||
repo_name = ".profile"
|
||||
gitea_repo = gitea.Repository.request(gitea_connect, owner, repo_name)
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "--dev":
|
||||
logger.debug("Detected run in `dev` mode.,fetched repo \n")
|
||||
target = qualify_target(gitea_repo, gitea_connect)
|
||||
logger.debug("Decoding readme contents\n")
|
||||
|
||||
readme_contents = str(target.this.decoded_content, encoding="utf-8")
|
||||
readme_contents = str(b64decode(target.this), encoding="utf-8")
|
||||
if not (new_content := churn(readme_contents)):
|
||||
logger.info("WakaReadme was not updated")
|
||||
return
|
||||
|
||||
logger.debug("WakaReadme stats has changed")
|
||||
update_metric = partial(
|
||||
gh_repo.update_file,
|
||||
path=target.path,
|
||||
message=target.commit_message,
|
||||
content=new_content,
|
||||
sha=target.sha,
|
||||
branch=target.branch,
|
||||
)
|
||||
if target.committer:
|
||||
update_metric = partial(update_metric, committer=target.committer)
|
||||
if target.author:
|
||||
update_metric = partial(update_metric, author=target.author)
|
||||
update_metric()
|
||||
# update_metric = partial(
|
||||
# gitea_repo.update_file,
|
||||
# path=target.path,
|
||||
# message=target.commit_message,
|
||||
# content=new_content,
|
||||
# sha=target.sha,
|
||||
# branch=target.branch,
|
||||
# )
|
||||
# if target.committer:
|
||||
# update_metric = partial(update_metric, committer=target.committer)
|
||||
# if target.author:
|
||||
# update_metric = partial(update_metric, author=target.author)
|
||||
# update_metric()
|
||||
b64_new_content = b64encode(bytes(new_content, "utf-8"))
|
||||
repo_content = gitea_repo.get_git_content()
|
||||
readmes = [c for c in repo_content if c.name == "README.md"]
|
||||
str_new_content = b64_new_content.decode("utf-8")
|
||||
gitea_repo.change_file(readmes[0].name, readmes[0].sha, str_new_content)
|
||||
logger.info("Stats updated successfully")
|
||||
return
|
||||
|
||||
|
||||
################### driver ###################
|
||||
@@ -518,7 +552,7 @@ if __name__ == "__main__":
|
||||
except RuntimeError as err:
|
||||
logger.error(f"{type(err).__name__}: {err}\n")
|
||||
sys.exit(1)
|
||||
except (GithubException, RequestException) as rq_exp:
|
||||
logger.critical(f"{rq_exp}\n")
|
||||
sys.exit(1)
|
||||
# except (GithubException, RequestException) as rq_exp:
|
||||
# logger.critical(f"{rq_exp}\n")
|
||||
# sys.exit(1)
|
||||
print("\nThanks for using WakaReadme!\n")
|
||||
|
@@ -15,8 +15,8 @@ classifiers = [
|
||||
"Programming Language :: Python",
|
||||
"Typing :: Typed",
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
dependencies = ["faker>=19.11.0", "pygithub>=2.1.1", "requests>=2.31.0"]
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["faker>=21.0.0", "pygithub>=2.1.1", "requests>=2.31.0", "py-gitea>=0.2.6"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/athul/waka-readme"
|
||||
@@ -36,7 +36,7 @@ extra = ["loguru>=0.7.2", "python-dotenv>=1.0.0"]
|
||||
#############################
|
||||
|
||||
[tool.pdm.dev-dependencies]
|
||||
tooling = ["bandit>=1.7.5", "black>=23.10.0", "ruff>=0.1.1", "pyright>=1.1.332"]
|
||||
tooling = ["bandit>=1.7.6", "black>=23.12.1", "ruff>=0.1.9", "pyright>=1.1.342"]
|
||||
|
||||
####################
|
||||
# Configurations #
|
||||
@@ -47,11 +47,11 @@ exclude_dirs = [".github", "tests", ".venv", ".vscode"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
target-version = ["py311"]
|
||||
target-version = ["py312"]
|
||||
|
||||
[tool.pyright]
|
||||
exclude = ["**/__pycache__", ".venv/"]
|
||||
pythonVersion = "3.11"
|
||||
pythonVersion = "3.12"
|
||||
pythonPlatform = "All"
|
||||
typeCheckingMode = "strict"
|
||||
|
||||
@@ -72,7 +72,7 @@ select = [
|
||||
"D",
|
||||
]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
target-version = "py312"
|
||||
extend-exclude = ["**/__pycache__"]
|
||||
|
||||
[tool.ruff.isort]
|
||||
|
Reference in New Issue
Block a user