Skip to content

Commit

Permalink
Merge pull request #41 from GrafeasGroup/packaging
Browse files Browse the repository at this point in the history
PACKAGING!
  • Loading branch information
itsthejoker committed Aug 8, 2022
2 parents f0fb552 + 68290f9 commit 716752f
Show file tree
Hide file tree
Showing 40 changed files with 848 additions and 1,202 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/build_and_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Release

on:
push:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: '3.10.x'
- name: Install Env
# shiv will download the dependencies it needs on its own
run: |
pip install --upgrade pip
pip install shiv
pip install poetry
pip install poetry2setup
- name: Add CURRENT_TIME env property
# the smart thing to do here would be to use the commit hash, but
# github releases are ALPHABETIZED, so a commit hash of `abcdef` will
# not be listed as the latest release if `defabc` came before. (╥﹏╥)
run: echo "CURRENT_TIME_VERSION=v$(date '+%s')" >> $GITHUB_ENV
- name: Build the sucker
run: |
sed -i -e "s/?????/${{ env.CURRENT_TIME_VERSION }}/g" bubbles/__init__.py
make build
- uses: ncipollo/release-action@v1
with:
artifacts: "build/bubbles.pyz"
body: "It's releasin' time"
generateReleaseNotes: true
tag: ${{ env.CURRENT_TIME_VERSION }}
commit: master
token: ${{ secrets.GITHUB_TOKEN }}
34 changes: 34 additions & 0 deletions .github/workflows/test_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Build bubbles.pyz and test

on: [pull_request]

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: '3.10.x'
- name: Install Env
# shiv will download the dependencies it needs on its own
run: |
pip install --upgrade pip
pip install shiv
pip install poetry
pip install poetry2setup
- name: Add CURRENT_TIME env property
# the smart thing to do here would be to use the commit hash, but
# github releases are ALPHABETIZED, so a commit hash of `abcdef` will
# not be listed as the latest release if `defabc` came before. (╥﹏╥)
run: echo "CURRENT_TIME_VERSION=v$(date '+%s')" >> $GITHUB_ENV
- name: Build the sucker
run: |
sed -i -e "s/?????/${{ env.CURRENT_TIME_VERSION }}/g" bubbles/__init__.py
make build
- name: Remove source to make sure it doesn't interfere with the tests
run: rm -rf bubbles/
- name: Run selfcheck on compiled binary
run: ./build/bubbles.pyz selfcheck
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,7 @@ presence_log.json

asdf.py
test.py

# build artifacts
bubbles.pyz
setup.py
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
setup:
poetry2setup > setup.py

build: setup shiv

clean:
rm setup.py

shiv:
mkdir -p build
shiv -c bubbles -o build/bubbles.pyz . --compressed
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ You may need a .env file for secrets -- copy `.env-example` to `.env` and fill i
If you're testing commands locally that do not need to access to advanced functionality (external services, mostly), you can invoke the interactive terminal by running:

```shell script
python bubblesRTM.py --interactive
python bubbles/main.py --interactive
```

This will create a shell session where you can test commands without needing to be hooked up to anything special.
Expand All @@ -37,7 +37,7 @@ Bubbles uses a plugin manager to register commands. Each command is registered i
### Example Command

```python
from bubbles.config import PluginManager
from bubbles.commands import Plugin


def hello_world(rtmclient, client, user_list, data):
Expand All @@ -46,7 +46,7 @@ def hello_world(rtmclient, client, user_list, data):
)


PluginManager.register_plugin(hello_world, r"hello")
PLUGIN = Plugin(callable=hello_world, regex=r"hello")
```

The above plugin will post "Hello, world!" to the channel you message Bubbles from with the following any of the following syntax:
Expand All @@ -60,21 +60,21 @@ bubbles hello
If you want to write a command that doesn't need the prefix to trigger, just add the `ignore_prefix=True` into the register command.

```python
PluginManager.register_plugin(hello_world, r"hello", ignore_prefix=True)
PLUGIN = Plugin(callable=hello_world, regex=r"hello", ignore_prefix=True)
```

Now it will trigger any time that the word "hello" is put into chat. `register_plugin` can handle a few more edge cases as well:

`flags`: used for combining `re` compilation flags for regex. For example:

```python
PluginManager.register_plugin(hello_world, r"hello", flags=re.IGNORECASE | re.MULTILINE)
PLUGIN = Plugin(callable=hello_world, regex=r"hello", flags=re.IGNORECASE | re.MULTILINE)
```

`callback`: if you need to keep track of messages, a command callback can be called on every message. To see an example of this in action (and using a class structure for a plugin), take a look at `bubbles/commands/yell.py`.

## Running the bot

```shell script
python bubblesRTM.py
python bubbles/main.py
```
5 changes: 1 addition & 4 deletions bubbles/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
# Don't touch!
# This actually enables loading all the files in the commands subdirectory and
# works alongside bubbles.commands.__init__
from bubbles.commands import *
__version__ = "?????" # This is populated by the CI pipeline
42 changes: 13 additions & 29 deletions bubbles/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
"""
Automatically load all python files inside this directory.
from dataclasses import dataclass, asdict
from typing import Callable

This allows the plugin manager to actually find everything!
"""
# source: https://stackoverflow.com/a/1057534
from typing import List, Union
import glob
from os.path import dirname, basename, isfile, join

from bubbles.config import PluginManager
@dataclass
class Plugin:
callable: Callable
regex: str
flags: int = None
callback: Callable = None
ignore_prefix: bool = False
help: str = None
interactive_friendly: bool = True

modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [
basename(f)[:-3] for f in modules if isfile(f) and not f.endswith("__init__.py")
]


def clean_text(text: Union[str, List]) -> str:
"""
Take the trigger word out of the text.
Examples:
!test -> !test
!test one -> !test one
@bubbles test -> test
@bubbles test one -> test one
"""
if isinstance(text, list):
text = " ".join(text)

return PluginManager.try_get_command_text(text) or text
def to_dict(self):
return asdict(self)
9 changes: 5 additions & 4 deletions bubbles/commands/backup_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import shlex
from pathlib import Path

from bubbles.config import PluginManager
from bubbles.commands import Plugin


def backup_db(payload):
Expand Down Expand Up @@ -39,8 +39,9 @@ def backup_db(payload):
os.remove(previous_backups[0])


PluginManager.register_plugin(
backup_db,
r"^backup",
PLUGIN = Plugin(
callable=backup_db,
regex=r"^backup",
help="!backup - creates and uploads a full backup of our postgres db.",
interactive_friendly=False,
)
14 changes: 4 additions & 10 deletions bubbles/commands/cute.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import requests

from bubbles.config import PluginManager
from bubbles.config import COMMAND_PREFIXES
from bubbles.commands import Plugin

# Pulled a bunch of these URLs from https://github.com/treboryx/animalsAPI -- many thanks

Expand All @@ -14,7 +14,6 @@
bunny_api = "https://api.bunnies.io/v2/loop/random/?media=gif"
duck_url = "https://random-d.uk/api/v1/random?type=png"
lizard_api = "https://nekos.life/api/v2/img/lizard"
owl_api = "http://pics.floofybot.moe/owl"
shibe_api = "http://shibe.online/api/shibes"
error_img = "https://www.pinclipart.com/picdir/middle/168-1688957_powerpuff-girls-cry-bubbles-clipart.png"

Expand Down Expand Up @@ -58,10 +57,6 @@ def get_fox():
return "fox", requests.get(fox_api).json()["image"]


def get_owl():
return "owl", requests.get(owl_api).json()["image"]


def get_duck():
return "duck", requests.get(duck_url).json()["url"]

Expand All @@ -76,7 +71,6 @@ def get_shibe():
"bunny": [get_bunny],
"lizard": [get_lizard],
"fox": [get_fox],
"owl": [get_owl],
"duck": [get_duck],
"shibe": [get_shibe],
}
Expand Down Expand Up @@ -114,9 +108,9 @@ def cute(data):
say(pic)


