Skip to content

Commit

Permalink
Merge pull request #1 from Ableytner/containerize
Browse files Browse the repository at this point in the history
Build the bot as a docker image
  • Loading branch information
Ableytner authored Oct 9, 2024
2 parents 65f075e + bbbf854 commit 5aac649
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 18 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/define-build-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build image

on:
workflow_call:

defaults:
run:
shell: bash

jobs:
build:
runs-on: [self-hosted, linux]
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: lowercase github.repository
run: |
echo "IMAGE_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV}
- name: Build
uses: docker/build-push-action@v6
with:
context: .
push: false
tags: ${{ env.IMAGE_NAME }}:latest
outputs: type=docker,dest=/tmp/image.tar
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: image
path: /tmp/image.tar
35 changes: 35 additions & 0 deletions .github/workflows/define-pylint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Define Pylint

on:
workflow_call:
inputs:
python-version:
required: true
type: string

defaults:
run:
shell: bash

jobs:
pylint:
runs-on:
- ${{ matrix.os }}
- self-hosted
strategy:
matrix:
os: [Linux]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
90 changes: 90 additions & 0 deletions .github/workflows/release-tagged-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Release tagged image

on: [workflow_dispatch]

env:
CURRENT_VERSION: 0.0.5

defaults:
run:
shell: bash

jobs:
pylint:
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
uses: ./.github/workflows/define-pylint.yml
with:
python-version: ${{ matrix.python-version }}
secrets: inherit

build:
needs: [pylint]
uses: ./.github/workflows/define-build-image.yml
secrets: inherit

tag:
runs-on: self-hosted
steps:
- uses: mukunku/[email protected]
id: check-tag
with:
tag: ${{ env.CURRENT_VERSION }}
- name: Fail if tag exists
if: steps.check-tag.outputs.exists == 'true'
run: |
echo "Tag ${{ env.CURRENT_VERSION }} exists!"
exit 1
- name: Print tag if it doesn't exist
if: steps.check-tag.outputs.exists == 'false'
run: |
echo "Tag ${{ env.CURRENT_VERSION }} doesn't yet exist and can be created"
push:
needs: [tag, build]
runs-on: [self-hosted, linux]
permissions:
contents: read
packages: write
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: lowercase github.repository
run: |
echo "IMAGE_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV}
- name: Download image artifact
uses: actions/download-artifact@v4
with:
name: image
path: /tmp
- name: Load image
run: |
docker load --input /tmp/image.tar
- name: Push
run: |
docker tag ${{ env.IMAGE_NAME }}:latest ghcr.io/${{ env.IMAGE_NAME }}:${{ env.CURRENT_VERSION }}
docker push ghcr.io/${{ env.IMAGE_NAME }}:${{ env.CURRENT_VERSION }}
docker tag ghcr.io/${{ env.IMAGE_NAME }}:${{ env.CURRENT_VERSION }} ghcr.io/${{ env.IMAGE_NAME }}:latest
docker push ghcr.io/${{ env.IMAGE_NAME }}:latest
release:
needs: [push]
runs-on: [self-hosted, linux]
permissions:
contents: write
steps:
- name: Add body.md
run: |
touch body.md
- name: Create new release
uses: ncipollo/release-action@v1
with:
bodyFile: "body.md"
tag: "${{ env.CURRENT_VERSION }}"
commit: "main"
token: ${{ secrets.GITHUB_TOKEN }}
21 changes: 21 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Run Tests

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
pylint:
strategy:
matrix:
python-version: ["3.10", "3.12"]
uses: ./.github/workflows/define-pylint.yml
with:
python-version: ${{ matrix.python-version }}
secrets: inherit
build:
needs: [pylint]
uses: ./.github/workflows/define-build-image.yml
secrets: inherit
8 changes: 7 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[MASTER]

ignore=tests

[MESSAGES CONTROL]

# Only show warnings with the listed confidence levels. Leave empty to show
Expand All @@ -22,7 +26,9 @@ disable=too-many-arguments,
too-many-instance-attributes,
no-name-in-module,
isinstance-second-argument-not-valid-type,
multiple-statements
multiple-statements,
relative-beyond-top-level,
too-many-positional-arguments

[FORMAT]

Expand Down
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM python:3.12-bookworm

RUN apt-get update \
&& useradd -m nikobot \
&& mkdir /home/nikobot/src \
&& chown nikobot /home/nikobot/src

COPY --chown=nikobot --chmod=755 src/ /home/nikobot/src/
COPY --chown=nikobot --chmod=755 requirements.txt /home/nikobot/requirements.txt

# install pip packages
RUN pip install -r /home/nikobot/requirements.txt

USER nikobot

ENTRYPOINT [ "python3", "/home/nikobot/src/main.py" ]
4 changes: 1 addition & 3 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ def __init__(self) -> None:
def start_bot(self):
"""Start the discord bot"""

with open("dc_token.txt", "r", encoding="utf8") as file:
token = file.readlines()[0]
self.run(token)
self.run(os.environ["DISCORD_TOKEN"])

async def setup_hook(self) -> None:
util.VolatileStorage["modules"] = []
Expand Down
6 changes: 3 additions & 3 deletions src/nikobot/modules/avatar.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ async def avatar(self, ctx: commands.context.Context | discord.interactions.Inte
await util.discord.reply(ctx, "User has a default avatar, which can't be downloadad.")
return

os.makedirs(f"{util.VolatileStorage["cache_dir"]}/avatars", exist_ok=True)
os.makedirs(f"{util.VolatileStorage['cache_dir']}/avatars", exist_ok=True)

# Download the user's avatar
response = requests.get(user_obj.avatar.url, timeout=30)
if response.status_code == 200:
with open(f"{util.VolatileStorage["cache_dir"]}/avatars/{user_obj}.png", "wb") as f:
with open(f"{util.VolatileStorage['cache_dir']}/avatars/{user_obj}.png", "wb") as f:
f.write(response.content)
else:
await util.discord.reply(ctx, "Failed to download avatar.")

# send the avatar
avatar_file = discord.File(f"{util.VolatileStorage["cache_dir"]}/avatars/{user_obj}.png",
avatar_file = discord.File(f"{util.VolatileStorage['cache_dir']}/avatars/{user_obj}.png",
filename=f"{user_obj}.png")
await util.discord.reply(ctx,
f"Profile picture of {user_obj.nick or user_obj.display_name or user_obj.name}:",
Expand Down
2 changes: 1 addition & 1 deletion src/nikobot/modules/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def _generate_help_specific_normal(self, command_name: str) -> discord.Embed:

desc = cmd.description.strip("__hidden__")
if "." in cmd.name:
desc += f"\nCommand is a part of the '{cmd.name.split(".", maxsplit=1)[0]}' module"
desc += f"\nCommand is a part of the '{cmd.name.split('.', maxsplit=1)[0]}' module"
answer.add_field(name="Description", value=desc)

return answer
Expand Down
6 changes: 2 additions & 4 deletions src/nikobot/modules/mal/malnotifier.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""A module containing MyAnimeList-related commands"""

import os
from datetime import datetime, timedelta
from threading import Thread

Expand All @@ -14,9 +15,6 @@

# pylint: disable=protected-access

with open("client_id.txt", "r", encoding="utf8") as file:
CLIENT_ID = file.readlines()[0]

command_group = app_commands.Group(
name="mal",
description="The module for MyAnimeList-related commands"
Expand Down Expand Up @@ -204,7 +202,7 @@ def import_users(self):
async def setup(bot: commands.Bot):
"""Setup the bot_commands cog"""

util.VolatileStorage["mal.CLIENT-ID"] = CLIENT_ID
util.VolatileStorage["mal.CLIENT-ID"] = os.environ["MAL_CLIENT_ID"]

mal_helper._setup()
manganato_helper._setup()
Expand Down
4 changes: 2 additions & 2 deletions src/nikobot/modules/mal/manga.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import requests
from PIL import Image
from discord import Embed, File, Color
from discord import Embed, File

from . import error, mal_helper, manganato_helper
from .chapter import Chapter
Expand Down Expand Up @@ -165,7 +165,7 @@ def picture_file(self) -> str:

path = os.path.join(util.VolatileStorage["cache_dir"], "mal")
os.makedirs(path, exist_ok=True)
path = os.path.join(path, f"preview_{self.mal_id}.{self.picture_url.rsplit(".", maxsplit=1)[1]}")
path = os.path.join(path, f"preview_{self.mal_id}.{self.picture_url.rsplit('.', maxsplit=1)[1]}")

if os.path.isfile(path):
return path
Expand Down
16 changes: 12 additions & 4 deletions src/nikobot/modules/music.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# pylint: skip-file

import discord
import youtube_dl
from discord.ext import commands, tasks
Expand Down Expand Up @@ -100,8 +102,9 @@ async def stop (self, ctx: commands.context.Context):
@tasks.loop(seconds=5)
async def song_scheduler(self):
"""manages the queue"""

for guild_id in list(self.active_plays.keys()): # list() to create a new object which can't change during the loop execution

# list() to create a new object which can't change during the loop execution
for guild_id in list(self.active_plays.keys()):
data = self.active_plays[guild_id]

if not data["playing"] and len(data["urls"]) > 0:
Expand All @@ -113,8 +116,13 @@ async def song_scheduler(self):

async def play_song(self, url: str, guild_id: int):
""" plays back the given song """
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
YDL_OPTIONS = {'format' : "bestaudio"}
FFMPEG_OPTIONS = {
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn'
}
YDL_OPTIONS = {
'format' : "bestaudio"
}
voice_clients: list[discord.voice_client.VoiceClient] = self.bot.voice_clients
vc: discord.voice_client.VoiceClient = [item for item in voice_clients if item.guild.id==guild_id][0]
with youtube_dl.YoutubeDL(YDL_OPTIONS) as ydl:
Expand Down
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# pylint: skip-file
2 changes: 2 additions & 0 deletions tests/test_aspect_parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# pylint: skip-file

from src.modules.tc4 import AspectParser

def test_create():
Expand Down
2 changes: 2 additions & 0 deletions tests/test_shortest_path2.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# pylint: skip-file

from src.modules.tc4 import AspectParser
from src.modules.tc4.shortest_path import ShortestPath
from src.modules.tc4.shortest_path2 import ShortestPath2
Expand Down

0 comments on commit 5aac649

Please sign in to comment.