gitwebhooks 2.4.1__tar.gz → 2.4.2__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.
Files changed (118) hide show
  1. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/AGENTS.md +29 -31
  2. gitwebhooks-2.4.2/CHANGELOG.md +285 -0
  3. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/CONSTITUTION.md +32 -12
  4. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/MANIFEST.in +1 -0
  5. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/PKG-INFO +20 -13
  6. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/README.md +18 -10
  7. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/README.zh.md +18 -10
  8. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/__init__.py +1 -1
  9. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/custom.py +6 -0
  10. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/factory.py +0 -25
  11. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/gitee.py +6 -0
  12. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/gitlab.py +6 -0
  13. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/init_wizard.py +12 -6
  14. gitwebhooks-2.4.2/gitwebhooks/cli/prompts.py +126 -0
  15. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/serve.py +4 -39
  16. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/service.py +13 -17
  17. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/config/loader.py +28 -10
  18. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/config/models.py +0 -1
  19. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/config/registry.py +0 -38
  20. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/config/server.py +1 -1
  21. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/base.py +0 -10
  22. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/custom.py +4 -7
  23. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/factory.py +0 -37
  24. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/gitee.py +4 -8
  25. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/github.py +2 -6
  26. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/gitlab.py +2 -6
  27. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/request.py +1 -1
  28. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/main/version.py +0 -2
  29. gitwebhooks-2.4.2/gitwebhooks/models/request.py +31 -0
  30. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/server.py +0 -2
  31. gitwebhooks-2.4.2/gitwebhooks/utils/executor.py +109 -0
  32. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/utils/systemd.py +2 -46
  33. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/PKG-INFO +20 -13
  34. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/SOURCES.txt +2 -2
  35. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.ini.sample +2 -2
  36. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/pyproject.toml +2 -3
  37. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/conftest.py +29 -108
  38. gitwebhooks-2.4.2/tests/fixtures/custom_payloads.py +67 -0
  39. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/fixtures/gitee_payloads.py +0 -93
  40. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/fixtures/github_payloads.py +0 -104
  41. gitwebhooks-2.4.2/tests/fixtures/gitlab_payloads.py +112 -0
  42. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/fixtures/signature_builder.py +0 -10
  43. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_command_execution.py +71 -37
  44. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_config_discovery.py +5 -3
  45. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_edge_cases.py +19 -10
  46. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_gitee_webhook.py +0 -3
  47. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_github_webhook.py +7 -9
  48. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/cli/test_config_view.py +0 -3
  49. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/cli/test_init_wizard.py +1 -6
  50. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_config_loading.py +2 -2
  51. gitwebhooks-2.4.2/tests/unit/test_executor.py +139 -0
  52. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_install_service_logic.py +1 -66
  53. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_main.py +9 -12
  54. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_prompts_config_level.py +10 -6
  55. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_signature_verification.py +37 -1
  56. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/utils/http_client.py +1 -0
  57. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/utils/server_manager.py +14 -155
  58. gitwebhooks-2.4.1/gitwebhooks/cli/prompts.py +0 -322
  59. gitwebhooks-2.4.1/gitwebhooks/models/request.py +0 -61
  60. gitwebhooks-2.4.1/gitwebhooks/utils/executor.py +0 -34
  61. gitwebhooks-2.4.1/tests/fixtures/custom_payloads.py +0 -249
  62. gitwebhooks-2.4.1/tests/fixtures/gitlab_payloads.py +0 -243
  63. gitwebhooks-2.4.1/tests/utils/certificate_generator.py +0 -236
  64. gitwebhooks-2.4.1/tests/utils/coverage_runner.py +0 -329
  65. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/.editorconfig +0 -0
  66. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/LICENSE +0 -0
  67. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/custom-body.png +0 -0
  68. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/custom-header.png +0 -0
  69. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/custom-response.png +0 -0
  70. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/gitee-success.png +0 -0
  71. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/gitee.png +0 -0
  72. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/github-success.png +0 -0
  73. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/github.png +0 -0
  74. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/gitlab-success.png +0 -0
  75. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/gitlab.png +0 -0
  76. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/install.png +0 -0
  77. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/doc/uninstall.png +0 -0
  78. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/__main__.py +0 -0
  79. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/__init__.py +0 -0
  80. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/github.py +0 -0
  81. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/auth/verifier.py +0 -0
  82. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/__init__.py +0 -0
  83. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/config.py +0 -0
  84. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/cli/help.py +0 -0
  85. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/config/__init__.py +0 -0
  86. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/handlers/__init__.py +0 -0
  87. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/logging/__init__.py +0 -0
  88. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/logging/setup.py +0 -0
  89. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/main/__init__.py +0 -0
  90. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/main/__main__.py +0 -0
  91. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/models/__init__.py +0 -0
  92. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/models/config.py +0 -0
  93. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/models/provider.py +0 -0
  94. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/models/result.py +0 -0
  95. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/utils/__init__.py +0 -0
  96. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/utils/constants.py +0 -0
  97. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks/utils/exceptions.py +0 -0
  98. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/dependency_links.txt +0 -0
  99. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/entry_points.txt +0 -0
  100. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/requires.txt +0 -0
  101. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/gitwebhooks.egg-info/top_level.txt +0 -0
  102. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/setup.cfg +0 -0
  103. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/__init__.py +0 -0
  104. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/__main__.py +0 -0
  105. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/fixtures/__init__.py +0 -0
  106. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/__init__.py +0 -0
  107. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_config_view_integration.py +0 -0
  108. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_custom_webhook.py +0 -0
  109. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/integration/test_gitlab_webhook.py +0 -0
  110. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/__init__.py +0 -0
  111. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/cli/__init__.py +0 -0
  112. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/cli/test_help.py +0 -0
  113. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_config_level.py +0 -0
  114. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_data_parsing.py +0 -0
  115. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_provider_detection.py +0 -0
  116. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_request_handler.py +0 -0
  117. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/unit/test_service_install_context.py +0 -0
  118. {gitwebhooks-2.4.1 → gitwebhooks-2.4.2}/tests/utils/__init__.py +0 -0
@@ -8,14 +8,14 @@
8
8
 
9
9
  | 项 | 值 |
10
10
  |----|----|
