gitwebhooks 2.1.1__tar.gz → 2.1.3__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 (104) hide show
  1. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/CLAUDE.md +2 -0
  2. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/PKG-INFO +25 -1
  3. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/README.md +24 -0
  4. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/README.zh.md +24 -0
  5. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/cli/init_wizard.py +122 -44
  6. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks.egg-info/PKG-INFO +25 -1
  7. gitwebhooks-2.1.3/gitwebhooks.egg-info/entry_points.txt +2 -0
  8. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/pyproject.toml +2 -2
  9. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/cli/test_init_wizard.py +14 -9
  10. gitwebhooks-2.1.1/gitwebhooks.egg-info/entry_points.txt +0 -2
  11. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/.editorconfig +0 -0
  12. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/LICENSE +0 -0
  13. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/MANIFEST.in +0 -0
  14. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/custom-body.png +0 -0
  15. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/custom-header.png +0 -0
  16. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/custom-response.png +0 -0
  17. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/gitee-success.png +0 -0
  18. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/gitee.png +0 -0
  19. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/github-success.png +0 -0
  20. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/github.png +0 -0
  21. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/gitlab-success.png +0 -0
  22. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/gitlab.png +0 -0
  23. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/install.png +0 -0
  24. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/doc/uninstall.png +0 -0
  25. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/git-webhooks-server.ini.sample +0 -0
  26. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/__init__.py +0 -0
  27. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/__main__.py +0 -0
  28. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/__init__.py +0 -0
  29. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/custom.py +0 -0
  30. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/factory.py +0 -0
  31. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/gitee.py +0 -0
  32. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/github.py +0 -0
  33. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/gitlab.py +0 -0
  34. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/auth/verifier.py +0 -0
  35. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/cli/__init__.py +0 -0
  36. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/cli/config.py +0 -0
  37. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/cli/prompts.py +0 -0
  38. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/cli/service.py +0 -0
  39. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/config/__init__.py +0 -0
  40. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/config/loader.py +0 -0
  41. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/config/models.py +0 -0
  42. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/config/registry.py +0 -0
  43. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/config/server.py +0 -0
  44. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/__init__.py +0 -0
  45. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/base.py +0 -0
  46. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/custom.py +0 -0
  47. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/factory.py +0 -0
  48. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/gitee.py +0 -0
  49. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/github.py +0 -0
  50. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/gitlab.py +0 -0
  51. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/handlers/request.py +0 -0
  52. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/logging/__init__.py +0 -0
  53. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/logging/setup.py +0 -0
  54. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/main/__init__.py +0 -0
  55. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/main/__main__.py +0 -0
  56. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/models/__init__.py +0 -0
  57. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/models/provider.py +0 -0
  58. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/models/request.py +0 -0
  59. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/models/result.py +0 -0
  60. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/server.py +0 -0
  61. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/utils/__init__.py +0 -0
  62. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/utils/constants.py +0 -0
  63. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/utils/exceptions.py +0 -0
  64. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/utils/executor.py +0 -0
  65. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks/utils/systemd.py +0 -0
  66. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks.egg-info/SOURCES.txt +0 -0
  67. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks.egg-info/dependency_links.txt +0 -0
  68. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks.egg-info/requires.txt +0 -0
  69. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/gitwebhooks.egg-info/top_level.txt +0 -0
  70. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/setup.cfg +0 -0
  71. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/__init__.py +0 -0
  72. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/__main__.py +0 -0
  73. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/conftest.py +0 -0
  74. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/__init__.py +0 -0
  75. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/custom_payloads.py +0 -0
  76. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/gitee_payloads.py +0 -0
  77. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/github_payloads.py +0 -0
  78. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/gitlab_payloads.py +0 -0
  79. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/fixtures/signature_builder.py +0 -0
  80. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/__init__.py +0 -0
  81. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_command_execution.py +0 -0
  82. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_config_view_integration.py +0 -0
  83. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_custom_webhook.py +0 -0
  84. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_edge_cases.py +0 -0
  85. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_gitee_webhook.py +0 -0
  86. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_github_webhook.py +0 -0
  87. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/integration/test_gitlab_webhook.py +0 -0
  88. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/test_auth/__init__.py +0 -0
  89. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/test_config/__init__.py +0 -0
  90. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/test_handlers/__init__.py +0 -0
  91. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/test_integration/__init__.py +0 -0
  92. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/__init__.py +0 -0
  93. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/cli/__init__.py +0 -0
  94. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/cli/test_config_view.py +0 -0
  95. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/test_config_loading.py +0 -0
  96. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/test_data_parsing.py +0 -0
  97. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/test_provider_detection.py +0 -0
  98. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/test_request_handler.py +0 -0
  99. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/unit/test_signature_verification.py +0 -0
  100. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/utils/__init__.py +0 -0
  101. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/utils/certificate_generator.py +0 -0
  102. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/utils/coverage_runner.py +0 -0
  103. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/utils/http_client.py +0 -0
  104. {gitwebhooks-2.1.1 → gitwebhooks-2.1.3}/tests/utils/server_manager.py +0 -0
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitwebhooks
3
- Version: 2.1.1
3
+ Version: 2.1.3
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>
@@ -489,6 +489,30 @@ python3 -m pytest tests/
489
489
  python3 -m unittest discover tests/
