From 9129c1fa076cf431ad693eb3b0a774138e2da839 Mon Sep 17 00:00:00 2001 From: Gamingdy Date: Mon, 28 Sep 2026 21:41:23 +0200 Subject: [PATCH 1/6] feat: created a script to update readme with contributors and latest tag --- .github/scripts/update_readme.py | 195 ++++++++++++++++++++++++++++ .github/workflows/update-readme.yml | 52 ++++++++ README.md | 32 ++--- 3 files changed, 264 insertions(+), 15 deletions(-) create mode 100644 .github/scripts/update_readme.py create mode 100644 .github/workflows/update-readme.yml diff --git a/.github/scripts/update_readme.py b/.github/scripts/update_readme.py new file mode 100644 index 0000000..f464721 --- /dev/null +++ b/.github/scripts/update_readme.py @@ -0,0 +1,195 @@ +import json +import os +import re +import subprocess +import urllib.request +from pathlib import Path + +README = Path("README.md") + +CONTRIBUTORS_START = "" +CONTRIBUTORS_END = "" + +VERSION_START = "" +VERSION_END = "" + +GITHUB_REPOSITORY = os.environ["GITHUB_REPOSITORY"] + + +def github_api(url: str): + request = urllib.request.Request( + url, + headers={ + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2026-03-10", + "User-Agent": "README-metadata-updater", + }, + ) + + with urllib.request.urlopen(request) as response: + return json.load(response) + + +def get_contributors(): + """Fetch all repository collaborators, handling pagination.""" + contributors = [] + page = 1 + + while True: + url = ( + f"https://api.github.com/repos/" + f"{GITHUB_REPOSITORY}/contributors" + f"?per_page=100&page={page}" + ) + + users = github_api(url) + + if not users: + break + + contributors.extend(users) + + if len(users) < 100: + break + + page += 1 + + return contributors + + +def generate_contributors(contributors): + """Generate the Markdown for the collaborators.""" + contributors.sort( + key=lambda user: user["login"].lower() + ) + + entries = [] + + for user in contributors: + login = user["login"].capitalize() + avatar_url = user["avatar_url"] + profile_url = user["html_url"] + + entries.append( + f' ' + f'[{login}]({profile_url})' + ) + + return ", ".join(entries) + + +def get_latest_tag(): + """ + Return the highest version tag according to Git's version sorting. + + Examples: + v1.10.0 > v1.9.0 + v2.0.0 > v1.99.0 + """ + + result = subprocess.run( + [ + "git", + "tag", + "--sort=-v:refname", + ], + capture_output=True, + text=True, + check=True, + ) + + tags = [ + tag.strip() + for tag in result.stdout.splitlines() + if tag.strip() + ] + + if not tags: + raise RuntimeError("No Git tags found.") + + return tags[0] + + +def replace_section( + content: str, + start_marker: str, + end_marker: str, + replacement: str, +): + """Replace the content between two README markers.""" + + pattern = ( + re.escape(start_marker) + + r".*?" + + re.escape(end_marker) + ) + + replacement_text = ( + f"{start_marker} " + f"{replacement} " + f"{end_marker}" + ) + + updated, count = re.subn( + pattern, + replacement_text, + content, + count=1, + flags=re.DOTALL, + ) + + if count != 1: + raise RuntimeError( + f"Could not find README markers:\n" + f"{start_marker}\n" + f"...\n" + f"{end_marker}" + ) + + return updated + + +def main(): + if not README.exists(): + raise FileNotFoundError("README.md not found.") + + content = README.read_text(encoding="utf-8") + + # Fetch contributors once. + contributors_data = get_contributors() + contributors = generate_contributors(contributors_data) + + # Get the latest version tag. + latest_tag = get_latest_tag() + + # Update contributors. + content = replace_section( + content, + CONTRIBUTORS_START, + CONTRIBUTORS_END, + contributors, + ) + + # Update version. + content = replace_section( + content, + VERSION_START, + VERSION_END, + latest_tag, + ) + + README.write_text( + content, + encoding="utf-8", + ) + + print( + f"Found {len(contributors_data)} contributors." + ) + print(f"Latest tag: {latest_tag}") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml new file mode 100644 index 0000000..78dbab9 --- /dev/null +++ b/.github/workflows/update-readme.yml @@ -0,0 +1,52 @@ +name: Update README metadata + +on: + push: + tags: + - "*" + + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-readme: + runs-on: ubuntu-latest + + steps: + - name: Checkout default branch + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.repository.default_branch }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Fetch all tags + run: git fetch --tags --force + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.x" + + - name: Update README + env: + GITHUB_REPOSITORY: ${{ github.repository }} + run: python .github/scripts/update_readme.py + + - name: Commit README changes + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add README.md + + if git diff --cached --quiet; then + echo "README is already up to date." + exit 0 + fi + + git commit -m "docs: update README metadata" + + git push origin HEAD:${{ github.event.repository.default_branch }} \ No newline at end of file diff --git a/README.md b/README.md index 03d3896..dcbee29 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

-
+ Image showing Graven development discord logo
DJ4H
This project is under the GNU GPL v3 license

@@ -17,11 +17,11 @@ Most of the contributors are part of the staff but the members are also allowed ## Global information -| Global information | | -|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Description | DJ4H is a Discord bot designed to enhance server engagement. It includes features for tracking activity engagement, providing a dynamic and interactive experience for communities. | -| Collaborators | drawing [Gamingdy](https://github.com/Gamingdy), drawing [Lindwen](https://github.com/Lindwen), drawing [Loïc R](https://github.com/Lramelot), drawing [GabHas](https://github.com/TheRealGabHas), drawing [AntoineJT](https://github.com/AntoineJT) | -| Version | 1.0.0 | +| Global information | | +|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Description | DJ4H is a Discord bot designed to enhance server engagement. It includes features for tracking activity engagement, providing a dynamic and interactive experience for communities. | +| Contributors | Alessevan [Alessevan](https://github.com/Alessevan), Alexandre-josepavel [Alexandre-josepavel](https://github.com/alexandre-josepavel), Antoinejt [Antoinejt](https://github.com/AntoineJT), Dependabot[bot] [Dependabot[bot]](https://github.com/apps/dependabot), Flenderrax [Flenderrax](https://github.com/FlenderrAX), Gamingdy [Gamingdy](https://github.com/gamingdy), Lindwen [Lindwen](https://github.com/Lindwen), Lramelot [Lramelot](https://github.com/Lramelot), Mityno [Mityno](https://github.com/Mityno), Redstom [Redstom](https://github.com/RedsTom), Renovate[bot] [Renovate[bot]](https://github.com/apps/renovate), Therealgabhas [Therealgabhas](https://github.com/TheRealGabHas) | +| Version | v1.5.4 | --- @@ -59,18 +59,18 @@ Required command parameters are shown in brackets (`[required]`) while optional ### Configuration (Admin only) -| Command | Description | -| --- | --- | +| Command | Description | +|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------| | `/config [channel] [delay]` | Sets the game channel and the required delay to score a point. Time prefixes: `s` (seconds), `m` (minutes), `h` (hours), `d` (days). | -| `/set [member] [score]` | Sets a member's score to the specified value. | -| `/dump_log` | Retrieves the bot's log file. | +| `/set [member] [score]` | Sets a member's score to the specified value. | +| `/dump_log` | Retrieves the bot's log file. | ### Player -| Command | Description | -| --- | --- | +| Command | Description | +|----------------|--------------------------------------------| | `/leaderboard` | Displays an image with the top 10 players. | -| `/score` | Shows your own score. | +| `/score` | Shows your own score. | ## Installation @@ -97,7 +97,8 @@ Required command parameters are shown in brackets (`[required]`) while optional cp .env.example .env ``` -Then fill in `BOT_TOKEN`. Every variable is documented in `.env.example`; the commented-out ones are optional and show their default value. +Then fill in `BOT_TOKEN`. Every variable is documented in `.env.example`; the commented-out ones are optional and show +their default value. ## Usage @@ -116,6 +117,7 @@ docker compose -f compose.prod.yaml up -d ``` Make a deployment + ```bash # clone repository git checkout master @@ -148,7 +150,7 @@ DJ4H/ ├── config.py # Configuration and logging ├── commands/ # Discord commands │ ├── cogs/game.py # /leaderboard and /score commands -�� └── handler/events.py # Main game logic +│ └── handler/events.py # Main game logic ├── utils/ │ ├── database/ # Database layer │ │ ├── connection.py # SQLite connection From 19a2f36bfdc8f96ee8bde4db800af9dc132fca14 Mon Sep 17 00:00:00 2001 From: Gamingdy Date: Wed, 30 Sep 2026 23:37:56 +0200 Subject: [PATCH 2/6] fix: set user_id and guild_id primary between them, so an user can be on multiple jd4h leaderboard --- ...298b0_fix_guild_id_and_user_id_primary_.py | 55 +++++++++++++++++++ config.py | 3 +- main.py | 2 +- utils/database/schema.py | 2 +- 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 alembic/versions/534babd298b0_fix_guild_id_and_user_id_primary_.py diff --git a/alembic/versions/534babd298b0_fix_guild_id_and_user_id_primary_.py b/alembic/versions/534babd298b0_fix_guild_id_and_user_id_primary_.py new file mode 100644 index 0000000..c441904 --- /dev/null +++ b/alembic/versions/534babd298b0_fix_guild_id_and_user_id_primary_.py @@ -0,0 +1,55 @@ +"""Fix guild_id and user_id primary between them for jd4h + +Revision ID: 534babd298b0 +Revises: c818d80153fa +Create Date: 2026-09-30 23:29:56.655212 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = '534babd298b0' +down_revision: Union[str, Sequence[str], None] = 'c818d80153fa' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_table( + "users_new", + sa.Column("user_id", sa.BigInteger(), nullable=False), + sa.Column("guild_id", sa.BigInteger(), nullable=False), + sa.Column("score", sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint("user_id", "guild_id"), + ) + + op.execute(""" + INSERT INTO users_new (user_id, guild_id, score) + SELECT user_id, guild_id, score + FROM users + """) + + op.drop_table("users") + op.rename_table("users_new", "users") + + +def downgrade() -> None: + op.create_table( + "users_old", + sa.Column("user_id", sa.BigInteger(), nullable=False), + sa.Column("guild_id", sa.BigInteger(), nullable=False), + sa.Column("score", sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint("user_id"), + ) + + op.execute(""" + INSERT INTO users_old (user_id, guild_id, score) + SELECT user_id, guild_id, score + FROM users + """) + + op.drop_table("users") + op.rename_table("users_old", "users") diff --git a/config.py b/config.py index e8deb9c..fe0e4fe 100644 --- a/config.py +++ b/config.py @@ -11,11 +11,10 @@ env_debug_guild_id = os.getenv("DEBUG_GUILD_ID", None) try: - DEBUG_GUILD_ID = int(env_debug_guild_id) if env_debug_guild_id is not None else 0 + DEBUG_GUILD_ID = [int(env_debug_guild_id)] if env_debug_guild_id is not None else 0 except ValueError: raise ValueError("DEBUG_GUILD_ID must be an integer representing a guild ID.") - DATABASE_PATH = os.getenv("DATABASE_PATH", "dj4h.db") MAGIC_COLOR = 5220337 # RNGdle sync interval in seconds (default 12 * 60 * 60s = 12 hours) diff --git a/main.py b/main.py index 069df7b..abd7afa 100644 --- a/main.py +++ b/main.py @@ -14,7 +14,7 @@ bot = discord.AutoShardedBot( intents=discord.Intents.default(), help_command=None, # Disable the default help command - debug_guilds=[DEBUG_GUILD_ID] if DEBUG_GUILD_ID else None, + debug_guilds=DEBUG_GUILD_ID if DEBUG_GUILD_ID else None, ) diff --git a/utils/database/schema.py b/utils/database/schema.py index ffbbead..b4163f9 100644 --- a/utils/database/schema.py +++ b/utils/database/schema.py @@ -24,7 +24,7 @@ class User(Base): __tablename__ = "users" user_id = Column(BigInteger, primary_key=True, nullable=False) - guild_id = Column(BigInteger, nullable=False) + guild_id = Column(BigInteger, primary_key=True, nullable=False) score = Column(BigInteger, nullable=False) From 3fc781f2395f966276f5891f9c642981611f6af6 Mon Sep 17 00:00:00 2001 From: Gamingdy Date: Wed, 30 Sep 2026 23:46:11 +0200 Subject: [PATCH 3/6] feat: added dependabot rule to ignore python update and only go notify for version patch --- .github/dependabot.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ae1ecfe..ce02597 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,14 +6,19 @@ updates: interval: "weekly" cooldown: default-days: 7 - + - package-ecosystem: "docker" directory: "/" schedule: interval: "daily" cooldown: default-days: 7 - + ignore: + - dependency-name: "python" + update-types: + - "version-update:semver-minor" + - "version-update:semver-major" + - package-ecosystem: "pip" directory: "/" schedule: From c8bfc6c1f21f498f32312c2ab10fbdb0c95c3baa Mon Sep 17 00:00:00 2001 From: Gamingdy Date: Wed, 30 Sep 2026 23:58:43 +0200 Subject: [PATCH 4/6] style: black reformat --- .github/scripts/update_readme.py | 43 +++++++++----------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/.github/scripts/update_readme.py b/.github/scripts/update_readme.py index f464721..0179eb8 100644 --- a/.github/scripts/update_readme.py +++ b/.github/scripts/update_readme.py @@ -58,10 +58,8 @@ def get_contributors(): def generate_contributors(contributors): - """Generate the Markdown for the collaborators.""" - contributors.sort( - key=lambda user: user["login"].lower() - ) + """Generate the Markdown for the contributors.""" + contributors.sort(key=lambda user: user["login"].lower()) entries = [] @@ -74,7 +72,7 @@ def generate_contributors(contributors): f' ' - f'[{login}]({profile_url})' + f"[{login}]({profile_url})" ) return ", ".join(entries) @@ -100,11 +98,7 @@ def get_latest_tag(): check=True, ) - tags = [ - tag.strip() - for tag in result.stdout.splitlines() - if tag.strip() - ] + tags = [tag.strip() for tag in result.stdout.splitlines() if tag.strip()] if not tags: raise RuntimeError("No Git tags found.") @@ -113,24 +107,16 @@ def get_latest_tag(): def replace_section( - content: str, - start_marker: str, - end_marker: str, - replacement: str, + content: str, + start_marker: str, + end_marker: str, + replacement: str, ): """Replace the content between two README markers.""" - pattern = ( - re.escape(start_marker) - + r".*?" - + re.escape(end_marker) - ) + pattern = re.escape(start_marker) + r".*?" + re.escape(end_marker) - replacement_text = ( - f"{start_marker} " - f"{replacement} " - f"{end_marker}" - ) + replacement_text = f"{start_marker} {replacement} {end_marker}" updated, count = re.subn( pattern, @@ -142,10 +128,7 @@ def replace_section( if count != 1: raise RuntimeError( - f"Could not find README markers:\n" - f"{start_marker}\n" - f"...\n" - f"{end_marker}" + f"Could not find README markers:\n" f"{start_marker}\n" f"...\n" f"{end_marker}" ) return updated @@ -185,9 +168,7 @@ def main(): encoding="utf-8", ) - print( - f"Found {len(contributors_data)} contributors." - ) + print(f"Found {len(contributors_data)} contributors.") print(f"Latest tag: {latest_tag}") From a0eab3831ff6462ae296c2721474dbb07562b497 Mon Sep 17 00:00:00 2001 From: Gamingdy Date: Thu, 1 Oct 2026 00:22:39 +0200 Subject: [PATCH 5/6] feat: added a condition to ignore bot account for readme update --- .github/scripts/update_readme.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/scripts/update_readme.py b/.github/scripts/update_readme.py index 0179eb8..f50c1ca 100644 --- a/.github/scripts/update_readme.py +++ b/.github/scripts/update_readme.py @@ -64,6 +64,8 @@ def generate_contributors(contributors): entries = [] for user in contributors: + if user.get("type") == "Bot": + continue login = user["login"].capitalize() avatar_url = user["avatar_url"] profile_url = user["html_url"] From 8b60485e623f3ac41ae27c7cb45895d4925e8f7f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Sep 2026 22:42:51 +0000 Subject: [PATCH 6/6] docs: update README metadata --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dcbee29..0478542 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ Most of the contributors are part of the staff but the members are also allowed | Global information | | |--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Description | DJ4H is a Discord bot designed to enhance server engagement. It includes features for tracking activity engagement, providing a dynamic and interactive experience for communities. | -| Contributors | Alessevan [Alessevan](https://github.com/Alessevan), Alexandre-josepavel [Alexandre-josepavel](https://github.com/alexandre-josepavel), Antoinejt [Antoinejt](https://github.com/AntoineJT), Dependabot[bot] [Dependabot[bot]](https://github.com/apps/dependabot), Flenderrax [Flenderrax](https://github.com/FlenderrAX), Gamingdy [Gamingdy](https://github.com/gamingdy), Lindwen [Lindwen](https://github.com/Lindwen), Lramelot [Lramelot](https://github.com/Lramelot), Mityno [Mityno](https://github.com/Mityno), Redstom [Redstom](https://github.com/RedsTom), Renovate[bot] [Renovate[bot]](https://github.com/apps/renovate), Therealgabhas [Therealgabhas](https://github.com/TheRealGabHas) | -| Version | v1.5.4 | +| Contributors | Alessevan [Alessevan](https://github.com/Alessevan), Alexandre-josepavel [Alexandre-josepavel](https://github.com/alexandre-josepavel), Antoinejt [Antoinejt](https://github.com/AntoineJT), Flenderrax [Flenderrax](https://github.com/FlenderrAX), Gamingdy [Gamingdy](https://github.com/gamingdy), Lindwen [Lindwen](https://github.com/Lindwen), Lramelot [Lramelot](https://github.com/Lramelot), Mityno [Mityno](https://github.com/Mityno), Redstom [Redstom](https://github.com/RedsTom), Therealgabhas [Therealgabhas](https://github.com/TheRealGabHas) | +| Version | v1.5.5 | ---