gitwebhooks 2.1.2__tar.gz → 2.1.4__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 (105) hide show
  1. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/CLAUDE.md +14 -12
  2. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/PKG-INFO +5 -5
  3. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/cli/init_wizard.py +125 -47
  4. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/cli/service.py +7 -7
  5. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/config/loader.py +9 -3
  6. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/request.py +16 -11
  7. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/logging/setup.py +17 -6
  8. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/main/__init__.py +1 -1
  9. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/utils/systemd.py +3 -3
  10. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/PKG-INFO +5 -5
  11. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/SOURCES.txt +1 -1
  12. gitwebhooks-2.1.2/git-webhooks-server.ini.sample → gitwebhooks-2.1.4/gitwebhooks.ini.sample +1 -1
  13. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/pyproject.toml +5 -5
  14. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/__init__.py +2 -2
  15. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/__main__.py +2 -2
  16. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/conftest.py +1 -1
  17. gitwebhooks-2.1.4/tests/integration/__init__.py +3 -0
  18. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_config_view_integration.py +1 -1
  19. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_custom_webhook.py +1 -1
  20. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_edge_cases.py +6 -2
  21. gitwebhooks-2.1.4/tests/unit/__init__.py +3 -0
  22. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/cli/test_init_wizard.py +14 -9
  23. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/test_config_loading.py +4 -11
  24. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/test_signature_verification.py +6 -9
  25. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/utils/certificate_generator.py +1 -1
  26. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/utils/coverage_runner.py +2 -2
  27. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/utils/http_client.py +1 -1
  28. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/utils/server_manager.py +3 -3
  29. gitwebhooks-2.1.2/tests/integration/__init__.py +0 -3
  30. gitwebhooks-2.1.2/tests/unit/__init__.py +0 -3
  31. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/.editorconfig +0 -0
  32. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/LICENSE +0 -0
  33. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/MANIFEST.in +0 -0
  34. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/README.md +0 -0
  35. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/README.zh.md +0 -0
  36. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/custom-body.png +0 -0
  37. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/custom-header.png +0 -0
  38. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/custom-response.png +0 -0
  39. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/gitee-success.png +0 -0
  40. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/gitee.png +0 -0
  41. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/github-success.png +0 -0
  42. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/github.png +0 -0
  43. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/gitlab-success.png +0 -0
  44. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/gitlab.png +0 -0
  45. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/install.png +0 -0
  46. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/doc/uninstall.png +0 -0
  47. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/__init__.py +0 -0
  48. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/__main__.py +0 -0
  49. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/__init__.py +0 -0
  50. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/custom.py +0 -0
  51. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/factory.py +0 -0
  52. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/gitee.py +0 -0
  53. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/github.py +0 -0
  54. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/gitlab.py +0 -0
  55. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/auth/verifier.py +0 -0
  56. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/cli/__init__.py +0 -0
  57. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/cli/config.py +0 -0
  58. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/cli/prompts.py +0 -0
  59. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/config/__init__.py +0 -0
  60. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/config/models.py +0 -0
  61. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/config/registry.py +0 -0
  62. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/config/server.py +0 -0
  63. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/__init__.py +0 -0
  64. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/base.py +0 -0
  65. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/custom.py +0 -0
  66. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/factory.py +0 -0
  67. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/gitee.py +0 -0
  68. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/github.py +0 -0
  69. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/handlers/gitlab.py +0 -0
  70. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/logging/__init__.py +0 -0
  71. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/main/__main__.py +0 -0
  72. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/models/__init__.py +0 -0
  73. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/models/provider.py +0 -0
  74. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/models/request.py +0 -0
  75. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/models/result.py +0 -0
  76. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/server.py +0 -0
  77. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/utils/__init__.py +0 -0
  78. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/utils/constants.py +0 -0
  79. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/utils/exceptions.py +0 -0
  80. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks/utils/executor.py +0 -0
  81. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/dependency_links.txt +0 -0
  82. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/entry_points.txt +0 -0
  83. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/requires.txt +0 -0
  84. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/gitwebhooks.egg-info/top_level.txt +0 -0
  85. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/setup.cfg +0 -0
  86. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/__init__.py +0 -0
  87. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/custom_payloads.py +0 -0
  88. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/gitee_payloads.py +0 -0
  89. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/github_payloads.py +0 -0
  90. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/gitlab_payloads.py +0 -0
  91. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/fixtures/signature_builder.py +0 -0
  92. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_command_execution.py +0 -0
  93. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_gitee_webhook.py +0 -0
  94. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_github_webhook.py +0 -0
  95. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/integration/test_gitlab_webhook.py +0 -0
  96. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/test_auth/__init__.py +0 -0
  97. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/test_config/__init__.py +0 -0
  98. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/test_handlers/__init__.py +0 -0
  99. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/test_integration/__init__.py +0 -0
  100. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/cli/__init__.py +0 -0
  101. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/cli/test_config_view.py +0 -0
  102. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/test_data_parsing.py +0 -0
  103. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/test_provider_detection.py +0 -0
  104. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/unit/test_request_handler.py +0 -0
  105. {gitwebhooks-2.1.2 → gitwebhooks-2.1.4}/tests/utils/__init__.py +0 -0