PluginManager.register_plugin(
cute,
r"^cute",
PLUGIN = Plugin(
callable=cute,
regex=r"^cute",
help=(
f"!cute [{', '.join([k for k in animals.keys()])}] - Specify an animal"
f" for a cute picture! Or just !cute for a random one."
Expand Down
9 changes: 5 additions & 4 deletions bubbles/commands/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import subprocess
from typing import Callable

from bubbles.config import PluginManager, COMMAND_PREFIXES
from bubbles.config import COMMAND_PREFIXES
from bubbles.commands import Plugin
from bubbles.service_utils import (
verify_service_up,
say_code,
Expand Down Expand Up @@ -119,9 +120,9 @@ def deploy(payload):
_deploy_service(service, say)


PluginManager.register_plugin(
deploy,
r"^deploy ?(.+)",
PLUGIN = Plugin(
callable=deploy,
regex=r"^deploy ?(.+)",
help=(
f"!deploy [{', '.join(SERVICES)}] - deploys the code currently on github to"
f" production."
Expand Down
9 changes: 6 additions & 3 deletions bubbles/commands/echo.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from bubbles.config import PluginManager
from bubbles.commands import Plugin

import re

# find a link in the slack format, then strip out the text at the end.
Expand All @@ -23,6 +24,8 @@ def echo(payload):
payload["extras"]["say"](f"```{' '.join(text.split()[1:])}```")


PluginManager.register_plugin(
echo, r"^echo", help="Repeats back whatever you pass in. Mostly for debugging."
PLUGIN = Plugin(
callable=echo,
regex=r"^echo",
help="Repeats back whatever you pass in. Mostly for debugging.",
)
4 changes: 2 additions & 2 deletions bubbles/commands/exclamation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from bubbles.config import PluginManager
from bubbles.commands import Plugin


def exclamation(payload):
Expand All @@ -11,4 +11,4 @@ def exclamation(payload):
pass


PluginManager.register_plugin(exclamation, r"^!")
PLUGIN = Plugin(callable=exclamation, regex=r"^!")
5 changes: 3 additions & 2 deletions bubbles/commands/f.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random

from bubbles.config import PluginManager
from bubbles.commands import Plugin


F = """
⠀⠀⢀⡤⢶⣶⣶⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Expand All @@ -23,4 +24,4 @@ def fancy_f(payload):
payload["extras"]["say"](F)


PluginManager.register_plugin(fancy_f, r"^[fF]$", ignore_prefix=True)
PLUGIN = Plugin(callable=fancy_f, regex=r"^[fF]$", ignore_prefix=True)
8 changes: 5 additions & 3 deletions bubbles/commands/fuckoff.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import random
import re

from bubbles.config import PluginManager, USERNAME
from bubbles.config import USERNAME
from bubbles.commands import Plugin


pattern = r"""
f+u+c+k+(\ )?(?:(y+o+u+|u+|o+f+))?[,\ ]+?{0}
Expand All @@ -24,6 +26,6 @@ def fuck_off(payload):
payload["extras"]["say"](random.choice(responses))


PluginManager.register_plugin(
fuck_off, pattern, flags=re.IGNORECASE, ignore_prefix=True
PLUGIN = Plugin(
callable=fuck_off, regex=pattern, flags=re.IGNORECASE, ignore_prefix=True
)
8 changes: 4 additions & 4 deletions bubbles/commands/help.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict

from bubbles.config import PluginManager
from bubbles.commands import Plugin


def format_text(data: Dict) -> str:
Expand All @@ -13,7 +13,7 @@ def format_text(data: Dict) -> str:

def help(payload):
plugins_with_help = dict()
for plugin in PluginManager.plugins:
for plugin in payload["extras"]["meta"].plugins:
if plugin["help"] is not None:
# grab the name of the command and the help string.
plugin_split = str(plugin["callable"]).split()
Expand All @@ -31,6 +31,6 @@ def help(payload):
payload["extras"]["say"](format_text(plugins_with_help))


PluginManager.register_plugin(
help, r"^help$", help="!help - Lists out all available commands!"
PLUGIN = Plugin(
callable=help, regex=r"^help$", help="!help - Lists out all available commands!"
)
Loading

0 comments on commit 716752f

Please sign in to comment.