11
- | 语言 | Python(`requires-python = ">=3.6"`,classifiers 覆盖至 3.14) |
11
+ | 语言 | Python(`requires-python = ">=3.7"`,classifiers 覆盖 3.7–3.14) |
12
12
  | 运行时依赖 | **无**(仅标准库;`pyproject.toml` 的 `dependencies = []` 是硬约定) |
13
- | 开发依赖 | `pytest`、`pytest-cov`(可选,仅作测试运行器) |
14
- | 代码规模 | ~4.9k 行(`gitwebhooks/`) |
13
+ | 开发依赖 | `pytest`、`pytest-cov`(dev extra;**全量测试套件的运行器**) |
14
+ | 代码规模 | 4.6k 行(`gitwebhooks/`,4570 行) |
15
15
  | 配置格式 | INI(`configparser`) |
16
16
  | HTTP | 标准库 `http.server` |
17
17
  | 打包 | `setuptools`,可发布 PyPI,亦支持原地从源码运行 |
18
- | 当前版本 | `2.4.1`(`pyproject.toml` 与 `gitwebhooks/__init__.py` **两处**) |
18
+ | 当前版本 | `2.4.2`(`pyproject.toml` 与 `gitwebhooks/__init__.py` **两处**) |
19
19
 
20
20
  **支持平台**:GitHub(HMAC-SHA1 签名)、Gitee(签名或密码)、GitLab(token)、custom(自定义 Header + JSON 路径识别)。
21
21
 
@@ -64,6 +64,7 @@ utils/ 常量、异常、命令执行、systemd 辅助
64
64
  gitwebhooks-cli # Bash 包装脚本:自动定位包并以 python3 -m gitwebhooks.main 运行
65
65
  pyproject.toml # 打包、版本号(源 1)、入口点 gitwebhooks.main:main
66
66
  MANIFEST.in # sdist 清单
67
+ CHANGELOG.md # 更新日志(Keep a Changelog;发布时必须更新)
67
68
  gitwebhooks.ini.sample # 配置模板(改配置项须同步)
68
69
  scripts/pre-release-check.sh # 发布前校验(构建 + 隔离环境安装 + CLI 冒烟)
69
70
  gitwebhooks/
@@ -78,7 +79,7 @@ gitwebhooks/
78
79
  │ ├── serve.py # cmd_serve:启动服务器 / systemd 安装卸载分发
79
80
  │ ├── service.py # systemd 安装卸载实现(被 serve.py 调用,非子命令)
80
81
  │ ├── config.py # cmd_init / cmd_view
81
- │ ├── init_wizard.py # 交互式配置向导(⚠️ 779 行,见宪章 §1.2)
82
+ │ ├── init_wizard.py # 交互式配置向导(⚠️ 785 行,见宪章 §1.2)
82
83
  │ ├── prompts.py # 交互提示辅助
83
84
  │ └── help.py # help 子命令(输出由 argparse format_help 生成,与 --help 同源)
84
85
  ├── config/
@@ -103,7 +104,7 @@ gitwebhooks/
103
104
  ├── utils/
104
105
  │ ├── constants.py # HTTP 常量、Header 名、路径、RESERVED_SECTIONS、SENSITIVE_KEYWORDS
105
106
  │ ├── exceptions.py # 自定义异常(含 ConfigurationError)
106
- │ ├── executor.py # execute_deployment(异步 subprocess)
107
+ │ ├── executor.py # execute_deployment(异步 subprocess;守护线程排空输出 + wait 回收)
107
108
  │ └── systemd.py # systemd 检测与服务文件生成
108
109
  └── logging/setup.py # 日志配置
109
110
  tests/
@@ -112,7 +113,7 @@ tests/
112
113
  ├── unit/ # 单元测试(unit/cli/ 为 CLI 子命令测试)
113
114
  ├── integration/ # 端到端 webhook / 配置发现 / 命令执行
114
115
  ├── fixtures/ # 各平台 payload 与签名构造器
115
- └── utils/ # 测试辅助(HTTP 客户端、服务器管理、证书生成)
116
+ └── utils/ # 测试辅助(HTTP 客户端、线程内测试服务器)
116
117
  doc/ # README 截图(二进制资源)
117
118
  .dsh/skills/ # DSH 项目技能(项目唯一技能来源)
118
119
  ```
@@ -195,22 +196,25 @@ python3 -m build && python3 -m twine upload dist/*
195
196
 
196
197
  ## 测试与质量门禁
197
198
 
198
- **项目自带 runner(无需 pytest,推荐)**:
199
+ **全量测试(权威,必须用这个)** — 先装 dev extra:
199
200
 
200
201
  ```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)
202
+ pip install -e ".[dev]" # 含 pytest
203
+ python3 -m pytest tests/ # 228 个测试全跑,约 10 秒
206
204
  ```
207
205
 
208
- **pytest 驱动(可选,需自行安装 `pytest`)**:
206
+ **零依赖子集 runner**(`unittest`,**不是**全量):
209
207
 
210
208
  ```bash
211
- python3 -m pytest tests/
209
+ python3 -m tests # 只跑到不依赖 pytest 的模块(当前 128 个)
210
+ python3 -m tests -q # 仅摘要
211
+ python3 -m tests -f # 失败即停
212
+ python3 -m tests -v # 详细
212
213
  ```
213
214
 
215
+ > ⚠️ `python3 -m tests` 跑不到 `tests/unit/test_main.py` 等 7 个 pytest 风格模块
216
+ > (当前约 100 个测试),因此**不能**用它声称「测试全通过」。
217
+
214
218
  **语法静态校验**:
215
219
 
216
220
  ```bash
@@ -219,27 +223,18 @@ python3 -m compileall -q gitwebhooks
219
223
 
220
224
  ### 门禁纪律
221
225
 
222
- - 交付前至少跑 `python3 -m compileall -q gitwebhooks` + 爆炸半径内测试;
226
+ - 交付前跑 `python3 -m compileall -q gitwebhooks` + **全量** `python3 -m pytest tests/`;
223
227
  - **如实区分**「本机真跑过 / 只做了静态检查 / 未执行」;声称通过时给出**实际计数**(跑了多少 / 失败 / 跳过);
224
228
  - **禁止吞输出**(`>/dev/null`、`2>/dev/null`、`-q` 用于可能失败的命令);
