Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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