From 94e4a6cbde9526cde18d6ca85871e271f8e10403 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sat, 25 Feb 2023 01:52:33 +0530 Subject: [PATCH 01/38] feat: added ability to generate stats on PR and sent to latest comment on PR --- .github/workflows/review_pr.yml | 54 +++++++++++++++++++++++++++++++++ sources/main.py | 13 ++++++-- sources/manager_download.py | 20 ++++++++++++ sources/manager_environment.py | 1 + 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/review_pr.yml diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml new file mode 100644 index 0000000..d67df3a --- /dev/null +++ b/.github/workflows/review_pr.yml @@ -0,0 +1,54 @@ +name: REVIEW_PULL_REQUEST + +on: + pull_request: + types: [ opened, edited, reopened, synchronize ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/dev' }} + +jobs: + publish-server-image: + name: Run Test and Review PR + runs-on: ubuntu-latest + + steps: + - name: Checkout ๐Ÿ›Ž๏ธ + uses: actions/checkout@v3 + + - name: Setup Python 3.8 ๐Ÿ + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Install Dependencies ๐Ÿ“ฅ + run: pip install -r requirements.txt + + - name: Run Current Tests ๐Ÿงช + env: + INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} + INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} + PR_NUMBER: ${{ github.event.number }} + INPUT_SHOW_TIMEZONE: true + INPUT_SHOW_PROJECTS: True + INPUT_SHOW_EDITORS: True + INPUT_SHOW_OS: True + INPUT_SHOW_LANGUAGE: True + INPUT_SYMBOL_VERSION: 1 + INPUT_SHOW_LINES_OF_CODE: True + INPUT_SHOW_LOC_CHART: True + INPUT_SHOW_PROFILE_VIEWS: True + INPUT_SHOW_TOTAL_CODE_TIME: True + INPUT_SHOW_SHORT_INFO: True + INPUT_SHOW_COMMIT: True + INPUT_SHOW_DAYS_OF_WEEK: True + INPUT_SHOW_LANGUAGE_PER_REPO: True + INPUT_SHOW_UPDATED_DATE: True + INPUT_COMMIT_BY_ME: True + INPUT_DEBUG_LOGGING: True + DEBUG_RUN: True + run: python3 sources/main.py + + + diff --git a/sources/main.py b/sources/main.py index 9b474d8..8d980b9 100644 --- a/sources/main.py +++ b/sources/main.py @@ -185,8 +185,17 @@ async def main(): init_localization_manager() DBM.i("Managers initialized.") - if GHM.update_readme(await get_stats()): - DBM.g("Readme updated!") + stats = await get_stats() + if not EM.DEBUG_RUN: + if GHM.update_readme(stats): + DBM.g("Readme updated!") + else: + DBM.i("Commenting PR...") + pr_data = await DM.get_remote_graphql("get_pr_id", pr_number=EM.PR_NUMBER) + pr_id = pr_data["data"]["repository"]["pullRequest"]["id"] + await DM.get_remote_graphql("add_pr_comment", pr_id=pr_id, comment=stats) + DBM.g("PR commented!") + DBM.g("Debug run, readme not updated. check the latest comment for the generated stats.") await DM.close_remote_resources() diff --git a/sources/manager_download.py b/sources/manager_download.py index 0505644..a98c06a 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -121,6 +121,26 @@ GITHUB_API_QUERIES = { } } """, + # Query to collect current PR ID + # NOTE: Only to be used for PR review not to be used with actual action + "get_pr_id": """ +{ + repository(owner: "anmol098", name: "waka-readme-stats") { + pullRequest(number: $pr_number) { + id + } + } +} + """, + "add_pr_comment": """ +mutation { + addComment(input: {subjectId: "$pr_id", body: "$comment"}) { + subject { + id + } + } +} + """ } diff --git a/sources/manager_environment.py b/sources/manager_environment.py index a38a782..e018075 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -46,3 +46,4 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY + PR_NUMBER = getenv("PR_NUMBER", "") From 18d83c74add3826c1a59d05490f2d103f8efd0a5 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sat, 25 Feb 2023 03:08:52 +0530 Subject: [PATCH 02/38] fix: added step to create assets folder --- .github/workflows/review_pr.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index d67df3a..dd5c50f 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -25,6 +25,9 @@ jobs: - name: Install Dependencies ๐Ÿ“ฅ run: pip install -r requirements.txt + - name: Create assets folder ๐Ÿ“ฅ + run: mkdir assets + - name: Run Current Tests ๐Ÿงช env: INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} From 8bd25d079cc4221b35ecdd8624f207cc9d679c33 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sat, 25 Feb 2023 13:20:08 +0530 Subject: [PATCH 03/38] fix: adding github auth token to only github api --- sources/manager_download.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sources/manager_download.py b/sources/manager_download.py index a98c06a..81bff81 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -156,8 +156,7 @@ async def init_download_manager(): "waka_latest": f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}", "waka_all": f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}", "github_stats": f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}", - }, - {"Authorization": f"Bearer {EM.GH_TOKEN}"}, + } ) @@ -177,7 +176,7 @@ class DownloadManager: _REMOTE_RESOURCES_CACHE = dict() @staticmethod - async def load_remote_resources(resources: Dict[str, str], github_headers: Dict[str, str]): + async def load_remote_resources(resources: Dict[str, str]): """ Prepare DownloadManager to launch GitHub API queries and launch all static queries. :param resources: Dictionary of static queries, "IDENTIFIER": "URL". @@ -185,7 +184,6 @@ class DownloadManager: """ for resource, url in resources.items(): DownloadManager._REMOTE_RESOURCES_CACHE[resource] = DownloadManager._client.get(url) - DownloadManager._client.headers = github_headers @staticmethod async def close_remote_resources(): @@ -252,7 +250,8 @@ class DownloadManager: :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - res = await DownloadManager._client.post("https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}) + headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"} + res = await DownloadManager._client.post("https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers) if res.status_code == 200: return res.json() else: From 3b5a864a2be0cc16737a6867ea0899d36a54574e Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sun, 26 Feb 2023 01:52:51 +0530 Subject: [PATCH 04/38] fix: added ability to use github action token when commenting on PR --- .github/workflows/review_pr.yml | 1 + sources/main.py | 4 ++-- sources/manager_download.py | 2 +- sources/manager_environment.py | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index dd5c50f..ceb79ef 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -32,6 +32,7 @@ jobs: env: INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} + CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.number }} INPUT_SHOW_TIMEZONE: true INPUT_SHOW_PROJECTS: True diff --git a/sources/main.py b/sources/main.py index 8d980b9..ba687af 100644 --- a/sources/main.py +++ b/sources/main.py @@ -191,9 +191,9 @@ async def main(): DBM.g("Readme updated!") else: DBM.i("Commenting PR...") - pr_data = await DM.get_remote_graphql("get_pr_id", pr_number=EM.PR_NUMBER) + pr_data = await DM.get_remote_graphql("get_pr_id", pr_number=EM.PR_NUMBER, use_github_action=True) pr_id = pr_data["data"]["repository"]["pullRequest"]["id"] - await DM.get_remote_graphql("add_pr_comment", pr_id=pr_id, comment=stats) + await DM.get_remote_graphql("add_pr_comment", pr_id=pr_id, comment=stats, use_github_action=True) DBM.g("PR commented!") DBM.g("Debug run, readme not updated. check the latest comment for the generated stats.") await DM.close_remote_resources() diff --git a/sources/manager_download.py b/sources/manager_download.py index 81bff81..27c7ce7 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -250,7 +250,7 @@ class DownloadManager: :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"} + headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not kwargs.get('use_github_action', False) else EM.CURRENT_GITHUB_ACTION_TOKEN}"} res = await DownloadManager._client.post("https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers) if res.status_code == 200: return res.json() diff --git a/sources/manager_environment.py b/sources/manager_environment.py index e018075..ee1da4d 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -47,3 +47,4 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY PR_NUMBER = getenv("PR_NUMBER", "") + CURRENT_GITHUB_ACTION_TOKEN = getenv("CURRENT_GITHUB_ACTION_TOKEN", "") From 10eb622b20ec82919c38cf4ba971a6a1af36135c Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sun, 26 Feb 2023 02:12:05 +0530 Subject: [PATCH 05/38] fix: Run Action when functional files are changed in repository --- .github/workflows/review_pr.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index ceb79ef..942ab4f 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -3,6 +3,10 @@ name: REVIEW_PULL_REQUEST on: pull_request: types: [ opened, edited, reopened, synchronize ] + paths: + - 'sources/**' + - 'requirements.txt' + - '.github/workflows/review_pr.yml' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -28,12 +32,12 @@ jobs: - name: Create assets folder ๐Ÿ“ฅ run: mkdir assets - - name: Run Current Tests ๐Ÿงช + - name: Run Action Preview on Current Code ๐Ÿงช env: INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} - CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.number }} + CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This is for testing purpose only not for production + PR_NUMBER: ${{ github.event.number }} # This is for testing purpose only not for production INPUT_SHOW_TIMEZONE: true INPUT_SHOW_PROJECTS: True INPUT_SHOW_EDITORS: True @@ -50,8 +54,8 @@ jobs: INPUT_SHOW_LANGUAGE_PER_REPO: True INPUT_SHOW_UPDATED_DATE: True INPUT_COMMIT_BY_ME: True - INPUT_DEBUG_LOGGING: True - DEBUG_RUN: True + INPUT_DEBUG_LOGGING: True # This is for testing purpose only not for production + DEBUG_RUN: True # This is for testing purpose only not for production run: python3 sources/main.py From 76fa3a61c96efc4768c6c640a89ee82cc5cc4dc0 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sun, 26 Feb 2023 02:30:00 +0530 Subject: [PATCH 06/38] fix: close #374 close #312 --- README.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 458609e..31da994 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,11 @@ jobs: ```yml - uses: anmol098/waka-readme-stats@master - with: - WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} - GH_TOKEN: ${{ secrets.GH_TOKEN }} - SHOW_OS: "False" - SHOW_PROJECTS: "False" + with: + WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + SHOW_OS: "False" + SHOW_PROJECTS: "False" ``` ### Flags Available @@ -288,14 +288,15 @@ Contributions are welcome! โ™ฅ! Please share any features, and add unit tests! U # Selected Contributors 1. [Anmol Pratap Singh](https://github.com/anmol098): Maintainer -2. [Prabhat Singh](https://github.com/prabhatdev): For code timeline graph [#18](https://github.com/anmol098/waka-readme-stats/pull/18) -2. [Aravind V. Nair](https://github.com/aravindvnair99): Maintainer and For Pull Request [#188](https://github.com/anmol098/waka-readme-stats/pull/188) And Other improvements -3. [Hedy Li](https://github.com/hedythedev): For Pull Request [#34](https://github.com/anmol098/waka-readme-stats/pull/34) and [#23](https://github.com/anmol098/waka-readme-stats/pull/23) -4. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29) -5. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45) -6. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48) -7. [Daniel Rowe](https://github.com/DanRowe): For Pull Request [#57](https://github.com/anmol098/waka-readme-stats/pull/57) -8. [Ss5h](https://github.com/tlatkdgus1): For adding support for natural sentence writing for translation [#136](https://github.com/anmol098/waka-readme-stats/pull/136) +2. [Alexander Sergeev](https://github.com/pseusys): Maintainer +3. [Aravind V. Nair](https://github.com/aravindvnair99): Maintainer +4. [Prabhat Singh](https://github.com/prabhatdev): For code timeline graph [#18](https://github.com/anmol098/waka-readme-stats/pull/18) +5. [Hedy Li](https://github.com/hedythedev): For Pull Request [#34](https://github.com/anmol098/waka-readme-stats/pull/34) and [#23](https://github.com/anmol098/waka-readme-stats/pull/23) +6. [Pedro Torres](https://github.com/Corfucinas): For Pull Request [#29](https://github.com/anmol098/waka-readme-stats/pull/29) +7. [Aaron Meese](https://github.com/ajmeese7): For Pull Request [#45](https://github.com/anmol098/waka-readme-stats/pull/45) +8. [Arnav Jindal](https://github.com/Daggy1234): For Pull Request [#48](https://github.com/anmol098/waka-readme-stats/pull/48) +9. [Daniel Rowe](https://github.com/DanRowe): For Pull Request [#57](https://github.com/anmol098/waka-readme-stats/pull/57) +10. [Ss5h](https://github.com/tlatkdgus1): For adding support for natural sentence writing for translation [#136](https://github.com/anmol098/waka-readme-stats/pull/136)
Special mention for those who are currently making their profile readme more awesome :smile: :tada: @@ -420,6 +421,10 @@ Contributions are welcome! โ™ฅ! Please share any features, and add unit tests! U - [Muhammad Bilal](https://github.com/BilalJaved15) + - [Wyatt Walsh](https://www.github.com/wyattowalsh) + + - [Nithin Balaji](https://github.com/thenithinbalaji) +
From 01fa5beabc453a05e6d4bc60d115c1f3f1220901 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sun, 26 Feb 2023 02:33:00 +0530 Subject: [PATCH 07/38] fix: linter --- sources/manager_download.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sources/manager_download.py b/sources/manager_download.py index 27c7ce7..7d00706 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -123,7 +123,7 @@ GITHUB_API_QUERIES = { """, # Query to collect current PR ID # NOTE: Only to be used for PR review not to be used with actual action - "get_pr_id": """ + "get_pr_id": """ { repository(owner: "anmol098", name: "waka-readme-stats") { pullRequest(number: $pr_number) { @@ -132,7 +132,7 @@ GITHUB_API_QUERIES = { } } """, - "add_pr_comment": """ + "add_pr_comment": """ mutation { addComment(input: {subjectId: "$pr_id", body: "$comment"}) { subject { @@ -251,7 +251,9 @@ class DownloadManager: :return: Response JSON dictionary. """ headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not kwargs.get('use_github_action', False) else EM.CURRENT_GITHUB_ACTION_TOKEN}"} - res = await DownloadManager._client.post("https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers) + res = await DownloadManager._client.post("https://api.github.com/graphql", + json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, + headers=headers) if res.status_code == 200: return res.json() else: From 1a65d61a0cc19a98b21d80689981ebb117937f06 Mon Sep 17 00:00:00 2001 From: Anmol Singh Date: Sun, 26 Feb 2023 02:39:57 +0530 Subject: [PATCH 08/38] fix: linter --- sources/manager_download.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/manager_download.py b/sources/manager_download.py index 7d00706..50aa799 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -140,7 +140,7 @@ mutation { } } } - """ + """, } @@ -251,9 +251,9 @@ class DownloadManager: :return: Response JSON dictionary. """ headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not kwargs.get('use_github_action', False) else EM.CURRENT_GITHUB_ACTION_TOKEN}"} - res = await DownloadManager._client.post("https://api.github.com/graphql", - json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, - headers=headers) + res = await DownloadManager._client.post( + "https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers + ) if res.status_code == 200: return res.json() else: From 80967953cff51c873f2e254533d8143dd78646ca Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 08:01:04 +0100 Subject: [PATCH 09/38] adjusted --- .github/workflows/review_pr.yml | 11 ++++----- sources/main.py | 8 ++----- sources/manager_download.py | 41 ++++++++------------------------- sources/manager_github.py | 20 +++++++++++++--- 4 files changed, 32 insertions(+), 48 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index 942ab4f..d4a2426 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -2,7 +2,7 @@ name: REVIEW_PULL_REQUEST on: pull_request: - types: [ opened, edited, reopened, synchronize ] + types: [ review_requested ] paths: - 'sources/**' - 'requirements.txt' @@ -15,6 +15,7 @@ concurrency: jobs: publish-server-image: name: Run Test and Review PR + if: ${{ github.event.requested_reviewer.login == 'anmol098'}} runs-on: ubuntu-latest steps: @@ -36,9 +37,7 @@ jobs: env: INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} - CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This is for testing purpose only not for production - PR_NUMBER: ${{ github.event.number }} # This is for testing purpose only not for production - INPUT_SHOW_TIMEZONE: true + INPUT_SHOW_TIMEZONE: True INPUT_SHOW_PROJECTS: True INPUT_SHOW_EDITORS: True INPUT_SHOW_OS: True @@ -56,7 +55,5 @@ jobs: INPUT_COMMIT_BY_ME: True INPUT_DEBUG_LOGGING: True # This is for testing purpose only not for production DEBUG_RUN: True # This is for testing purpose only not for production + PR_NUMBER: ${{ github.event.number }} # This is for testing purpose only not for production run: python3 sources/main.py - - - diff --git a/sources/main.py b/sources/main.py index ba687af..d234159 100644 --- a/sources/main.py +++ b/sources/main.py @@ -190,12 +190,8 @@ async def main(): if GHM.update_readme(stats): DBM.g("Readme updated!") else: - DBM.i("Commenting PR...") - pr_data = await DM.get_remote_graphql("get_pr_id", pr_number=EM.PR_NUMBER, use_github_action=True) - pr_id = pr_data["data"]["repository"]["pullRequest"]["id"] - await DM.get_remote_graphql("add_pr_comment", pr_id=pr_id, comment=stats, use_github_action=True) - DBM.g("PR commented!") - DBM.g("Debug run, readme not updated. check the latest comment for the generated stats.") + GHM.push_to_pr(stats) + DBM.g("Debug run, readme not updated. Check the latest comment for the generated stats.") await DM.close_remote_resources() diff --git a/sources/manager_download.py b/sources/manager_download.py index 50aa799..2dfb2b5 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -11,7 +11,6 @@ from manager_environment import EnvironmentManager as EM from manager_github import GitHubManager as GHM from manager_debug import DebugManager as DBM - GITHUB_API_QUERIES = { # Query to collect info about all user repositories, including: is it a fork, name and owner login. # NB! Query includes information about recent repositories only (apparently, contributed within a year). @@ -121,26 +120,6 @@ GITHUB_API_QUERIES = { } } """, - # Query to collect current PR ID - # NOTE: Only to be used for PR review not to be used with actual action - "get_pr_id": """ -{ - repository(owner: "anmol098", name: "waka-readme-stats") { - pullRequest(number: $pr_number) { - id - } - } -} - """, - "add_pr_comment": """ -mutation { - addComment(input: {subjectId: "$pr_id", body: "$comment"}) { - subject { - id - } - } -} - """, } @@ -151,12 +130,10 @@ async def init_download_manager(): - Launch static queries in background. """ await DownloadManager.load_remote_resources( - { - "linguist": "https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml", - "waka_latest": f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}", - "waka_all": f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}", - "github_stats": f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}", - } + linguist="https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml", + waka_latest=f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}", + waka_all=f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}", + github_stats=f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}", ) @@ -176,11 +153,10 @@ class DownloadManager: _REMOTE_RESOURCES_CACHE = dict() @staticmethod - async def load_remote_resources(resources: Dict[str, str]): + async def load_remote_resources(**resources: str): """ Prepare DownloadManager to launch GitHub API queries and launch all static queries. - :param resources: Dictionary of static queries, "IDENTIFIER": "URL". - :param github_headers: Dictionary of headers for GitHub API queries. + :param resources: Static queries, formatted like "IDENTIFIER"="URL". """ for resource, url in resources.items(): DownloadManager._REMOTE_RESOURCES_CACHE[resource] = DownloadManager._client.get(url) @@ -243,14 +219,15 @@ class DownloadManager: return await DownloadManager._get_remote_resource(resource, safe_load) @staticmethod - async def _fetch_graphql_query(query: str, **kwargs) -> Dict: + async def _fetch_graphql_query(query: str, use_github_action: bool = False, **kwargs) -> Dict: """ Execute GitHub GraphQL API simple query. :param query: Dynamic query identifier. + :param use_github_action: Whether to perform query using CURRENT_GITHUB_ACTION_TOKEN. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not kwargs.get('use_github_action', False) else EM.CURRENT_GITHUB_ACTION_TOKEN}"} + headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not use_github_action else EM.CURRENT_GITHUB_ACTION_TOKEN}"} res = await DownloadManager._client.post( "https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers ) diff --git a/sources/manager_github.py b/sources/manager_github.py index e4bd7fb..e172483 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -17,6 +17,7 @@ def init_github_manager(): class GitHubManager: + _GITHUB: Github USER: AuthenticatedUser REPO: Repository _README: ContentFile @@ -35,9 +36,9 @@ class GitHubManager: - README.md file of this repo. - Parsed contents of the file. """ - github = Github(EM.GH_TOKEN) - GitHubManager.USER = github.get_user() - GitHubManager.REPO = github.get_repo(f"{GitHubManager.USER.login}/{GitHubManager.USER.login}") + GitHubManager._GITHUB = Github(EM.GH_TOKEN) + GitHubManager.USER = GitHubManager._GITHUB.get_user() + GitHubManager.REPO = GitHubManager._GITHUB.get_repo(f"{GitHubManager.USER.login}/{GitHubManager.USER.login}") GitHubManager._README = GitHubManager.REPO.get_readme() GitHubManager._README_CONTENTS = str(b64decode(GitHubManager._README.content), "utf-8") @@ -81,6 +82,7 @@ class GitHubManager: Updates readme with given data if necessary. Uses commit author, commit message and branch name specified by environmental variables. + :param stats: Readme stats to be pushed. :returns: whether the README.md file was updated or not. """ DBM.i("Updating README...") @@ -100,6 +102,18 @@ class GitHubManager: DBM.w("README update not needed!") return False + @staticmethod + def push_to_pr(stats: str): + """ + Pushes readme data to current PR body instead of committing it. + + :param stats: Readme stats to be pushed. + """ + DBM.i("Commenting PR...") + pull_request = GitHubManager._GITHUB.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) + pull_request.create_issue_comment(stats) + DBM.g("PR commented!") + @staticmethod def update_chart(chart_path: str): """ From cb50297d3ad6306313ef716564f1e181b4479677 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 08:40:21 +0100 Subject: [PATCH 10/38] hiding outdated comments --- .github/workflows/review_pr.yml | 3 +-- sources/manager_github.py | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index d4a2426..e3b8b95 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -2,7 +2,7 @@ name: REVIEW_PULL_REQUEST on: pull_request: - types: [ review_requested ] + types: [ opened, edited, reopened, synchronize ] paths: - 'sources/**' - 'requirements.txt' @@ -15,7 +15,6 @@ concurrency: jobs: publish-server-image: name: Run Test and Review PR - if: ${{ github.event.requested_reviewer.login == 'anmol098'}} runs-on: ubuntu-latest steps: diff --git a/sources/manager_github.py b/sources/manager_github.py index e172483..3c95b4f 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -4,6 +4,7 @@ from re import sub from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException from manager_environment import EnvironmentManager as EM +from manager_download import DownloadManager as DM from manager_debug import DebugManager as DBM @@ -109,9 +110,14 @@ class GitHubManager: :param stats: Readme stats to be pushed. """ + prefix = "README stats current output:\n\n" DBM.i("Commenting PR...") + pull_request = GitHubManager._GITHUB.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) - pull_request.create_issue_comment(stats) + for comment in [ic for ic in pull_request.get_issue_comments() if ic.body.startswith(prefix)]: + DM.get_remote_graphql("hide_outdated_comment", id=comment.id) + + pull_request.create_issue_comment(f"{prefix}{stats}") DBM.g("PR commented!") @staticmethod From 1686d114fb827bae07ea19cb0e30cc1c550b415a Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 08:40:24 +0100 Subject: [PATCH 11/38] hiding outdated comments --- sources/manager_download.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sources/manager_download.py b/sources/manager_download.py index 2dfb2b5..ecea548 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -119,6 +119,13 @@ GITHUB_API_QUERIES = { } } } +""", + "hide_outdated_comment": """ +mutation { + minimizeComment(input: {classifier:OUTDATED, subjectId: "$id"}) { + clientMutationId + } +} """, } From 6f58b50f2f561931290a662a07f80d6d5af4443d Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 08:43:35 +0100 Subject: [PATCH 12/38] circular import error fixed --- sources/main.py | 2 +- sources/manager_download.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sources/main.py b/sources/main.py index d234159..648c72a 100644 --- a/sources/main.py +++ b/sources/main.py @@ -181,7 +181,7 @@ async def main(): Initializes all managers, collects user info and updates README.md if necessary. """ init_github_manager() - await init_download_manager() + await init_download_manager(GHM.USER.login) init_localization_manager() DBM.i("Managers initialized.") diff --git a/sources/manager_download.py b/sources/manager_download.py index ecea548..5c514a2 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -8,7 +8,6 @@ from httpx import AsyncClient from yaml import safe_load from manager_environment import EnvironmentManager as EM -from manager_github import GitHubManager as GHM from manager_debug import DebugManager as DBM GITHUB_API_QUERIES = { @@ -121,7 +120,7 @@ GITHUB_API_QUERIES = { } """, "hide_outdated_comment": """ -mutation { +mutation { minimizeComment(input: {classifier:OUTDATED, subjectId: "$id"}) { clientMutationId } @@ -130,17 +129,19 @@ mutation { } -async def init_download_manager(): +async def init_download_manager(user_login: str): """ Initialize download manager: - Setup headers for GitHub GraphQL requests. - Launch static queries in background. + + :param user_login: GitHub user login. """ await DownloadManager.load_remote_resources( linguist="https://cdn.jsdelivr.net/gh/github/linguist@master/lib/linguist/languages.yml", waka_latest=f"https://wakatime.com/api/v1/users/current/stats/last_7_days?api_key={EM.WAKATIME_API_KEY}", waka_all=f"https://wakatime.com/api/v1/users/current/all_time_since_today?api_key={EM.WAKATIME_API_KEY}", - github_stats=f"https://github-contributions.vercel.app/api/v1/{GHM.USER.login}", + github_stats=f"https://github-contributions.vercel.app/api/v1/{user_login}", ) From 30c30d2c89efdfb4d8a0817084f823e81e3c217c Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 08:50:36 +0100 Subject: [PATCH 13/38] newlines removed from prefix --- sources/manager_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 3c95b4f..f57033c 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -110,14 +110,14 @@ class GitHubManager: :param stats: Readme stats to be pushed. """ - prefix = "README stats current output:\n\n" + prefix = "README stats current output:" DBM.i("Commenting PR...") pull_request = GitHubManager._GITHUB.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) for comment in [ic for ic in pull_request.get_issue_comments() if ic.body.startswith(prefix)]: DM.get_remote_graphql("hide_outdated_comment", id=comment.id) - pull_request.create_issue_comment(f"{prefix}{stats}") + pull_request.create_issue_comment(f"{prefix}\n\n{stats}") DBM.g("PR commented!") @staticmethod From 2e2497e3026f27c63f24f23f5de5cf397fa0e24a Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 09:30:49 +0100 Subject: [PATCH 14/38] pr_number is an integer --- sources/manager_download.py | 5 ++--- sources/manager_environment.py | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sources/manager_download.py b/sources/manager_download.py index 5c514a2..62c2ed4 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -227,15 +227,14 @@ class DownloadManager: return await DownloadManager._get_remote_resource(resource, safe_load) @staticmethod - async def _fetch_graphql_query(query: str, use_github_action: bool = False, **kwargs) -> Dict: + async def _fetch_graphql_query(query: str, **kwargs) -> Dict: """ Execute GitHub GraphQL API simple query. :param query: Dynamic query identifier. - :param use_github_action: Whether to perform query using CURRENT_GITHUB_ACTION_TOKEN. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not use_github_action else EM.CURRENT_GITHUB_ACTION_TOKEN}"} + headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"} res = await DownloadManager._client.post( "https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers ) diff --git a/sources/manager_environment.py b/sources/manager_environment.py index ee1da4d..53c543c 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -46,5 +46,4 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY - PR_NUMBER = getenv("PR_NUMBER", "") - CURRENT_GITHUB_ACTION_TOKEN = getenv("CURRENT_GITHUB_ACTION_TOKEN", "") + PR_NUMBER = int(getenv("PR_NUMBER", "0")) From 1d2121e7473f331ce8b3ae577fdaabaec72a176c Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 09:34:04 +0100 Subject: [PATCH 15/38] await comment hiding --- sources/main.py | 2 +- sources/manager_github.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/main.py b/sources/main.py index 648c72a..21347b2 100644 --- a/sources/main.py +++ b/sources/main.py @@ -190,7 +190,7 @@ async def main(): if GHM.update_readme(stats): DBM.g("Readme updated!") else: - GHM.push_to_pr(stats) + await GHM.push_to_pr(stats) DBM.g("Debug run, readme not updated. Check the latest comment for the generated stats.") await DM.close_remote_resources() diff --git a/sources/manager_github.py b/sources/manager_github.py index f57033c..45ed276 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -104,7 +104,7 @@ class GitHubManager: return False @staticmethod - def push_to_pr(stats: str): + async def push_to_pr(stats: str): """ Pushes readme data to current PR body instead of committing it. @@ -115,7 +115,7 @@ class GitHubManager: pull_request = GitHubManager._GITHUB.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) for comment in [ic for ic in pull_request.get_issue_comments() if ic.body.startswith(prefix)]: - DM.get_remote_graphql("hide_outdated_comment", id=comment.id) + await DM.get_remote_graphql("hide_outdated_comment", id=comment.id) pull_request.create_issue_comment(f"{prefix}\n\n{stats}") DBM.g("PR commented!") From db09a1deedadfe6fa05041b0a635d416c0d1cb29 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 09:48:03 +0100 Subject: [PATCH 16/38] stats commits pushed on behalf of bot --- .github/workflows/review_pr.yml | 1 + sources/manager_download.py | 20 ++++++++++++-------- sources/manager_environment.py | 2 ++ sources/manager_github.py | 12 ++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index e3b8b95..a09185c 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -55,4 +55,5 @@ jobs: INPUT_DEBUG_LOGGING: True # This is for testing purpose only not for production DEBUG_RUN: True # This is for testing purpose only not for production PR_NUMBER: ${{ github.event.number }} # This is for testing purpose only not for production + CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This is for testing purpose only not for production run: python3 sources/main.py diff --git a/sources/manager_download.py b/sources/manager_download.py index 62c2ed4..6208fc4 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -227,14 +227,15 @@ class DownloadManager: return await DownloadManager._get_remote_resource(resource, safe_load) @staticmethod - async def _fetch_graphql_query(query: str, **kwargs) -> Dict: + async def _fetch_graphql_query(query: str, use_github_action: bool = False, **kwargs) -> Dict: """ Execute GitHub GraphQL API simple query. :param query: Dynamic query identifier. + :param use_github_action: Use GitHub actions bot auth token instead of current user. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"} + headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not use_github_action else EM.CURRENT_GITHUB_ACTION_TOKEN}"} res = await DownloadManager._client.post( "https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers ) @@ -267,19 +268,21 @@ class DownloadManager: return list(), dict(hasNextPage=False) @staticmethod - async def _fetch_graphql_paginated(query: str, **kwargs) -> Dict: + async def _fetch_graphql_paginated(query: str, use_github_action: bool = False, **kwargs) -> Dict: """ Execute GitHub GraphQL API paginated query. Queries 100 new results each time until no more results are left. Merges result list into single query, clears pagination-related info. :param query: Dynamic query identifier. + :param use_github_action: Use GitHub actions bot auth token instead of current user. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - initial_query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination="first: 100") + initial_query_response = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs, pagination="first: 100") page_list, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response) while page_info["hasNextPage"]: - query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination=f'first: 100, after: "{page_info["endCursor"]}"') + pagination = f'first: 100, after: "{page_info["endCursor"]}"' + query_response = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs, pagination=pagination) new_page_list, page_info = DownloadManager._find_pagination_and_data_list(query_response) page_list += new_page_list _, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response) @@ -287,7 +290,7 @@ class DownloadManager: return initial_query_response @staticmethod - async def get_remote_graphql(query: str, **kwargs) -> Dict: + async def get_remote_graphql(query: str, use_github_action: bool = False, **kwargs) -> Dict: """ Execute GitHub GraphQL API query. The queries are defined in `GITHUB_API_QUERIES`, all parameters should be passed as kwargs. @@ -295,15 +298,16 @@ class DownloadManager: Merges paginated sub-queries if pagination is required for the query. Parse and return response as JSON. :param query: Dynamic query identifier. + :param use_github_action: Use GitHub actions bot auth token instead of current user. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ key = f"{query}_{md5(dumps(kwargs, sort_keys=True).encode('utf-8')).digest()}" if key not in DownloadManager._REMOTE_RESOURCES_CACHE: if "$pagination" in GITHUB_API_QUERIES[query]: - res = await DownloadManager._fetch_graphql_paginated(query, **kwargs) + res = await DownloadManager._fetch_graphql_paginated(query, use_github_action, **kwargs) else: - res = await DownloadManager._fetch_graphql_query(query, **kwargs) + res = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs) DownloadManager._REMOTE_RESOURCES_CACHE[key] = res else: res = DownloadManager._REMOTE_RESOURCES_CACHE[key] diff --git a/sources/manager_environment.py b/sources/manager_environment.py index 53c543c..d98fb07 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -46,4 +46,6 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY + PR_NUMBER = int(getenv("PR_NUMBER", "0")) + CURRENT_GITHUB_ACTION_TOKEN = getenv("CURRENT_GITHUB_ACTION_TOKEN", "") diff --git a/sources/manager_github.py b/sources/manager_github.py index 45ed276..c757dae 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -18,7 +18,6 @@ def init_github_manager(): class GitHubManager: - _GITHUB: Github USER: AuthenticatedUser REPO: Repository _README: ContentFile @@ -37,9 +36,9 @@ class GitHubManager: - README.md file of this repo. - Parsed contents of the file. """ - GitHubManager._GITHUB = Github(EM.GH_TOKEN) - GitHubManager.USER = GitHubManager._GITHUB.get_user() - GitHubManager.REPO = GitHubManager._GITHUB.get_repo(f"{GitHubManager.USER.login}/{GitHubManager.USER.login}") + github = Github(EM.GH_TOKEN) + GitHubManager.USER = github.get_user() + GitHubManager.REPO = github.get_repo(f"{GitHubManager.USER.login}/{GitHubManager.USER.login}") GitHubManager._README = GitHubManager.REPO.get_readme() GitHubManager._README_CONTENTS = str(b64decode(GitHubManager._README.content), "utf-8") @@ -113,9 +112,10 @@ class GitHubManager: prefix = "README stats current output:" DBM.i("Commenting PR...") - pull_request = GitHubManager._GITHUB.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) + github = Github(EM.CURRENT_GITHUB_ACTION_TOKEN) + pull_request = github.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) for comment in [ic for ic in pull_request.get_issue_comments() if ic.body.startswith(prefix)]: - await DM.get_remote_graphql("hide_outdated_comment", id=comment.id) + await DM.get_remote_graphql("hide_outdated_comment", use_github_action=True, id=comment.id) pull_request.create_issue_comment(f"{prefix}\n\n{stats}") DBM.g("PR commented!") From 2821558b6636c095f79a8b711b04d9be2eccae09 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:16:13 +0100 Subject: [PATCH 17/38] making commit using bot test --- .github/workflows/review_pr.yml | 18 +++++++++++++++--- sources/manager_download.py | 17 ++++++++--------- sources/manager_environment.py | 5 +++-- sources/manager_github.py | 9 +-------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index a09185c..5d0fb80 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -29,10 +29,16 @@ jobs: - name: Install Dependencies ๐Ÿ“ฅ run: pip install -r requirements.txt - - name: Create assets folder ๐Ÿ“ฅ + - name: Create Assets Folder ๐Ÿ“ฅ run: mkdir assets + - name: Create Previous Comments ๐Ÿซฃ + uses: int128/hide-comment-action@v1 + with: + starts-with: "README stats current output:" + - name: Run Action Preview on Current Code ๐Ÿงช + id: make-stats env: INPUT_GH_TOKEN: ${{ secrets.INPUT_GITHUB_TOKEN }} INPUT_WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} @@ -54,6 +60,12 @@ jobs: INPUT_COMMIT_BY_ME: True INPUT_DEBUG_LOGGING: True # This is for testing purpose only not for production DEBUG_RUN: True # This is for testing purpose only not for production - PR_NUMBER: ${{ github.event.number }} # This is for testing purpose only not for production - CURRENT_GITHUB_ACTION_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This is for testing purpose only not for production run: python3 sources/main.py + + - name: Create Comment + uses: jungwinter/comment@v1 + with: + type: create + body: ${{ steps.run_tests.outputs.README_CONTENT }} + issue_number: ${{ github.event.number }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/sources/manager_download.py b/sources/manager_download.py index 6208fc4..71db5d9 100644 --- a/sources/manager_download.py +++ b/sources/manager_download.py @@ -227,7 +227,7 @@ class DownloadManager: return await DownloadManager._get_remote_resource(resource, safe_load) @staticmethod - async def _fetch_graphql_query(query: str, use_github_action: bool = False, **kwargs) -> Dict: + async def _fetch_graphql_query(query: str, **kwargs) -> Dict: """ Execute GitHub GraphQL API simple query. :param query: Dynamic query identifier. @@ -235,7 +235,7 @@ class DownloadManager: :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - headers = {"Authorization": f"Bearer {EM.GH_TOKEN if not use_github_action else EM.CURRENT_GITHUB_ACTION_TOKEN}"} + headers = {"Authorization": f"Bearer {EM.GH_TOKEN}"} res = await DownloadManager._client.post( "https://api.github.com/graphql", json={"query": Template(GITHUB_API_QUERIES[query]).substitute(kwargs)}, headers=headers ) @@ -268,7 +268,7 @@ class DownloadManager: return list(), dict(hasNextPage=False) @staticmethod - async def _fetch_graphql_paginated(query: str, use_github_action: bool = False, **kwargs) -> Dict: + async def _fetch_graphql_paginated(query: str, **kwargs) -> Dict: """ Execute GitHub GraphQL API paginated query. Queries 100 new results each time until no more results are left. @@ -278,11 +278,11 @@ class DownloadManager: :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ - initial_query_response = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs, pagination="first: 100") + initial_query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination="first: 100") page_list, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response) while page_info["hasNextPage"]: pagination = f'first: 100, after: "{page_info["endCursor"]}"' - query_response = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs, pagination=pagination) + query_response = await DownloadManager._fetch_graphql_query(query, **kwargs, pagination=pagination) new_page_list, page_info = DownloadManager._find_pagination_and_data_list(query_response) page_list += new_page_list _, page_info = DownloadManager._find_pagination_and_data_list(initial_query_response) @@ -290,7 +290,7 @@ class DownloadManager: return initial_query_response @staticmethod - async def get_remote_graphql(query: str, use_github_action: bool = False, **kwargs) -> Dict: + async def get_remote_graphql(query: str, **kwargs) -> Dict: """ Execute GitHub GraphQL API query. The queries are defined in `GITHUB_API_QUERIES`, all parameters should be passed as kwargs. @@ -298,16 +298,15 @@ class DownloadManager: Merges paginated sub-queries if pagination is required for the query. Parse and return response as JSON. :param query: Dynamic query identifier. - :param use_github_action: Use GitHub actions bot auth token instead of current user. :param kwargs: Parameters for substitution of variables in dynamic query. :return: Response JSON dictionary. """ key = f"{query}_{md5(dumps(kwargs, sort_keys=True).encode('utf-8')).digest()}" if key not in DownloadManager._REMOTE_RESOURCES_CACHE: if "$pagination" in GITHUB_API_QUERIES[query]: - res = await DownloadManager._fetch_graphql_paginated(query, use_github_action, **kwargs) + res = await DownloadManager._fetch_graphql_paginated(query, **kwargs) else: - res = await DownloadManager._fetch_graphql_query(query, use_github_action, **kwargs) + res = await DownloadManager._fetch_graphql_query(query, **kwargs) DownloadManager._REMOTE_RESOURCES_CACHE[key] = res else: res = DownloadManager._REMOTE_RESOURCES_CACHE[key] diff --git a/sources/manager_environment.py b/sources/manager_environment.py index d98fb07..a13b170 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -47,5 +47,6 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY - PR_NUMBER = int(getenv("PR_NUMBER", "0")) - CURRENT_GITHUB_ACTION_TOKEN = getenv("CURRENT_GITHUB_ACTION_TOKEN", "") + @staticmethod + def set_variable(name: str, content: str): + environ[name] = content diff --git a/sources/manager_github.py b/sources/manager_github.py index c757dae..07340dc 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -4,7 +4,6 @@ from re import sub from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException from manager_environment import EnvironmentManager as EM -from manager_download import DownloadManager as DM from manager_debug import DebugManager as DBM @@ -111,13 +110,7 @@ class GitHubManager: """ prefix = "README stats current output:" DBM.i("Commenting PR...") - - github = Github(EM.CURRENT_GITHUB_ACTION_TOKEN) - pull_request = github.get_repo("anmol098/waka-readme-stats").get_pull(EM.PR_NUMBER) - for comment in [ic for ic in pull_request.get_issue_comments() if ic.body.startswith(prefix)]: - await DM.get_remote_graphql("hide_outdated_comment", use_github_action=True, id=comment.id) - - pull_request.create_issue_comment(f"{prefix}\n\n{stats}") + EM.set_variable("GITHUB_OUTPUT", f"README_CONTENT={prefix}\n\n{stats}") DBM.g("PR commented!") @staticmethod From e23ce9dc4b5ce0fac0bca7cfab6d711b76217d0a Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:19:46 +0100 Subject: [PATCH 18/38] correct ID used --- .github/workflows/review_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index 5d0fb80..777bc63 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -66,6 +66,6 @@ jobs: uses: jungwinter/comment@v1 with: type: create - body: ${{ steps.run_tests.outputs.README_CONTENT }} + body: ${{ steps.make-stats.outputs.README_CONTENT }} issue_number: ${{ github.event.number }} token: ${{ secrets.GITHUB_TOKEN }} From 1d90aba35c54bc9155ebc46855eff6e23f1e9abb Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:27:24 +0100 Subject: [PATCH 19/38] proper GH variable setting --- sources/manager_environment.py | 7 +++++-- sources/manager_github.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sources/manager_environment.py b/sources/manager_environment.py index a13b170..fe0930a 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -48,5 +48,8 @@ class EnvironmentManager: DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY @staticmethod - def set_variable(name: str, content: str): - environ[name] = content + def set_github_output(name: str, content: str): + if "GITHUB_OUTPUT" not in environ.keys(): + raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!") + with open(environ["GITHUB_OUTPUT"], "a") as fh: + fh.write(f"{name}={content}") diff --git a/sources/manager_github.py b/sources/manager_github.py index 07340dc..8714c47 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -110,7 +110,7 @@ class GitHubManager: """ prefix = "README stats current output:" DBM.i("Commenting PR...") - EM.set_variable("GITHUB_OUTPUT", f"README_CONTENT={prefix}\n\n{stats}") + EM.set_github_output("README_CONTENT", f"{prefix}\n\n{stats}") DBM.g("PR commented!") @staticmethod From 4201e3299035018d949a2e3267af031a92e9aa56 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:33:20 +0100 Subject: [PATCH 20/38] readme content escaped --- sources/manager_environment.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sources/manager_environment.py b/sources/manager_environment.py index fe0930a..7436ce2 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -51,5 +51,6 @@ class EnvironmentManager: def set_github_output(name: str, content: str): if "GITHUB_OUTPUT" not in environ.keys(): raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!") + escaped = content.replace("%", "%25").replace("\n", "%0A").replace("\r", "%0D") with open(environ["GITHUB_OUTPUT"], "a") as fh: - fh.write(f"{name}={content}") + fh.write(f"{name}={escaped}") From 72dbd411069c2be24cb54fe898b72c8112e2532f Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:40:58 +0100 Subject: [PATCH 21/38] readme content multiline fixed --- sources/manager_environment.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sources/manager_environment.py b/sources/manager_environment.py index 7436ce2..777ba9e 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -1,4 +1,6 @@ from os import getenv, environ +from random import choice +from string import ascii_letters class EnvironmentManager: @@ -51,6 +53,9 @@ class EnvironmentManager: def set_github_output(name: str, content: str): if "GITHUB_OUTPUT" not in environ.keys(): raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!") + eol = "".join(choice(ascii_letters) for _ in range(10)) escaped = content.replace("%", "%25").replace("\n", "%0A").replace("\r", "%0D") with open(environ["GITHUB_OUTPUT"], "a") as fh: - fh.write(f"{name}={escaped}") + fh.write(f"{name}<<{eol}") + fh.write(escaped) + fh.write(eol) From ecd3d32ceb55330ff84dea7ff5cd64bcc71cbfa7 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:46:32 +0100 Subject: [PATCH 22/38] prefix added to readme contents --- sources/manager_environment.py | 13 ------------- sources/manager_github.py | 24 ++++++++++++++++++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/sources/manager_environment.py b/sources/manager_environment.py index 777ba9e..a38a782 100644 --- a/sources/manager_environment.py +++ b/sources/manager_environment.py @@ -1,6 +1,4 @@ from os import getenv, environ -from random import choice -from string import ascii_letters class EnvironmentManager: @@ -48,14 +46,3 @@ class EnvironmentManager: DEBUG_LOGGING = getenv("INPUT_DEBUG_LOGGING", "0").lower() in _TRUTHY DEBUG_RUN = getenv("DEBUG_RUN", "False").lower() in _TRUTHY - - @staticmethod - def set_github_output(name: str, content: str): - if "GITHUB_OUTPUT" not in environ.keys(): - raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!") - eol = "".join(choice(ascii_letters) for _ in range(10)) - escaped = content.replace("%", "%25").replace("\n", "%0A").replace("\r", "%0D") - with open(environ["GITHUB_OUTPUT"], "a") as fh: - fh.write(f"{name}<<{eol}") - fh.write(escaped) - fh.write(eol) diff --git a/sources/manager_github.py b/sources/manager_github.py index 8714c47..e34588d 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -1,5 +1,8 @@ from base64 import b64decode +from os import environ +from random import choice from re import sub +from string import ascii_letters from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException @@ -102,16 +105,25 @@ class GitHubManager: return False @staticmethod - async def push_to_pr(stats: str): + def set_github_output(stats: str): """ - Pushes readme data to current PR body instead of committing it. + Outputs readme data as current action output instead of committing it. - :param stats: Readme stats to be pushed. + param stats: Readme stats to be outputted. """ + DBM.i("Setting README contents as action output...") + if "GITHUB_OUTPUT" not in environ.keys(): + raise Exception("Not in GitHub environment ('GITHUB_OUTPUT' not defined)!") + prefix = "README stats current output:" - DBM.i("Commenting PR...") - EM.set_github_output("README_CONTENT", f"{prefix}\n\n{stats}") - DBM.g("PR commented!") + eol = "".join(choice(ascii_letters) for _ in range(10)) + with open(environ["GITHUB_OUTPUT"], "a") as fh: + fh.write(f"README_CONTENT<<{eol}") + fh.write(f"{prefix}\n\n{stats}") + fh.write(eol) + + DBM.g("Action output set!") + @staticmethod def update_chart(chart_path: str): From aae864e9246d73630150ae3526da78b1287df582 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:49:29 +0100 Subject: [PATCH 23/38] method name fixed --- sources/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/main.py b/sources/main.py index 21347b2..d760b46 100644 --- a/sources/main.py +++ b/sources/main.py @@ -190,7 +190,7 @@ async def main(): if GHM.update_readme(stats): DBM.g("Readme updated!") else: - await GHM.push_to_pr(stats) + GHM.set_github_output(stats) DBM.g("Debug run, readme not updated. Check the latest comment for the generated stats.") await DM.close_remote_resources() From 389a64085e055a6097b4c6d6163d7d25c506d766 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 10:52:56 +0100 Subject: [PATCH 24/38] new lines added to GH output --- .github/workflows/review_pr.yml | 2 +- sources/manager_github.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index 777bc63..8c13e2f 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -62,7 +62,7 @@ jobs: DEBUG_RUN: True # This is for testing purpose only not for production run: python3 sources/main.py - - name: Create Comment + - name: Create Comment ๐Ÿ’ฌ uses: jungwinter/comment@v1 with: type: create diff --git a/sources/manager_github.py b/sources/manager_github.py index e34588d..89cec06 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -118,13 +118,12 @@ class GitHubManager: prefix = "README stats current output:" eol = "".join(choice(ascii_letters) for _ in range(10)) with open(environ["GITHUB_OUTPUT"], "a") as fh: - fh.write(f"README_CONTENT<<{eol}") - fh.write(f"{prefix}\n\n{stats}") - fh.write(eol) + fh.write(f"README_CONTENT<<{eol}\n") + fh.write(f"{prefix}\n\n{stats}\n") + fh.write(f"{eol}\n") DBM.g("Action output set!") - @staticmethod def update_chart(chart_path: str): """ From b6233625fed92bebe2e7364d5cd0d1be5f5d0215 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 11:47:09 +0100 Subject: [PATCH 25/38] saving assets on debug run --- .github/workflows/review_pr.yml | 16 +++++++ sources/graphics_list_formatter.py | 12 ++--- sources/main.py | 44 +++++++++---------- ...anager_localization.py => manager_file.py} | 24 +++++++--- sources/manager_github.py | 6 +-- sources/yearly_commit_calculator.py | 6 +++ 6 files changed, 71 insertions(+), 37 deletions(-) rename sources/{manager_localization.py => manager_file.py} (53%) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/review_pr.yml index 8c13e2f..a24fc7d 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/review_pr.yml @@ -62,6 +62,22 @@ jobs: DEBUG_RUN: True # This is for testing purpose only not for production run: python3 sources/main.py + - name: Save Branch Name Without Slashes ๐Ÿ“› + if: ${{ github.ref != 'refs/heads/master' }} + env: + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + BRANCH_NAME=${{ env.BRANCH_NAME }} + BRANCH_NAME=${BRANCH_NAME////_} + echo BRANCH_NAME=${BRANCH_NAME} >> $GITHUB_ENV + + - name: Upload Artifact ๐Ÿ“ฆ + uses: actions/upload-artifact@v3 + if: ${{ github.ref != 'refs/heads/master' }} + with: + name: ${{ format('github-pages-for-branch-{0}', env.BRANCH_NAME) }} + path: assets + - name: Create Comment ๐Ÿ’ฌ uses: jungwinter/comment@v1 with: diff --git a/sources/graphics_list_formatter.py b/sources/graphics_list_formatter.py index 10f4862..fd06eb5 100644 --- a/sources/graphics_list_formatter.py +++ b/sources/graphics_list_formatter.py @@ -7,7 +7,7 @@ from pytz import timezone, utc from manager_download import DownloadManager as DM from manager_environment import EnvironmentManager as EM from manager_github import GitHubManager as GHM -from manager_localization import LocalizationManager as LM +from manager_file import FileManager as FM DAY_TIME_EMOJI = ["๐ŸŒž", "๐ŸŒ†", "๐ŸŒƒ", "๐ŸŒ™"] # Emojis, representing different times of day. @@ -109,17 +109,17 @@ async def make_commit_day_time_list(time_zone: str) -> str: sum_week = sum(week_days) day_times = day_times[1:] + day_times[:1] - dt_names = [f"{DAY_TIME_EMOJI[i]} {LM.t(DAY_TIME_NAMES[i])}" for i in range(len(day_times))] + dt_names = [f"{DAY_TIME_EMOJI[i]} {FM.t(DAY_TIME_NAMES[i])}" for i in range(len(day_times))] dt_texts = [f"{day_time} commits" for day_time in day_times] dt_percents = [round((day_time / sum_day) * 100, 2) for day_time in day_times] - title = LM.t("I am an Early") if sum(day_times[0:2]) >= sum(day_times[2:4]) else LM.t("I am a Night") + title = FM.t("I am an Early") if sum(day_times[0:2]) >= sum(day_times[2:4]) else FM.t("I am a Night") stats += f"**{title}** \n\n```text\n{make_list(names=dt_names, texts=dt_texts, percents=dt_percents, top_num=7, sort=False)}\n```\n" if EM.SHOW_DAYS_OF_WEEK: - wd_names = [LM.t(week_day) for week_day in WEEK_DAY_NAMES] + wd_names = [FM.t(week_day) for week_day in WEEK_DAY_NAMES] wd_texts = [f"{week_day} commits" for week_day in week_days] wd_percents = [round((week_day / sum_week) * 100, 2) for week_day in week_days] - title = LM.t("I am Most Productive on") % wd_names[wd_percents.index(max(wd_percents))] + title = FM.t("I am Most Productive on") % wd_names[wd_percents.index(max(wd_percents))] stats += f"๐Ÿ“… **{title}** \n\n```text\n{make_list(names=wd_names, texts=wd_texts, percents=wd_percents, top_num=7, sort=False)}\n```\n" return stats @@ -144,5 +144,5 @@ def make_language_per_repo_list(repositories: Dict) -> str: percents = [round(language_count[lang]["count"] / len(repos_with_language) * 100, 2) for lang in names] top_language = max(list(language_count.keys()), key=lambda x: language_count[x]["count"]) - title = f"**{LM.t('I Mostly Code in') % top_language}** \n\n" if len(repos_with_language) > 0 else "" + title = f"**{FM.t('I Mostly Code in') % top_language}** \n\n" if len(repos_with_language) > 0 else "" return f"{title}```text\n{make_list(names=names, texts=texts, percents=percents)}\n```\n\n" diff --git a/sources/main.py b/sources/main.py index d760b46..92386e4 100644 --- a/sources/main.py +++ b/sources/main.py @@ -10,7 +10,7 @@ from humanize import intword, naturalsize, intcomma from manager_download import init_download_manager, DownloadManager as DM from manager_environment import EnvironmentManager as EM from manager_github import init_github_manager, GitHubManager as GHM -from manager_localization import init_localization_manager, LocalizationManager as LM +from manager_file import init_localization_manager, FileManager as FM from manager_debug import init_debug_manager, DebugManager as DBM from graphics_chart_drawer import create_loc_graph, GRAPH_PATH from yearly_commit_calculator import calculate_yearly_commit_data @@ -33,33 +33,33 @@ async def get_waka_time_stats() -> str: stats += f"{await make_commit_day_time_list(data['data']['timezone'])}\n\n" if EM.SHOW_TIMEZONE or EM.SHOW_LANGUAGE or EM.SHOW_EDITORS or EM.SHOW_PROJECTS or EM.SHOW_OS: - no_activity = LM.t("No Activity Tracked This Week") - stats += f"๐Ÿ“Š **{LM.t('This Week I Spend My Time On')}** \n\n```text\n" + no_activity = FM.t("No Activity Tracked This Week") + stats += f"๐Ÿ“Š **{FM.t('This Week I Spend My Time On')}** \n\n```text\n" if EM.SHOW_TIMEZONE: DBM.i("Adding user timezone info...") time_zone = data["data"]["timezone"] - stats += f"๐Ÿ•‘๏ธŽ {LM.t('Timezone')}: {time_zone}\n\n" + stats += f"๐Ÿ•‘๏ธŽ {FM.t('Timezone')}: {time_zone}\n\n" if EM.SHOW_LANGUAGE: DBM.i("Adding user top languages info...") lang_list = no_activity if len(data["data"]["languages"]) == 0 else make_list(data["data"]["languages"]) - stats += f"๐Ÿ’ฌ {LM.t('Languages')}: \n{lang_list}\n\n" + stats += f"๐Ÿ’ฌ {FM.t('Languages')}: \n{lang_list}\n\n" if EM.SHOW_EDITORS: DBM.i("Adding user editors info...") edit_list = no_activity if len(data["data"]["editors"]) == 0 else make_list(data["data"]["editors"]) - stats += f"๐Ÿ”ฅ {LM.t('Editors')}: \n{edit_list}\n\n" + stats += f"๐Ÿ”ฅ {FM.t('Editors')}: \n{edit_list}\n\n" if EM.SHOW_PROJECTS: DBM.i("Adding user projects info...") project_list = no_activity if len(data["data"]["projects"]) == 0 else make_list(data["data"]["projects"]) - stats += f"๐Ÿฑโ€๐Ÿ’ป {LM.t('Projects')}: \n{project_list}\n\n" + stats += f"๐Ÿฑโ€๐Ÿ’ป {FM.t('Projects')}: \n{project_list}\n\n" if EM.SHOW_OS: DBM.i("Adding user operating systems info...") os_list = no_activity if len(data["data"]["operating_systems"]) == 0 else make_list(data["data"]["operating_systems"]) - stats += f"๐Ÿ’ป {LM.t('operating system')}: \n{os_list}\n\n" + stats += f"๐Ÿ’ป {FM.t('operating system')}: \n{os_list}\n\n" stats = f"{stats[:-1]}```\n\n" @@ -75,20 +75,20 @@ async def get_short_github_info() -> str: :returns: String representation of the info. """ DBM.i("Adding short GitHub info...") - stats = f"**๐Ÿฑ {LM.t('My GitHub Data')}** \n\n" + stats = f"**๐Ÿฑ {FM.t('My GitHub Data')}** \n\n" DBM.i("Adding user disk usage info...") if GHM.USER.disk_usage is None: - disk_usage = LM.t("Used in GitHub's Storage") % "?" + disk_usage = FM.t("Used in GitHub's Storage") % "?" DBM.p("Please add new github personal access token with user permission!") else: - disk_usage = LM.t("Used in GitHub's Storage") % naturalsize(GHM.USER.disk_usage) + disk_usage = FM.t("Used in GitHub's Storage") % naturalsize(GHM.USER.disk_usage) stats += f"> ๐Ÿ“ฆ {disk_usage} \n > \n" data = await DM.get_remote_json("github_stats") DBM.i("Adding contributions info...") if len(data["years"]) > 0: - contributions = LM.t("Contributions in the year") % (intcomma(data["years"][0]["total"]), data["years"][0]["year"]) + contributions = FM.t("Contributions in the year") % (intcomma(data["years"][0]["total"]), data["years"][0]["year"]) stats += f"> ๐Ÿ† {contributions}\n > \n" else: DBM.p("GitHub contributions data unavailable!") @@ -96,23 +96,23 @@ async def get_short_github_info() -> str: DBM.i("Adding opted for hire info...") opted_to_hire = GHM.USER.hireable if opted_to_hire: - stats += f"> ๐Ÿ’ผ {LM.t('Opted to Hire')}\n > \n" + stats += f"> ๐Ÿ’ผ {FM.t('Opted to Hire')}\n > \n" else: - stats += f"> ๐Ÿšซ {LM.t('Not Opted to Hire')}\n > \n" + stats += f"> ๐Ÿšซ {FM.t('Not Opted to Hire')}\n > \n" DBM.i("Adding public repositories info...") public_repo = GHM.USER.public_repos if public_repo != 1: - stats += f"> ๐Ÿ“œ {LM.t('public repositories') % public_repo} \n > \n" + stats += f"> ๐Ÿ“œ {FM.t('public repositories') % public_repo} \n > \n" else: - stats += f"> ๐Ÿ“œ {LM.t('public repository') % public_repo} \n > \n" + stats += f"> ๐Ÿ“œ {FM.t('public repository') % public_repo} \n > \n" DBM.i("Adding private repositories info...") private_repo = GHM.USER.owned_private_repos if GHM.USER.owned_private_repos is not None else 0 if public_repo != 1: - stats += f"> ๐Ÿ”‘ {LM.t('private repositories') % private_repo} \n > \n" + stats += f"> ๐Ÿ”‘ {FM.t('private repositories') % private_repo} \n > \n" else: - stats += f"> ๐Ÿ”‘ {LM.t('private repository') % private_repo} \n > \n" + stats += f"> ๐Ÿ”‘ {FM.t('private repository') % private_repo} \n > \n" DBM.g("Short GitHub info added!") return stats @@ -144,13 +144,13 @@ async def get_stats() -> str: if EM.SHOW_PROFILE_VIEWS: DBM.i("Adding profile views info...") data = GHM.REPO.get_views_traffic(per="week") - stats += f"![Profile Views](http://img.shields.io/badge/{quote(LM.t('Profile Views'))}-{data['count']}-blue)\n\n" + stats += f"![Profile Views](http://img.shields.io/badge/{quote(FM.t('Profile Views'))}-{data['count']}-blue)\n\n" if EM.SHOW_LINES_OF_CODE: DBM.i("Adding lines of code info...") total_loc = sum([yearly_data[y][q][d] for y in yearly_data.keys() for q in yearly_data[y].keys() for d in yearly_data[y][q].keys()]) - data = f"{intword(total_loc)} {LM.t('Lines of code')}" - stats += f"![Lines of code](https://img.shields.io/badge/{quote(LM.t('From Hello World I have written'))}-{quote(data)}-blue)\n\n" + data = f"{intword(total_loc)} {FM.t('Lines of code')}" + stats += f"![Lines of code](https://img.shields.io/badge/{quote(FM.t('From Hello World I have written'))}-{quote(data)}-blue)\n\n" if EM.SHOW_SHORT_INFO: stats += await get_short_github_info() @@ -165,7 +165,7 @@ async def get_stats() -> str: await create_loc_graph(yearly_data, GRAPH_PATH) GHM.update_chart(GRAPH_PATH) chart_path = f"{GHM.USER.login}/{GHM.USER.login}/{GHM.branch()}/{GRAPH_PATH}" - stats += f"**{LM.t('Timeline')}**\n\n![Lines of Code chart](https://raw.githubusercontent.com/{chart_path})\n\n" + stats += f"**{FM.t('Timeline')}**\n\n![Lines of Code chart](https://raw.githubusercontent.com/{chart_path})\n\n" if EM.SHOW_UPDATED_DATE: DBM.i("Adding last updated time...") diff --git a/sources/manager_localization.py b/sources/manager_file.py similarity index 53% rename from sources/manager_localization.py rename to sources/manager_file.py index 497ec2e..b6fb39d 100644 --- a/sources/manager_localization.py +++ b/sources/manager_file.py @@ -10,10 +10,10 @@ def init_localization_manager(): Initialize localization manager. Load GUI translations JSON file. """ - LocalizationManager.load_localization("translation.json") + FileManager.load_localization("translation.json") -class LocalizationManager: +class FileManager: """ Class for handling localization (and maybe other file IO in future). Stores localization in dictionary. @@ -28,9 +28,9 @@ class LocalizationManager: :param file: Localization file path, related to current file (in sources root). """ - with open(join(dirname(__file__), file), encoding="utf-8") as config_file: + with open(join("sources", file), encoding="utf-8") as config_file: data = load(config_file) - LocalizationManager._LOCALIZATION = data[EM.LOCALE] + FileManager._LOCALIZATION = data[EM.LOCALE] @staticmethod def t(key: str) -> str: @@ -40,4 +40,18 @@ class LocalizationManager: :param key: Localization key. :returns: Translation string. """ - return LocalizationManager._LOCALIZATION[key] + return FileManager._LOCALIZATION[key] + + @staticmethod + def write_file(name: str, content: str, append: bool = False, assets: bool = False): + """ + Save output file. + + :param name: File name. + :param content: File content (utf-8 string). + :param append: True for appending to file, false for rewriting. + :param assets: True for saving to 'assets' directory, false otherwise. + """ + name = join(name, "assets") if assets else name + with open(name, "a" if append else "w", encoding="utf-8") as file: + file.write(content) diff --git a/sources/manager_github.py b/sources/manager_github.py index 89cec06..0f1660e 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -7,6 +7,7 @@ from string import ascii_letters from github import Github, AuthenticatedUser, Repository, ContentFile, InputGitAuthor, UnknownObjectException from manager_environment import EnvironmentManager as EM +from manager_file import FileManager as FM from manager_debug import DebugManager as DBM @@ -117,10 +118,7 @@ class GitHubManager: prefix = "README stats current output:" eol = "".join(choice(ascii_letters) for _ in range(10)) - with open(environ["GITHUB_OUTPUT"], "a") as fh: - fh.write(f"README_CONTENT<<{eol}\n") - fh.write(f"{prefix}\n\n{stats}\n") - fh.write(f"{eol}\n") + FM.write_file(environ["GITHUB_OUTPUT"], f"README_CONTENT<<{eol}\n{prefix}\n\n{stats}\n{eol}\n", append=True) DBM.g("Action output set!") diff --git a/sources/yearly_commit_calculator.py b/sources/yearly_commit_calculator.py index 49bce72..cc52f40 100644 --- a/sources/yearly_commit_calculator.py +++ b/sources/yearly_commit_calculator.py @@ -1,3 +1,4 @@ +from json import dumps from re import search from datetime import datetime from typing import Dict @@ -5,6 +6,7 @@ from typing import Dict from manager_download import DownloadManager as DM from manager_environment import EnvironmentManager as EM from manager_github import GitHubManager as GHM +from manager_file import FileManager as FM from manager_debug import DebugManager as DBM @@ -19,12 +21,16 @@ async def calculate_yearly_commit_data(repositories: Dict) -> Dict: DBM.i("Calculating yearly commit data...") yearly_data = dict() total = len(repositories["data"]["user"]["repositories"]["nodes"]) + for ind, repo in enumerate(repositories["data"]["user"]["repositories"]["nodes"]): if repo["name"] not in EM.IGNORED_REPOS: repo_name = "private" if repo["isPrivate"] else f"{repo['owner']['login']}/{repo['name']}" DBM.i(f"\t{ind + 1}/{total} Retrieving repo: {repo_name}") await update_yearly_data_with_commit_stats(repo, yearly_data) DBM.g("Yearly commit data calculated!") + + if EM.DEBUG_RUN: + FM.write_file("yearly_data.json", dumps(yearly_data), assets=True) return yearly_data From 38a74e3a740669cf911e0fc0507e8743e65d991e Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 12:23:28 +0100 Subject: [PATCH 26/38] file path join fixed --- sources/manager_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/manager_file.py b/sources/manager_file.py index b6fb39d..20248ab 100644 --- a/sources/manager_file.py +++ b/sources/manager_file.py @@ -52,6 +52,6 @@ class FileManager: :param append: True for appending to file, false for rewriting. :param assets: True for saving to 'assets' directory, false otherwise. """ - name = join(name, "assets") if assets else name + name = join("assets", name) if assets else name with open(name, "a" if append else "w", encoding="utf-8") as file: file.write(content) From cd6377a956bf985488fa5b0effc714725026d5ef Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 12:45:17 +0100 Subject: [PATCH 27/38] inlining LOC chart --- sources/manager_file.py | 2 +- sources/manager_github.py | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sources/manager_file.py b/sources/manager_file.py index 20248ab..741b681 100644 --- a/sources/manager_file.py +++ b/sources/manager_file.py @@ -1,5 +1,5 @@ from json import load -from os.path import join, dirname +from os.path import join from typing import Dict from manager_environment import EnvironmentManager as EM diff --git a/sources/manager_github.py b/sources/manager_github.py index 0f1660e..2b7c1e7 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -1,4 +1,4 @@ -from base64 import b64decode +from base64 import b64decode, b64encode from os import environ from random import choice from re import sub @@ -123,20 +123,33 @@ class GitHubManager: DBM.g("Action output set!") @staticmethod - def update_chart(chart_path: str): + def update_chart(chart_path: str) -> str: """ Updates lines of code chart. + Inlines data into readme if in debug mode, commits otherwise. Uses commit author, commit message and branch name specified by environmental variables. :param chart_path: path to saved lines of code chart. + :returns: string to add to README file. """ DBM.i("Updating lines of code chart...") with open(chart_path, "rb") as input_file: data = input_file.read() - try: - contents = GitHubManager.REPO.get_contents(chart_path) - GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author()) - DBM.g("Lines of code chart updated!") - except UnknownObjectException: - GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author()) - DBM.g("Lines of code chart created!") + + if not EM.DEBUG_RUN: + DBM.i("Pushing chart to repo...") + chart_path = f"https://raw.githubusercontent.com/{GitHubManager.USER.login}/{GitHubManager.USER.login}/{GitHubManager.branch()}/{chart_path}" + + try: + contents = GitHubManager.REPO.get_contents(chart_path) + GitHubManager.REPO.update_file(contents.path, "Charts Updated", data, contents.sha, committer=GitHubManager._get_author()) + DBM.g("Lines of code chart updated!") + except UnknownObjectException: + GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author()) + DBM.g("Lines of code chart created!") + + else: + DBM.i("Inlining chart...") + chart_path = f"data:image/png;base64,{b64encode(data)}" + + return f"**{FM.t('Timeline')}**\n\n![Lines of Code chart]({chart_path})\n\n" From cdb2dabb462bdce78333232f024602785969f58f Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 12:45:47 +0100 Subject: [PATCH 28/38] main reference added --- sources/main.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sources/main.py b/sources/main.py index 92386e4..602bef7 100644 --- a/sources/main.py +++ b/sources/main.py @@ -163,9 +163,7 @@ async def get_stats() -> str: if EM.SHOW_LOC_CHART: await create_loc_graph(yearly_data, GRAPH_PATH) - GHM.update_chart(GRAPH_PATH) - chart_path = f"{GHM.USER.login}/{GHM.USER.login}/{GHM.branch()}/{GRAPH_PATH}" - stats += f"**{FM.t('Timeline')}**\n\n![Lines of Code chart](https://raw.githubusercontent.com/{chart_path})\n\n" + stats += GHM.update_chart(GRAPH_PATH) if EM.SHOW_UPDATED_DATE: DBM.i("Adding last updated time...") From 816d50aac7e1b7deaa726d530cbe8015fb3913cf Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 12:50:04 +0100 Subject: [PATCH 29/38] bytes decoding added --- sources/manager_github.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 2b7c1e7..8d963f3 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -150,6 +150,6 @@ class GitHubManager: else: DBM.i("Inlining chart...") - chart_path = f"data:image/png;base64,{b64encode(data)}" + chart_path = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" return f"**{FM.t('Timeline')}**\n\n![Lines of Code chart]({chart_path})\n\n" From aa55876b781c1ddda63c71e0cc47dbd552b8e64e Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:30:38 +0100 Subject: [PATCH 30/38] embedding fallback :( --- sources/manager_github.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 8d963f3..69220dc 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -147,9 +147,10 @@ class GitHubManager: except UnknownObjectException: GitHubManager.REPO.create_file(chart_path, "Charts Added", data, committer=GitHubManager._get_author()) DBM.g("Lines of code chart created!") + return f"**{FM.t('Timeline')}**\n\n![Lines of Code chart]({chart_path})\n\n" else: DBM.i("Inlining chart...") - chart_path = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" - - return f"**{FM.t('Timeline')}**\n\n![Lines of Code chart]({chart_path})\n\n" + hint = f"You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated image." + encoded_image = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" + return f"
\n\tBase64 encoded image\n\t```\t\n{encoded_image}\t\n```
\n\n{hint}" From 6a3c175169a728a4161dc35f566f82723a1a3906 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:34:28 +0100 Subject: [PATCH 31/38] lint and section header --- sources/manager_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 69220dc..62ea054 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -151,6 +151,6 @@ class GitHubManager: else: DBM.i("Inlining chart...") - hint = f"You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated image." + hint = "You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated base64 image." encoded_image = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" - return f"
\n\tBase64 encoded image\n\t```\t\n{encoded_image}\t\n```
\n\n{hint}" + return f"
\n {hint}\n ```\n {encoded_image}\n ```
\n" From cf7fcd7c965987aad3e7cd677ebfd81500dff474 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:39:01 +0100 Subject: [PATCH 32/38] html tags instead of md used --- sources/manager_github.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 62ea054..cdb5914 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -151,6 +151,6 @@ class GitHubManager: else: DBM.i("Inlining chart...") - hint = "You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated base64 image." + hint = 'You can use this website to view the generated base64 image.' encoded_image = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" - return f"
\n {hint}\n ```\n {encoded_image}\n ```
\n" + return f"
\n {hint}\n {encoded_image}\n
\n" From 03d0a9a91b98a16bb4c7ec75001a7800aa564c57 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:43:53 +0100 Subject: [PATCH 33/38] multiline code block used --- sources/manager_github.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index cdb5914..511c6d8 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -151,6 +151,5 @@ class GitHubManager: else: DBM.i("Inlining chart...") - hint = 'You can use this website to view the generated base64 image.' - encoded_image = f"data:image/png;base64,{b64encode(data).decode('utf-8')}" - return f"
\n {hint}\n {encoded_image}\n
\n" + hint = "You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated base64 image." + return f"{hint}\n```\n\tdata:image/png;base64,{b64encode(data).decode('utf-8')}\n```\n\n" From fa4fb9be362ec0eca56e5b61fc8c1264ab580bfd Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:45:48 +0100 Subject: [PATCH 34/38] unnecessary tab removed --- sources/manager_github.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/manager_github.py b/sources/manager_github.py index 511c6d8..8bff82a 100644 --- a/sources/manager_github.py +++ b/sources/manager_github.py @@ -152,4 +152,4 @@ class GitHubManager: else: DBM.i("Inlining chart...") hint = "You can use [this website](https://codebeautify.org/base64-to-image-converter) to view the generated base64 image." - return f"{hint}\n```\n\tdata:image/png;base64,{b64encode(data).decode('utf-8')}\n```\n\n" + return f"{hint}\n```\ndata:image/png;base64,{b64encode(data).decode('utf-8')}\n```\n\n" From 2b26d2e9360a63ce56841a34ec919e826561ea58 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 13:56:48 +0100 Subject: [PATCH 35/38] docker build cache enabled --- .github/workflows/build_image.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_image.yml b/.github/workflows/build_image.yml index 338f66e..615534c 100644 --- a/.github/workflows/build_image.yml +++ b/.github/workflows/build_image.yml @@ -39,3 +39,5 @@ jobs: push: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/releases') }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max From 21168a6ed5e8eeb9d560e435349eeedcb1067b89 Mon Sep 17 00:00:00 2001 From: pseusys Date: Sun, 26 Feb 2023 14:01:39 +0100 Subject: [PATCH 36/38] docker build setup added --- .github/workflows/build_image.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build_image.yml b/.github/workflows/build_image.yml index 615534c..80b5ebb 100644 --- a/.github/workflows/build_image.yml +++ b/.github/workflows/build_image.yml @@ -16,6 +16,9 @@ jobs: - name: Checkout ๐Ÿ›Ž๏ธ uses: actions/checkout@v3 + - name: Set up Docker Buildx ๐Ÿ‹ + uses: docker/setup-buildx-action@v2 + - name: Log in to the container registry ๐Ÿšช uses: docker/login-action@v2 with: From efbdaa0ca4159d1cd607f61b6331015fcd6acaef Mon Sep 17 00:00:00 2001 From: Aravind Nair <22199259+aravindvnair99@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:32:54 +0530 Subject: [PATCH 37/38] Update and rename review_pr.yml to ci.yml --- .github/workflows/{review_pr.yml => ci.yml} | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) rename .github/workflows/{review_pr.yml => ci.yml} (88%) diff --git a/.github/workflows/review_pr.yml b/.github/workflows/ci.yml similarity index 88% rename from .github/workflows/review_pr.yml rename to .github/workflows/ci.yml index a24fc7d..dd6492e 100644 --- a/.github/workflows/review_pr.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,15 @@ -name: REVIEW_PULL_REQUEST +name: CI on: pull_request: - types: [ opened, edited, reopened, synchronize ] - paths: - - 'sources/**' - - 'requirements.txt' - - '.github/workflows/review_pr.yml' + workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/dev' }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true jobs: - publish-server-image: + ci: name: Run Test and Review PR runs-on: ubuntu-latest From 42e1f0e3a5c0388e1fbc53801797bd346507ee7b Mon Sep 17 00:00:00 2001 From: Aravind Nair <22199259+aravindvnair99@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:34:38 +0530 Subject: [PATCH 38/38] Update ci.yml --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd6492e..57455e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,8 +54,8 @@ jobs: INPUT_SHOW_LANGUAGE_PER_REPO: True INPUT_SHOW_UPDATED_DATE: True INPUT_COMMIT_BY_ME: True - INPUT_DEBUG_LOGGING: True # This is for testing purpose only not for production - DEBUG_RUN: True # This is for testing purpose only not for production + INPUT_DEBUG_LOGGING: True # Not for prod + DEBUG_RUN: True # Not for prod run: python3 sources/main.py - name: Save Branch Name Without Slashes ๐Ÿ“›