Skip to content

Commit

Permalink
Modernize codebase (#34)
Browse files Browse the repository at this point in the history
* Switch to a trunk-based release

* Include Nanika's shutdown handlers

* Update `?about` with fresh info

* Rename `HajPages` to `RoboPages`

This is for consistency with `RoboView` and others. Plus, Haj is an internal reference to a dear mentor of mine

* Include basic help command

* Move `DevTools` cog into `Admin`

* Include Catherine-Chan's reload-all command

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Align to best practices

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Check if docker env and send diff revision text

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Include requirements.txt

* Upgrade Dockerfile to 3.12 and remove poetry installation

* Fix `?about` command not working on Docker

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add ping command

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fix logging not working for files

* Update .gitignore

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
No767 and pre-commit-ci[bot] authored Jan 3, 2024
1 parent aff9334 commit e5269c7
Show file tree
Hide file tree
Showing 19 changed files with 634 additions and 160 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ celerybeat.pid
.venv
env/
venv/
rodhaj-venv/
ENV/
env.bak/
venv.bak/
Expand Down
4 changes: 2 additions & 2 deletions bot/cogs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ class VersionInfo(NamedTuple):
major: int
minor: int
micro: int
releaselevel: Literal["alpha", "beta", "final"]
releaselevel: Literal["main", "alpha", "beta", "final"]

def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.micro}-{self.releaselevel}"


EXTENSIONS = [module.name for module in iter_modules(__path__, f"{__package__}.")]
VERSION: VersionInfo = VersionInfo(major=0, minor=1, micro=0, releaselevel="alpha")
VERSION: VersionInfo = VersionInfo(major=0, minor=1, micro=0, releaselevel="main")
184 changes: 184 additions & 0 deletions bot/cogs/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import asyncio
import importlib
import os
import re
import subprocess # nosec # We already know this is dangerous, but it's needed
import sys
from typing import Literal, Optional

import discord
from discord.ext import commands
from discord.ext.commands import Greedy
from libs.utils import RoboContext
from rodhaj import Rodhaj

GIT_PULL_REGEX = re.compile(r"\s+(?P<filename>.*)\b\s+\|\s+[\d]")


class Admin(commands.Cog, command_attrs=dict(hidden=True)):
"""Administrative commands for Rodhaj"""

def __init__(self, bot: Rodhaj) -> None:
self.bot = bot

@property
def display_emoji(self) -> discord.PartialEmoji:
return discord.PartialEmoji(name="\U00002699")

async def cog_check(self, ctx: RoboContext) -> bool:
return await self.bot.is_owner(ctx.author)

async def reload_or_load_extension(self, module: str) -> None:
try:
await self.bot.reload_extension(module)
except commands.ExtensionNotLoaded:
await self.bot.load_extension(module)

def find_modules_from_git(self, output: str) -> list[tuple[int, str]]:
files = GIT_PULL_REGEX.findall(output)
ret: list[tuple[int, str]] = []
for file in files:
root, ext = os.path.splitext(file)
if ext != ".py" or root.endswith("__init__"):
continue

true_root = ".".join(root.split("/")[1:])

if true_root.startswith("cogs") or true_root.startswith("libs"):
# A subdirectory within these are a part of the codebase

ret.append((true_root.count(".") + 1, true_root))

# For reload order, the submodules should be reloaded first
ret.sort(reverse=True)
return ret

