Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*

!botcore/
!docs/
!tests/

!pyproject.toml
!poetry.lock
!tox.ini
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,6 @@ dmypy.json

# Vscode
.vscode

# Development & prototyping environment
/bot/
2 changes: 1 addition & 1 deletion botcore/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
Initialise the base bot instance.

Args:
guild_id: The ID of the guild use for :func:`wait_until_guild_available`.
guild_id: The ID of the guild used for :func:`wait_until_guild_available`.
allowed_roles: A list of role IDs that the bot is allowed to mention.
http_session (aiohttp.ClientSession): The session to use for the bot.
redis_session: The `async_rediscache.RedisSession`_ to use for the bot.
Expand Down
13 changes: 7 additions & 6 deletions dev/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ FROM python:3.9-slim
ENV PIP_NO_CACHE_DIR=false \
POETRY_VIRTUALENVS_CREATE=false

ENTRYPOINT ["/bin/bash"]
CMD ["./docker-entrypoint.sh"]

# Install poetry
RUN pip install -U poetry

RUN mkdir bot
WORKDIR /bot
WORKDIR /app

# Install project dependencies
COPY pyproject.toml poetry.lock ./
RUN poetry install --no-dev
RUN poetry install --no-root

# Copy the source code in last to optimize rebuilding the image
COPY . .
# Install again, this time with the root project
RUN poetry install

ENTRYPOINT ["python"]
CMD ["-m", "bot"]
53 changes: 53 additions & 0 deletions dev/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Local Development & Testing
===========================

To test your features locally, there are a few possible approaches:

1. Install your local copy of botcore into a pre-existing project such as bot
2. Use the provided template from the :repo-file:`dev/bot <dev/bot>` folder

See below for more info on both approaches.

What's going to be common between them is you'll need to write code to test your feature.
This might mean adding new commands, modifying existing ones, changing utilities, etc.
The steps below should provide most of the groundwork you need, but the exact requirements will
vary by the feature you're working on.


Option 1
--------
1. Navigate to the project you want to install bot-core in, such as bot or sir-lancebot
2. Run ``pip install /path/to/botcore`` in the project's environment

- The path provided to install should be the root directory of this project on your machine.
That is, the folder which contains the ``pyproject.toml`` file.
- Make sure to install in the correct environment. Most Python Discord projects use
poetry, so you can run ``poetry run pip install /path/to/botcore``.

3. You can now use features from your local bot-core changes.
To load new changes, run the install command again.


Option 2
--------
1. Copy the :repo-file:`bot template folder <dev/bot>` to the root of the bot-core project.
This copy is going to be git-ignored, so you're free to modify it however you like.
2. Run the project

- Locally: You can run it on your system using ``python -m bot``
- Docker: You can run on docker using ``docker compose up -d bot``.

3. Configure the environment variables used by the program.
You can set them in an ``.env`` file in the project root directory. The variables are:

- ``TOKEN`` (required): Discord bot token, with all intents enabled
- ``GUILD_ID`` (required): The guild the bot should monitor
- ``PREFIX``: The prefix to use for invoking bot commands. Defaults to mentions and ``!``
- ``ALLOWED_ROLES``: A comma seperated list of role IDs which the bot is allowed to mention

4. You can now test your changes. You do not need to do anything to reinstall the
library if you modify your code.

.. tip::
The docker-compose included contains services from our other applications
to help you test out certain features. Use them as needed.
24 changes: 24 additions & 0 deletions dev/bot/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import asyncio
import logging
import os
import sys

import botcore

if os.name == "nt":
# Change the event loop policy on Windows to avoid exceptions on exit
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

# Some basic logging to get existing loggers to show
logging.getLogger().addHandler(logging.StreamHandler())
logging.getLogger().setLevel(logging.DEBUG)
logging.getLogger("discord").setLevel(logging.ERROR)


class Bot(botcore.BotBase):
"""Sample Bot implementation."""

async def setup_hook(self) -> None:
"""Load extensions on startup."""
await super().setup_hook()
asyncio.create_task(self.load_extensions(sys.modules[__name__]))
34 changes: 34 additions & 0 deletions dev/bot/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import asyncio
import os

