duck-dynasty / duckbot

A Discord bot for personal friend group
GNU General Public License v3.0
9 stars 10 forks source link

duckbot

GitHub License GitHub Issues Build Status codecov Code style: black Imports: isort

A Discord bot for personal friend group. If you don't know me personally, consider how freaking weird it'd be to ask for the access token. Feel free to steal the code though.

View the wiki for a short description on what the Duck does.

https://user-images.githubusercontent.com/3149083/135654217-244d7457-9db9-4c30-a98a-785b25453fd8.mp4

Development

Before running DuckBot, you want to create a virtualenv to develop in. DuckBot runs on python3.10, so prefer to use that.

python3.10 -m venv --clear --prompt duckbot venv
. venv/bin/activate
pip install --upgrade pip setuptools wheel
SETUPTOOLS_ENABLE_FEATURES="legacy-editable" pip install --editable .[dev]

The dev extras will also install development dependencies, like pytest. The installation commands should be run whenever you merge from upstream.

Run Tests & Formatter

pytest  # runs tests, lint and format checks
format  # reformats the entire code base

You can also collect code coverage locally using:

pytest --cov=duckbot --cov-branch --cov-report term-missing:skip-covered

Coverage is collected in the github actions. View the Codecov configuration to see the minimum required coverage. Discord.py decorators make it difficult to cover methods directly, so don't aim for 100% coverage.

Run DuckBot

Before running DuckBot, you need to have a duckbot/.env file with the API tokens. It should look something like this:

duck@pond$ cat duckbot/.env
DISCORD_TOKEN=thesecrettoken
OPENWEATHER_TOKEN=thesecrettoken
BOT_GITHUB_TOKEN=somesecrettoken
WOLFRAM_ALPHA_TOKEN=broitssecret
OXFORD_DICTIONARY_ID=icanttellyou
OXFORD_DICTIONARY_KEY=itsasecret
ANTHROPIC_API_KEY=itsasecret

You only need the discord token. DuckBot will still function without the others, but features that use the tokens won't work. With your tokens available, you can jam them into your shell environment, so you can run DuckBot. You may want to put this into your bashrc for convenience.

export $(cat duckbot/.env | xargs)

Finally, there are two ways to run DuckBot. For a production-like environment, you should run using docker-compose. This will stand up the database alongside DuckBot.

docker-compose up --build

If your work doesn't need a full setup, you can just run python -m duckbot for less wait time. Depending on what apt packages you have installed, some features may not work, see the Dockerfile for what packages you'd need. For testing simple new commands though, this works fine enough.

Deployment

Deployment scripts are written using CDK, the AWS Cloud Development Kit. The CDK dependencies can be installed alongside DuckBot.

SETUPTOOLS_ENABLE_FEATURES="legacy-editable" pip install --editable .[dev,cdk]  # run from repository root

You'll then actually need CDK. It's a nodejs package, so you'll need that as well.

npm install -g aws-cdk

Adding New Secrets

To add new secrets (like tokens), app.py needs to be modified. Add a secret to the existing list of secrets there.

Make sure you also update the docker-compose file, and this readme to include information on how developers can get their own copy of the secrets.

Note About Secrets and Deployments

CDK is just python code at the end of the day, we take advantage of that to make sure the deployment process actually creates the secrets that DuckBot would use in prod. In app.py, there's logic which creates the secrets via API calls, taking the value from the current environment. Those same secrets are passed to the stack, which are used to inject the secrets into the duckbot container.

Actually saving the secrets is disabled by default, but is enabled for the GitHub actions deploy step. Writing secrets can be enabled by passing --context write_secrets=true to a cdk command.

Using CDK

You'll need AWS credentials to use CDK. The following examples assume you have those credentials saved under a duckbot AWS CLI profile. The cdk commands need to be run from the .aws directory.

You can also technically deploy using CDK, but should avoid that. Let the actions workflows do that.

Synthesize a Stack

cdk synth --profile duckbot

Synthesizing products cdk.out/duckbot.template.json, the CloudFormation template that you can deploy. It also dumps the YML version out to the console.

Diff a Stack

cdk diff --profile duckbot

Produces a diff between the stack already deployed and what you have locally.