225
229
  - CLI 子命令增删时,**必须**核对全部引用点:`cli/__init__.py` 注册、`cli/help.py`、`README.md`、`README.zh.md`、`scripts/pre-release-check.sh`、相关测试。
226
230
 
227
- ### ⚠️ 已知测试基线偏差
228
-
229
- 以下 7 个测试模块直接 `import pytest`,**在未安装 pytest 的环境下整体无法导入**(报 `ModuleNotFoundError`):
231
+ ### 测试基线
230
232
 
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
- ```
233
+ **`python3 -m pytest tests/`(Python 3.14)**:`228 passed`,约 10 秒,**0 挂起**。
237
234
 
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)。
235
+ **`python3 -m tests`(无 pytest)**:`Ran 128 tests`,5 个 error(pytest 风格模块无法导入)。这些 error 是**子集 runner 的已知限制**,不是代码缺陷。
241
236
 
242
- 判定改动是否引入回归时,**必须与此基线对比**:新增 failure 才算回归;7 个 error 是既有环境缺陷,不得当作新缺陷,也不得隐去不报。宪章 §6.1 要求新测试用 `unittest` 编写,不新增 pytest 依赖。
237
+ 判定改动是否引入回归时,必须以**全量 pytest 结果**为准。
243
238
 
244
239
  ## 代码审查
245
240
 
@@ -262,7 +257,7 @@ tests/unit/cli/test_init_wizard.py
262
257
  2. **禁止反复猜测试错**:遇报错先查权威来源(Python 官方文档、`README*.md`、本宪章)确认根因,再最小复现验证;
263
258
  3. **最小改动**:只改任务相关代码,拒绝过度抽象(YAGNI / KISS);
264
259
  4. **匹配现有风格**:命名、目录、抽象层级与周边代码一致;注释 / docstring 语言**按层就近一致**(核心模块英文、CLI 交互层中文,见宪章 §2.1),代码标识符一律英文,commit 用**中文**;
265
- 5. **同步文档**:用户可见行为变更 → 两个 README;架构 / 命令变更 → 本文档;命令或配置项增删 → 核对 §「门禁纪律」的引用点清单;
260
+ 5. **同步文档**:用户可见行为变更 → 两个 README **+ `CHANGELOG.md` 的「未发布」小节**;架构 / 命令变更 → 本文档;命令或配置项增删 → 核对 §「门禁纪律」的引用点清单;
266
261
  6. **零依赖**:不引入运行时第三方依赖(`dependencies` 保持为空);
267
262
  7. **版本双源**:改版本号必须同时改 `pyproject.toml` 与 `gitwebhooks/__init__.py`,提交前 `grep` 复核。
268
263
 
@@ -273,9 +268,11 @@ tests/unit/cli/test_init_wizard.py
273
268
  | **`serve` vs `service`** | 独立 `service` 子命令已移除;systemd 管理是 `serve install` / `serve uninstall`。`cli/service.py` 是内部实现模块,不是子命令。 |
274
269
  | **版本双源** | `pyproject.toml` 与 `gitwebhooks/__init__.py` 各存一份版本号,无自动同步;`main/version.py` 从包 `__version__` 读取。 |
275
270
  | **两处平台注册** | 新增平台须同时改 `handlers/factory.py` 与 `auth/factory.py`,并加 `handlers/<p>.py` 与 `auth/<p>.py`;漏一处会「识别了平台但无法验证」。 |
276
- | **pytest 依赖** | 7 个测试模块 `import pytest` 导致无 pytest 环境整体导入失败(见上「已知测试基线偏差」)。新测试用 `unittest`。 |
271
+ | **测试挂起(P0)** | 历史上两处:① `sys.exit` 被 mock 成 no-op ⇒ `while True` 无限重试;② patch 了 `gitwebhooks.main.WebhookServer`,但 `cmd_serve` 用的是 `gitwebhooks.cli.serve.WebhookServer` ⇒ **真实启动服务器**。测试若卡住,先查这两类。 |
272
+ | **测试因「恰好成立」而通过** | 例:用 `main([])` 断言返回码,实际走的是「打印帮助」分支;`-m gitwebhooks.cli` 恒返回 1(模块不存在),却让「配置缺失返回 1」的断言通过。断言必须对应被测行为。 |
277
273
  | **配置常量分散风险** | 路径列表、Header 名、状态码、敏感字段关键词的唯一出处是 `utils/constants.py`;别处硬编码即漂移。 |
278
274
  | **命令执行信任边界** | `execute_deployment` 使用 `shell=True`。安全前提是「命令只来自本地配置文件」——**禁止**把请求体内容拼进命令。 |
275
+ | **禁止创建无人读取的管道** | `stdout=PIPE` 而不读 ⇒ 输出超过管道缓冲区(Linux 64 KiB)后命令**永久阻塞**(「推送后没反应、无报错、无日志尾」)。当前实现用守护线程合并排空 `stdout`/`stderr` 并 `wait()` 回收;改动此处**必须**保持「有消费者 + 有回收」,回归测试见 `tests/unit/test_executor.py`。 |
279
276
  | **CLI 文档漂移** | README 两个语言版本与 `scripts/pre-release-check.sh` 曾残留已删除的 `service` 引用;增删子命令时按引用点清单全查。 |
280
277
  | **模块入口是 `gitwebhooks.main`** | `gitwebhooks.cli` 是子命令包,**没有** `__main__.py`,`python3 -m gitwebhooks.cli` 会失败;模块方式启动一律用 `python3 -m gitwebhooks.main`。 |
281
278
  | **帮助只有一个来源** | 帮助文本由 argparse 从解析器定义生成:`help.py` 不再持有手写文案。改选项后 `help <cmd>` 与 `<cmd> --help` 自动同步,不要另写一份帮助字符串。 |
@@ -286,6 +283,7 @@ tests/unit/cli/test_init_wizard.py
286
283
  | 文档 | 内容 |
287
284
  |------|------|
288
285
  | [`CONSTITUTION.md`](./CONSTITUTION.md) | **编码宪章(最高准则)**:适用范围、架构不变量、安全、测试、合规分级、审查矩阵 |
286
+ | [`CHANGELOG.md`](./CHANGELOG.md) | **更新日志**(Keep a Changelog):各版本的用户可感知变更;发布时必须更新 |
289
287
  | [`AGENTS.md`](./AGENTS.md)(本文档) | Agent 入口:架构、命令、门禁、陷阱 |
290
288
  | [`README.md`](./README.md) | 用户手册(英文):安装、配置、使用、发布 |
291
289
  | [`README.zh.md`](./README.zh.md) | 用户手册(中文) |
@@ -0,0 +1,285 @@
1
+ # 更新日志 (Changelog)
2
+
3
+ 本文件记录本项目所有值得注意的变更。
4
+
5
+ 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
6
+ 版本号遵循 [语义化版本 (Semantic Versioning)](https://semver.org/lang/zh-CN/)。
7
+
8
+ 变更类型:`Added / 新增`、`Changed / 变更`、`Deprecated / 弃用`、`Removed / 移除`、
9
+ `Fixed / 修复`、`Security / 安全`。
10
+
11
+ > **关于历史条目**:本文件自 v2.4.1 起正式维护。v2.4.1 之前没有 git tag,
12
+ > 早期条目由提交历史整理而成,日期取该版本最后一次提交的日期;
13
+ > 版本切分以历史上的 `chore: 发布版本 X` 提交为准,可能与当时 PyPI 上的上传时点存在偏差。
14
+
15
+ ---
16
+
17
+ ## [未发布 / Unreleased]
18
+
19
+ <!-- 发布新版本时:把本节的条目移动到新的版本号小节,并更新下方链接。 -->
20
+
21
+ ## [2.4.2] - 2026-10-12
22
+
23
+ > ### ⚠️ 升级注意事项(行为变更)
24
+ >
25
+ > 本版修复了一个认证绕过。**若你的配置是 `verify=true` 但 `secret` 留空,或在 custom 平台把 `header_token` 显式留空,升级后这些请求会被拒绝(401)**——
26
+ > 这在旧版是「静默放行」,也就是任何人只要不带 token 就能触发你的部署命令。
27
+ > 升级后请为每个平台配置真实的 `secret`;确实不需要验证时请显式设 `verify=false`。
28
+ >
29
+ > 另外 `[ssl] enable` 写非布尔值(如 `maybe`)从「静默当作关闭」改为直接报错退出。
30
+
31
+ ### Fixed / 修复
32
+
33
+ - **测试套件会永久挂起**(全量 `pytest` 跑不完——是「卡死」不是「慢」)。两处根因:
34
+ ① `test_ask_config_level_keyboard_interrupt_confirms` 把 `sys.exit` mock 成 no-op,
35
+ 导致 `while True` 无限重试;② `test_main_*` 把 `gitwebhooks.main.WebhookServer` 打桩,
36
+ 但 `cmd_serve` 实际使用 `gitwebhooks.cli.serve.WebhookServer`,于是**真的启动了服务器**。
37
+ - **测试套件运行时间**约 55 秒降到约 10 秒。主因是每个集成测试都要等
38
+ `serve_forever()` 默认 0.5 秒的 `poll_interval` 才完成 teardown;另有 17 处固定
39
+ `time.sleep()`(合计约 12 秒)与每次服务器启动固定 0.25 秒等待。现改为条件轮询
40
+ (`WebhookTestCase.wait_until` / `wait_for_file` / `wait_for_log_contains`)。
41
+ - 修复若干**从未真正运行过**的测试(此前因缺少 pytest 而整体无法导入):
42
+ - `tests/unit/test_main.py` 3 个用例断言的是重构前的 CLI(无子命令即启动服务器);
43
+ - `tests/unit/test_install_service_logic.py` 导入了已被删除的 `cmd_install`;
44
+ - `tests/integration/test_config_discovery.py` 在 `cwd=tmp_path` 下未传 `PYTHONPATH`,
45
+ 且自身推算仓库根路径多了一层。
46
+ - `tests/unit/test_config_loading.py` 用 `python -m gitwebhooks.cli`(该模块不可执行)
47
+ 断言返回码 1,属于**因错误原因通过**;改用 `python -m gitwebhooks.main serve`,
48
+ 现在真正验证配置缺失 / 非法 INI 的处理。
49
+ - `tests/integration/test_edge_cases.py::test_large_command_output_handled` 名为「大输出」,
50
+ 实际把输出**重定向进文件**,从未经过管道——正是它让管道阻塞缺陷长期未被发现。
51
+ - `.gitignore` 现在覆盖 `*.env`(此前 `secret.env` 等不会被忽略)。
52
+ - `scripts/pre-release-check.sh` 不再吞掉全部输出(原先连构建与安装都 `>/dev/null 2>&1`,
53
+ 失败时没有任何线索);现为成功静默、失败打印完整输出。
54
+ - **部署命令输出超过管道缓冲区后会永久卡死**(表现为「推送后没反应、无报错、无日志尾」)。
55
+ `execute_deployment` 原先用 `stdout=PIPE, stderr=PIPE` 启动命令却**从不读取**这两个管道,
56
+ 且 `Popen` 对象被直接丢弃 ⇒ 进程一直留在 `subprocess._active`、**管道读端永不释放**,
57
+ 命令输出超过管道缓冲区(Linux 默认 64 KiB)后写端阻塞在 `write()`。
58
+ `composer install`、`git reset --hard`、`npm ci`、`docker build` 等输出量足以触发。
59
+ 现由守护线程持续排空 stdout/stderr(合并读取)并在结束后 `wait()` 回收子进程。
60
+ - 部署失败(非 0 退出码)现在会记录退出码与输出尾部,此前完全无迹可查。
61
+ - 声明的最低 Python 版本修正为 **3.7**(原为 `>=3.6` 并带 3.6 分类器)。
62
+ 包在 import 阶段即依赖 `dataclasses`(Python 3.7+ 才有),此前 3.6 用户会安装成功、
63
+ 但 `import gitwebhooks` 必然失败。
64
+ - **安全:空 secret 会放行未认证请求**。`gitlab` / `gitee` / `custom` 三个验证器直接比较
65
+ `signature == secret`,当配置里 `secret` 为空且请求未带 token 时 `'' == ''` 成立,
66
+ 于是 `verify=True` 形同虚设——而未认证的 webhook 会触发部署命令(任意 shell)。
67
+ `github` 验证器本就有 `if not secret` 保护,现三者也补上同样的保护。
68
+ - **声明支持的 Python 3.7 / 3.8 实际无法启动 CLI**:`cli/init_wizard.py` 用了
69
+ PEP 585 的 `tuple[bool, str]` 注解(3.9+ 才有),且没有 `from __future__ import annotations`;
70
+ 该模块在 `main → cli → cli.config → init_wizard` 链上被无条件导入,故 3.7/3.8 上
71
+ `gitwebhooks-cli` 直接 `TypeError: 'type' object is not subscriptable`。改用 `typing.Tuple`。
72
+ - **`custom` 在 `header_token` 显式留空时静默跳过验证**:`verify_enabled` 由「Header 名是否非空」
73
+ 推导,因此 `verify=true` + `header_token=` 会让验证器无条件返回成功(违反宪章 §5.3)。
74
+ 现改为由 `config.verify` 决定:`verify=false` 才放行,`verify=true` 必须真正校验。
75
+ - `[ssl] enable` 写错(如 `maybe`)原先被静默当作「未启用 SSL」;现抛 `ConfigurationError`。
76
+ - pipx 自动探测用了过时的 venv 名 `gitwebhooks-server`(包名是 `gitwebhooks`),该分支实际不可达。
77
+ - `serve uninstall --purge` 删错文件:`cli/service.py` 写的是 `~/.gitwebhook.ini`(少一个 s),
78
+ 与真实路径 `~/.gitwebhooks.ini` 不符,导致配置文件从未被清理。
79
+ - 配置错误不再抛原生异常:`[ssl] enable=true` 但缺 `key_file`/`cert_file` 时原先冒泡
80
+ `configparser.NoOptionError`,`[server] port` 非整数时冒泡 `ValueError`;现均转为
81
+ 带明确说明的 `ConfigurationError`。
82
+ - `gitwebhooks.ini.sample` 现在可直接运行:原先 `[ssl] enable=true` 配占位证书路径、
83
+ 且 `log_file=/var/log/...` 非 root 不可写,导致文档推荐的「从源码运行」命令必定失败。
84
+ - README 中的 `~/.gitwebhook.ini` / `~/.gitwebhook.log` 拼写错误(共 12 处,中英各 6),
85
+ 以及交互向导的默认日志路径同款拼写错误。
86
+
87
+ ### Changed / 变更
88
+
89
+ - **完整测试套件改用 `python3 -m pytest tests/`**(`pytest` 本就是 `pyproject.toml` 的
90
+ dev extra),共 228 个测试;`python3 -m tests` 明确为**零依赖子集运行器**(128 个),
91
+ 不再被当作「测试全通过」的依据。宪章 §6.1 / §7.1 同步更新。
92
+ - 去除 `gitwebhooks/cli/serve.py` 中与 `gitwebhooks/main/__init__.py` 重复的
93
+ `find_config_file` 与 `format_config_error`(两份实现已漂移),改为复用后者。
94
+ - `execute_deployment` 现在返回排空输出的工作线程(`Optional[threading.Thread]`),
95
+ 便于调用方按需 join;原有调用方忽略返回值即可,行为不变。
96
+ - 部署输出逐行记入日志(DEBUG 级),失败时把尾部重新以 WARNING 级输出。
97
+ - **常量集中(宪章 §1.2/§1.3)**:各 handler 改为使用 `utils/constants.py` 的 Header 常量
98
+ (原先硬编码 `'X-Hub-Signature'` 等字面量);`config/loader.py` 的保留节名改用
99
+ `RESERVED_SECTIONS`;`cli/service.py` 与 `cli/init_wizard.py` 的配置路径改用
100
+ `CONFIG_PATH_USER/LOCAL/SYSTEM`,不再各自硬编码路径列表。
101
+ - 交互向导的配置级别菜单文案改用 `CONFIG_PATH_*` 常量(原先硬编码三个路径,已与常量漂移)。
102
+ - README 的测试命令改为 `python3 -m pytest tests/`(完整套件);原先写 `python3 -m unittest discover tests/`,
103
+ 在未装 pytest 的环境下会报 5 个导入错误并退出非 0,且它并不是完整套件。
104
+ - 测试辅助类 `TestServer` / `TestConfigBuilder` / `TestWebhookClient` 加 `__test__ = False`,
105
+ 消除 pytest 的 26 条 `PytestCollectionWarning`。
106
+ - `execute_deployment` 的 `shell=True` 处补上信任边界注释(宪章 §5.2 要求)。
107
+
108
+ ### Removed / 移除
109
+
110
+ - 死代码清理(宪章 §3.2「零死代码」):
111
+ - 10 个未使用的 import;
112
+ - 8 个无任何引用的函数:`check_systemd`、`get_cli_path`、`confirm_overwrite`、
113
+ `ask_question`、`validate_address`、`validate_path`、`validate_bool`、`validate_text`;
114
+ - `tests/utils/server_manager.py` 的 `TestServerProcess` 死类(同时含未使用的
115
+ `cli_script` 变量、指向不可执行模块的 `-m gitwebhooks.cli`,以及同款「创建未读管道」缺陷);
116
+ - 无引用的测试工具 `tests/utils/certificate_generator.py` 与 `tests/utils/coverage_runner.py`。
117
+ - 6 个无引用的类方法:`VerifierFactory.get_verifier`、`HandlerFactory.from_headers`、
118
+ `ConfigurationRegistry.get_provider_config` / `get_repository_config` / `has_repository`、
119
+ `WebhookRequest.repo_identifier`;
120
+ - 4 个无引用常量:`prompts.QUESTIONS`、`prompts.PLATFORM_QUESTIONS`、
121
+ `service.E_SYSTEMD`、`service.E_EXISTS`;
122
+ - 生产与测试中共 20 处未使用的 import(上一轮只清理了生产侧 10 处)。
123
+ - 第二轮(独立复查发现):`WebhookHandler.get_provider` 及 4 个平台覆写、
124
+ `tests/conftest.py` 的 5 个未被调用的辅助函数、`_read_log_file`、
125
+ 9 个 `PayloadBuilder` 方法与 `generate_invalid_signature`、
126
+ 14 个无引用的 fixture 常量,以及由此产生的 5 处 `Provider` 孤儿 import。
127
+
128
+ ## [2.4.1] - 2026-10-12
129
+
130
+ ### Fixed / 修复
131
+
132
+ - **`-h` / `--help` 现在遵循标准 Unix 约定**:在主命令与每个子命令层级都可用,
133
+ 输出到 stdout,退出码为 `0`。此前它会打印 `Error: -h/--help parameters are not supported.`
134
+ 并以退出码 `1` 结束。
135
+ - 帮助文本改为**由 argparse 从解析器定义生成**,`help <命令>` 与 `<命令> --help`
136
+ 输出完全一致;删除 `cli/help.py` 中重复维护的手写帮助文案。
137
+ - 修正文档中已失效的命令引用:
138
+ - 启动服务器必须带 `serve` 子命令(`./gitwebhooks-cli serve -c file.ini`);
139
+ 原文档写作 `./gitwebhooks-cli -c file.ini`,实际只会打印帮助。
140
+ - 模块入口是 `python3 -m gitwebhooks.main`(`gitwebhooks.cli` 无 `__main__.py`)。
141
+ - README 结构树删除不存在的 `cli.py` 与 `install.sh`。
142
+ - `cli/init_wizard.py` 的完成提示、`scripts/pre-release-check.sh` 的 CLI 检查
143
+ 此前仍指向已移除的 `service` 子命令(导致发布前检查实际失效)。
144
+
145
+ ### Changed / 变更
146
+
147
+ - `-v` / `--version` 注册为 argparse 参数,因此会出现在 `--help` 中;
148
+ 不再由 `main()` 的预检查拦截(该预检查还会让 `serve -v` 意外打印版本号)。
149
+ - 新增 `tests/unit/cli/test_help.py`(基于 `unittest`)覆盖各层级 `help`/`version`
150
+ 的退出码、输出流与 `help <cmd>` ≡ `<cmd> --help` 的一致性。
151
+
152
+ ### 工程与治理 / Tooling & Governance
153
+
154
+ - 迁移到 DSH 管理:新增 `CONSTITUTION.md`(项目编码宪章)与
155
+ `.dsh/skills/code-review`(代码审查技能);`CLAUDE.md` 由 `AGENTS.md` 取代。
156
+ - 清理其他 agent 工具残留:`.claude/`、`.specify/`、`.gitignore` 中的 SpecKit 段落、
157
+ 4 个空的 `tests/test_*` 目录。
158
+ - 修正 `.gitignore` 中拼错的配置文件名(`.gitwebhook.ini` → `.gitwebhooks.ini`),
159
+ 避免用户本地配置与密钥被误提交。
160
+
161
+ ## [2.4.0] - 2026-01-16
162
+
163
+ ### Removed / 移除
164
+
165
+ - 彻底移除 `service` 子命令及其向后兼容代码;systemd 服务管理改由
166
+ `serve install` / `serve uninstall` 承担(`gitwebhooks/cli/service.py` 保留为内部实现模块)。
167
+
168
+ ## [2.3.1] - 2026-01-16
169
+
170
+ ### Fixed / 修复
171
+
172
+ - 修复 `serve` 命令显示弃用警告的问题。
173
+ - 恢复被误删的 `gitwebhooks-cli` 脚本。
174
+
175
+ ## [2.3.0] - 2026-01-16
176
+
177
+ ### Added / 新增
178
+
179
+ - 服务安装时的配置级别选择:`serve install --config-level user|local|system`。
180
+
181
+ ### Changed / 变更
182
+
183
+ - 重构 CLI 命令结构,使其符合标准 Unix 工具规范。
184
+
185
+ > 注:本次发布提交(`chore: 发布版本 2.3.0`)中 `pyproject.toml` 的版本号仍为 `2.2.0`,
186
+ > 版本号是在紧随其后的 `chore: 更新 pyproject.toml 版本号到 2.3.0` 中才更新的。
187
+
188
+ ## [2.2.0] - 2026-01-15
189
+
190
+ ### Added / 新增
191
+
192
+ - 配置文件优先级自动查找:未指定 `-c` 时依次查找
193
+ `~/.gitwebhooks.ini` → `/usr/local/etc/gitwebhooks.ini` → `/etc/gitwebhooks.ini`。
194
+
195
+ ## [2.1.4] - 2026-01-15
196
+
197
+ ### Changed / 变更
198
+
199
+ - 统一项目命名为 `gitwebhooks`。
200
+
201
+ ### Fixed / 修复
202
+
203
+ - 修复多个测试与实现问题。
204
+
205
+ ## [2.1.3] - 2026-01-14
206
+
207
+ ### Fixed / 修复
208
+
209
+ - 修复配置初始化向导的多个问题。
210
+ - 恢复被误删的 `constitution.md`。
211
+
212
+ ## [2.1.2] - 2026-01-14
213
+
214
+ ### Added / 新增
215
+
216
+ - 发布前验证流程:`scripts/pre-release-check.sh`(构建 + 隔离环境安装 + CLI 冒烟)。
217
+
218
+ ### Fixed / 修复
219
+
220
+ - 修复 CLI 入口点配置:`gitwebhooks.cli:main` → `gitwebhooks.main:main`。
221
+
222
+ ## [2.1.1] - 2026-01-14
223
+
224
+ ### Fixed / 修复
225
+
226
+ - 修正 README 中的包名(`git-webhooks-server` → `gitwebhooks`)。
227
+
228
+ ## [2.1.0] - 2026-01-14
229
+
230
+ ### Added / 新增
231
+
232
+ - 安装方法指导与服务文件自适应功能。
233
+
234
+ ## [2.0.0] - 2026-01-14
235
+
236
+ 首个发布到 PyPI 的版本,将原单文件实现重构为模块化包。
237
+
238
+ ### Added / 新增
239
+
240
+ - 模块化包结构 `gitwebhooks/`:`models/`、`config/`、`auth/`、`handlers/`、`utils/`、`logging/`。
241
+ - 完整测试套件(单元测试 + 集成测试)。
242
+ - CLI 子命令取代 `install.sh`:`config init`(交互式配置向导)、`config view`(查看配置,敏感字段高亮)。
243
+
244
+ ### Changed / 变更
245
+
246
+ - 安装方式简化为原地运行模式。
247
+ - 源码按模块拆分,所有源码注释统一为英文。
248
+
249
+ ### Fixed / 修复
250
+
251
+ - 修复 Gitee webhook 签名验证算法。
252
+ - 修复 `install.sh --uninstall` 参数不生效的问题。
253
+ - 修复服务模板与安装脚本缺少 `WorkingDirectory` 的问题。
254
+ - 修复服务文件创建问题,并增加详细模式。
255
+
256
+ ### Removed / 移除
257
+
258
+ - 移除旧的单文件实现与 `install.sh`。
259
+
260
+ ---
261
+
262
+ ## 2.0.0 之前(未发布到 PyPI)
263
+
264
+ 2020–2022 年间为单文件实现(`git-webhooks-server.py`),已具备以下能力:
265
+
266
+ - 支持 GitHub、Gitee、GitLab 与自定义 webhook 源。
267
+ - 按 Header 识别平台;支持签名 / token / 密码验证。
268
+ - 支持指定需要处理的事件类型(`handle_events`)。
269
+ - 自定义 webhook 通过 `identifier_path` 提取仓库标识。
270
+ - 支持 SSL。
271
+ - 修复重启后服务无法启动的问题。
272
+
273
+ [未发布 / Unreleased]: https://gitee.com/holyhi/git-webhooks-server/compare/v2.4.2...HEAD
274
+ [2.4.2]: https://pypi.org/project/gitwebhooks/2.4.2/
275
+ [2.4.1]: https://pypi.org/project/gitwebhooks/2.4.1/
276
+ [2.4.0]: https://pypi.org/project/gitwebhooks/2.4.0/
277
+ [2.3.1]: https://pypi.org/project/gitwebhooks/2.3.1/
278
+ [2.3.0]: https://pypi.org/project/gitwebhooks/2.3.0/
279
+ [2.2.0]: https://pypi.org/project/gitwebhooks/2.2.0/
280
+ [2.1.4]: https://pypi.org/project/gitwebhooks/2.1.4/
281
+ [2.1.3]: https://pypi.org/project/gitwebhooks/2.1.3/
282
+ [2.1.2]: https://pypi.org/project/gitwebhooks/2.1.2/
283
+ [2.1.1]: https://pypi.org/project/gitwebhooks/2.1.1/
284
+ [2.1.0]: https://pypi.org/project/gitwebhooks/2.1.0/
285
+ [2.0.0]: https://pypi.org/project/gitwebhooks/2.0.0/
@@ -76,8 +76,10 @@ standing instructions 分层如下,**冲突时以上级为准**:
76
76
  - **必须**:消除魔法数字与魔法字符串,提取为 `utils/constants.py` 中的常量或类常量;HTTP 状态码、Header 名、消息文案一律走常量。
77
77
  - **建议**:单文件不超过 **400 行**;超过时按语义边界拆分(独立类型 > 独立函数组 > 辅助逻辑)。
78
78
 
79
- > **已知存量偏差(基线,非许可)**:`gitwebhooks/cli/init_wizard.py`(779 行)、`gitwebhooks/cli/service.py`(352 行)、`gitwebhooks/cli/prompts.py`(322 行)超过 400 行。
80
- > 这些文件**不允许继续变大**;触及它们时应评估拆分,拆分须作为独立任务登记,不得夹带在无关改动里。
79
+ > **已知存量偏差(基线,非许可)**:`gitwebhooks/cli/init_wizard.py`(785 行)超过 400 行。
80
+ > 该文件**不允许继续变大**;触及它时应评估拆分,拆分须作为独立任务登记,不得夹带在无关改动里。
81
+ >
82
+ > 复核口径:`find gitwebhooks -name '*.py' | xargs wc -l | awk '$1>400'`(本清单必须与命令输出一致;写入前先跑一次)。
81
83
 
82
84
  ### 1.3 命名与目录
83
85
 
@@ -133,6 +135,15 @@ standing instructions 分层如下,**冲突时以上级为准**:
133
135
 
134
136
  > 存量偏差:`scripts/pre-release-check.sh` 曾校验已被移除的 `service` 子命令,属于此类漏改;该引用已修正为 `serve`。
135
137
 
138
+ - **必须(扫描口径)**:死代码扫描**必须覆盖类体内的成员与方法**以及**模块级常量**,不能只扫模块顶层的 `def`/`class`。本项目曾因只扫顶层而漏掉 10 处(工厂方法、注册表 getter、未引用常量)。
139
+ - **已知误报(不判违规)**:`BaseHTTPRequestHandler` 按名字分发的 `do_GET` / `do_POST` / `do_HEAD` / `log_message` / `handle`——静态扫描看不到框架分发,**不得**据此判为死代码。
140
+ - **已登记跟踪(经判定为有意保留的公开 API,非死代码)**:
141
+ - `gitwebhooks/main/__init__.py` 的 `run_server`——与 `cli/serve.py` 的 `start_server` 重复,仅被测试覆盖,**应在后续独立改动中收敛为一处**;
142
+ - `gitwebhooks/models/config.py` 的 `ServiceInstallContext`——仅被测试覆盖;
143
+ - `gitwebhooks/utils/systemd.py` 的 `InstallationType.UNKNOWN`——枚举完备性。
144
+
145
+ 这三项**不得再增加**;新增同类项必须在此登记,否则视为死代码。
146
+
136
147
  ### 3.3 领域惯例(核心不变量)
137
148
 
138
149
  以下为本项目的**架构不变量**,违反视为 P1 及以上:
@@ -141,7 +152,11 @@ standing instructions 分层如下,**冲突时以上级为准**:
141
152
  - **必须**:平台中立——各平台(GitHub / Gitee / GitLab / custom)地位平等,平台识别**只**依据请求 Header;除已文档化的 Header / 事件名差异外,不得有平台特权分支。
142
153
  - **必须**:平台标识与 Header / 事件名 / 常量集中定义,不得散落字面量(见 §1.2)。
143
154
  - **必须**:请求体解析同时支持 JSON 与 `application/x-www-form-urlencoded`;新增平台不得削减既有支持。
144
- - **必须**:命令执行异步非阻塞,且 `stdin=subprocess.DEVNULL`——避免继承 stdin 造成文件描述符泄漏。
155
+ - **必须**:命令执行异步非阻塞,且**禁止创建无人读取的管道**:
156
+ - `stdin` 必须为 `subprocess.DEVNULL`(避免继承 stdin 造成文件描述符泄漏);
157
+ - stdout / stderr 若用 `subprocess.PIPE`,则**必须**有消费者持续排空(本项目用守护线程合并读取并写入日志)。**禁止**只创建 `PIPE` 而不读——命令输出超过管道缓冲区(Linux 默认 64 KiB)后写端会**永久阻塞在 `write()`**,表现为「推送后没反应、无报错、无日志尾」;
158
+ - 子进程**必须** `wait()` 回收。不回收会让它永久留在 `subprocess._active`,**管道读端也永不释放**,即使 Popen 对象已被丢弃;
159
+ - 失败(非 0 退出码)**必须**记录退出码与输出尾部,使故障可诊断。
145
160
  - **必须**(CLI 约定,遵循标准 Unix 工具规范):
146
161
  - `-h` / `--help` 在**每一个命令层级**(主命令、`serve`/`config`、其下动作)都必须可用,帮助输出到 **stdout**,退出码 **0**;
147
162
  - `-v` / `--version` 在**主命令层**可用,输出到 stdout,退出码 0;
@@ -196,9 +211,12 @@ standing instructions 分层如下,**冲突时以上级为准**:
196
211
  ### 6.1 框架与覆盖
197
212
 
198
213
  - **必须**:测试位于 `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`),作为独立任务登记。
214
+ - **必须**:**完整测试套件 = `python3 -m pytest tests/`**(`pytest` 是 `pyproject.toml` 已声明的 dev extra)。开发环境应先 `pip install -e ".[dev]"`。
215
+ - **必须**:`python3 -m tests` 是**零依赖子集运行器**(仅 `unittest`),不是完整套件——**禁止**把它当作「测试全通过」的依据。
216
+ - **禁止**:**测试静默不运行**。若某模块因缺少可选依赖无法导入,运行器与实际报告**必须**明确指出被跳过的模块与原因;「跑完没报错」不得掩盖「有一半测试从未执行」。
217
+ - **必须**:新测试优先用 `unittest.TestCase`(零依赖可跑);使用 `pytest` 风格(`tmp_path`/`monkeypatch`/`capsys`/`parametrize`)的模块属于**完整套件的一部分**,必须能在 `pytest` 下跑通。
218
+ - **禁止**:任何形式的测试挂起(死循环、真实启动服务器、等待真实 stdin)。每个测试必须能在秒级完成;发现挂起视为 P0。
219
+ - **必须**:测试**禁止**因「断言恰好也成立」而通过——断言必须对应被测行为(例:用 `main([])` 断言返回码,实际走的却是「打印帮助」分支)。
202
220
 
203
221
  - **必须**:Bug 修复附带**能复现该 bug 的测试**(先 Red 后 Green)。
204
222
  - **必须**:修改平台逻辑时,覆盖该平台的签名验证(成功 + 失败)与仓库识别路径。
@@ -219,14 +237,14 @@ standing instructions 分层如下,**冲突时以上级为准**:
219
237
 
220
238
  | 目的 | 命令 | 说明 |
221
239
  |------|------|------|
222
- | 全量测试 | `python3 -m tests` | 项目自带 runner(`unittest` 驱动) |
223
- | 静默测试 | `python3 -m tests -q` | 仅输出摘要 |
240
+ | **全量测试(权威)** | `python3 -m pytest tests/` | 228 个测试全跑;需 `pip install -e ".[dev]"` |
241
+ | 零依赖子集 | `python3 -m tests` | 项目自带 runner(`unittest`),**跑不到** pytest 风格的模块 |
242
+ | 静默子集 | `python3 -m tests -q` | 仅输出摘要 |
224
243
  | 失败即停 | `python3 -m tests -f` | 快速定位 |
225
- | pytest 驱动(可选) | `python3 -m pytest tests/` | 需另装 `pytest`;非必需路径 |
226
244
  | 语法检查 | `python3 -m compileall -q gitwebhooks` | 快速静态校验 |
227
245
 
228
- - **必须**:交付前至少跑通 `python3 -m compileall -q gitwebhooks` 与爆炸半径内的测试。
229
- - **禁止**:以「pytest 未安装」为由跳过测试并声称通过(见 §6.2)。
246
+ - **必须**:交付前至少跑通 `python3 -m compileall -q gitwebhooks` 与**全量** `python3 -m pytest tests/`。
247
+ - **禁止**:以「pytest 未安装」为由跳过测试并声称通过(见 §6.2);此时应如实报告「只跑了子集」。
230
248
 
231
249
  ### 7.2 发布
232
250
 
@@ -234,8 +252,10 @@ standing instructions 分层如下,**冲突时以上级为准**:
234
252
  - **必须**:版本号在 `pyproject.toml` 与 `gitwebhooks/__init__.py` 的 `__version__` **两处同步**;两处不一致视为 P1 缺陷。
235
253
 
236
254
  > 这是一处已知的双源风险(无自动同步机制)。改版本时必须两处都改,并在提交前 `grep` 复核。
237
- - **必须**:发布流程 = ① 跑 `pre-release-check.sh` → ② 两处改版本号 → ③ 行为变更时更新两个 README → ④ 打语义化版本 tag → ⑤ 构建并上传。
255
+ - **必须**:发布流程 = ① 在 `CHANGELOG.md` 的「未发布」小节写完本次变更 → ② 两处改版本号 → ③ 把「未发布」条目移入新版本小节并填上日期 → ④ 行为变更时更新两个 README → ⑤ 跑 `pre-release-check.sh` → ⑥ 打语义化版本 tag → ⑦ 构建并上传。
256
+ - **必须**:`CHANGELOG.md` 保持 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 结构;每个已发布版本都有条目,条目用中文描述**用户可感知**的变更,不写轮次日志与过程叙述。
238
257
  - **禁止**:未跑校验脚本就上传 PyPI。
258
+ - **禁止**:发布新版本而不更新 `CHANGELOG.md`。
239
259
 
240
260
  ---
241
261
 
@@ -3,6 +3,7 @@ include README.zh.md
3
3
  include LICENSE
4
4
  include AGENTS.md
5
5
  include CONSTITUTION.md
6
+ include CHANGELOG.md
6
7
  include *.editorconfig
7
8
  include *.sample
8
9
  recursive-include doc *.png