devs-webhook 1.0.0__tar.gz → 1.0.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.
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/PKG-INFO +1 -1
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/cli/worker.py +23 -6
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/config.py +14 -1
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/container_pool.py +12 -2
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/test_dispatcher.py +2 -2
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/PKG-INFO +1 -1
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/pyproject.toml +1 -1
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/LICENSE +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/README.md +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/app.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/cli/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/base_dispatcher.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/claude_dispatcher.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/deduplication.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/repository_manager.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/task_processor.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/webhook_config.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/core/webhook_handler.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/github/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/github/app_auth.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/github/client.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/github/models.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/github/parser.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/main_cli.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/sources/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/sources/base.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/sources/sqs_source.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/sources/webhook_source.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/__init__.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/async_utils.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/container_logs.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/github.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/logging.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/s3_artifacts.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook/utils/serialization.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/SOURCES.txt +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/dependency_links.txt +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/entry_points.txt +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/requires.txt +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/devs_webhook.egg-info/top_level.txt +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/setup.cfg +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_allowlist.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_authentication.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_authorized_users.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_container_logs.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_single_queue.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_sqs_burst.py +0 -0
- {devs_webhook-1.0.0 → devs_webhook-1.0.2}/tests/test_webhook_parser.py +0 -0
|
@@ -29,7 +29,8 @@ logger = structlog.get_logger()
|
|
|
29
29
|
@click.option('--repo-path', required=True, help='Path to repository on host')
|
|
30
30
|
@click.option('--task-type', default='claude', help='Task type: claude or tests (default: claude)')
|
|
31
31
|
@click.option('--timeout', default=3600, help='Task timeout in seconds (default: 3600)')
|
|
32
|
-
|
|
32
|
+
@click.option('--worker-logs-dir', default=None, help='Directory for worker log files (enables file logging)')
|
|
33
|
+
def worker(task_id: str, dev_name: str, repo_name: str, repo_path: str, task_type: str, timeout: int, worker_logs_dir: Optional[str]):
|
|
33
34
|
"""Process a single webhook task in an isolated subprocess.
|
|
34
35
|
|
|
35
36
|
This command runs the complete task processing logic in a separate process to provide
|
|
@@ -47,15 +48,30 @@ def worker(task_id: str, dev_name: str, repo_name: str, repo_path: str, task_typ
|
|
|
47
48
|
"""
|
|
48
49
|
# Set environment variable to redirect console output to stderr
|
|
49
50
|
os.environ['DEVS_WEBHOOK_MODE'] = '1'
|
|
50
|
-
|
|
51
|
-
# Configure structured logging for subprocess
|
|
51
|
+
|
|
52
|
+
# Configure structured logging for subprocess
|
|
52
53
|
import logging
|
|
54
|
+
|
|
55
|
+
# Build list of handlers - always include stderr
|
|
56
|
+
handlers = [logging.StreamHandler(sys.stderr)]
|
|
57
|
+
|
|
58
|
+
# Add file handler if worker_logs_dir is provided
|
|
59
|
+
log_file_path = None
|
|
60
|
+
if worker_logs_dir:
|
|
61
|
+
log_dir = Path(worker_logs_dir)
|
|
62
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
log_file_path = log_dir / f"{task_id}.log"
|
|
64
|
+
file_handler = logging.FileHandler(log_file_path, encoding='utf-8')
|
|
65
|
+
file_handler.setLevel(logging.INFO)
|
|
66
|
+
file_handler.setFormatter(logging.Formatter('%(message)s'))
|
|
67
|
+
handlers.append(file_handler)
|
|
68
|
+
|
|
53
69
|
logging.basicConfig(
|
|
54
|
-
|
|
70
|
+
handlers=handlers,
|
|
55
71
|
level=logging.INFO,
|
|
56
72
|
format='%(message)s'
|
|
57
73
|
)
|
|
58
|
-
|
|
74
|
+
|
|
59
75
|
structlog.configure(
|
|
60
76
|
processors=[
|
|
61
77
|
structlog.stdlib.filter_by_level,
|
|
@@ -79,7 +95,8 @@ def worker(task_id: str, dev_name: str, repo_name: str, repo_path: str, task_typ
|
|
|
79
95
|
repo_name=repo_name,
|
|
80
96
|
repo_path=repo_path,
|
|
81
97
|
timeout=timeout,
|
|
82
|
-
pid=os.getpid()
|
|
98
|
+
pid=os.getpid(),
|
|
99
|
+
log_file=str(log_file_path) if log_file_path else None)
|
|
83
100
|
|
|
84
101
|
try:
|
|
85
102
|
# Read payload from stdin
|
|
@@ -109,6 +109,16 @@ class WebhookConfig(BaseSettings, BaseConfig):
|
|
|
109
109
|
description="Enable writing container output to log files"
|
|
110
110
|
)
|
|
111
111
|
|
|
112
|
+
# Worker process logging (captures full worker subprocess logs)
|
|
113
|
+
worker_logs_dir: Path = Field(
|
|
114
|
+
default_factory=lambda: Path("/var/log/devs-webhook/workers"),
|
|
115
|
+
description="Directory for worker subprocess logs"
|
|
116
|
+
)
|
|
117
|
+
worker_logs_enabled: bool = Field(
|
|
118
|
+
default=True,
|
|
119
|
+
description="Enable writing worker subprocess logs to files (recommended)"
|
|
120
|
+
)
|
|
121
|
+
|
|
112
122
|
# Task source configuration
|
|
113
123
|
task_source: str = Field(
|
|
114
124
|
default="webhook",
|
|
@@ -212,7 +222,10 @@ class WebhookConfig(BaseSettings, BaseConfig):
|
|
|
212
222
|
# Container logs directory (if enabled)
|
|
213
223
|
if self.container_logs_enabled:
|
|
214
224
|
self.container_logs_dir.mkdir(parents=True, exist_ok=True)
|
|
215
|
-
|
|
225
|
+
# Worker logs directory (if enabled)
|
|
226
|
+
if self.worker_logs_enabled:
|
|
227
|
+
self.worker_logs_dir.mkdir(parents=True, exist_ok=True)
|
|
228
|
+
|
|
216
229
|
def validate_required_settings(self) -> None:
|
|
217
230
|
"""Validate that required settings are present."""
|
|
218
231
|
missing = []
|
|
@@ -575,12 +575,22 @@ class ContainerPool:
|
|
|
575
575
|
"--task-type", queued_task.task_type,
|
|
576
576
|
"--timeout", str(3600) # 60 minute timeout
|
|
577
577
|
]
|
|
578
|
-
|
|
578
|
+
|
|
579
|
+
# Add worker logs directory if enabled
|
|
580
|
+
if self.config.worker_logs_enabled:
|
|
581
|
+
cmd.extend(["--worker-logs-dir", str(self.config.worker_logs_dir)])
|
|
582
|
+
|
|
583
|
+
# Determine log file path for logging
|
|
584
|
+
worker_log_file = None
|
|
585
|
+
if self.config.worker_logs_enabled:
|
|
586
|
+
worker_log_file = str(self.config.worker_logs_dir / f"{queued_task.task_id}.log")
|
|
587
|
+
|
|
579
588
|
logger.info("Launching worker subprocess",
|
|
580
589
|
task_id=queued_task.task_id,
|
|
581
590
|
container=dev_name,
|
|
582
591
|
command_length=len(' '.join(cmd)),
|
|
583
|
-
stdin_payload_size=len(stdin_json)
|
|
592
|
+
stdin_payload_size=len(stdin_json),
|
|
593
|
+
worker_log_file=worker_log_file)
|
|
584
594
|
|
|
585
595
|
# Launch subprocess with timeout
|
|
586
596
|
# Set environment to suppress console output
|
|
@@ -479,8 +479,8 @@ class TestDispatcher(BaseDispatcher):
|
|
|
479
479
|
|
|
480
480
|
try:
|
|
481
481
|
# Execute command in the container
|
|
482
|
-
# Use
|
|
483
|
-
shell_cmd = f"cd {container_workspace_dir} && exec /bin/zsh -
|
|
482
|
+
# Use login shell (-l) for proper PATH/env, but not interactive (-i) to avoid ZLE errors
|
|
483
|
+
shell_cmd = f"cd {container_workspace_dir} && exec /bin/zsh -lc '{command}'"
|
|
484
484
|
cmd = [
|
|
485
485
|
'docker', 'exec', '-i', # -i for stdin, no TTY
|
|
486
486
|
container_name,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|