gitwebhooks 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitwebhooks/__init__.py +18 -0
- gitwebhooks/__main__.py +10 -0
- gitwebhooks/auth/__init__.py +20 -0
- gitwebhooks/auth/custom.py +40 -0
- gitwebhooks/auth/factory.py +73 -0
- gitwebhooks/auth/gitee.py +86 -0
- gitwebhooks/auth/github.py +52 -0
- gitwebhooks/auth/gitlab.py +29 -0
- gitwebhooks/auth/verifier.py +34 -0
- gitwebhooks/cli.py +107 -0
- gitwebhooks/config/__init__.py +17 -0
- gitwebhooks/config/loader.py +170 -0
- gitwebhooks/config/models.py +145 -0
- gitwebhooks/config/registry.py +104 -0
- gitwebhooks/config/server.py +85 -0
- gitwebhooks/handlers/__init__.py +22 -0
- gitwebhooks/handlers/base.py +107 -0
- gitwebhooks/handlers/custom.py +73 -0
- gitwebhooks/handlers/factory.py +83 -0
- gitwebhooks/handlers/gitee.py +113 -0
- gitwebhooks/handlers/github.py +43 -0
- gitwebhooks/handlers/gitlab.py +43 -0
- gitwebhooks/handlers/request.py +248 -0
- gitwebhooks/logging/__init__.py +10 -0
- gitwebhooks/logging/setup.py +57 -0
- gitwebhooks/models/__init__.py +14 -0
- gitwebhooks/models/provider.py +22 -0
- gitwebhooks/models/request.py +61 -0
- gitwebhooks/models/result.py +40 -0
- gitwebhooks/server.py +128 -0
- gitwebhooks/utils/__init__.py +14 -0
- gitwebhooks/utils/constants.py +42 -0
- gitwebhooks/utils/exceptions.py +34 -0
- gitwebhooks/utils/executor.py +34 -0
- gitwebhooks-2.0.0.dist-info/METADATA +312 -0
- gitwebhooks-2.0.0.dist-info/RECORD +40 -0
- gitwebhooks-2.0.0.dist-info/WHEEL +5 -0
- gitwebhooks-2.0.0.dist-info/entry_points.txt +2 -0
- gitwebhooks-2.0.0.dist-info/licenses/LICENSE +21 -0
- gitwebhooks-2.0.0.dist-info/top_level.txt +1 -0
gitwebhooks/server.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""HTTP server main logic
|
|
2
|
+
|
|
3
|
+
Creates and runs the HTTP server, handles webhook requests.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import ssl
|
|
8
|
+
import sys
|
|
9
|
+
from http.server import HTTPServer
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from gitwebhooks.config.loader import ConfigLoader
|
|
13
|
+
from gitwebhooks.config.registry import ConfigurationRegistry
|
|
14
|
+
from gitwebhooks.config.server import ServerConfig
|
|
15
|
+
from gitwebhooks.handlers.request import WebhookRequestHandler
|
|
16
|
+
from gitwebhooks.logging.setup import setup_logging
|
|
17
|
+
from gitwebhooks.utils.exceptions import ConfigurationError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WebhookServer:
|
|
21
|
+
"""Git Webhooks server main class
|
|
22
|
+
|
|
23
|
+
Responsible for creating and running the HTTP server, handling webhook requests.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, config_path: str,
|
|
27
|
+
registry: Optional[ConfigurationRegistry] = None):
|
|
28
|
+
"""Initialize Webhook server
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
config_path: INI configuration file path
|
|
32
|
+
registry: Configuration registry (optional, for dependency injection)
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
ConfigurationError: Invalid or missing configuration
|
|
36
|
+
"""
|
|
37
|
+
self.config_path = config_path
|
|
38
|
+
self.loader = ConfigLoader(config_path)
|
|
39
|
+
self.registry = registry or ConfigurationRegistry(self.loader)
|
|
40
|
+
self.server_config = self.registry.server_config
|
|
41
|
+
|
|
42
|
+
# Configure logging
|
|
43
|
+
self._setup_logging()
|
|
44
|
+
|
|
45
|
+
def _setup_logging(self) -> None:
|
|
46
|
+
"""Configure logging system
|
|
47
|
+
|
|
48
|
+
Sets up logging based on server configuration:
|
|
49
|
+
- If log_file is empty, output to stdout only
|
|
50
|
+
- If log_file is non-empty, output to both file and stdout
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ConfigurationError: Log file cannot be created
|
|
54
|
+
"""
|
|
55
|
+
setup_logging(self.server_config.log_file)
|
|
56
|
+
|
|
57
|
+
def create_http_server(self) -> HTTPServer:
|
|
58
|
+
"""Create HTTP server instance
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Configured HTTPServer instance
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
ConfigurationError: Invalid server configuration
|
|
65
|
+
OSError: Failed to bind address
|
|
66
|
+
"""
|
|
67
|
+
# Configure handler class (inject dependencies)
|
|
68
|
+
WebhookRequestHandler.configure(
|
|
69
|
+
self.registry.provider_configs,
|
|
70
|
+
self.registry.repository_configs
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Create server
|
|
74
|
+
server = HTTPServer(
|
|
75
|
+
(self.server_config.address, self.server_config.port),
|
|
76
|
+
WebhookRequestHandler
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Configure SSL (if enabled)
|
|
80
|
+
if self.server_config.ssl_enabled:
|
|
81
|
+
server.socket = self._wrap_socket_ssl(server.socket)
|
|
82
|
+
|
|
83
|
+
return server
|
|
84
|
+
|
|
85
|
+
def _wrap_socket_ssl(self, socket):
|
|
86
|
+
"""Wrap socket with SSL
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
socket: Raw socket
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
SSL-wrapped socket
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
ConfigurationError: Invalid SSL configuration
|
|
96
|
+
ssl.SSLError: SSL initialization failed
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
100
|
+
context.load_cert_chain(
|
|
101
|
+
certfile=self.server_config.ssl_cert_file,
|
|
102
|
+
keyfile=self.server_config.ssl_key_file
|
|
103
|
+
)
|
|
104
|
+
return context.wrap_socket(socket, server_side=True)
|
|
105
|
+
except (ssl.SSLError, OSError) as e:
|
|
106
|
+
raise ConfigurationError(f'SSL configuration error: {e}')
|
|
107
|
+
|
|
108
|
+
def run(self) -> None:
|
|
109
|
+
"""Start server main loop
|
|
110
|
+
|
|
111
|
+
This method blocks until the server is stopped.
|
|
112
|
+
"""
|
|
113
|
+
server = self.create_http_server()
|
|
114
|
+
|
|
115
|
+
ssl_message = ' with SSL' if self.server_config.ssl_enabled else ''
|
|
116
|
+
logging.info('Serving on %s port %d%s...',
|
|
117
|
+
self.server_config.address,
|
|
118
|
+
self.server_config.port,
|
|
119
|
+
ssl_message)
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
server.serve_forever()
|
|
123
|
+
except KeyboardInterrupt:
|
|
124
|
+
logging.info('Server stopped by user')
|
|
125
|
+
server.shutdown()
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logging.error('Server error: %s', e)
|
|
128
|
+
raise
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""HTTP and response constants definition
|
|
2
|
+
|
|
3
|
+
Defines all constants used in the project.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# HTTP Status Codes
|
|
7
|
+
HTTP_OK = 200
|
|
8
|
+
HTTP_BAD_REQUEST = 400
|
|
9
|
+
HTTP_UNAUTHORIZED = 401
|
|
10
|
+
HTTP_FORBIDDEN = 403
|
|
11
|
+
HTTP_NOT_FOUND = 404
|
|
12
|
+
HTTP_NOT_ACCEPTABLE = 406
|
|
13
|
+
HTTP_PRECONDITION_FAILED = 412
|
|
14
|
+
HTTP_INTERNAL_SERVER_ERROR = 500
|
|
15
|
+
|
|
16
|
+
# HTTP Content Types
|
|
17
|
+
CONTENT_TYPE_JSON = 'application/json'
|
|
18
|
+
CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
|
|
19
|
+
|
|
20
|
+
# HTTP Headers
|
|
21
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
|
22
|
+
HEADER_CONTENT_LENGTH = 'Content-Length'
|
|
23
|
+
HEADER_GITHUB_EVENT = 'X-GitHub-Event'
|
|
24
|
+
HEADER_GITHUB_SIGNATURE = 'X-Hub-Signature'
|
|
25
|
+
HEADER_GITEE_EVENT = 'X-Gitee-Event'
|
|
26
|
+
HEADER_GITEE_TOKEN = 'X-Gitee-Token'
|
|
27
|
+
HEADER_GITEE_TIMESTAMP = 'X-Gitee-Timestamp'
|
|
28
|
+
HEADER_GITLAB_EVENT = 'X-Gitlab-Event'
|
|
29
|
+
HEADER_GITLAB_TOKEN = 'X-Gitlab-Token'
|
|
30
|
+
|
|
31
|
+
# Response Messages
|
|
32
|
+
MESSAGE_OK = b'OK'
|
|
33
|
+
MESSAGE_FORBIDDEN = 'Forbidden'
|
|
34
|
+
MESSAGE_BAD_REQUEST = 'Bad Request'
|
|
35
|
+
MESSAGE_UNAUTHORIZED = 'Unauthorized'
|
|
36
|
+
MESSAGE_NOT_FOUND = 'Not Found'
|
|
37
|
+
MESSAGE_NOT_ACCEPTABLE = 'Not Acceptable'
|
|
38
|
+
MESSAGE_PRECONDITION_FAILED = 'Precondition Failed'
|
|
39
|
+
MESSAGE_INTERNAL_SERVER_ERROR = 'Internal Server Error'
|
|
40
|
+
|
|
41
|
+
# Reserved configuration sections
|
|
42
|
+
RESERVED_SECTIONS = {'server', 'ssl', 'github', 'gitee', 'gitlab', 'custom'}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Custom exception classes
|
|
2
|
+
|
|
3
|
+
Defines all exception types used in the project.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WebhookError(Exception):
|
|
8
|
+
"""Webhook processing error base class"""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SignatureValidationError(WebhookError):
|
|
13
|
+
"""Signature verification failed"""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UnsupportedEventError(WebhookError):
|
|
18
|
+
"""Unsupported event type"""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UnsupportedProviderError(WebhookError):
|
|
23
|
+
"""Unrecognized platform provider"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ConfigurationError(WebhookError):
|
|
28
|
+
"""Configuration error or missing"""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class RequestParseError(WebhookError):
|
|
33
|
+
"""Request parsing failed"""
|
|
34
|
+
pass
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Command executor
|
|
2
|
+
|
|
3
|
+
Asynchronously executes deployment commands.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def execute_deployment(repo_name: str, cwd: str, cmd: str) -> None:
|
|
11
|
+
"""Execute deployment command
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
repo_name: Repository name (for logging)
|
|
15
|
+
cwd: Working directory
|
|
16
|
+
cmd: Command to execute
|
|
17
|
+
|
|
18
|
+
Note:
|
|
19
|
+
Command executes asynchronously without blocking the server.
|
|
20
|
+
stdin is set to DEVNULL to prevent file descriptor leaks.
|
|
21
|
+
"""
|
|
22
|
+
logging.info('[%s] Executing: %s', repo_name, cmd)
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
subprocess.Popen(
|
|
26
|
+
cmd,
|
|
27
|
+
cwd=cwd,
|
|
28
|
+
shell=True,
|
|
29
|
+
stdin=subprocess.DEVNULL, # Prevent inheriting stdin, avoid fd leaks
|
|
30
|
+
stdout=subprocess.PIPE,
|
|
31
|
+
stderr=subprocess.PIPE
|
|
32
|
+
)
|
|
33
|
+
except (OSError, subprocess.SubprocessError) as e:
|
|
34
|
+
logging.warning('[%s] Execution failed: %s', repo_name, e)
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitwebhooks
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: A lightweight Git webhook server for automated deployment supporting GitHub, Gitee, GitLab, and custom webhooks
|
|
5
|
+
Author-email: Troy Tse <troy@holyhi.net>
|
|
6
|
+
Maintainer-email: Troy Tse <troy@holyhi.net>
|
|
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
|
|
12
|
+
Keywords: webhook,git,github,gitee,gitlab,deployment,automation,server,devops
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Environment :: No Input/Output (Daemon)
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: System Administrators
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
29
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
30
|
+
Classifier: Topic :: System :: Installation/Setup
|
|
31
|
+
Classifier: Topic :: System :: Systems Administration
|
|
32
|
+
Classifier: Typing :: Typed
|
|
33
|
+
Requires-Python: >=3.6
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# Simple Git Webhooks Server
|
|
42
|
+
|
|
43
|
+
[README](README.md) | [中文说明](README.zh.md)
|
|
44
|
+
|
|
45
|
+
## Table of Contents
|
|
46
|
+
- [Introduction](#introduction)
|
|
47
|
+
- [Architecture](#architecture)
|
|
48
|
+
- [Installation](#installation)
|
|
49
|
+
- [Uninstallation](#uninstallation)
|
|
50
|
+
- [Usage](#usage)
|
|
51
|
+
- [Github](#github)
|
|
52
|
+
- [Gitee](#gitee)
|
|
53
|
+
- [Gitlab](#gitlab)
|
|
54
|
+
- [Custom](#custom)
|
|
55
|
+
- [Configuration](#configuration)
|
|
56
|
+
- [Project Structure](#project-structure)
|
|
57
|
+
|
|
58
|
+
## Introduction
|
|
59
|
+
|
|
60
|
+
A lightweight Git webhook server for automated deployment.
|
|
61
|
+
|
|
62
|
+
- Implemented with Python 3.6+ (standard library only)
|
|
63
|
+
- Supports Github, Gitee, Gitlab, and custom repositories
|
|
64
|
+
- Custom working directory and command for different repositories
|
|
65
|
+
- Installable as a Systemd service
|
|
66
|
+
- Modular architecture for easy extension and testing
|
|
67
|
+
|
|
68
|
+
## Architecture
|
|
69
|
+
|
|
70
|
+
**Version 2.0** features a modular package structure:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
gitwebhooks/
|
|
74
|
+
├── models/ # Data models (Provider, Request, Result)
|
|
75
|
+
├── config/ # Configuration management
|
|
76
|
+
├── auth/ # Signature verification
|
|
77
|
+
├── handlers/ # Webhook handlers
|
|
78
|
+
├── utils/ # Utilities
|
|
79
|
+
└── logging/ # Logging setup
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Key Features:**
|
|
83
|
+
- **Dependency Injection**: ConfigurationRegistry, VerifierFactory, HandlerFactory
|
|
84
|
+
- **Abstract Base Classes**: SignatureVerifier, WebhookHandler
|
|
85
|
+
- **No External Dependencies**: 100% Python standard library
|
|
86
|
+
- **In-Place Execution**: CLI runs from source directory
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
### Prerequisites
|
|
91
|
+
|
|
92
|
+
- Python 3.6 or higher
|
|
93
|
+
- sudo/root access (for installation)
|
|
94
|
+
|
|
95
|
+
### Install from Source
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Clone or download the repository
|
|
99
|
+
git clone https://github.com/troytse/git-webhooks-server.git
|
|
100
|
+
cd git-webhooks-server
|
|
101
|
+
|
|
102
|
+
# Run the installation script
|
|
103
|
+
./install.sh
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The installer will:
|
|
107
|
+
1. Create a hard link for `gitwebhooks-cli` in `/usr/local/bin`
|
|
108
|
+
2. Copy configuration file to `/usr/local/etc/git-webhooks-server.ini`
|
|
109
|
+
3. Optionally install as a systemd service
|
|
110
|
+
|
|
111
|
+

|
|
112
|
+
|
|
113
|
+
### Manual Installation
|
|
114
|
+
|
|
115
|
+
To install manually without the script:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Make CLI executable
|
|
119
|
+
chmod +x gitwebhooks-cli
|
|
120
|
+
|
|
121
|
+
# Create hard link to system path
|
|
122
|
+
sudo ln "$(pwd)/gitwebhooks-cli" /usr/local/bin/gitwebhooks-cli
|
|
123
|
+
|
|
124
|
+
# Copy configuration
|
|
125
|
+
sudo cp git-webhooks-server.ini.sample /usr/local/etc/git-webhooks-server.ini
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Verify Installation
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
gitwebhooks-cli --help
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Uninstallation
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
cd git-webhooks-server
|
|
138
|
+
./install.sh --uninstall
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+

|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
### 1. Configure Repository
|
|
146
|
+
|
|
147
|
+
Edit `/usr/local/etc/git-webhooks-server.ini`:
|
|
148
|
+
|
|
149
|
+
```ini
|
|
150
|
+
[your_name/repository]
|
|
151
|
+
cwd=/path/to/your/repository
|
|
152
|
+
cmd=git fetch --all && git reset --hard origin/master && git pull
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 2. Restart Service
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
systemctl restart git-webhooks-server
|
|
159
|
+
# Or run directly:
|
|
160
|
+
gitwebhooks-cli -c /usr/local/etc/git-webhooks-server.ini
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Add Webhook
|
|
164
|
+
|
|
165
|
+
#### Github
|
|
166
|
+
|
|
167
|
+

|
|
168
|
+

|
|
169
|
+
|
|
170
|
+
#### Gitee
|
|
171
|
+
|
|
172
|
+

|
|
173
|
+

|
|
174
|
+
|
|
175
|
+
#### Gitlab
|
|
176
|
+
|
|
177
|
+

|
|
178
|
+

|
|
179
|
+
|
|
180
|
+
#### Custom
|
|
181
|
+
|
|
182
|
+
For custom webhook sources, configure like this:
|
|
183
|
+
|
|
184
|
+
```ini
|
|
185
|
+
[custom]
|
|
186
|
+
# Header to identify the source
|
|
187
|
+
header_name=X-Custom-Header
|
|
188
|
+
header_value=Custom-Git-Hookshot
|
|
189
|
+
# Header for token verification
|
|
190
|
+
header_token=X-Custom-Token
|
|
191
|
+
# Path to repository name in JSON payload
|
|
192
|
+
identifier_path=project.path_with_namespace
|
|
193
|
+
verify=True
|
|
194
|
+
secret=123456
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The handler accepts POST data with `application/json` or `application/x-www-form-urlencoded` content type. See [Github](https://developer.github.com/webhooks/event-payloads/#example-delivery) / [Gitee](https://gitee.com/help/articles/4186) / [Gitlab](https://gitlab.com/help/user/project/integrations/webhooks#push-events) for payload examples.
|
|
198
|
+
|
|
199
|
+
Example payload:
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"project": {
|
|
203
|
+
"path_with_namespace": "your_name/repository"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+

|
|
209
|
+

|
|
210
|
+

|
|
211
|
+
|
|
212
|
+
## Configuration
|
|
213
|
+
|
|
214
|
+
Default configuration file: `/usr/local/etc/git-webhooks-server.ini`
|
|
215
|
+
|
|
216
|
+
### Server Configuration
|
|
217
|
+
|
|
218
|
+
```ini
|
|
219
|
+
[server]
|
|
220
|
+
address=0.0.0.0 # Listen address
|
|
221
|
+
port=6789 # Listen port
|
|
222
|
+
log_file=/var/log/git-webhooks-server.log # Log file (empty = stdout only)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### SSL Configuration (Optional)
|
|
226
|
+
|
|
227
|
+
```ini
|
|
228
|
+
[ssl]
|
|
229
|
+
enable=False
|
|
230
|
+
key_file=/path/to/key.pem
|
|
231
|
+
cert_file=/path/to/cert.pem
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Provider Configuration
|
|
235
|
+
|
|
236
|
+
```ini
|
|
237
|
+
[github]
|
|
238
|
+
verify=True # Enable signature verification
|
|
239
|
+
secret=your_webhook_secret
|
|
240
|
+
handle_events=push,pull_request # Events to handle (empty = all)
|
|
241
|
+
|
|
242
|
+
[gitee]
|
|
243
|
+
verify=True
|
|
244
|
+
secret=your_webhook_secret
|
|
245
|
+
|
|
246
|
+
[gitlab]
|
|
247
|
+
verify=True
|
|
248
|
+
secret=your_webhook_token
|
|
249
|
+
|
|
250
|
+
[custom]
|
|
251
|
+
header_name=X-Custom-Header
|
|
252
|
+
header_value=Your-Identifier
|
|
253
|
+
header_token=X-Custom-Token
|
|
254
|
+
identifier_path=project.path_with_namespace
|
|
255
|
+
verify=True
|
|
256
|
+
secret=your_secret
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Repository Configuration
|
|
260
|
+
|
|
261
|
+
```ini
|
|
262
|
+
[owner/repository]
|
|
263
|
+
cwd=/path/to/repo # Working directory
|
|
264
|
+
cmd=your_command # Command to execute
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Project Structure
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
git-webhooks-server/
|
|
271
|
+
├── gitwebhooks/ # Python package (modular v2.0)
|
|
272
|
+
│ ├── __init__.py
|
|
273
|
+
│ ├── __main__.py
|
|
274
|
+
│ ├── cli.py # CLI entry point
|
|
275
|
+
│ ├── server.py # HTTP server
|
|
276
|
+
│ ├── models/ # Data models
|
|
277
|
+
│ ├── config/ # Configuration management
|
|
278
|
+
│ ├── auth/ # Signature verification
|
|
279
|
+
│ ├── handlers/ # Webhook handlers
|
|
280
|
+
│ ├── utils/ # Utilities
|
|
281
|
+
│ └── logging/ # Logging setup
|
|
282
|
+
├── gitwebhooks-cli # CLI wrapper script
|
|
283
|
+
├── install.sh # Installation script
|
|
284
|
+
├── git-webhooks-server.ini.sample
|
|
285
|
+
└── tests/ # Test suite
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Development
|
|
289
|
+
|
|
290
|
+
### Running from Source
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Method 1: Use CLI tool (recommended)
|
|
294
|
+
./gitwebhooks-cli -c git-webhooks-server.ini.sample
|
|
295
|
+
|
|
296
|
+
# Method 2: Use module entry
|
|
297
|
+
python3 -m gitwebhooks.cli -c git-webhooks-server.ini.sample
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Running Tests
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Using pytest
|
|
304
|
+
python3 -m pytest tests/
|
|
305
|
+
|
|
306
|
+
# Or using unittest
|
|
307
|
+
python3 -m unittest discover tests/
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## License
|
|
311
|
+
|
|
312
|
+
MIT License
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
gitwebhooks/__init__.py,sha256=lBuLRzIrUhawp8mQG3IB5HZiksNeUmuuDBRK5_hcZvw,422
|
|
2
|
+
gitwebhooks/__main__.py,sha256=E53ngtaBCyt5R0TFmbt5NwO-Oc9vSAFE53fugqTSZ1g,192
|
|
3
|
+
gitwebhooks/cli.py,sha256=hromNOiH7rWW_8Y66j3aywmvCEhHP4M8FL8n_jbigFk,2973
|
|
4
|
+
gitwebhooks/server.py,sha256=keQcfOysoitx7cINcTkaDvhe6nScIFL2K8dCCViFF-o,3986
|
|
5
|
+
gitwebhooks/auth/__init__.py,sha256=Hu88BS6aOickrWBBWM2ppTzy2xOJfWODYkp752bPTPM,532
|
|
6
|
+
gitwebhooks/auth/custom.py,sha256=zDJdQCOCCd1u1D10T7a6rE2KUggBXvgjtTkQPL3Thfc,1216
|
|
7
|
+
gitwebhooks/auth/factory.py,sha256=vvI1epyIGQ4MSgjRrW7Gya98Kc9k8WzjOru_PpMgOB8,2474
|
|
8
|
+
gitwebhooks/auth/gitee.py,sha256=8o_tKugZrW2or-uoRzjCo3h-WRlm3zbYmkTNbf5zL6s,3249
|
|
9
|
+
gitwebhooks/auth/github.py,sha256=sY3xPwfYvD3tID5b26qHhTI1E9EW2VNHaFEygmsZYCg,1619
|
|
10
|
+
gitwebhooks/auth/gitlab.py,sha256=Aoz77VbYRASxNXqOAnK5__9hkGgaf9kLMoCgOnvFMNE,862
|
|
11
|
+
gitwebhooks/auth/verifier.py,sha256=onIvbmFVWpk7vkdEiyF48S4KrtbP48NH3FLz0fE24XE,971
|
|
12
|
+
gitwebhooks/config/__init__.py,sha256=CnU2ybNi8Yf5YqGWe7uls98ditREEuxuj5mW0t1ti0s,413
|
|
13
|
+
gitwebhooks/config/loader.py,sha256=rrMBunCE1swj-KMDvkTxy-mzG-Lalz-l0Hsw1Xw0rFc,5390
|
|
14
|
+
gitwebhooks/config/models.py,sha256=oZ0ISLxh0zq5U7fqpAk2as7qHsOcbwj257BZEaK1zO8,4758
|
|
15
|
+
gitwebhooks/config/registry.py,sha256=5_rsi9rKkgxiDSnnRmPYCy6AQCEBPxeKgmUC-_4u6h4,3165
|
|
16
|
+
gitwebhooks/config/server.py,sha256=ucFDoLF4QWPqn_-rBRe2uerpxMS6AgM2TLbC89o9zdQ,2739
|
|
17
|
+
gitwebhooks/handlers/__init__.py,sha256=nkGxNoHdrcNtQ2I5TlVNqJovUfmG7vDlagxGLsCKqsk,505
|
|
18
|
+
gitwebhooks/handlers/base.py,sha256=Hd_FScG3E5fe2ZCihFaAghWHGdQLliix1r_Mxeyp1S0,3416
|
|
19
|
+
gitwebhooks/handlers/custom.py,sha256=rGkIdOqrqdW64VTLwbcTS4zOAfcZAL1OdDq5UcsJsEI,2660
|
|
20
|
+
gitwebhooks/handlers/factory.py,sha256=wZHHSVXh_pJvdipkdmtMdzaTsTny7zEGxZqSVlAsr6Q,2570
|
|
21
|
+
gitwebhooks/handlers/gitee.py,sha256=_mXqVXYBRQB1JMWO-QbaBxTD3Efj_ZFYMWa3csfLjgQ,4149
|
|
22
|
+
gitwebhooks/handlers/github.py,sha256=gUMFn4Y47JM8m4ot55_zGaDFOzM03Gz8J9_Ov8aFBjo,1617
|
|
23
|
+
gitwebhooks/handlers/gitlab.py,sha256=UkK3R_KSKSt0s7XAtH1_G_uid85tqiL12qND8_PnosA,1610
|
|
24
|
+
gitwebhooks/handlers/request.py,sha256=uedC-zAehQZzG4YIUdq4TsQYPZ-PoVHkKDJb-FEC27s,8989
|
|
25
|
+
gitwebhooks/logging/__init__.py,sha256=CmL5WD2RgZ76uhrxzwnIfOEd_HgTZMTtTjjqYSY06GA,146
|
|
26
|
+
gitwebhooks/logging/setup.py,sha256=Y9h0WGDudCrdLZ8dm_Xp3zt_Xp7x7WdDio4MK9ZFBCg,1577
|
|
27
|
+
gitwebhooks/models/__init__.py,sha256=DmZBPoNeh7eB9Ntr6d4T9QY6-LckvrHNGg8FVcpuvP0,273
|
|
28
|
+
gitwebhooks/models/provider.py,sha256=lmjJvGjklD1VTKB6UF9V-gZCPwXhiip8DR8qXs_A-F8,451
|
|
29
|
+
gitwebhooks/models/request.py,sha256=UkdTiBpX4-XipeOnhE0SvAaR53bFFh8EKftSVFjNBLM,1838
|
|
30
|
+
gitwebhooks/models/result.py,sha256=0M3fjeUH3CM4Mjpc9e4ZxBdfPO9xlODRRdlshVomQYQ,1020
|
|
31
|
+
gitwebhooks/utils/__init__.py,sha256=qZcrINToHF8qAtIIDAjOlzfKcohCVyYe2ZaKYsWbOxY,219
|
|
32
|
+
gitwebhooks/utils/constants.py,sha256=QUfm4GX-pphHIG-b9VVHDpN4Wegp5gF7RfLGnAeLVAc,1246
|
|
33
|
+
gitwebhooks/utils/exceptions.py,sha256=Mfz-FOCiHZiYmpSQDw36S9HarLE2wPLfFbkeHfWJnkk,627
|
|
34
|
+
gitwebhooks/utils/executor.py,sha256=-zQUV5t-eq0JF6T4EvsUlvg4lnBtahRGrV8N3iVgx_c,923
|
|
35
|
+
gitwebhooks-2.0.0.dist-info/licenses/LICENSE,sha256=NV5F0xpN-DVJuhc0qzOsXtLjf3l8X18zehW_7F4qI50,1083
|
|
36
|
+
gitwebhooks-2.0.0.dist-info/METADATA,sha256=qmhF7fmb4F03SgnlLkWdVThn2Zj-nk_dBL1tVEENG1s,8156
|
|
37
|
+
gitwebhooks-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
gitwebhooks-2.0.0.dist-info/entry_points.txt,sha256=AVgLU9oFCt0XW_GbziMiGoHREewpn6JJQ_FTYX7jsGc,57
|
|
39
|
+
gitwebhooks-2.0.0.dist-info/top_level.txt,sha256=9a6CxnHxBD53HL38GUeZETIvnUhUKcgDRIGJkCqwc3o,12
|
|
40
|
+
gitwebhooks-2.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Troy Tse <troy@holyhi.net>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gitwebhooks
|