Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
5 changes: 1 addition & 4 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,15 @@ tmp/
.DS_Store

# 测试
test/
tests/
.pytest_cache/
.coverage
htmlcov/

# 文档
docs/
*.md
LICENSE

# 容器相关
Dockerfile
docker/
.dockerignore
docker-compose.yml
2 changes: 1 addition & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jobs:
pip install -r ./requirements.txt
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
pylint $(git ls-files '*.py' | grep -v "tests/")
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.venv/
.pytest_cache/
__pycache__/

*.pyc
Expand Down
6 changes: 6 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[MASTER]
ignore=tests
ignore-patterns=test_.*?.py

[FORMAT]
max-line-length=120
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ RUN mkdir -p /app/templates \

COPY --chown=appuser:appuser . .

VOLUME [ "/app/config" ]

USER appuser

EXPOSE 8000

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
190 changes: 53 additions & 137 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ source .venv/bin/activate # Linux/Mac

```bash
pip install -r requirements.txt
# 或者使用 Poetry
# poetry install
```

4. 配置文件设置:
Expand All @@ -90,7 +92,7 @@ pip install -r requirements.txt
或者复制示例配置文件:

```bash
cp config.yaml.example config.yaml
cp config/config.example.yaml config.yaml
```

## 配置说明
Expand Down Expand Up @@ -129,13 +131,13 @@ GITHUB_WEBHOOK:
## 运行

```bash
uvicorn app:app --host 0.0.0.0 --port 8000
uvicorn main:app --host 0.0.0.0 --port 8000
```

或者直接执行:

```bash
python app.py
python main.py
```

## GitHub Webhook 设置
Expand All @@ -149,144 +151,51 @@ python app.py

## 开发路线图

### 1. GitHub API 轮询(计划中)

对于无法使用 webhook 的场景(如私有仓库或受限环境),我们计划实现基于 GitHub API 的轮询机制。

#### 设计概要

- **配置方式**:

```yaml
GITHUB_API_POLLING:
- NAME: "polling-example"
REPO:
- "username/repo"
BRANCH:
- "main"
INTERVAL: 300 # 轮询间隔(秒)
EVENTS:
- "push"
- "pull_request"
TOKEN: "github_personal_access_token" # GitHub 个人访问令牌
ONEBOT:
- type: "group"
id: 123456789
```

- **功能**:
- 定时检查仓库变更
- 对比上次轮询结果,只通知新变更
- 支持提交、PR、Issue 等多种数据类型轮询
- 优化请求频率,避免触发 GitHub API 限流

- **实现计划**:
- 使用 `APScheduler` 实现定时任务
- 使用 `aiohttp` 实现异步 HTTP 请求
- 使用本地文件存储上次轮询状态 ~~(轻量化的玩意不可能给你上数据库 or Redis)~~
- 封装 GitHub API 客户端,处理认证和错误

### 2. 自定义模板系统(计划中)

允许用户自定义各类事件的通知消息格式,提供更灵活的展示方式。

#### 设计概要

- **模板存储**:
- 模板文件存储在 `templates/` 目录下
- 按照事件类型命名,如 `templates/push.txt`、`templates/issues.txt` 等
- 也可以创建自定义命名的模板文件用于不同场景

- **配置方式**:

```yaml
GITHUB_WEBHOOK:
- NAME: "github"
REPO:
- "username/repo"
BRANCH:
- "main"
SECRET: "your_secret"
EVENTS:
- "push"
- "issues"
TEMPLATES: # 为不同事件类型指定自定义模板
push: "custom_push.txt" # 使用自定义推送模板
issues: "default" # 使用默认 issues 模板
ONEBOT:
- type: "group"
id: 123456789
```

- **模板示例** (`templates/push.txt`):

```
📢 GitHub 推送通知
仓库:{{ repo_name }}
分支:{{ branch }}
推送者:{{ pusher }}
提交数量:{{ commit_count }}
{% for commit in commits %}
[{{ loop.index }}] {{ commit.id[:7] }} by {{ commit.author.name }}
{{ commit.message.split('\n')[0] }}
{% endfor %}
```

- **模板示例** (`templates/issues.txt`):

```
📋 Issue {{ action }}
仓库:{{ repo_name }}
标题:{{ issue.title }}
作者:{{ issue.user.login }}
链接:{{ issue.html_url }}
```

- **功能**:
- 基于 Jinja2 模板引擎
- 支持条件语句和循环
- 每个 Webhook 可以指定不同的模板集合
- 提供默认模板,无需配置即可使用
- 模板变量自动文档化(将提供变量参考)

- **实现计划**:
- 引入 Jinja2 依赖
- 实现模板目录扫描和加载机制
- 开发模板缓存以提高性能
- 提供模板变量参考文档
- 添加模板验证功能,避免语法错误