import aiohttp
import discord
import dotenv
from discord.ext import commands

import botcore
from . import Bot

dotenv.load_dotenv()
botcore.utils.apply_monkey_patches()

roles = os.getenv("ALLOWED_ROLES")
roles = [int(role) for role in roles.split(",")] if roles else []

bot = Bot(
guild_id=int(os.getenv("GUILD_ID")),
http_session=None, # type: ignore # We need to instantiate the session in an async context
allowed_roles=roles,
command_prefix=commands.when_mentioned_or(os.getenv("PREFIX", "!")),
intents=discord.Intents.all(),
description="Bot-core test bot.",
)


async def main() -> None:
"""Run the bot."""
bot.http_session = aiohttp.ClientSession()
async with bot:
await bot.start(os.getenv("TOKEN"))

asyncio.run(main())
33 changes: 33 additions & 0 deletions dev/bot/cog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from discord.ext import commands

from . import Bot


class Cog(commands.Cog):
"""A simple discord.py cog."""

def __init__(self, _bot: Bot):
self.bot = _bot

@commands.Cog.listener()
async def on_ready(self) -> None:
"""Print a message when the client (re)connects."""
print("Client is ready.")

@commands.command()
async def reload(self, ctx: commands.Context) -> None:
"""Reload all available cogs."""
message = await ctx.send(":hourglass_flowing_sand: Reloading")
for ext in list(self.bot.extensions):
await self.bot.reload_extension(ext)
await message.edit(content=":white_check_mark: Done")

@commands.command()
async def ping(self, ctx: commands.Context) -> None:
"""Test if the bot is online."""
await ctx.send("We are live!")


async def setup(_bot: Bot) -> None:
"""Install the cog."""
await _bot.add_cog(Cog(_bot))
27 changes: 0 additions & 27 deletions dev/docker-compose.yaml

This file was deleted.

61 changes: 61 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Modified version of python-discord/bot

version: "3.8"

x-restart-policy: &restart_policy
restart: unless-stopped

services:
postgres:
<< : *restart_policy
image: postgres:13-alpine
environment:
POSTGRES_DB: pysite
POSTGRES_PASSWORD: pysite
POSTGRES_USER: pysite
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pysite"]
interval: 2s
timeout: 1s
retries: 5

redis:
<< : *restart_policy
image: redis:5.0.9
ports:
- "6379:6379"

snekbox:
<< : *restart_policy
image: ghcr.io/python-discord/snekbox:latest
init: true
ipc: none
ports:
- "8060:8060"
privileged: true

web:
<< : *restart_policy
image: ghcr.io/python-discord/site:latest
command: ["run", "--debug"]
ports:
- "8000:8000"
tty: true
environment:
DATABASE_URL: postgres://pysite:pysite@postgres:5432/pysite
METRICITY_DB_URL: postgres://pysite:pysite@postgres:5432/metricity
SECRET_KEY: suitable-for-development-only
STATIC_ROOT: /var/www/static

bot:
<< : *restart_policy
build:
context: .
dockerfile: dev/Dockerfile
volumes:
- .:/app:ro
tty: true
env_file:
- .env
environment:
BOT_API_KEY: badbot13m0n8f570f942013fc818f234916ca531
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
Changelog
=========

- :bug:`107` Declare aiodns as a project dependency.
- :support:`107` Add a sample project with boilerplate and documentation explaining how to develop for bot-core.


- :release:`7.5.0 <23rd July 2022>`
- :feature:`101` Add a utility to clean a string or referenced message's content

Expand Down
2 changes: 2 additions & 0 deletions docs/development.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.. Stub file to expose the README to sphinx
.. include:: ../dev/README.rst
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Reference
:caption: Other:
:hidden:

development
changelog


Expand All @@ -26,4 +27,5 @@ Extras
* :ref:`genindex`
* :ref:`search`
* :repo-file:`Information <docs/README.md>`
* :doc:`development`
* :doc:`changelog`
Loading