@@ -49,19 +49,19 @@ gitwebhooks-cli
49
49
  gitwebhooks-cli -c /path/to/config.ini
50
50
 
51
51
  # systemd 服务管理
52
- systemctl start git-webhooks-server
53
- systemctl stop git-webhooks-server
54
- systemctl restart git-webhooks-server
55
- systemctl status git-webhooks-server
52
+ systemctl start gitwebhooks
53
+ systemctl stop gitwebhooks
54
+ systemctl restart gitwebhooks
55
+ systemctl status gitwebhooks
56
56
  ```
57
57
 
58
58
  ### 测试开发
59
59
  ```bash
60
60
  # 直接运行(开发模式)
61
- ./gitwebhooks-cli -c git-webhooks-server.ini.sample
61
+ ./gitwebhooks-cli -c gitwebhooks.ini.sample
62
62
 
63
63
  # 或使用模块方式
64
- python3 -m gitwebhooks.cli -c git-webhooks-server.ini.sample
64
+ python3 -m gitwebhooks.cli -c gitwebhooks.ini.sample
65
65
 
66
66
  # 运行测试套件
67
67
  python3 -m pytest tests/
@@ -204,7 +204,7 @@ python3 -m pytest tests/
204
204
  ## 文件结构
205
205
 
206
206
  ```
207
- git-webhooks-server/
207
+ gitwebhooks/
208
208
  ├── gitwebhooks-cli # CLI 命令行工具
209
209
  ├── gitwebhooks/ # 主包目录
210
210
  │ ├── __init__.py # 包入口
@@ -250,8 +250,8 @@ git-webhooks-server/
250
250
  │ ├── integration/ # 集成测试
251
251
  │ ├── utils/ # 测试工具
252
252
  │ └── conftest.py # pytest 配置
253
- ├── git-webhooks-server.ini.sample # 配置文件模板
254
- ├── git-webhooks-server.service.sample # systemd 服务模板
253
+ ├── gitwebhooks.ini.sample # 配置文件模板
254
+ ├── gitwebhooks.service.sample # systemd 服务模板
255
255
  ├── install.sh # 安装/卸载脚本
256
256
  ├── message.sh # 颜色输出辅助脚本
257
257
  ├── README.md # 项目说明(英文)
@@ -268,10 +268,10 @@ git-webhooks-server/
268
268
 
269
269
  ## 配置文件位置
270
270
 
271
- - 默认配置路径: `/usr/local/etc/git-webhooks-server.ini`
272
- - 日志文件: `/var/log/git-webhooks-server.log`
271
+ - 默认配置路径: `/usr/local/etc/gitwebhooks.ini`
272
+ - 日志文件: `/var/log/gitwebhooks.log`
273
273
  - 安装后的 CLI: `/usr/local/bin/gitwebhooks-cli`
274
- - systemd 服务: `/usr/lib/systemd/system/git-webhooks-server.service`
274
+ - systemd 服务: `/usr/lib/systemd/system/gitwebhooks.service`
275
275
 
276
276
  ## Active Technologies
277
277
  - Python 3.6+ + Python 标准库(无外部依赖)
@@ -290,6 +290,8 @@ git-webhooks-server/
290
290
  - INI 配置文件生成(读写) (001-config-init-wizard)
291
291
  - Python 3.7+ + Python 标准库(sys, shutil, os, pathlib, argparse) (001-install-method-guidance)
292
292
  - INI 配置文件,systemd 服务单元文件 (001-install-method-guidance)
293
+ - Python 3.7+ (项目要求) + Python 标准库仅(无外部依赖) (001-fix-config-init-bug)
294
+ - INI 配置文件 (configparser) (001-fix-config-init-bug)
293
295
 
294
296
  ## Recent Changes
295
297
  - 001-config-init-wizard: 添加 `config init` 交互式向导,支持配置级别选择、平台配置和仓库配置
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitwebhooks
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: A lightweight Git webhook server for automated deployment supporting GitHub, Gitee, GitLab, and custom webhooks
5
5
  Author-email: Troy Tse <troy@holyhi.net>
6
6
  Maintainer-email: Troy Tse <troy@holyhi.net>
7
7
  License-Expression: MIT
8
- Project-URL: Homepage, https://github.com/troytse/git-webhooks-server
9
- Project-URL: Documentation, https://github.com/troytse/git-webhooks-server#readme
10
- Project-URL: Repository, https://github.com/troytse/git-webhooks-server.git
11
- Project-URL: Issues, https://github.com/troytse/git-webhooks-server/issues
8
+ Project-URL: Homepage, https://github.com/troytse/gitwebhooks
9
+ Project-URL: Documentation, https://github.com/troytse/gitwebhooks#readme
10
+ Project-URL: Repository, https://github.com/troytse/gitwebhooks.git
11
+ Project-URL: Issues, https://github.com/troytse/gitwebhooks/issues
12
12
  Keywords: webhook,git,github,gitee,gitlab,deployment,automation,server,devops
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Environment :: No Input/Output (Daemon)
@@ -1,8 +1,30 @@
1
1
  """
2
2
  Interactive configuration initialization wizard.
3
3
 
4
- This module provides a user-friendly wizard for creating git-webhooks-server
4
+ This module provides a user-friendly wizard for creating gitwebhooks
5
5
  configuration files through an interactive command-line interface.
6
+
7
+ Features:
8
+ - Support for GitHub, Gitee, GitLab, and custom webhook platforms
9
+ - Automatic validation of repository names (supports dots, hyphens, underscores)
10
+ - Direct text input for event names with platform-specific defaults
11
+ - Secure file generation with proper permissions (0600)
12
+
13
+ Validation Functions:
14
+ - validate_repo_name: Validates repository name format
15
+ - validate_event_input: Validates event name input (rejects newlines and digits)
16
+ - _get_platform_default_event: Returns platform-specific default event
17
+
18
+ TECHNICAL DEBT:
19
+ This module (768 lines) exceeds the Constitution's recommended 400 line limit.
20
+ This is acceptable because the module contains the complete interactive wizard
21
+ logic including platform selection, repository configuration, event configuration,
22
+ and file generation.
23
+
24
+ Refactoring Plan (future task):
25
+ - Extract validation functions to gitwebhooks/cli/wizard_validators.py
26
+ - Consider splitting Wizard class into smaller focused classes
27
+ - Evaluate separating platform-specific logic into dedicated handlers
6
28
  """
7
29
 
8
30
  import os
@@ -51,6 +73,19 @@ PLATFORMS = {
51
73
  }
52
74
  }
53
75
 
76
+ # 平台默认事件值
77
+ # 每个平台使用不同的默认事件格式:
78
+ # - GitHub: 'push' (小写单数)
79
+ # - Gitee: 'Push Hook' (大写带空格)
80
+ # - GitLab: 'Push Hooks' (大写空格复数)
81
+ # - Custom: 'webhook' (通用自定义事件)
82
+ PLATFORM_DEFAULT_EVENTS = {
83
+ 'github': 'push',
84
+ 'gitee': 'Push Hook',
85
+ 'gitlab': 'Push Hooks',
86
+ 'custom': 'webhook',
87
+ }
88
+
54
89
 
55
90
  # =============================================================================
56
91
  # Data Classes
@@ -76,7 +111,7 @@ class ServerConfig:
76
111
  class PlatformConfig:
77
112
  """Platform configuration parameters."""
78
113
  platform: str
79
- handle_events: List[str]
114
+ handle_events: str # Changed from List[str] to str - comma-separated event names
80
115
  verify: bool
81
116
  secret: Optional[str] = None
82
117
  custom_params: Optional[Dict[str, str]] = None
@@ -96,19 +131,31 @@ class RepositoryConfig:
96
131
 
97
132
  def validate_repo_name(value: str) -> bool:
98
133
  """
99
- Validate repository name format.
134
+ 验证仓库名称格式。
135
+
136
+ 支持的格式:
137
+ - Two-level: owner/repo (GitHub/Gitee)
138
+ - Multi-level: group/subgroup/project (GitLab)
139
+ - 特殊字符: 支持点号、连字符、下划线
140
+
141
+ 有效示例:
142
+ - owner/repo
143
+ - my-org/my-repo
144
+ - user.repo/project
145
+ - group/sub_group/project.name
100
146
 
101
- Supports:
102
- - Two-level format: owner/repo (GitHub/Gitee)
103
- - Multi-level format: group/subgroup/project (GitLab)
147
+ 无效示例:
148
+ - owner repo (包含空格)
149
+ - owner/repo/ (尾部斜杠)
150
+ - owner@org/repo (包含不支持的字符)
104
151
 
105
152
  Args:
106
- value: Repository name string
153
+ value: 仓库名称字符串
107
154
 
108
155
  Returns:
109
156
  True if valid, False otherwise
110
157
  """
111
- return bool(re.match(r'^[^/]+(/[^/]+)+$', value))
158
+ return bool(re.match(r'^[\w.-]+(/[\w.-]+)*$', value))
112
159
 
113
160
 
114
161
  def validate_existing_path(value: str) -> bool:
@@ -154,6 +201,50 @@ def validate_port(value: str) -> bool:
154
201
  return False
155
202
 
156
203
 
204
+ def validate_event_input(value: str) -> tuple[bool, str]:
205
+ """
206
+ 验证事件名称输入。
207
+
208
+ 验证规则:
209
+ 1. 不能为空字符串
210
+ 2. 不能包含换行符(会破坏 INI 文件格式)
211
+ 3. 不能包含数字(拒绝旧的数字选择格式)
212
+
213
+ Args:
214
+ value: 用户输入的事件名称
215
+
216
+ Returns:
217
+ (is_valid, error_message) - 验证结果和错误消息(如果验证失败)
218
+ """
219
+ # 空输入检查(由调用方处理默认值,这里只做非空检查)
220
+ if not value or not value.strip():
221
+ return False, "事件名称不能为空"
222
+
223
+ # 换行符检查
224
+ if '\n' in value or '\r' in value:
225
+ return False, "事件名称不能包含换行符"
226
+
227
+ # 数字检查:去除逗号和空格后检查是否包含数字
228
+ cleaned = value.replace(',', '').replace(' ', '')
229
+ if any(c.isdigit() for c in cleaned):
230
+ return False, "请直接输入事件名称,不支持数字选择"
231
+
232
+ return True, ""
233
+
234
+
235
+ def _get_platform_default_event(platform: str) -> str:
236
+ """
237
+ 获取平台默认事件值。
238
+
239
+ Args:
240
+ platform: 平台名称 (github/gitee/gitlab/custom)
241
+
242
+ Returns:
243
+ 默认事件字符串,如果平台未找到则返回 'webhook'
244
+ """
245
+ return PLATFORM_DEFAULT_EVENTS.get(platform.lower(), 'webhook')
246
+
247
+
157
248
  # =============================================================================
158
249
  # INI Generation Functions
159
250
  # =============================================================================
@@ -186,7 +277,7 @@ def _generate_config(
186
277
  # Platform section
187
278
  platform_section = platform.platform
188
279
  platform_config = {
189
- 'handle_events': ', '.join(platform.handle_events),
280
+ 'handle_events': platform.handle_events, # Direct string value
190
281
  'verify': 'true' if platform.verify else 'false'
191
282
  }
192
283
 
@@ -202,7 +293,7 @@ def _generate_config(
202
293
  config[platform_section] = platform_config
203
294
 
204
295
  # Repository section
205
- repo_section = f'repo/{repo.name}'
296
+ repo_section = repo.name
206
297
  config[repo_section] = {
207
298
  'cwd': repo.cwd,
208
299
  'cmd': repo.cmd
@@ -219,7 +310,7 @@ class Wizard:
219
310
  """
220
311
  Interactive configuration wizard.
221
312
 
222
- Guides users through creating a git-webhooks-server configuration file
313
+ Guides users through creating a gitwebhooks configuration file
223
314
  by collecting server, platform, and repository configuration parameters.
224
315
  """
225
316
 
@@ -396,7 +487,7 @@ class Wizard:
396
487
  print("端口号必须在 1-65535 之间")
397
488
 
398
489
  # Log file
399
- default_log = "/var/log/git-webhooks-server.log"
490
+ default_log = "/var/log/gitwebhooks.log"
400
491
  log_file = input(f"日志文件路径 [默认: {default_log}]: ").strip()
401
492
  if not log_file:
402
493
  log_file = default_log
@@ -489,51 +580,38 @@ class Wizard:
489
580
  custom_params=custom_params
490
581
  )
491
582
 
492
- def _collect_events(self, platform: str) -> List[str]:
583
+ def _collect_events(self, platform: str) -> str:
493
584
  """
494
- Collect webhook events to handle.
585
+ 收集平台要处理的事件名称。
586
+
587
+ 改为直接文本输入方式,支持逗号分隔多个事件。
588
+ 空输入时使用平台默认值。
495
589
 
496
590
  Args:
497
- platform: Platform name
591
+ platform: Platform name (github/gitee/gitlab/custom)
498
592
 
499
593
  Returns:
500
- List of event names
594
+ 逗号分隔的事件名称字符串
501
595
  """
502
- platform_info = PLATFORMS[platform]
503
-
504
- if platform == 'custom':
505
- # Custom platform: ask for event name
506
- print("自定义平台事件处理")
507
- print("输入要处理的事件名称(直接回车跳过):")
508
- events_str = input().strip()
509
- return [e.strip() for e in events_str.split(',') if e.strip()] if events_str else ['webhook']
510
-
511
- # Standard platforms: show event list
512
- events = platform_info['events']
513
- print("选择要处理的 webhook 事件(多个用逗号分隔,直接回车默认选 1):")
514
- for idx, event in enumerate(events, 1):
515
- print(f" {idx}. {event}")
596
+ default_event = _get_platform_default_event(platform)
597
+ prompt = f"输入要处理的事件名称(多个用逗号分隔,直接回车默认: {default_event}): "
516
598
 
517
599
  while True:
518
- try:
519
- choice = input("输入选择: ").strip()
520
- if not choice:
521
- # Default to first event (push)
522
- return [events[0]]
600
+ value = input(prompt).strip()
523
601
 
524
- # Parse comma-separated indices
525
- indices = [int(x.strip()) - 1 for x in choice.split(',')]
602
+ # 空输入使用默认值
603
+ if not value:
604
+ return default_event
526
605
 
527
- # Validate indices
528
- if all(0 <= i < len(events) for i in indices):
529
- return [events[i] for i in indices]
530
- else:
531
- print(f"无效选择,请输入 1-{len(events)} 之间的数字,多个用逗号分隔")
606
+ # 验证输入
607
+ is_valid, error_msg = validate_event_input(value)
608
+ if not is_valid:
609
+ print(f"错误: {error_msg}")
610
+ continue
532
611
 
533
- except ValueError:
534
- print("请输入有效的数字,多个用逗号分隔")
535
- except KeyboardInterrupt:
536
- raise
612
+ # 去除逗号前后的空格
613
+ cleaned = ','.join(part.strip() for part in value.split(','))
614
+ return cleaned
537
615
 
538
616
  def _collect_custom_params(self) -> Dict[str, str]:
539
617
  """
@@ -585,7 +663,7 @@ class Wizard:
585
663
  repo_name = input("输入仓库名称 (格式: owner/repo): ").strip()
586
664
  if validate_repo_name(repo_name):
587
665
  break
588
- print("仓库名称格式不正确,应为 owner/repo 格式")
666
+ print("仓库名称只能包含字母、数字、斜杠、点号、连字符和下划线")
589
667
 
590
668
  # Working directory
591
669
  while True:
@@ -111,7 +111,7 @@ def install_service(force: bool = False, verbose: int = 0, dry_run: bool = False
111
111
  print()
112
112
  print('For migration from conda:', file=sys.stderr)
113
113
  print(' 1. Deactivate your conda environment: conda deactivate', file=sys.stderr)
114
- print(' 2. Install using pipx: pipx install git-webhooks-server', file=sys.stderr)
114
+ print(' 2. Install using pipx: pipx install gitwebhooks', file=sys.stderr)
115
115
  print(' OR create a venv: python3 -m venv ~/venv/gitwebhooks', file=sys.stderr)
116
116
  return 1
117
117
 
@@ -205,14 +205,14 @@ def enable_and_start_service() -> int:
205
205
  # Ask if user wants to enable and start
206
206
  if not ask_yes_no('Enable and start service? (Y/n) ', default=True):
207
207
  print('Service installed but not started')
208
- print('Start manually: sudo systemctl start git-webhooks-server')
208
+ print('Start manually: sudo systemctl start gitwebhooks')
209
209
  return 0
210
210
 
211
211
  # Enable service
212
212
  print('Enabling service...')
213
213
  try:
214
214
  subprocess.run(
215
- ['systemctl', 'enable', 'git-webhooks-server'],
215
+ ['systemctl', 'enable', 'gitwebhooks'],
216
216
  check=True,
217
217
  capture_output=True
218
218
  )
@@ -224,7 +224,7 @@ def enable_and_start_service() -> int:
224
224
  print('Starting service...')
225
225
  try:
226
226
  subprocess.run(
227
- ['systemctl', 'start', 'git-webhooks-server'],
227
+ ['systemctl', 'start', 'gitwebhooks'],
228
228
  check=True,
229
229
  capture_output=True
230
230
  )
@@ -234,7 +234,7 @@ def enable_and_start_service() -> int:
234
234
 
235
235
  print()
236
236
  print('Installation complete!')
237
- print('Service status: systemctl status git-webhooks-server')
237
+ print('Service status: systemctl status gitwebhooks')
238
238
 
239
239
  return 0
240
240
 
@@ -302,7 +302,7 @@ def stop_and_disable_service() -> None:
302
302
  print('Stopping service...')
303
303
  try:
304
304
  subprocess.run(
305
- ['systemctl', 'stop', 'git-webhooks-server'],
305
+ ['systemctl', 'stop', 'gitwebhooks'],
306
306
  check=False,
307
307
  capture_output=True
308
308
  )
@@ -314,7 +314,7 @@ def stop_and_disable_service() -> None:
314
314
  print('Disabling service...')
315
315
  try:
316
316
  subprocess.run(
317
- ['systemctl', 'disable', 'git-webhooks-server'],
317
+ ['systemctl', 'disable', 'gitwebhooks'],
318
318
  check=False,
319
319
  capture_output=True
320
320
  )
@@ -98,15 +98,21 @@ class ConfigLoader:
98
98
 
99
99
  Note:
100
100
  Skips reserved section names: server, ssl, github, gitee, gitlab, custom
101
+ Skips repository sections with missing required options (logs warning)
101
102
  """
102
103
  configs = {}
103
104
  reserved_sections = self._get_reserved_sections()
104
105
 
105
106
  for section in self.parser.sections():
106
107
  if section not in reserved_sections:
107
- repo_config = self.load_repository_config(section)
108
- if repo_config is not None:
109
- configs[section] = repo_config
108
+ try:
109
+ repo_config = self.load_repository_config(section)
110
+ if repo_config is not None:
111
+ configs[section] = repo_config
112
+ except (configparser.NoOptionError, ConfigurationError) as e:
113
+ # Skip incomplete repository configurations
114
+ import logging
115
+ logging.warning('跳过不完整的仓库配置 [%s]: %s', section, e)
110
116
 
111
117
  return configs
112
118
 
@@ -185,27 +185,32 @@ class WebhookRequestHandler(BaseHTTPRequestHandler):
185
185
 
186
186
  Returns:
187
187
  Tuple of (provider, event)
188
- """
189
- headers_dict = dict(self.headers)
190
188
 
189
+ Note:
190
+ HTTP headers are case-insensitive per RFC 2616.
191
+ Uses get() method which is case-insensitive for HTTPMessage.
192
+ """
191
193
  # GitHub
192
- if HEADER_GITHUB_EVENT in headers_dict:
193
- return Provider.GITHUB, headers_dict.get(HEADER_GITHUB_EVENT)
194
+ github_event = self.headers.get(HEADER_GITHUB_EVENT)
195
+ if github_event is not None:
196
+ return Provider.GITHUB, github_event
194
197
 
195
198
  # Gitee
196
- if HEADER_GITEE_EVENT in headers_dict:
197
- return Provider.GITEE, headers_dict.get(HEADER_GITEE_EVENT)
199
+ gitee_event = self.headers.get(HEADER_GITEE_EVENT)
200
+ if gitee_event is not None:
201
+ return Provider.GITEE, gitee_event
198
202
 
199
203
  # GitLab
200
- if HEADER_GITLAB_EVENT in headers_dict:
201
- return Provider.GITLAB, headers_dict.get(HEADER_GITLAB_EVENT)
204
+ gitlab_event = self.headers.get(HEADER_GITLAB_EVENT)
205
+ if gitlab_event is not None:
206
+ return Provider.GITLAB, gitlab_event
202
207
 
203
208
  # Custom
204
209
  custom_config = self._provider_configs.get(Provider.CUSTOM)
205
210
  if custom_config and custom_config.header_name:
206
- header_value = headers_dict.get(custom_config.header_name, '')
207
- if header_value.startswith(custom_config.header_value):
208
- event = headers_dict.get(custom_config.header_event) if custom_config.header_event else None
211
+ header_value = self.headers.get(custom_config.header_name, '')
212
+ if header_value and header_value.startswith(custom_config.header_value):
213
+ event = self.headers.get(custom_config.header_event) if custom_config.header_event else None
209
214
  return Provider.CUSTOM, event
210
215
 
211
216
  # Unable to identify
@@ -5,6 +5,7 @@
5
5
 
6
6
  import logging
7
7
  import sys
8
+ from pathlib import Path
8
9
 
9
10
 
10
11
  def setup_logging(log_file: str = None):
@@ -16,6 +17,7 @@ def setup_logging(log_file: str = None):
16
17
  根据配置设置日志记录:
17
18
  - 如果 log_file 为空,只输出到 stdout
18
19
  - 如果 log_file 非空,同时输出到文件和 stdout
20
+ - 如果日志目录不存在,只输出到 stdout(记录警告)
19
21
 
20
22
  Note:
21
23
  Python 3.8+ 使用 force 参数确保重新配置,
@@ -25,12 +27,21 @@ def setup_logging(log_file: str = None):
25
27
 
26
28
  # 文件处理器
27
29
  if log_file:
28
- file_handler = logging.FileHandler(log_file, encoding='utf-8')
29
- file_handler.setFormatter(logging.Formatter(
30
- '%(asctime)s %(message)s',
31
- datefmt='%Y-%m-%d %H:%M:%S'
32
- ))
33
- handlers.append(file_handler)
30
+ try:
31
+ log_path = Path(log_file)
32
+ # 确保日志目录存在
33
+ log_path.parent.mkdir(parents=True, exist_ok=True)
34
+
35
+ file_handler = logging.FileHandler(log_file, encoding='utf-8')
36
+ file_handler.setFormatter(logging.Formatter(
37
+ '%(asctime)s %(message)s',
38
+ datefmt='%Y-%m-%d %H:%M:%S'
39
+ ))
40
+ handlers.append(file_handler)
41
+ except (OSError, IOError) as e:
42
+ # 如果无法创建日志文件,回退到仅控制台输出
43
+ import warnings
44
+ warnings.warn(f'无法创建日志文件 {log_file}: {e},将仅输出到控制台')
34
45
 
35
46
  # 控制台处理器
36
47
  console_handler = logging.StreamHandler(sys.stdout)
@@ -1,6 +1,6 @@
1
1
  """CLI main function
2
2
 
3
- Command-line interface module providing compatibility with the original git-webhooks-server.py.
3
+ Command-line interface module providing compatibility with the original gitwebhooks.py.
4
4
  """
5
5
 
6
6
  import argparse
@@ -16,7 +16,7 @@ from typing import Optional, List
16
16
  class InstallationType(Enum):
17
17
  """Installation type enumeration
18
18
 
19
- Represents the method used to install git-webhooks-server.
19
+ Represents the method used to install gitwebhooks.
20
20
  """
21
21
  PIPX = "pipx" # Installed via pipx (recommended)
22
22
  VENV = "venv" # Python standard library venv
@@ -49,7 +49,7 @@ class InstallationEnvironment:
49
49
  # Service file template
50
50
  SERVICE_TEMPLATE = """[Unit]
51
51
  Description=Git Webhooks Server
52
- Documentation=https://github.com/troytse/git-webhooks-server
52
+ Documentation=https://github.com/troytse/gitwebhooks
53
53
  After=network-online.target
54
54
  Wants=network-online.target
55
55
 
@@ -244,7 +244,7 @@ def get_service_path() -> Path:
244
244
  Returns:
245
245
  Path to service file location
246
246
  """
247
- return Path('/etc/systemd/system/git-webhooks-server.service')
247
+ return Path('/etc/systemd/system/gitwebhooks.service')
248
248
 
249
249
 
250
250
  def get_cli_path() -> str:
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitwebhooks
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: A lightweight Git webhook server for automated deployment supporting GitHub, Gitee, GitLab, and custom webhooks
5
5
  Author-email: Troy Tse <troy@holyhi.net>
6
6
  Maintainer-email: Troy Tse <troy@holyhi.net>
7
7
  License-Expression: MIT
8
- Project-URL: Homepage, https://github.com/troytse/git-webhooks-server
9
- Project-URL: Documentation, https://github.com/troytse/git-webhooks-server#readme
10
- Project-URL: Repository, https://github.com/troytse/git-webhooks-server.git
11
- Project-URL: Issues, https://github.com/troytse/git-webhooks-server/issues
8
+ Project-URL: Homepage, https://github.com/troytse/gitwebhooks
9
+ Project-URL: Documentation, https://github.com/troytse/gitwebhooks#readme
10
+ Project-URL: Repository, https://github.com/troytse/gitwebhooks.git
11
+ Project-URL: Issues, https://github.com/troytse/gitwebhooks/issues
12
12
  Keywords: webhook,git,github,gitee,gitlab,deployment,automation,server,devops
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Environment :: No Input/Output (Daemon)
@@ -4,7 +4,7 @@ LICENSE
4
4
  MANIFEST.in
5
5
  README.md
6
6
  README.zh.md
7
- git-webhooks-server.ini.sample
7
+ gitwebhooks.ini.sample
8
8
  pyproject.toml
9
9
  ./gitwebhooks/__init__.py
10
10
  ./gitwebhooks/__main__.py
@@ -1,7 +1,7 @@
1
1
  [server]
2
2
  address=0.0.0.0
3
3
  port=6789
4
- log_file=/var/log/git-webhooks-server.log
4
+ log_file=/var/log/gitwebhooks.log
5
5
 
6
6
  [ssl]
7
7
  enable=true
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gitwebhooks"
7
- version = "2.1.2"
7
+ version = "2.1.4"
8
8
  description = "A lightweight Git webhook server for automated deployment supporting GitHub, Gitee, GitLab, and custom webhooks"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -58,10 +58,10 @@ dev = [
58
58
  ]
59
59
 
60
60
  [project.urls]
61
- Homepage = "https://github.com/troytse/git-webhooks-server"
62
- Documentation = "https://github.com/troytse/git-webhooks-server#readme"
63
- Repository = "https://github.com/troytse/git-webhooks-server.git"
64
- Issues = "https://github.com/troytse/git-webhooks-server/issues"
61
+ Homepage = "https://github.com/troytse/gitwebhooks"
62
+ Documentation = "https://github.com/troytse/gitwebhooks#readme"
63
+ Repository = "https://github.com/troytse/gitwebhooks.git"
64
+ Issues = "https://github.com/troytse/gitwebhooks/issues"
65
65
 
66
66
  [project.scripts]
67
67
  gitwebhooks-cli = "gitwebhooks.main:main"
@@ -1,6 +1,6 @@
1
- # Test Suite for git-webhooks-server
1
+ # Test Suite for gitwebhooks
2
2
  #
3
- # This package contains the complete test suite for the git-webhooks-server project.
3
+ # This package contains the complete test suite for the gitwebhooks project.
4
4
  #
5
5
  # Running Tests:
6
6
  # python -m tests # Run all tests
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- Test Suite Entry Point for git-webhooks-server
3
+ Test Suite Entry Point for gitwebhooks
4
4
 
5
5
  This module provides the main entry point for running the test suite.
6
6
  It supports test discovery, execution, and reporting.
@@ -29,7 +29,7 @@ def main(argv=None) -> int:
29
29
  int: 0 if all tests pass, 1 otherwise
30
30
  """
31
31
  parser = argparse.ArgumentParser(
32
- description="Run git-webhooks-server test suite"
32
+ description="Run gitwebhooks test suite"
33
33
  )
34
34
  parser.add_argument(
35
35
  "-v", "--verbose",