## API 参考

### Webhook 接口

- **路径**: `/github-webhook`
- **方法**: POST
- **请求头**:
- `Content-Type`: application/json
- `X-GitHub-Event`: 事件类型
- `X-Hub-Signature-256`: SHA-256 HMAC 签名

- **响应**:

```json
{
"status": "success|ignored",
"message": "处理信息"
}
```
详细的开发路线图请参考 开发路线图文档。

## 项目结构

- app.py: 主应用入口和 Web 服务器
- hooks/github_webhook.py: GitHub Webhook 处理逻辑
- send_message.py: OneBot 消息发送客户端
- settings.py: 配置加载和验证
- requirements.txt: 项目依赖
```
onebot-github-webhook/
├── app/ # 应用程序核心模块
│ ├── api/ # API 接口
│ ├── core/ # 核心功能
│ │ ├── github.py # GitHub Webhook 处理逻辑
│ │ └── onebot.py # OneBot 消息发送客户端
│ ├── models/ # 数据模型
│ │ └── config.py # 配置模型
│ └── utils/ # 工具函数
│ └── matching.py # 匹配规则工具
├── config/ # 配置文件目录
│ ├── config.example.yaml # 示例配置文件
│ └── templates/ # 消息模板目录
│ ├── push/ # 推送事件模板
│ ├── issues/ # Issue 事件模板
│ └── pull_request/ # Pull Request 事件模板
├── docs/ # 文档目录
│ └── src/ # mdBook 文档源
├── tests/ # 测试目录
│ ├── test_matching.py # 匹配规则测试
│ ├── test_onebot_sender.py # OneBot 发送器测试
│ └── test_webhook_signature.py # Webhook 签名验证测试
├── docker/ # Docker 相关文件
│ └── docker-compose.yml # Docker Compose 配置文件
├── main.py # 应用程序入口点
├── Dockerfile # Docker 构建文件
├── pyproject.toml # Python 项目配置
├── poetry.lock # Poetry 依赖锁定文件
└── README.md # 项目说明文档
```

## 部署建议

### Docker 部署(计划支持)
### Docker 部署

```bash
docker run -d \
Expand All @@ -296,6 +205,13 @@ docker run -d \
e1saps/onebot-github-webhook:latest
```

或使用 Docker Compose:

```bash
cd docker
docker-compose up -d
```

### Systemd 服务

创建 `/etc/systemd/system/onebot-github-webhook.service`:
Expand All @@ -308,7 +224,7 @@ After=network.target
[Service]
User=www-data
WorkingDirectory=/opt/onebot-github-webhook
ExecStart=/opt/onebot-github-webhook/.venv/bin/python -m uvicorn app:app --host 0.0.0.0 --port 8000
ExecStart=/opt/onebot-github-webhook/.venv/bin/python -m uvicorn main:app --host 0.0.0.0 --port 8000
Restart=on-failure
RestartSec=5s

Expand Down Expand Up @@ -350,4 +266,4 @@ A: 本程序暂时不支持推送到多个 QQ 机器人

## 许可证

本项目采用 [Apache License 2.0](LICENSE) 许可证。
本项目采用 Apache License 2.0 许可证。
31 changes: 2 additions & 29 deletions hooks/github_webhook.py → app/core/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,13 @@
import hmac
import hashlib
import logging
import fnmatch
from typing import Optional, Dict, Any, List

from fastapi import Request, HTTPException, Header

logger = logging.getLogger(__name__)

def match_pattern(value: str, pattern: str) -> bool:
"""
检查字符串是否匹配配置中的模式
支持大小写不敏感匹配和通配符模式
from app.utils.matching import match_pattern

Args:
value: 要匹配的字符串 (例如 'user/repo' 或 'main')
pattern: 配置中的模式 (例如 'user/*', 'feature/*')
treat_star_as_all: 是否将单独的 "*" 视为匹配所有内容(用于分支匹配)

Returns:
bool: 是否匹配
"""
if not value or not pattern:
return False

value = value.lower()
pattern = pattern.lower()

# 分支匹配特殊情况:单独的 "*" 匹配所有内容
if pattern == "*":
return True

if '*' in pattern or '?' in pattern or '[' in pattern:
return fnmatch.fnmatch(value, pattern)

return value == pattern
logger = logging.getLogger(__name__)

async def verify_signature(
request: Request,
Expand Down
File renamed without changes.
26 changes: 26 additions & 0 deletions app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2025 AptS-1547
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
OneBot GitHub Webhook models 模块
本模块用于定义 OneBot GitHub Webhook 的数据模型,包括 Webhook 配置和 OneBot 目标类型。
版本:0.1.0-alpha
日期:2025-04-17
本程序遵循 Apache License 2.0 许可证
"""

from .config import Config

__all__ = [
"Config",
]
Loading