490
490
  ```
491
491
 
492
+ ### Releasing to PyPI
493
+
494
+ **IMPORTANT**: Before releasing to PyPI, you MUST run the pre-release validation script:
495
+
496
+ ```bash
497
+ ./scripts/pre-release-check.sh
498
+ ```
499
+
500
+ This script validates:
501
+ - Package builds successfully
502
+ - CLI entry point works (`gitwebhooks-cli`)
503
+ - All subcommands work (`service`, `config`)
504
+ - Module imports work correctly
505
+
506
+ Only after all checks pass, proceed with publishing:
507
+
508
+ ```bash
509
+ # Build the package
510
+ python3 -m build
511
+
512
+ # Upload to PyPI
513
+ python3 -m twine upload dist/*
514
+ ```
515
+
492
516
  ## License
493
517
 
494
518
  MIT License
@@ -449,6 +449,30 @@ python3 -m pytest tests/
449
449
  python3 -m unittest discover tests/
450
450
  ```
451
451
 
452
+ ### Releasing to PyPI
453
+
454
+ **IMPORTANT**: Before releasing to PyPI, you MUST run the pre-release validation script:
455
+
456
+ ```bash
457
+ ./scripts/pre-release-check.sh
458
+ ```
459
+
460
+ This script validates:
461
+ - Package builds successfully
462
+ - CLI entry point works (`gitwebhooks-cli`)
463
+ - All subcommands work (`service`, `config`)
464
+ - Module imports work correctly
465
+
466
+ Only after all checks pass, proceed with publishing:
467
+
468
+ ```bash
469
+ # Build the package
470
+ python3 -m build
471
+
472
+ # Upload to PyPI
473
+ python3 -m twine upload dist/*
474
+ ```
475
+
452
476
  ## License
453
477
 
454
478
  MIT License
@@ -449,6 +449,30 @@ python3 -m pytest tests/
449
449
  python3 -m unittest discover tests/
450
450
  ```
451
451
 
452
+ ### 发布到 PyPI
453
+
454
+ **重要提示**:发布到 PyPI 前,必须运行发布前验证脚本:
455
+
456
+ ```bash
457
+ ./scripts/pre-release-check.sh
458
+ ```
459
+
460
+ 此脚本会验证:
461
+ - 包能成功构建
462
+ - CLI 入口点正常工作(`gitwebhooks-cli`)
463
+ - 所有子命令正常工作(`service`、`config`)
464
+ - 模块导入正常工作
465
+
466
+ 只有在所有检查通过后,才能进行发布:
467
+
468
+ ```bash
469
+ # 构建包
470
+ python3 -m build
471
+
472
+ # 上传到 PyPI
473
+ python3 -m twine upload dist/*
474
+ ```
475
+
452
476
  ## 许可证
453
477
 
454
478
  MIT License
@@ -3,6 +3,28 @@ Interactive configuration initialization wizard.
3
3
 
4
4
  This module provides a user-friendly wizard for creating git-webhooks-server
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
@@ -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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitwebhooks
3
- Version: 2.1.1
3
+ Version: 2.1.3
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>
@@ -489,6 +489,30 @@ python3 -m pytest tests/
489
489
  python3 -m unittest discover tests/
490
490
  ```
491
491
 
492
+ ### Releasing to PyPI
493
+
494
+ **IMPORTANT**: Before releasing to PyPI, you MUST run the pre-release validation script:
495
+
496
+ ```bash
497
+ ./scripts/pre-release-check.sh
498
+ ```
499
+
500
+ This script validates:
501
+ - Package builds successfully
502
+ - CLI entry point works (`gitwebhooks-cli`)
503
+ - All subcommands work (`service`, `config`)
504
+ - Module imports work correctly
505
+
506
+ Only after all checks pass, proceed with publishing:
507
+
508
+ ```bash
509
+ # Build the package
510
+ python3 -m build
511
+
512
+ # Upload to PyPI
513
+ python3 -m twine upload dist/*
514
+ ```
515
+
492
516
  ## License
493
517
 
494
518
  MIT License
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gitwebhooks-cli = gitwebhooks.main:main
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gitwebhooks"
7
- version = "2.1.1"
7
+ version = "2.1.3"
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"
@@ -64,7 +64,7 @@ Repository = "https://github.com/troytse/git-webhooks-server.git"
64
64
  Issues = "https://github.com/troytse/git-webhooks-server/issues"
65
65
 
66
66
  [project.scripts]
67
- gitwebhooks-cli = "gitwebhooks.cli:main"
67
+ gitwebhooks-cli = "gitwebhooks.main:main"
68
68
 
69
69
  [tool.setuptools]
70
70
  package-dir = {"" = "."}
@@ -76,16 +76,20 @@ class TestInputValidation:
76
76
  assert validate_repo_name('org/team/sub-project') is True
77
77
  assert validate_repo_name('group/subgroup/project') is True
78
78
 
79
+ # Single-level format (now supported per spec)
80
+ assert validate_repo_name('owner') is True
81
+ assert validate_repo_name('myrepo') is True
82
+
79
83
  def test_validate_repo_name_invalid(self):
80
84
  """Test validate_repo_name rejects invalid formats."""
81
85
  from gitwebhooks.cli.init_wizard import validate_repo_name
82
86
 
83
- assert validate_repo_name('owner') is False
84
87
  assert validate_repo_name('owner/') is False
85
88
  assert validate_repo_name('/repo') is False
86
89
  assert validate_repo_name('') is False
87
90
  assert validate_repo_name('https://github.com/owner/repo') is False
88
91
  assert validate_repo_name('owner//repo') is False
92
+ assert validate_repo_name('owner repo') is False # spaces not allowed
89
93
 
90
94
  def test_validate_existing_path_valid(self):
91
95
  """Test validate_existing_path accepts existing directories."""
@@ -209,7 +213,7 @@ class TestINIGeneration:
209
213
  server = MagicMock()
210
214
  platform = PlatformConfig(
211
215
  platform='github',
212
- handle_events=['push', 'release'],
216
+ handle_events='push,release', # Changed from list to string
213
217
  verify=True,
214
218
  secret='test-secret',
215
219
  custom_params=None
@@ -219,7 +223,7 @@ class TestINIGeneration:
219
223
  config = _generate_config(server, platform, repo)
220
224
 
221
225
  assert config.has_section('github')
222
- assert config.get('github', 'handle_events') == 'push, release'
226
+ assert config.get('github', 'handle_events') == 'push,release' # No spaces
223
227
  assert config.get('github', 'verify') == 'true'
224
228
  assert config.get('github', 'secret') == 'test-secret'
225
229
 
@@ -237,9 +241,10 @@ class TestINIGeneration:
237
241
 
238
242
  config = _generate_config(server, platform, repo)
239
243
 
240
- assert config.has_section('repo/owner/repo')
241
- assert config.get('repo/owner/repo', 'cwd') == '/path/to/repo'
242
- assert config.get('repo/owner/repo', 'cmd') == 'git pull && ./deploy.sh'
244
+ # Section name no longer has 'repo/' prefix
245
+ assert config.has_section('owner/repo')
246
+ assert config.get('owner/repo', 'cwd') == '/path/to/repo'
247
+ assert config.get('owner/repo', 'cmd') == 'git pull && ./deploy.sh'
243
248
 
244
249
  def test_generate_custom_platform_section(self):
245
250
  """Test generating [custom] section with custom parameters."""
@@ -248,7 +253,7 @@ class TestINIGeneration:
248
253
  server = MagicMock()
249
254
  platform = PlatformConfig(
250
255
  platform='custom',
251
- handle_events=['push'],
256
+ handle_events='webhook', # Changed from list to string
252
257
  verify=False,
253
258
  secret=None,
254
259
  custom_params={
@@ -291,12 +296,12 @@ class TestDataClasses:
291
296
 
292
297
  platform = PlatformConfig(
293
298
  platform='github',
294
- handle_events=['push', 'release'],
299
+ handle_events='push,release', # Changed from list to string
295
300
  verify=True,
296
301
  secret='my-secret'
297
302
  )
298
303
  assert platform.platform == 'github'
299
- assert platform.handle_events == ['push', 'release']
304
+ assert platform.handle_events == 'push,release'
300
305
  assert platform.verify is True
301
306
  assert platform.secret == 'my-secret'
302
307
 
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- gitwebhooks-cli = gitwebhooks.cli:main
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes