wup 0.2.39__tar.gz → 0.2.40__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.
- {wup-0.2.39/wup.egg-info → wup-0.2.40}/PKG-INFO +4 -4
- {wup-0.2.39 → wup-0.2.40}/README.md +3 -3
- {wup-0.2.39 → wup-0.2.40}/pyproject.toml +1 -1
- {wup-0.2.39 → wup-0.2.40}/wup/__init__.py +1 -1
- {wup-0.2.39 → wup-0.2.40}/wup/cli.py +36 -0
- {wup-0.2.39 → wup-0.2.40}/wup/config.py +1 -1
- {wup-0.2.39 → wup-0.2.40}/wup/models/config.py +1 -1
- {wup-0.2.39 → wup-0.2.40}/wup/testql_watcher.py +54 -2
- {wup-0.2.39 → wup-0.2.40/wup.egg-info}/PKG-INFO +4 -4
- {wup-0.2.39 → wup-0.2.40}/LICENSE +0 -0
- {wup-0.2.39 → wup-0.2.40}/setup.cfg +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_e2e.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_monitoring_manifest.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_testql_monitor.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_testql_watcher.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_web_client.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/tests/test_wup.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/_ast_detector.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/_hash_detector.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/_yaml_detector.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/anomaly_detector.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/anomaly_models.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/assistant.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/cli_config_generator.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/cli_scanner.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/core.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/dependency_mapper.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/models/__init__.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/monitoring_manifest.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/planfile_reporter.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/testql_cli_generator.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/testql_discovery.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/testql_monitor.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/visual_diff.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup/web_client.py +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup.egg-info/SOURCES.txt +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup.egg-info/dependency_links.txt +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup.egg-info/entry_points.txt +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup.egg-info/requires.txt +0 -0
- {wup-0.2.39 → wup-0.2.40}/wup.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.40
|
|
4
4
|
Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
|
|
5
5
|
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -31,17 +31,17 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
## AI Cost Tracking
|
|
33
33
|
|
|
34
|
-
    
|
|
35
35
|
  
|
|
36
36
|
|
|
37
|
-
- 🤖 **LLM usage:** $
|
|
37
|
+
- 🤖 **LLM usage:** $3.0029 (50 commits)
|
|
38
38
|
- 👤 **Human dev:** ~$2047 (20.5h @ $100/h, 30min dedup)
|
|
39
39
|
|
|
40
40
|
Generated on 2026-05-22 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
    
|
|
45
45
|
|
|
46
46
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
47
47
|
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
7
|
  
|
|
8
8
|
|
|
9
|
-
- 🤖 **LLM usage:** $
|
|
9
|
+
- 🤖 **LLM usage:** $3.0029 (50 commits)
|
|
10
10
|
- 👤 **Human dev:** ~$2047 (20.5h @ $100/h, 30min dedup)
|
|
11
11
|
|
|
12
12
|
Generated on 2026-05-22 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
    
|
|
17
17
|
|
|
18
18
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
19
19
|
|
|
@@ -7,7 +7,7 @@ WUP monitors file changes and runs intelligent regression tests using a 3-layer
|
|
|
7
7
|
3. Detail Layer: Full tests with blame reports (only on failure)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
__version__ = "0.2.
|
|
10
|
+
__version__ = "0.2.40"
|
|
11
11
|
__author__ = "Tom Sapletta"
|
|
12
12
|
|
|
13
13
|
from .config import load_config, save_config, get_default_config
|
|
@@ -152,6 +152,8 @@ def watch(
|
|
|
152
152
|
Defaults (no extra flags): ``--mode testql`` and live probes every **60s**
|
|
153
153
|
(unless ``testql.probe_interval_s`` is set in wup.yaml). Use
|
|
154
154
|
``--mode default`` for the legacy HTTP-only watcher without TestQL.
|
|
155
|
+
|
|
156
|
+
If wup.yaml doesn't exist, it will be auto-generated based on project detection.
|
|
155
157
|
"""
|
|
156
158
|
project_path = Path(project).resolve()
|
|
157
159
|
|
|
@@ -160,6 +162,14 @@ def watch(
|
|
|
160
162
|
raise typer.Exit(1)
|
|
161
163
|
|
|
162
164
|
config_path = Path(config) if config else None
|
|
165
|
+
|
|
166
|
+
# Auto-generate config if it doesn't exist
|
|
167
|
+
if not find_config_file(project_path):
|
|
168
|
+
console.print("[cyan]🔍 No wup.yaml found - auto-detecting project type...[/cyan]")
|
|
169
|
+
_auto_generate_config(project_path, mode)
|
|
170
|
+
console.print("[green]✓ Auto-generated wup.yaml configuration[/green]")
|
|
171
|
+
console.print()
|
|
172
|
+
|
|
163
173
|
wup_config = _load_watch_config(project_path, config_path, probe_interval, mode)
|
|
164
174
|
effective_scenarios_dir = scenarios_dir or wup_config.testql.scenario_dir
|
|
165
175
|
|
|
@@ -191,6 +201,32 @@ def watch(
|
|
|
191
201
|
watcher.start_watching()
|
|
192
202
|
|
|
193
203
|
|
|
204
|
+
def _auto_generate_config(project_path: Path, mode: str):
|
|
205
|
+
"""Auto-generate wup.yaml based on project detection."""
|
|
206
|
+
from .cli_scanner import CLIScanner
|
|
207
|
+
from .cli_config_generator import CLIConfigGenerator
|
|
208
|
+
from .config import save_config, get_default_config
|
|
209
|
+
|
|
210
|
+
# Try CLI detection first
|
|
211
|
+
scanner = CLIScanner(str(project_path))
|
|
212
|
+
packages = scanner.scan()
|
|
213
|
+
|
|
214
|
+
if packages:
|
|
215
|
+
console.print("[cyan]📦 Detected CLI package(s)[/cyan]")
|
|
216
|
+
for pkg in packages:
|
|
217
|
+
console.print(f" - {pkg.name}: {len(pkg.commands)} command(s)")
|
|
218
|
+
console.print()
|
|
219
|
+
|
|
220
|
+
# Use CLI config generator
|
|
221
|
+
generator = CLIConfigGenerator(str(project_path))
|
|
222
|
+
generator.generate()
|
|
223
|
+
else:
|
|
224
|
+
# Use default config for web/mixed projects
|
|
225
|
+
console.print("[cyan]🌐 Using default configuration for web/mixed projects[/cyan]")
|
|
226
|
+
config = get_default_config(project_path)
|
|
227
|
+
save_config(config, project_path / "wup.yaml")
|
|
228
|
+
|
|
229
|
+
|
|
194
230
|
@app.command()
|
|
195
231
|
def map_deps(
|
|
196
232
|
project: str = typer.Argument(".", help="Path to the project root directory"),
|
|
@@ -175,7 +175,7 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
175
175
|
scenario_dir=testql_raw.get("scenario_dir", "scenarios/tests"),
|
|
176
176
|
smoke_scenario=testql_raw.get("smoke_scenario", "smoke.testql.toon.yaml"),
|
|
177
177
|
output_format=testql_raw.get("output_format", "json"),
|
|
178
|
-
extra_args=testql_raw.get("extra_args", ["--timeout 10s"]),
|
|
178
|
+
extra_args=testql_raw.get("extra_args", ["--timeout", "10s"]),
|
|
179
179
|
endpoint_discovery=testql_raw.get("endpoint_discovery", True),
|
|
180
180
|
probe_interval_s=int(testql_raw.get("probe_interval_s", 0) or 0),
|
|
181
181
|
health_scenario=testql_raw.get("health_scenario", ""),
|
|
@@ -61,7 +61,7 @@ class TestQLConfig:
|
|
|
61
61
|
scenario_dir: str = "scenarios/tests"
|
|
62
62
|
smoke_scenario: str = "smoke.testql.toon.yaml"
|
|
63
63
|
output_format: str = "json"
|
|
64
|
-
extra_args: List[str] = field(default_factory=lambda: ["--timeout 10s"])
|
|
64
|
+
extra_args: List[str] = field(default_factory=lambda: ["--timeout", "10s"])
|
|
65
65
|
endpoint_discovery: bool = True # Merge health probes from scenarios + service maps
|
|
66
66
|
probe_interval_s: int = 0 # Periodic live probes for all services (0 = file-change only)
|
|
67
67
|
health_scenario: str = "" # Fleet TestQL scenario on each periodic probe cycle (live run)
|
|
@@ -312,6 +312,19 @@ class TestQLWatcher(WupWatcher):
|
|
|
312
312
|
"""Score a scenario by relevance to service tokens."""
|
|
313
313
|
name = scenario.name.lower()
|
|
314
314
|
score = 0
|
|
315
|
+
|
|
316
|
+
# CLI scenarios require exact service name match
|
|
317
|
+
if name.startswith("cli-"):
|
|
318
|
+
# Extract service name from cli-{service}.testql.toon.yaml
|
|
319
|
+
scenario_service = name.replace("cli-", "").replace(".testql.toon.yaml", "")
|
|
320
|
+
# Score only if service name matches exactly
|
|
321
|
+
if scenario_service in tokens:
|
|
322
|
+
score += 10 # High score for exact match
|
|
323
|
+
else:
|
|
324
|
+
score = -10 # Penalize CLI scenarios that don't match
|
|
325
|
+
return score
|
|
326
|
+
|
|
327
|
+
# Non-CLI scenarios use original scoring
|
|
315
328
|
if any(token in name for token in tokens):
|
|
316
329
|
score += 3
|
|
317
330
|
if "api" in name or "endpoint" in name:
|
|
@@ -331,9 +344,13 @@ class TestQLWatcher(WupWatcher):
|
|
|
331
344
|
limit = (svc_config.quick_tests.max_endpoints
|
|
332
345
|
if svc_config and svc_config.quick_tests else self.quick_limit)
|
|
333
346
|
|
|
347
|
+
# Filter scenarios by service type
|
|
348
|
+
svc_type = svc_config.type if svc_config else "auto"
|
|
349
|
+
filtered_scenarios = self._filter_scenarios_by_type(all_scenarios, svc_type)
|
|
350
|
+
|
|
334
351
|
tokens = self._tokenize_service(service)
|
|
335
352
|
scored = sorted(
|
|
336
|
-
((self._score_scenario(s, tokens), s) for s in
|
|
353
|
+
((self._score_scenario(s, tokens), s) for s in filtered_scenarios),
|
|
337
354
|
key=lambda item: (item[0], item[1].name),
|
|
338
355
|
reverse=True,
|
|
339
356
|
)
|
|
@@ -346,10 +363,45 @@ class TestQLWatcher(WupWatcher):
|
|
|
346
363
|
for base in (self.scenarios_dir, self.project_root):
|
|
347
364
|
candidate = base / smoke_name
|
|
348
365
|
if candidate.exists():
|
|
349
|
-
|
|
366
|
+
# Only use smoke scenario if it matches service type
|
|
367
|
+
if self._scenario_matches_type(candidate, svc_type):
|
|
368
|
+
return [candidate]
|
|
369
|
+
|
|
370
|
+
# Fallback: don't return any scenarios for web services if no match found
|
|
371
|
+
# This prevents CLI scenarios from being assigned to web services
|
|
372
|
+
if svc_type == "web":
|
|
373
|
+
return []
|
|
350
374
|
|
|
351
375
|
return []
|
|
352
376
|
|
|
377
|
+
def _filter_scenarios_by_type(self, scenarios: List[Path], svc_type: str) -> List[Path]:
|
|
378
|
+
"""Filter scenarios by service type (web vs shell)."""
|
|
379
|
+
if svc_type == "auto":
|
|
380
|
+
return scenarios # No filtering for auto type
|
|
381
|
+
|
|
382
|
+
cli_prefix = "cli-"
|
|
383
|
+
if svc_type == "shell":
|
|
384
|
+
# Shell services: only CLI scenarios
|
|
385
|
+
return [s for s in scenarios if s.name.startswith(cli_prefix)]
|
|
386
|
+
elif svc_type == "web":
|
|
387
|
+
# Web services: exclude CLI scenarios
|
|
388
|
+
return [s for s in scenarios if not s.name.startswith(cli_prefix)]
|
|
389
|
+
else:
|
|
390
|
+
return scenarios
|
|
391
|
+
|
|
392
|
+
def _scenario_matches_type(self, scenario: Path, svc_type: str) -> bool:
|
|
393
|
+
"""Check if scenario matches service type."""
|
|
394
|
+
if svc_type == "auto":
|
|
395
|
+
return True
|
|
396
|
+
|
|
397
|
+
is_cli = scenario.name.startswith("cli-")
|
|
398
|
+
if svc_type == "shell":
|
|
399
|
+
return is_cli
|
|
400
|
+
elif svc_type == "web":
|
|
401
|
+
return not is_cli
|
|
402
|
+
else:
|
|
403
|
+
return True
|
|
404
|
+
|
|
353
405
|
def _run_testql(self, args: Sequence[str], timeout: int) -> subprocess.CompletedProcess:
|
|
354
406
|
cmd = [self.testql_bin, *args]
|
|
355
407
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.40
|
|
4
4
|
Summary: WUP (What's Up) - Intelligent file watcher for regression testing in large projects
|
|
5
5
|
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -31,17 +31,17 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
## AI Cost Tracking
|
|
33
33
|
|
|
34
|
-
    
|
|
35
35
|
  
|
|
36
36
|
|
|
37
|
-
- 🤖 **LLM usage:** $
|
|
37
|
+
- 🤖 **LLM usage:** $3.0029 (50 commits)
|
|
38
38
|
- 👤 **Human dev:** ~$2047 (20.5h @ $100/h, 30min dedup)
|
|
39
39
|
|
|
40
40
|
Generated on 2026-05-22 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
    
|
|
45
45
|
|
|
46
46
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
47
47
|
|
|
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
|