async def run_process(self, command: str) -> list[str]:
process = await asyncio.create_subprocess_shell(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
result = await process.communicate()

return [output.decode() for output in result]

def tick(self, opt: Optional[bool], label: Optional[str] = None) -> str:
lookup = {
True: "\U00002705",
False: "\U0000274c",
None: "\U000023e9",
}
emoji = lookup.get(opt, "\U0000274c")
if label is not None:
return f"{emoji}: {label}"
return emoji

def format_results(self, statuses: list) -> str:
desc = "\U00002705 - Successful reload | \U0000274c - Failed reload | \U000023e9 - Skipped\n\n"
status = "\n".join(f"- {status}: `{module}`" for status, module in statuses)
desc += status
return desc

async def reload_exts(self, module: str) -> list[tuple[str, str]]:
statuses = []
try:
await self.reload_or_load_extension(module)
statuses.append((self.tick(True), module))
except commands.ExtensionError:
statuses.append((self.tick(False), module))

return statuses

def reload_lib_modules(self, module: str) -> list[tuple[str, str]]:
statuses = []
try:
actual_module = sys.modules[module]
importlib.reload(actual_module)
statuses.append((self.tick(True), module))
except KeyError:
statuses.append((self.tick(None), module))
except Exception:
statuses.append((self.tick(False), module))
return statuses

# Umbra's sync command
# To learn more about it, see the link below (and ?tag ass on the dpy server):
# https://about.abstractumbra.dev/discord.py/2023/01/29/sync-command-example.html
@commands.guild_only()
@commands.command(name="sync")
async def sync(
self,
ctx: RoboContext,
guilds: Greedy[discord.Object],
spec: Optional[Literal["~", "*", "^"]] = None,
) -> None:
"""Performs a sync of the tree. This will sync, copy globally, or clear the tree."""
await ctx.defer()
if not guilds:
if spec == "~":
synced = await self.bot.tree.sync(guild=ctx.guild)
elif spec == "*":
self.bot.tree.copy_global_to(guild=ctx.guild) # type: ignore
synced = await self.bot.tree.sync(guild=ctx.guild)
elif spec == "^":
self.bot.tree.clear_commands(guild=ctx.guild)
await self.bot.tree.sync(guild=ctx.guild)
synced = []
else:
synced = await self.bot.tree.sync()

await ctx.send(
f"Synced {len(synced)} commands {'globally' if spec is None else 'to the current guild.'}"
)
return

ret = 0
for guild in guilds:
try:
await self.bot.tree.sync(guild=guild)
except discord.HTTPException:
pass
else:
ret += 1

await ctx.send(f"Synced the tree to {ret}/{len(guilds)}.")

@commands.command(name="reload-all", hidden=True)
async def reload(self, ctx: RoboContext) -> None:
"""Reloads all cogs and utils"""
async with ctx.typing():
stdout, _ = await self.run_process("git pull")

# progress and stuff is redirected to stderr in git pull
# however, things like "fast forward" and files
# along with the text "already up-to-date" are in stdout

if stdout.startswith("Already up-to-date."):
await ctx.send(stdout)
return

modules = self.find_modules_from_git(stdout)

mods_text = "\n".join(
f"{index}. `{module}`" for index, (_, module) in enumerate(modules, start=1)
)
prompt_text = (
f"This will update the following modules, are you sure?\n{mods_text}"
)

confirm = await ctx.prompt(prompt_text)
if not confirm:
await ctx.send("Aborting....")
return

statuses = []
for is_submodule, module in modules:
if is_submodule:
statuses = self.reload_lib_modules(module)
else:
statuses = await self.reload_exts(module)

await ctx.send(self.format_results(statuses))


async def setup(bot: Rodhaj) -> None:
await bot.add_cog(Admin(bot))
4 changes: 4 additions & 0 deletions bot/cogs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ def __init__(self, bot: Rodhaj) -> None:
self.bot = bot
self.pool = self.bot.pool

@property
def display_emoji(self) -> discord.PartialEmoji:
return discord.PartialEmoji(name="\U0001f6e0")

@alru_cache()
async def get_guild_config(self, guild_id: int) -> Optional[GuildConfig]:
# Normally using the star is bad practice but...
Expand Down
98 changes: 0 additions & 98 deletions bot/cogs/dev_tools.py

This file was deleted.

Loading

0 comments on commit e5269c7

Please sign in to comment.