Skip to content

Commit bf05916

Browse files
committed
Initial template
1 parent 9024975 commit bf05916

File tree

16 files changed

+398
-0
lines changed

16 files changed

+398
-0
lines changed

.env

Whitespace-only changes.

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
on: [pull_request]
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.ref }}
5+
cancel-in-progress: true
6+
jobs:
7+
lint:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v4
12+
- name: Install python
13+
uses: actions/setup-python@v5
14+
with:
15+
python-version: 3.11
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@v5
18+
with:
19+
version: 0.7
20+
- name: Install dependencies
21+
run: uv sync
22+
- name: Lint check
23+
run: uv run ruff check
24+
- name: Lint fix check
25+
run: |
26+
uv run ruff check --fix
27+
git diff --exit-code
28+
- name: Formatting check
29+
run: uv run ruff format --check
30+
test:
31+
runs-on: ubuntu-latest
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
- name: Install python
36+
uses: actions/setup-python@v5
37+
with:
38+
python-version: 3.11
39+
- name: Install uv
40+
uses: astral-sh/setup-uv@v5
41+
with:
42+
version: 0.7
43+
- name: Install dependencies
44+
run: uv sync
45+
- name: Run tests
46+
run: PYTHON_ENV=test uv run pytest

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__pycache__
2+
.pytest_cache
3+
.venv
4+
.ruff_cache

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
11
# bot-python
22
Starter kit for Python bot for Automa
3+
4+
Please read the [Bot Development](https://docs.automa.app/bot-development) docs to understand how this bot works.
5+
6+
* `/automa` endpoint is the receiver for the webhook from [Automa](https://automa.app)
7+
* `update` function in `app/update.py` is the logic responsible for updating code.
8+
* `AUTOMA_WEBHOOK_SECRET` environment variable is available to be set instead of hard-coding it.
9+
10+
### Production
11+
12+
Start the app in production mode:
13+
14+
```
15+
PYTHON_ENV=production uv run fastapi run
16+
```
17+
18+
### Development
19+
20+
Start the app in development mode:
21+
22+
```
23+
uv run fastapi dev
24+
```
25+
26+
### Testing
27+
28+
Run tests with:
29+
30+
```
31+
uv run pytest
32+
```
33+
34+
### Stack
35+
36+
* Uses [uv](https://docs.astral.sh/uv/) as a package manager.
37+
* Uses [fastapi](https://fastapi.tiangolo.com/) as a server.

app/__init__.py

Whitespace-only changes.

app/env.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import os
2+
from functools import lru_cache
3+
4+
from pydantic_settings import BaseSettings, SettingsConfigDict
5+
6+
environment = os.getenv("PYTHON_ENV", "development")
7+
8+
9+
class Config(BaseSettings):
10+
model_config = SettingsConfigDict(env_file=".env")
11+
12+
automa_webhook_secret: str = "atma_whsec_bot-python"
13+
14+
15+
@lru_cache
16+
def env():
17+
return Config()

app/main.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import json
2+
import logging
3+
4+
from automa.bot import AsyncAutoma
5+
from automa.bot.webhook import verify_webhook
6+
from fastapi import FastAPI, Request, Response
7+
8+
from .env import env
9+
from .update import update
10+
11+
app = FastAPI()
12+
13+
14+
@app.get("/health")
15+
async def health_check():
16+
return Response(status_code=200)
17+
18+
19+
@app.post("/automa")
20+
async def automa_hook(request: Request):
21+
signature = request.headers.get("webhook-signature")
22+
payload = (await request.body()).decode("utf-8")
23+
24+
# Verify request
25+
if not verify_webhook(env().automa_webhook_secret, signature, payload):
26+
logging.warning(
27+
"Invalid signature",
28+
)
29+
30+
return Response(status_code=401)
31+
32+
base_url = request.headers.get("x-automa-server-host")
33+
body = json.loads(payload)
34+
35+
# Create client with base URL
36+
automa = AsyncAutoma(base_url=base_url)
37+
38+
# Download code
39+
folder = await automa.code.download(body["data"])
40+
41+
try:
42+
update(folder)
43+
44+
# Propose code
45+
await automa.code.propose(
46+
{
47+
**body["data"],
48+
"proposal": {
49+
"message": "We changed your code",
50+
},
51+
}
52+
)
53+
finally:
54+
# Clean up
55+
await automa.code.cleanup(body["data"])
56+
57+
return Response(status_code=200)

app/update.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def update(folder: str):
2+
"""
3+
Update code in the specified folder.
4+
"""

pyproject.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[project]
2+
name = "bot-python"
3+
version = "0.1.0"
4+
5+
requires-python = ">=3.11"
6+
7+
classifiers = ["Private :: Do Not Upload"]
8+
9+
dependencies = [
10+
"automa-bot~=0.1.4",
11+
"fastapi-cli~=0.0.7",
12+
"fastapi~=0.115.11",
13+
"pydantic-settings~=2.8.1",
14+
"uvicorn~=0.34.0",
15+
]
16+
17+
[dependency-groups]
18+
dev = ["httpx~=0.28.1", "pytest-cov~=6.0.0", "pytest~=8.3.5", "ruff~=0.11.2"]
19+
20+
[tool.pytest.ini_options]
21+
pythonpath = "."
22+
testpaths = ["tests"]

tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)