gitwebhooks 2.3.1__tar.gz → 2.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitwebhooks-2.4.1/AGENTS.md +293 -0
- gitwebhooks-2.4.1/CONSTITUTION.md +310 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/MANIFEST.in +2 -1
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/PKG-INFO +21 -18
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/README.md +20 -17
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/README.zh.md +20 -17
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/__init__.py +1 -1
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/__init__.py +31 -62
- gitwebhooks-2.4.1/gitwebhooks/cli/help.py +86 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/init_wizard.py +1 -1
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/service.py +1 -50
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/main/__init__.py +31 -18
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/PKG-INFO +21 -18
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/SOURCES.txt +3 -5
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/pyproject.toml +1 -1
- gitwebhooks-2.4.1/tests/unit/cli/test_help.py +121 -0
- gitwebhooks-2.3.1/CLAUDE.md +0 -313
- gitwebhooks-2.3.1/gitwebhooks/cli/help.py +0 -155
- gitwebhooks-2.3.1/tests/test_auth/__init__.py +0 -2
- gitwebhooks-2.3.1/tests/test_config/__init__.py +0 -2
- gitwebhooks-2.3.1/tests/test_handlers/__init__.py +0 -2
- gitwebhooks-2.3.1/tests/test_integration/__init__.py +0 -2
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/.editorconfig +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/LICENSE +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/custom-body.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/custom-header.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/custom-response.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/gitee-success.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/gitee.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/github-success.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/github.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/gitlab-success.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/gitlab.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/install.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/doc/uninstall.png +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/__main__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/custom.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/factory.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/gitee.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/github.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/gitlab.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/auth/verifier.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/config.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/prompts.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/cli/serve.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/config/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/config/loader.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/config/models.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/config/registry.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/config/server.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/base.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/custom.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/factory.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/gitee.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/github.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/gitlab.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/handlers/request.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/logging/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/logging/setup.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/main/__main__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/main/version.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/models/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/models/config.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/models/provider.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/models/request.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/models/result.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/server.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/utils/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/utils/constants.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/utils/exceptions.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/utils/executor.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks/utils/systemd.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/dependency_links.txt +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/entry_points.txt +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/requires.txt +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.egg-info/top_level.txt +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/gitwebhooks.ini.sample +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/setup.cfg +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/__main__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/conftest.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/custom_payloads.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/gitee_payloads.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/github_payloads.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/gitlab_payloads.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/fixtures/signature_builder.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_command_execution.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_config_discovery.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_config_view_integration.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_custom_webhook.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_edge_cases.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_gitee_webhook.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_github_webhook.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/integration/test_gitlab_webhook.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/cli/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/cli/test_config_view.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/cli/test_init_wizard.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_config_level.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_config_loading.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_data_parsing.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_install_service_logic.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_main.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_prompts_config_level.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_provider_detection.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_request_handler.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_service_install_context.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/unit/test_signature_verification.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/utils/__init__.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/utils/certificate_generator.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/utils/coverage_runner.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/utils/http_client.py +0 -0
- {gitwebhooks-2.3.1 → gitwebhooks-2.4.1}/tests/utils/server_manager.py +0 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# AGENTS.md — gitwebhooks
|
|
2
|
+
|
|
3
|
+
> 轻量级 Git Webhook 服务器:接收 GitHub / Gitee / GitLab / 自定义平台的 webhook,按 INI 配置执行仓库部署命令。纯 Python 3 标准库实现,无外部运行时依赖。
|
|
4
|
+
>
|
|
5
|
+
> **⚠️ 最高编码准则见 [`CONSTITUTION.md`](./CONSTITUTION.md)(项目编码宪章)——所有 MUST 条款、合规分级与审查口径以宪章为准,冲突时宪章优先**。本文档为入口摘录,不重复宪章长文。
|
|
6
|
+
|
|
7
|
+
## 项目概述
|
|
8
|
+
|
|
9
|
+
| 项 | 值 |
|
|
10
|
+
|----|----|
|
|
11
|
+
| 语言 | Python(`requires-python = ">=3.6"`,classifiers 覆盖至 3.14) |
|
|
12
|
+
| 运行时依赖 | **无**(仅标准库;`pyproject.toml` 的 `dependencies = []` 是硬约定) |
|
|
13
|
+
| 开发依赖 | `pytest`、`pytest-cov`(可选,仅作测试运行器) |
|
|
14
|
+
| 代码规模 | ~4.9k 行(`gitwebhooks/`) |
|
|
15
|
+
| 配置格式 | INI(`configparser`) |
|
|
16
|
+
| HTTP | 标准库 `http.server` |
|
|
17
|
+
| 打包 | `setuptools`,可发布 PyPI,亦支持原地从源码运行 |
|
|
18
|
+
| 当前版本 | `2.4.1`(`pyproject.toml` 与 `gitwebhooks/__init__.py` **两处**) |
|
|
19
|
+
|
|
20
|
+
**支持平台**:GitHub(HMAC-SHA1 签名)、Gitee(签名或密码)、GitLab(token)、custom(自定义 Header + JSON 路径识别)。
|
|
21
|
+
|
|
22
|
+
## 宪章与文档层级
|
|
23
|
+
|
|
24
|
+
**最高编码准则:[`CONSTITUTION.md`](./CONSTITUTION.md)** —— 所有贡献者与 AI 代理必须遵守其 MUST 条款;本文档与 `README*.md`、`.dsh/skills/` 不得弱化宪章要求,**冲突时以宪章为准**。
|
|
25
|
+
|
|
26
|
+
| 优先级 | 文件 | 职责 |
|
|
27
|
+
|--------|------|------|
|
|
28
|
+
| 1 | `CONSTITUTION.md` | 编码宪章(MUST 条款、架构不变量、合规分级 A/B/C、审查矩阵) |
|
|
29
|
+
| 2 | `AGENTS.md`(本文档) | Agent 入口:架构、命令、约束摘录 |
|
|
30
|
+
| 3 | `README.md` / `README.zh.md` | 用户手册(安装、配置、使用;两语言须同步) |
|
|
31
|
+
| 4 | `.dsh/skills/*` | 操作技能(`code-review` 代码审查口径) |
|
|
32
|
+
|
|
33
|
+
## 架构
|
|
34
|
+
|
|
35
|
+
依赖方向单向(上层依赖下层):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
main/ cli/ 入口:参数解析、子命令分发、交互式向导
|
|
39
|
+
↓
|
|
40
|
+
server.py HTTP 服务器、请求生命周期编排
|
|
41
|
+
↓
|
|
42
|
+
handlers/ 平台事件识别 → 仓库分发 → 调用部署命令
|
|
43
|
+
auth/ 各平台签名 / token 校验(工厂 + 每平台一文件)
|
|
44
|
+
↓
|
|
45
|
+
config/ INI 加载、注册表、配置数据模型
|
|
46
|
+
models/ 与框架无关的数据类与枚举(Provider / WebhookRequest / 验证结果)
|
|
47
|
+
utils/ 常量、异常、命令执行、systemd 辅助
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**请求处理流程**:`do_POST()` → `_parse_provider()`(按 Header 识别平台)→ `_parse_data()`(JSON / form-urlencoded)→ 平台处理器验证签名 / token → 提取仓库标识 → 查配置 → 异步执行配置的命令。
|
|
51
|
+
|
|
52
|
+
**平台差异**(识别 Header / 仓库标识 / 验证方式):
|
|
53
|
+
|
|
54
|
+
| 平台 | 事件 Header | 仓库标识 | 验证 |
|
|
55
|
+
|------|-------------|----------|------|
|
|
56
|
+
| GitHub | `X-GitHub-Event` | `repository.full_name` | `X-Hub-Signature`(HMAC-SHA1) |
|
|
57
|
+
| Gitee | `X-Gitee-Event` | `repository.full_name` | 签名或密码 |
|
|
58
|
+
| GitLab | `X-Gitlab-Event` | `project.path_with_namespace` | `X-Gitlab-Token` |
|
|
59
|
+
| custom | 配置的 `header_event` | 配置的 `identifier_path` | 配置的 `header_token` |
|
|
60
|
+
|
|
61
|
+
## 文件结构
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
gitwebhooks-cli # Bash 包装脚本:自动定位包并以 python3 -m gitwebhooks.main 运行
|
|
65
|
+
pyproject.toml # 打包、版本号(源 1)、入口点 gitwebhooks.main:main
|
|
66
|
+
MANIFEST.in # sdist 清单
|
|
67
|
+
gitwebhooks.ini.sample # 配置模板(改配置项须同步)
|
|
68
|
+
scripts/pre-release-check.sh # 发布前校验(构建 + 隔离环境安装 + CLI 冒烟)
|
|
69
|
+
gitwebhooks/
|
|
70
|
+
├── __init__.py # 包入口、__version__(源 2)、导出 WebhookServer / Provider / WebhookRequest
|
|
71
|
+
├── server.py # WebhookServer 与请求处理器:编排与派发
|
|
72
|
+
├── main/
|
|
73
|
+
│ ├── __init__.py # create_parser / find_config_file / main(CLI 主函数)
|
|
74
|
+
│ ├── __main__.py # python3 -m gitwebhooks.main 入口
|
|
75
|
+
│ └── version.py # 版本输出
|
|
76
|
+
├── cli/
|
|
77
|
+
│ ├── __init__.py # 子命令注册(serve / config / help)
|
|
78
|
+
│ ├── serve.py # cmd_serve:启动服务器 / systemd 安装卸载分发
|
|
79
|
+
│ ├── service.py # systemd 安装卸载实现(被 serve.py 调用,非子命令)
|
|
80
|
+
│ ├── config.py # cmd_init / cmd_view
|
|
81
|
+
│ ├── init_wizard.py # 交互式配置向导(⚠️ 779 行,见宪章 §1.2)
|
|
82
|
+
│ ├── prompts.py # 交互提示辅助
|
|
83
|
+
│ └── help.py # help 子命令(输出由 argparse format_help 生成,与 --help 同源)
|
|
84
|
+
├── config/
|
|
85
|
+
│ ├── loader.py # INI 加载与自动查找
|
|
86
|
+
│ ├── registry.py # 配置注册表
|
|
87
|
+
│ ├── models.py # 配置数据类
|
|
88
|
+
│ └── server.py # 服务器 / SSL 配置
|
|
89
|
+
├── auth/
|
|
90
|
+
│ ├── verifier.py # 验证器基类
|
|
91
|
+
│ ├── factory.py # 验证器工厂
|
|
92
|
+
│ └── github.py gitee.py gitlab.py custom.py
|
|
93
|
+
├── handlers/
|
|
94
|
+
│ ├── base.py # 处理器基类
|
|
95
|
+
│ ├── request.py # 请求数据解析
|
|
96
|
+
│ ├── factory.py # 处理器工厂
|
|
97
|
+
│ └── github.py gitee.py gitlab.py custom.py
|
|
98
|
+
├── models/
|
|
99
|
+
│ ├── provider.py # Provider 枚举(Github / Gitee / Gitlab / Custom)
|
|
100
|
+
│ ├── request.py # WebhookRequest 数据类
|
|
101
|
+
│ ├── result.py # 验证结果
|
|
102
|
+
│ └── config.py # 配置模型
|
|
103
|
+
├── utils/
|
|
104
|
+
│ ├── constants.py # HTTP 常量、Header 名、路径、RESERVED_SECTIONS、SENSITIVE_KEYWORDS
|
|
105
|
+
│ ├── exceptions.py # 自定义异常(含 ConfigurationError)
|
|
106
|
+
│ ├── executor.py # execute_deployment(异步 subprocess)
|
|
107
|
+
│ └── systemd.py # systemd 检测与服务文件生成
|
|
108
|
+
└── logging/setup.py # 日志配置
|
|
109
|
+
tests/
|
|
110
|
+
├── __main__.py # 项目自带 runner:python3 -m tests
|
|
111
|
+
├── conftest.py # 共享夹具(临时目录、空闲端口、服务器管理等)
|
|
112
|
+
├── unit/ # 单元测试(unit/cli/ 为 CLI 子命令测试)
|
|
113
|
+
├── integration/ # 端到端 webhook / 配置发现 / 命令执行
|
|
114
|
+
├── fixtures/ # 各平台 payload 与签名构造器
|
|
115
|
+
└── utils/ # 测试辅助(HTTP 客户端、服务器管理、证书生成)
|
|
116
|
+
doc/ # README 截图(二进制资源)
|
|
117
|
+
.dsh/skills/ # DSH 项目技能(项目唯一技能来源)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 配置结构
|
|
121
|
+
|
|
122
|
+
INI 格式(`configparser`),保留节名以 `utils/constants.py` 的 `RESERVED_SECTIONS` 为准:
|
|
123
|
+
|
|
124
|
+
| 节 | 内容 |
|
|
125
|
+
|----|------|
|
|
126
|
+
| `[server]` | `address`、`port`、`log_file` |
|
|
127
|
+
| `[ssl]` | `enable`、`key_file`、`cert_file` |
|
|
128
|
+
| `[github]` / `[gitee]` / `[gitlab]` | `handle_events`、`verify`、`secret` |
|
|
129
|
+
| `[custom]` | `header_name`、`header_value`、`header_token`、`header_event`、`identifier_path`、`handle_events`、`verify`、`secret` |
|
|
130
|
+
| `[owner/repo]` | **仓库节**:`cwd`(工作目录)、`cmd`(收到 webhook 时执行的 shell 命令) |
|
|
131
|
+
|
|
132
|
+
- 仓库节名必须为 `owner/repo`;`identifier_path` 是 JSON 路径(如 `project.path_with_namespace`),用点号分隔。
|
|
133
|
+
- 改配置项**必须**同步 `gitwebhooks.ini.sample`、`RESERVED_SECTIONS` 与两个 README。
|
|
134
|
+
|
|
135
|
+
**默认部署路径**:配置 `/usr/local/etc/gitwebhooks.ini`、日志 `/var/log/gitwebhooks.log`、CLI `/usr/local/bin/gitwebhooks-cli`、systemd 单元 `/usr/lib/systemd/system/gitwebhooks.service`。
|
|
136
|
+
|
|
137
|
+
## 常用命令
|
|
138
|
+
|
|
139
|
+
### 运行服务
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# 从源码运行(开发模式,推荐)
|
|
143
|
+
./gitwebhooks-cli serve -c gitwebhooks.ini.sample
|
|
144
|
+
|
|
145
|
+
# 模块方式(等价)
|
|
146
|
+
python3 -m gitwebhooks.main serve -c gitwebhooks.ini.sample
|
|
147
|
+
|
|
148
|
+
# 不指定 -c:按优先级自动查找配置并打印所用路径
|
|
149
|
+
./gitwebhooks-cli serve
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
> ⚠️ 启动服务器**必须**带 `serve` 子命令。`./gitwebhooks-cli -c file.ini`(无子命令)只会打印帮助并返回 0,不会启动服务。
|
|
153
|
+
|
|
154
|
+
**配置文件查找优先级**(唯一出处 `utils/constants.py` 的 `CONFIG_SEARCH_PATHS`):
|
|
155
|
+
|
|
156
|
+
1. `~/.gitwebhooks.ini`(用户级,最高)
|
|
157
|
+
2. `/usr/local/etc/gitwebhooks.ini`(本地级)
|
|
158
|
+
3. `/etc/gitwebhooks.ini`(系统级)
|
|
159
|
+
|
|
160
|
+
### 子命令
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
./gitwebhooks-cli --help # 总览帮助(亦可 -h;每层级均支持)
|
|
164
|
+
./gitwebhooks-cli help # 等价形式:help 子命令
|
|
165
|
+
./gitwebhooks-cli help serve # 指定子命令帮助(serve / config)
|
|
166
|
+
./gitwebhooks-cli serve --help # 同上,标准 flag 形式(两者输出完全一致)
|
|
167
|
+
./gitwebhooks-cli --version # 版本(亦可 -v)
|
|
168
|
+
|
|
169
|
+
# 配置:交互式向导(可指定级别 system/local/user)
|
|
170
|
+
./gitwebhooks-cli config init
|
|
171
|
+
sudo ./gitwebhooks-cli config init system
|
|
172
|
+
./gitwebhooks-cli config view # 查看配置,敏感字段高亮
|
|
173
|
+
./gitwebhooks-cli config view -c /path/to/config.ini
|
|
174
|
+
|
|
175
|
+
# systemd 服务(注意:是 serve 的子动作,不是独立的 service 子命令)
|
|
176
|
+
sudo ./gitwebhooks-cli serve install [--force] [--dry-run] [--verbose] [--config-level user|local|system]
|
|
177
|
+
./gitwebhooks-cli serve install --config-level user
|
|
178
|
+
sudo ./gitwebhooks-cli serve uninstall [--purge]
|
|
179
|
+
|
|
180
|
+
# systemd 运行时
|
|
181
|
+
systemctl {start,stop,restart,status} gitwebhooks
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
> ⚠️ 独立的 `service` 子命令**已被移除**(见 git log `refactor: 彻底移除 service 命令`),改为 `serve install` / `serve uninstall`。文档或脚本中出现 `gitwebhooks-cli service ...` 即为过时引用。
|
|
185
|
+
|
|
186
|
+
### 安装与发布
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pip install . # 安装(无外部依赖)
|
|
190
|
+
pip install -e ".[dev]" # 开发安装(含 pytest)
|
|
191
|
+
|
|
192
|
+
./scripts/pre-release-check.sh # 发布前必须通过:构建 + 隔离 venv 安装 + CLI 冒烟
|
|
193
|
+
python3 -m build && python3 -m twine upload dist/*
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 测试与质量门禁
|
|
197
|
+
|
|
198
|
+
**项目自带 runner(无需 pytest,推荐)**:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
python3 -m tests # 全量
|
|
202
|
+
python3 -m tests -q # 仅摘要
|
|
203
|
+
python3 -m tests -f # 失败即停
|
|
204
|
+
python3 -m tests -v # 详细
|
|
205
|
+
python3 -m tests unit # 只跑单元测试(也可传 integration)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**pytest 驱动(可选,需自行安装 `pytest`)**:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
python3 -m pytest tests/
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**语法静态校验**:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
python3 -m compileall -q gitwebhooks
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 门禁纪律
|
|
221
|
+
|
|
222
|
+
- 交付前至少跑 `python3 -m compileall -q gitwebhooks` + 爆炸半径内测试;
|
|
223
|
+
- **如实区分**「本机真跑过 / 只做了静态检查 / 未执行」;声称通过时给出**实际计数**(跑了多少 / 失败 / 跳过);
|
|
224
|
+
- **禁止吞输出**(`>/dev/null`、`2>/dev/null`、`-q` 用于可能失败的命令);
|
|
225
|
+
- CLI 子命令增删时,**必须**核对全部引用点:`cli/__init__.py` 注册、`cli/help.py`、`README.md`、`README.zh.md`、`scripts/pre-release-check.sh`、相关测试。
|
|
226
|
+
|
|
227
|
+
### ⚠️ 已知测试基线偏差
|
|
228
|
+
|
|
229
|
+
以下 7 个测试模块直接 `import pytest`,**在未安装 pytest 的环境下整体无法导入**(报 `ModuleNotFoundError`):
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
tests/unit/test_main.py tests/unit/test_prompts_config_level.py
|
|
233
|
+
tests/unit/test_config_level.py tests/unit/test_service_install_context.py
|
|
234
|
+
tests/unit/test_install_service_logic.py tests/integration/test_config_discovery.py
|
|
235
|
+
tests/unit/cli/test_init_wizard.py
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**基线(2026-10-12 实测,Python 3.14,无 pytest)**:`Ran 121 tests`,**0 failures + 7 errors**。
|
|
239
|
+
- 7 个 error = 上述 pytest 导入失败(模块整体无法导入,不是因为断言失败);
|
|
240
|
+
- **0 failures**:此前的 `test_help_display_with_h_argument` 失败已修复(`-h` 现按标准约定返回码 0)。
|
|
241
|
+
|
|
242
|
+
判定改动是否引入回归时,**必须与此基线对比**:新增 failure 才算回归;7 个 error 是既有环境缺陷,不得当作新缺陷,也不得隐去不报。宪章 §6.1 要求新测试用 `unittest` 编写,不新增 pytest 依赖。
|
|
243
|
+
|
|
244
|
+
## 代码审查
|
|
245
|
+
|
|
246
|
+
代码 / 文档改动交付前,加载 **`.dsh/skills/code-review/SKILL.md`** 执行审查:按宪章输出 `P0–P3 × file:line × 依据条款 × 证据` 的结构化发现清单。
|
|
247
|
+
|
|
248
|
+
- 审查**只报不改**;发现自己问题的「顺手修一下」不属于审查结论。
|
|
249
|
+
- 涉及**必须运行才能确认**的项(如某失败是否被修复、某分支是否真的到达),标注「需主代理跑门禁确认」,**禁止**把推测写成已验证。
|
|
250
|
+
- 合规分级与审查矩阵见宪章 §10.2 / §10.3。
|
|
251
|
+
|
|
252
|
+
## Git 纪律
|
|
253
|
+
|
|
254
|
+
- 提交格式 `<类型>: <简短描述>`(feat / fix / docs / refactor / test / chore),**使用中文**;
|
|
255
|
+
- **禁止** AI 归属签名(`🤖 Generated with ...`)、`Co-Authored-By:` 形式的 AI 署名、emoji;
|
|
256
|
+
- 一次提交只含一项已完成工作,禁止夹带无关文件;未过门禁不得提交;
|
|
257
|
+
- 未经用户明确授权,**不得** `git commit` / `git push` / 改写历史。
|
|
258
|
+
|
|
259
|
+
## 开发原则
|
|
260
|
+
|
|
261
|
+
1. **文档优先**:改前先 `read` / `grep` 验证 API 与现有模式,不假设文件或函数存在;
|
|
262
|
+
2. **禁止反复猜测试错**:遇报错先查权威来源(Python 官方文档、`README*.md`、本宪章)确认根因,再最小复现验证;
|
|
263
|
+
3. **最小改动**:只改任务相关代码,拒绝过度抽象(YAGNI / KISS);
|
|
264
|
+
4. **匹配现有风格**:命名、目录、抽象层级与周边代码一致;注释 / docstring 语言**按层就近一致**(核心模块英文、CLI 交互层中文,见宪章 §2.1),代码标识符一律英文,commit 用**中文**;
|
|
265
|
+
5. **同步文档**:用户可见行为变更 → 两个 README;架构 / 命令变更 → 本文档;命令或配置项增删 → 核对 §「门禁纪律」的引用点清单;
|
|
266
|
+
6. **零依赖**:不引入运行时第三方依赖(`dependencies` 保持为空);
|
|
267
|
+
7. **版本双源**:改版本号必须同时改 `pyproject.toml` 与 `gitwebhooks/__init__.py`,提交前 `grep` 复核。
|
|
268
|
+
|
|
269
|
+
## 常见陷阱
|
|
270
|
+
|
|
271
|
+
| 问题 | 说明 |
|
|
272
|
+
|------|------|
|
|
273
|
+
| **`serve` vs `service`** | 独立 `service` 子命令已移除;systemd 管理是 `serve install` / `serve uninstall`。`cli/service.py` 是内部实现模块,不是子命令。 |
|
|
274
|
+
| **版本双源** | `pyproject.toml` 与 `gitwebhooks/__init__.py` 各存一份版本号,无自动同步;`main/version.py` 从包 `__version__` 读取。 |
|
|
275
|
+
| **两处平台注册** | 新增平台须同时改 `handlers/factory.py` 与 `auth/factory.py`,并加 `handlers/<p>.py` 与 `auth/<p>.py`;漏一处会「识别了平台但无法验证」。 |
|
|
276
|
+
| **pytest 依赖** | 7 个测试模块 `import pytest` 导致无 pytest 环境整体导入失败(见上「已知测试基线偏差」)。新测试用 `unittest`。 |
|
|
277
|
+
| **配置常量分散风险** | 路径列表、Header 名、状态码、敏感字段关键词的唯一出处是 `utils/constants.py`;别处硬编码即漂移。 |
|
|
278
|
+
| **命令执行信任边界** | `execute_deployment` 使用 `shell=True`。安全前提是「命令只来自本地配置文件」——**禁止**把请求体内容拼进命令。 |
|
|
279
|
+
| **CLI 文档漂移** | README 两个语言版本与 `scripts/pre-release-check.sh` 曾残留已删除的 `service` 引用;增删子命令时按引用点清单全查。 |
|
|
280
|
+
| **模块入口是 `gitwebhooks.main`** | `gitwebhooks.cli` 是子命令包,**没有** `__main__.py`,`python3 -m gitwebhooks.cli` 会失败;模块方式启动一律用 `python3 -m gitwebhooks.main`。 |
|
|
281
|
+
| **帮助只有一个来源** | 帮助文本由 argparse 从解析器定义生成:`help.py` 不再持有手写文案。改选项后 `help <cmd>` 与 `<cmd> --help` 自动同步,不要另写一份帮助字符串。 |
|
|
282
|
+
| **启动服务器必须带 `serve`** | `./gitwebhooks-cli -c file.ini`(无子命令)只打印帮助并返回 0,**不会**启动服务;正确写法是 `./gitwebhooks-cli serve -c file.ini`。文档一律以此为准。 |
|
|
283
|
+
|
|
284
|
+
## 受控文档索引
|
|
285
|
+
|
|
286
|
+
| 文档 | 内容 |
|
|
287
|
+
|------|------|
|
|
288
|
+
| [`CONSTITUTION.md`](./CONSTITUTION.md) | **编码宪章(最高准则)**:适用范围、架构不变量、安全、测试、合规分级、审查矩阵 |
|
|
289
|
+
| [`AGENTS.md`](./AGENTS.md)(本文档) | Agent 入口:架构、命令、门禁、陷阱 |
|
|
290
|
+
| [`README.md`](./README.md) | 用户手册(英文):安装、配置、使用、发布 |
|
|
291
|
+
| [`README.zh.md`](./README.zh.md) | 用户手册(中文) |
|
|
292
|
+
| [`gitwebhooks.ini.sample`](./gitwebhooks.ini.sample) | 配置模板 |
|
|
293
|
+
| [`.dsh/skills/code-review/SKILL.md`](./.dsh/skills/code-review/SKILL.md) | 代码审查口径与清单 |
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# gitwebhooks 项目编码宪章
|
|
2
|
+
|
|
3
|
+
> 本宪章是 gitwebhooks 项目的**最高编码准则**,所有贡献者与自动化工具(AI 编码代理)均须遵守。
|
|
4
|
+
> 「必须 (MUST)」「禁止 (MUST NOT)」为硬性规定;「建议 (SHOULD)」「不建议 (SHOULD NOT)」为强烈指引,
|
|
5
|
+
> 偏离需有充分理由并在代码审查中说明。
|
|
6
|
+
> 版本 v1.0;修订历史记录在 git log,不在本文维护。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 〇、适用范围与文档层级
|
|
11
|
+
|
|
12
|
+
### 0.1 适用范围(本宪章约束什么)
|
|
13
|
+
|
|
14
|
+
本宪章约束**项目自有代码与文档**:任何人(含 AI 代理)在本仓库内编写、修改、审查的内容,包括:
|
|
15
|
+
|
|
16
|
+
- Python 包 `gitwebhooks/`:`server.py`、`main/`、`cli/`、`config/`、`auth/`、`handlers/`、`models/`、`utils/`、`logging/`;
|
|
17
|
+
- 测试套件 `tests/`(unit / integration / fixtures / utils);
|
|
18
|
+
- 打包与脚本:`pyproject.toml`、`MANIFEST.in`、`gitwebhooks-cli`、`scripts/`;
|
|
19
|
+
- 配置模板 `gitwebhooks.ini.sample`;
|
|
20
|
+
- 项目文档:`README.md`、`README.zh.md`、`AGENTS.md`、本宪章、`.dsh/skills/`。
|
|
21
|
+
|
|
22
|
+
### 0.2 排除范围(不在宪章要求与审查范围)
|
|
23
|
+
|
|
24
|
+
**依赖产物、解释器标准库与构建产物不受本宪章条款约束,审查时不判违规**:
|
|
25
|
+
|
|
26
|
+
- Python 标准库与解释器自身;
|
|
27
|
+
- 第三方依赖(`pytest`、`pytest-cov` 等)及其安装产物(`.venv/`、`venv/`、`site-packages`);
|
|
28
|
+
- 构建与缓存产物:`dist/`、`build/`、`*.egg-info/`、`__pycache__/`、`.pytest_cache/`;
|
|
29
|
+
- 文档截图 `doc/*.png`(二进制资源)。
|
|
30
|
+
|
|
31
|
+
说明:
|
|
32
|
+
|
|
33
|
+
- **使用标准库惯例不构成违规**(如 `argparse` 的子命令风格、`configparser` 的取值方式);
|
|
34
|
+
- 例外:**写在上述产物之外的自有逻辑**仍受本宪章约束。
|
|
35
|
+
|
|
36
|
+
### 0.3 文档层级
|
|
37
|
+
|
|
38
|
+
standing instructions 分层如下,**冲突时以上级为准**:
|
|
39
|
+
|
|
40
|
+
| 优先级 | 文件 | 职责 |
|
|
41
|
+
|--------|------|------|
|
|
42
|
+
| 1 | `CONSTITUTION.md`(本文件) | 编码宪章、质量门禁、安全与 Agent 纪律 |
|
|
43
|
+
| 2 | `AGENTS.md` | Agent 入口(链接本宪章,摘录要点,不重复长文) |
|
|
44
|
+
| 3 | `README.md` / `README.zh.md` | 用户手册(安装、配置、使用) |
|
|
45
|
+
| 4 | `.dsh/skills/*` | 操作技能(如 `code-review` 代码审查口径) |
|
|
46
|
+
|
|
47
|
+
- 下级文档**不得弱化**本宪章的 MUST 条款;
|
|
48
|
+
- 细则性内容(使用示例、配置说明)以 `README*.md` 为准,本宪章不重复长文。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 一、代码组织
|
|
53
|
+
|
|
54
|
+
### 1.1 分层与职责
|
|
55
|
+
|
|
56
|
+
- **必须**:保持既有的模块化分层,各层职责单一,依赖方向单向(上层依赖下层,禁止反向):
|
|
57
|
+
|
|
58
|
+
| 层 | 路径 | 职责 |
|
|
59
|
+
|----|------|------|
|
|
60
|
+
| 入口 | `main/`、`cli/` | 参数解析、子命令分发、交互式向导 |
|
|
61
|
+
| 服务 | `server.py` | HTTP 服务器、请求生命周期编排 |
|
|
62
|
+
| 处理 | `handlers/` | 平台事件识别与仓库分发(按平台分文件) |
|
|
63
|
+
| 验证 | `auth/` | 各平台签名 / token 校验(工厂 + 每平台一文件) |
|
|
64
|
+
| 配置 | `config/` | INI 加载、注册表、配置数据模型 |
|
|
65
|
+
| 模型 | `models/` | 与框架无关的数据类与枚举 |
|
|
66
|
+
| 工具 | `utils/` | 常量、异常、命令执行、systemd 辅助 |
|
|
67
|
+
|
|
68
|
+
- **必须**:`models/`、`config/`、`auth/`、`handlers/` 之间不得循环导入。
|
|
69
|
+
- **必须**:`server.py` 只做编排——平台识别、验证、查表、派发;平台专属解析逻辑放对应 `handlers/<platform>.py`。
|
|
70
|
+
- **建议**:新增平台支持时,**同时**新增 `handlers/<platform>.py` 与 `auth/<platform>.py`,并在两个工厂中各注册一处;不要用 `if platform == ...` 在主流程里分叉。
|
|
71
|
+
|
|
72
|
+
### 1.2 规模指标(所有语言)
|
|
73
|
+
|
|
74
|
+
- **必须**:圈复杂度 ≤ 10;嵌套 ≤ 3 层;方法 ≤ 80 行;参数 ≤ 5 个。
|
|
75
|
+
- **必须**:DRY——同一逻辑出现 3 处及以上必须提取复用。
|
|
76
|
+
- **必须**:消除魔法数字与魔法字符串,提取为 `utils/constants.py` 中的常量或类常量;HTTP 状态码、Header 名、消息文案一律走常量。
|
|
77
|
+
- **建议**:单文件不超过 **400 行**;超过时按语义边界拆分(独立类型 > 独立函数组 > 辅助逻辑)。
|
|
78
|
+
|
|
79
|
+
> **已知存量偏差(基线,非许可)**:`gitwebhooks/cli/init_wizard.py`(779 行)、`gitwebhooks/cli/service.py`(352 行)、`gitwebhooks/cli/prompts.py`(322 行)超过 400 行。
|
|
80
|
+
> 这些文件**不允许继续变大**;触及它们时应评估拆分,拆分须作为独立任务登记,不得夹带在无关改动里。
|
|
81
|
+
|
|
82
|
+
### 1.3 命名与目录
|
|
83
|
+
|
|
84
|
+
- **必须**:模块与文件命名用完整小写单词或下划线(`init_wizard.py` 而非 `iw.py`);与同目录既有风格一致。
|
|
85
|
+
- **必须**:私有方法 / 函数使用**单下划线**前缀(如 `_parse_provider`),与现有代码一致;**不使用**双下划线前缀(`__init__`、`__post_init__` 等 dunder 除外)。
|
|
86
|
+
- **必须**:公有 API 不加下划线前缀。
|
|
87
|
+
- **必须**:配置节名与仓库标识遵循 `[owner/repo]` 约定;保留节名集合以 `utils/constants.py` 的 `RESERVED_SECTIONS` 为唯一出处。
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 二、注释与文档
|
|
92
|
+
|
|
93
|
+
### 2.1 注释语言
|
|
94
|
+
|
|
95
|
+
本仓库的注释与文案语言**按层就近一致**,不强制全仓统一;新增 / 修改时匹配**所在模块**的既有语言:
|
|
96
|
+
|
|
97
|
+
| 层 | 语言 | 现状 |
|
|
98
|
+
|----|------|------|
|
|
99
|
+
| 核心模块(`server.py`、`models/`、`config/`、`auth/`、`handlers/`、`utils/`) | **英文** docstring 与注释 | 现有文件均为英文,保持一致 |
|
|
100
|
+
| CLI 交互层(`cli/init_wizard.py`、`cli/prompts.py`、`cli/config.py`、`logging/setup.py`) | **中文** docstring 与注释 | 现有文件以中文为主,保持一致 |
|
|
101
|
+
| 用户可见输出 | 交互式向导与 `config` 子命令用**中文**;`argparse` 帮助文案用**英文** | 现状如此 |
|
|
102
|
+
| 治理文档(`CONSTITUTION.md`、`AGENTS.md`、`.dsh/skills/*`、`README.zh.md`) | **中文** | — |
|
|
103
|
+
| commit message | **中文**(见 §9.3) | — |
|
|
104
|
+
|
|
105
|
+
- **禁止**:在同一文件内新建中英混排的注释块(匹配不了就选该文件的主导语言)。
|
|
106
|
+
- **禁止**:为「统一语言」而批量重写既有注释——那是无关 drive-by 改动(§3.1)。
|
|
107
|
+
- **允许**:`gitwebhooks-cli` 等面向维护者的 shell 包装脚本使用中文注释(既有惯例)。
|
|
108
|
+
- **必须**:代码标识符(类名、函数名、变量名、配置键)一律用**英文**。
|
|
109
|
+
|
|
110
|
+
### 2.2 文档注释与同步
|
|
111
|
+
|
|
112
|
+
- **必须**:对外暴露的 API(`WebhookServer` 公共方法、`handlers` / `auth` / `config` 的公共方法、CLI 子命令、枚举)具备用途与关键参数 / 返回值说明。
|
|
113
|
+
- **必须**:注释解释**意图**而非复述代码;临时方案以 `TODO:` / `FIXME:` 标注并附原因。
|
|
114
|
+
- **必须**:功能变更同步更新对应文档——用户可见行为(CLI 命令、配置项、平台支持)变更时更新 `README.md` **与** `README.zh.md`;架构或命令入口变更时更新 `AGENTS.md`。
|
|
115
|
+
- **禁止**:为「将来可能用到」编写文档或注释。
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 三、编码原则
|
|
120
|
+
|
|
121
|
+
### 3.1 最少编码
|
|
122
|
+
|
|
123
|
+
- **必须**:以最少代码实现需求,拒绝冗余抽象(YAGNI / KISS);不为可能的扩展提前设计。
|
|
124
|
+
- **必须**:单次变更范围限于任务本身,**禁止**无关 drive-by 重构。
|
|
125
|
+
- **必须**:**零外部运行时依赖**——`pyproject.toml` 的 `[project].dependencies` 必须保持为空数组。新增任何运行时依赖都需要用户明确批准,并在本宪章修订流程中登记。
|
|
126
|
+
|
|
127
|
+
### 3.2 零死代码
|
|
128
|
+
|
|
129
|
+
- **禁止**:未被调用的函数 / 方法 / 类 / 常量、未使用的 import、无引用的配置项。
|
|
130
|
+
- **禁止**:生产路径残留调试输出(`print()` 用于调试、`breakpoint()`、`pdb`);日志一律走 `logging`。
|
|
131
|
+
- **必须**:触及旧代码时发现死代码**必须**移除或登记跟踪(见 §10.2 合规分级)。
|
|
132
|
+
- **必须**:命令 / 子命令被移除时,同步清理**所有**引用点(`cli/__init__.py` 注册、`cli/help.py` 文案、README 两个语言版本、`scripts/pre-release-check.sh`、相关测试)。
|
|
133
|
+
|
|
134
|
+
> 存量偏差:`scripts/pre-release-check.sh` 曾校验已被移除的 `service` 子命令,属于此类漏改;该引用已修正为 `serve`。
|
|
135
|
+
|
|
136
|
+
### 3.3 领域惯例(核心不变量)
|
|
137
|
+
|
|
138
|
+
以下为本项目的**架构不变量**,违反视为 P1 及以上:
|
|
139
|
+
|
|
140
|
+
- **必须**:配置驱动行为——仓库专属逻辑(工作目录、执行命令)**只**来自 INI 配置,**禁止**把仓库名或仓库专属分支写进 Python 代码。
|
|
141
|
+
- **必须**:平台中立——各平台(GitHub / Gitee / GitLab / custom)地位平等,平台识别**只**依据请求 Header;除已文档化的 Header / 事件名差异外,不得有平台特权分支。
|
|
142
|
+
- **必须**:平台标识与 Header / 事件名 / 常量集中定义,不得散落字面量(见 §1.2)。
|
|
143
|
+
- **必须**:请求体解析同时支持 JSON 与 `application/x-www-form-urlencoded`;新增平台不得削减既有支持。
|
|
144
|
+
- **必须**:命令执行异步非阻塞,且 `stdin=subprocess.DEVNULL`——避免继承 stdin 造成文件描述符泄漏。
|
|
145
|
+
- **必须**(CLI 约定,遵循标准 Unix 工具规范):
|
|
146
|
+
- `-h` / `--help` 在**每一个命令层级**(主命令、`serve`/`config`、其下动作)都必须可用,帮助输出到 **stdout**,退出码 **0**;
|
|
147
|
+
- `-v` / `--version` 在**主命令层**可用,输出到 stdout,退出码 0;
|
|
148
|
+
- 帮助文本是**单一来源**——由 argparse 从解析器定义生成;`help` 子命令与 `-h/--help` 必须输出**完全一致**的文本,**禁止**另外维护一份手写帮助字符串;
|
|
149
|
+
- 用法错误输出到 **stderr** 且退出码非 0;`help <未知命令>` 同样如此。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 四、配置与数据正确性
|
|
154
|
+
|
|
155
|
+
### 4.1 配置结构
|
|
156
|
+
|
|
157
|
+
- **必须**:配置为 INI 格式、人类可读;新增配置项同步更新 `gitwebhooks.ini.sample`。
|
|
158
|
+
- **必须**:配置文件查找优先级为 `~/.gitwebhooks.ini` > `/usr/local/etc/gitwebhooks.ini` > `/etc/gitwebhooks.ini`;该顺序以 `utils/constants.py` 的 `CONFIG_SEARCH_PATHS` 为唯一出处,不得在别处硬编码路径列表。
|
|
159
|
+
- **必须**:找不到配置文件时给出**明确**错误信息(含已尝试的路径),不得静默使用默认值继续启动。
|
|
160
|
+
- **必须**:缺失的必需配置项在**启动时**报错退出,不得推迟到收到 webhook 时才失败。
|
|
161
|
+
|
|
162
|
+
### 4.2 数据正确性
|
|
163
|
+
|
|
164
|
+
- **必须**:对外部输入(请求体、Header、配置值)做显式校验后再使用;不得依赖「调用方一定传对」。
|
|
165
|
+
- **必须**:JSON 路径提取(如 custom 平台的 `identifier_path`)在路径不存在时返回明确失败,不得抛未捕获异常。
|
|
166
|
+
- **必须**:命令执行使用仓库配置的 `cwd`,不得使用进程继承的当前目录。
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 五、安全与数据保护
|
|
171
|
+
|
|
172
|
+
### 5.1 凭据
|
|
173
|
+
|
|
174
|
+
- **必须**:密钥 / token **只**存在于配置文件,**禁止**硬编码进源码、测试或文档示例(示例值一律留空或写占位路径)。
|
|
175
|
+
- **必须**:生成的配置文件权限为 **0600**(仅属主可读写)。
|
|
176
|
+
- **禁止**:把 secret / token 原文写入日志或错误输出。日志中出现配置值时,敏感字段必须脱敏;敏感字段判定以 `utils/constants.py` 的 `SENSITIVE_KEYWORDS` 为准。
|
|
177
|
+
- **必须**:`config view` 对敏感字段做高亮 / 提示,且**不得**改变「本地可读」这一前提去新增网络出口。
|
|
178
|
+
|
|
179
|
+
### 5.2 命令执行
|
|
180
|
+
|
|
181
|
+
- **必须**:执行命令使用 `shell=True` 时必须确认命令来源**仅为本地配置文件**(信任边界),并在代码注释中写明该前提。
|
|
182
|
+
- **禁止**:将 webhook 请求体中的任意内容拼进待执行命令(命令注入)。
|
|
183
|
+
- **必须**:命令执行失败(`OSError` / `SubprocessError`)记录 warning 并继续服务,不得让异常冒泡终止 HTTP 处理线程。
|
|
184
|
+
|
|
185
|
+
### 5.3 请求与传输
|
|
186
|
+
|
|
187
|
+
- **必须**:webhook 端点拒绝不支持的方法(如 GET 返回 403)。
|
|
188
|
+
- **必须**:支持的各平台签名验证逻辑不得被静默跳过;`verify=False` 是**配置显式选择**,不是代码默认省略校验。
|
|
189
|
+
- **必须**:SSL 证书与私钥路径在服务器启动前校验;文件缺失 / 不可读时明确报错。
|
|
190
|
+
- **建议**:服务以非特权用户运行。
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 六、测试
|
|
195
|
+
|
|
196
|
+
### 6.1 框架与覆盖
|
|
197
|
+
|
|
198
|
+
- **必须**:测试位于 `tests/`,单元测试在 `tests/unit/`,端到端 / 集成测试在 `tests/integration/`,共享夹具在 `tests/fixtures/`,测试工具在 `tests/utils/`。
|
|
199
|
+
- **必须**:测试可同时被 `unittest` 与 `pytest` 驱动——**导入了 `pytest` 的测试文件属于已知偏差**,不得新增;新测试统一用 `unittest.TestCase` 编写(`pytest` 仅作为可选的运行器)。
|
|
200
|
+
|
|
201
|
+
> **已知存量偏差**:`tests/unit/test_main.py`、`tests/unit/test_config_level.py`、`tests/unit/test_install_service_logic.py`、`tests/unit/test_service_install_context.py`、`tests/unit/test_prompts_config_level.py`、`tests/unit/cli/test_init_wizard.py`、`tests/integration/test_config_discovery.py` 直接 `import pytest`,导致无 pytest 环境下 **7 个测试模块整体无法导入**。修复方向是移除 `pytest` 依赖(改用 `unittest`),作为独立任务登记。
|
|
202
|
+
|
|
203
|
+
- **必须**:Bug 修复附带**能复现该 bug 的测试**(先 Red 后 Green)。
|
|
204
|
+
- **必须**:修改平台逻辑时,覆盖该平台的签名验证(成功 + 失败)与仓库识别路径。
|
|
205
|
+
- **必须**:测试不得依赖外部网络、真实 Git 平台或固定端口(端口从 `get_free_port()` 之类的辅助函数获取)。
|
|
206
|
+
|
|
207
|
+
### 6.2 验证纪律
|
|
208
|
+
|
|
209
|
+
- **必须**:交付前真跑测试并**如实区分**「本机真跑过 / 只做了静态检查 / 未执行」;不得用「已验证」笼统概括。
|
|
210
|
+
- **禁止**:吞输出——可能失败的命令不得 `>/dev/null`、`2>/dev/null`、`-q`;失败时输出是唯一线索。
|
|
211
|
+
- **必须**:声称「测试通过」时给出**实际计数**(跑了多少、失败多少、跳过多少),并说明运行环境是否具备 `pytest`。
|
|
212
|
+
- **禁止**:把「未安装依赖导致的导入错误」当作「改动引入的失败」,也**禁止**反过来把它当作正常基线而不报告。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 七、工具链与质量门禁
|
|
217
|
+
|
|
218
|
+
### 7.1 门禁命令
|
|
219
|
+
|
|
220
|
+
| 目的 | 命令 | 说明 |
|
|
221
|
+
|------|------|------|
|
|
222
|
+
| 全量测试 | `python3 -m tests` | 项目自带 runner(`unittest` 驱动) |
|
|
223
|
+
| 静默测试 | `python3 -m tests -q` | 仅输出摘要 |
|
|
224
|
+
| 失败即停 | `python3 -m tests -f` | 快速定位 |
|
|
225
|
+
| pytest 驱动(可选) | `python3 -m pytest tests/` | 需另装 `pytest`;非必需路径 |
|
|
226
|
+
| 语法检查 | `python3 -m compileall -q gitwebhooks` | 快速静态校验 |
|
|
227
|
+
|
|
228
|
+
- **必须**:交付前至少跑通 `python3 -m compileall -q gitwebhooks` 与爆炸半径内的测试。
|
|
229
|
+
- **禁止**:以「pytest 未安装」为由跳过测试并声称通过(见 §6.2)。
|
|
230
|
+
|
|
231
|
+
### 7.2 发布
|
|
232
|
+
|
|
233
|
+
- **必须**:发布 PyPI **前**运行 `./scripts/pre-release-check.sh` 并全部通过;**禁止**跳过。
|
|
234
|
+
- **必须**:版本号在 `pyproject.toml` 与 `gitwebhooks/__init__.py` 的 `__version__` **两处同步**;两处不一致视为 P1 缺陷。
|
|
235
|
+
|
|
236
|
+
> 这是一处已知的双源风险(无自动同步机制)。改版本时必须两处都改,并在提交前 `grep` 复核。
|
|
237
|
+
- **必须**:发布流程 = ① 跑 `pre-release-check.sh` → ② 两处改版本号 → ③ 行为变更时更新两个 README → ④ 打语义化版本 tag → ⑤ 构建并上传。
|
|
238
|
+
- **禁止**:未跑校验脚本就上传 PyPI。
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 八、文案与双语文档
|
|
243
|
+
|
|
244
|
+
- **必须**:`argparse` 生成的帮助与错误文案使用**英文**;交互式向导与 `config` 子命令的面向用户提示使用**中文**(与现有实现一致,见 §2.1)。
|
|
245
|
+
- **必须**:`README.md`(英文)与 `README.zh.md`(中文)描述同一事实;修改一处**必须**同步检查另一处,不得只改一边。
|
|
246
|
+
- **禁止**:README 或任何用户可见输出中引用不存在的子命令或已删除的动作(如历史上的 `service`)——这属于 §3.2 的死引用,见 §10.3 审查矩阵。
|
|
247
|
+
- **必须**:README 中的配置示例与 `gitwebhooks.ini.sample` 保持一致。
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 九、Agent 与工作流纪律
|
|
252
|
+
|
|
253
|
+
### 9.1 计划与范围
|
|
254
|
+
|
|
255
|
+
- **必须**:动手前先读代码验证事实,不假设 API / 文件存在(文档优先)。
|
|
256
|
+
- **必须**:任务拆分为可独立验证的单元;涉及 3+ 文件或 30 分钟以上时拆分。
|
|
257
|
+
- **禁止**:反复猜测试错(No Guess-Retry Loop)——遇报错先查权威来源(Python 官方文档、本项目 `README*.md` 与本宪章),确认根因再用最小复现验证。
|
|
258
|
+
|
|
259
|
+
### 9.2 委派
|
|
260
|
+
|
|
261
|
+
- **建议**:静态代码审查派给只读的审查者(加载 `.dsh/skills/code-review/SKILL.md`),影响面调研派独立的探索任务;**产出(代码与文档)一律由主代理完成**。
|
|
262
|
+
- **必须**:只读审查者**不得**被授予写权限;其结论中的「必须运行才能确认」项标注为「需主代理跑门禁确认」,**禁止**把推测写成已验证。
|
|
263
|
+
|
|
264
|
+
### 9.3 Git 纪律
|
|
265
|
+
|
|
266
|
+
- **必须**:提交信息格式为 `<类型>: <简短描述>`,使用中文;类型取 `feat` / `fix` / `docs` / `refactor` / `test` / `chore`。
|
|
267
|
+
- **禁止**:提交信息中出现 AI 归属签名、推广内容或 emoji(如 `🤖 Generated with ...`、`Co-Authored-By:` 形式的 AI 署名)。
|
|
268
|
+
- **必须**:一次提交只含一项已完成的工作;**禁止**夹带无关文件。
|
|
269
|
+
- **必须**:提交前确认改动通过其对应门禁(§7.1);未过门禁的改动不得提交。
|
|
270
|
+
- **禁止**:未经用户明确授权执行 `git commit` / `git push` / 改写历史。
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 十、修订与合规
|
|
275
|
+
|
|
276
|
+
### 10.1 修订流程
|
|
277
|
+
|
|
278
|
+
1. 记录拟修改内容与理由;
|
|
279
|
+
2. 更新本文件并递增版本号;
|
|
280
|
+
3. 同步 `AGENTS.md` 与本宪章引用到的其它文档;
|
|
281
|
+
4. 以本次修订的口径复查存量代码的合规性。
|
|
282
|
+
|
|
283
|
+
版本号遵循语义化版本:**MAJOR** = 原则移除或治理性不兼容变更;**MINOR** = 新增原则或实质性扩展;**PATCH** = 措辞澄清。
|
|
284
|
+
|
|
285
|
+
### 10.2 合规分级
|
|
286
|
+
|
|
287
|
+
审查发现按下列分级处理:
|
|
288
|
+
|
|
289
|
+
| 级别 | 定义 | 处理 |
|
|
290
|
+
|------|------|------|
|
|
291
|
+
| **A(必须修)** | 违反 MUST / MUST NOT(安全、数据正确性、架构不变量、死代码、凭据泄露) | 阻塞交付,修复后**重跑门禁** |
|
|
292
|
+
| **B(应当修)** | 违反 SHOULD,或存量偏差被本次改动**扩大** | 本轮修复或登记 backlog |
|
|
293
|
+
| **C(可登记)** | 存量偏差、不影响本次改动的风格问题 | 登记跟踪,不阻塞交付 |
|
|
294
|
+
|
|
295
|
+
- **必须**:存量偏差(本宪章已标注的「已知存量偏差」)不因一次无关改动而阻塞;但**扩大**既有偏差属于 A 级。
|
|
296
|
+
|
|
297
|
+
### 10.3 审查矩阵
|
|
298
|
+
|
|
299
|
+
| 改动类型 | 审查口径 |
|
|
300
|
+
|----------|----------|
|
|
301
|
+
| Python 源码 | 全套清单(宪章 → 分层 → 规模 → 安全 → 测试) |
|
|
302
|
+
| CLI 子命令增删 | 额外核对**所有**引用点(注册、帮助、两个 README、脚本、测试)——见 §3.2 |
|
|
303
|
+
| 配置项增删 | 额外核对 `gitwebhooks.ini.sample`、`RESERVED_SECTIONS`、两个 README |
|
|
304
|
+
| 纯文档 | 只需文档一致性核对(双语文档同步、命令 / 配置示例真实存在、无悬空引用) |
|
|
305
|
+
| 版本发布 | 额外核对两处版本号同步与 `pre-release-check.sh` 通过 |
|
|
306
|
+
|
|
307
|
+
### 10.4 审查拒绝
|
|
308
|
+
|
|
309
|
+
- 审查者**只报不改**;不得在审查中顺手修复。
|
|
310
|
+
- 同一改动对 P2 / P3 只报一次,登记后放行;P0 / P1 修复后**重跑门禁**,不重跑同一审查实例。
|