wup 0.2.48__tar.gz → 0.2.49__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.48/wup.egg-info → wup-0.2.49}/PKG-INFO +26 -6
- {wup-0.2.48 → wup-0.2.49}/README.md +25 -5
- {wup-0.2.48 → wup-0.2.49}/pyproject.toml +1 -1
- {wup-0.2.48 → wup-0.2.49}/wup/__init__.py +1 -1
- {wup-0.2.48 → wup-0.2.49}/wup/config.py +51 -42
- {wup-0.2.48 → wup-0.2.49}/wup/testql_watcher.py +30 -27
- {wup-0.2.48 → wup-0.2.49/wup.egg-info}/PKG-INFO +26 -6
- {wup-0.2.48 → wup-0.2.49}/LICENSE +0 -0
- {wup-0.2.48 → wup-0.2.49}/setup.cfg +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_auto_detection.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_cli_filtering.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_e2e.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_monitoring_manifest.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_service_inference.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_testql_monitor.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_testql_watcher.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_visual_diff_periodic_skip.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_visual_diff_progress.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_web_client.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/tests/test_wup.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/_ast_detector.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/_base_detector.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/_hash_detector.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/_yaml_detector.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/anomaly_detector.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/anomaly_models.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/assistant.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/bus.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/cli.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/cli_config_generator.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/cli_scanner.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/core.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/dependency_mapper.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/event_store.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/file_watcher/events/file_events.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/models/__init__.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/models/config.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/monitoring_manifest.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/planfile_reporter.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testing/events/health_events.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testing/events/test_results.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testing/handlers/event_handlers.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testing/handlers/health_handlers.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testing/queries/health_queries.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testql_cli_generator.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testql_discovery.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/testql_monitor.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/visual_diff.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup/web_client.py +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup.egg-info/SOURCES.txt +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup.egg-info/dependency_links.txt +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup.egg-info/entry_points.txt +0 -0
- {wup-0.2.48 → wup-0.2.49}/wup.egg-info/requires.txt +0 -0
- {wup-0.2.48 → wup-0.2.49}/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.49
|
|
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
|
+
  
|
|
36
36
|
|
|
37
|
-
- 🤖 **LLM usage:** $3.
|
|
38
|
-
- 👤 **Human dev:** ~$
|
|
37
|
+
- 🤖 **LLM usage:** $3.1175 (62 commits)
|
|
38
|
+
- 👤 **Human dev:** ~$2574 (25.7h @ $100/h, 30min dedup)
|
|
39
39
|
|
|
40
40
|
Generated on 2026-05-24 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
|
|
|
@@ -512,6 +512,26 @@ python3 -m pytest tests/test_testql_watcher.py -v
|
|
|
512
512
|
python3 -m pytest tests/ --cov=wup
|
|
513
513
|
```
|
|
514
514
|
|
|
515
|
+
### Goal wrapper (local `.venv`)
|
|
516
|
+
|
|
517
|
+
When `goal` is installed globally, it may inherit another project's `VIRTUAL_ENV`.
|
|
518
|
+
Use the local wrapper to force `wup/.venv` before running `goal` commands:
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
# Default: runs goal -a
|
|
522
|
+
bash scripts/goal-local
|
|
523
|
+
|
|
524
|
+
# Explicit arguments
|
|
525
|
+
bash scripts/goal-local -a
|
|
526
|
+
bash scripts/goal-local --dry-run
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
If needed, point to a specific `goal` binary:
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
GOAL_BIN=/home/tom/.local/bin/goal bash scripts/goal-local -a
|
|
533
|
+
```
|
|
534
|
+
|
|
515
535
|
### Examples
|
|
516
536
|
|
|
517
537
|
```bash
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
|
+
  
|
|
8
8
|
|
|
9
|
-
- 🤖 **LLM usage:** $3.
|
|
10
|
-
- 👤 **Human dev:** ~$
|
|
9
|
+
- 🤖 **LLM usage:** $3.1175 (62 commits)
|
|
10
|
+
- 👤 **Human dev:** ~$2574 (25.7h @ $100/h, 30min dedup)
|
|
11
11
|
|
|
12
12
|
Generated on 2026-05-24 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
|
|
|
@@ -484,6 +484,26 @@ python3 -m pytest tests/test_testql_watcher.py -v
|
|
|
484
484
|
python3 -m pytest tests/ --cov=wup
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
+
### Goal wrapper (local `.venv`)
|
|
488
|
+
|
|
489
|
+
When `goal` is installed globally, it may inherit another project's `VIRTUAL_ENV`.
|
|
490
|
+
Use the local wrapper to force `wup/.venv` before running `goal` commands:
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
# Default: runs goal -a
|
|
494
|
+
bash scripts/goal-local
|
|
495
|
+
|
|
496
|
+
# Explicit arguments
|
|
497
|
+
bash scripts/goal-local -a
|
|
498
|
+
bash scripts/goal-local --dry-run
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
If needed, point to a specific `goal` binary:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
GOAL_BIN=/home/tom/.local/bin/goal bash scripts/goal-local -a
|
|
505
|
+
```
|
|
506
|
+
|
|
487
507
|
### Examples
|
|
488
508
|
|
|
489
509
|
```bash
|
|
@@ -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.49"
|
|
11
11
|
__author__ = "Tom Sapletta"
|
|
12
12
|
|
|
13
13
|
from .config import load_config, save_config, get_default_config
|
|
@@ -6,7 +6,7 @@ Handles loading and validation of wup.yaml configuration files.
|
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Optional
|
|
9
|
+
from typing import Optional, List
|
|
10
10
|
|
|
11
11
|
import yaml
|
|
12
12
|
|
|
@@ -98,38 +98,27 @@ def load_config(project_root: Path, config_path: Optional[Path] = None) -> WupCo
|
|
|
98
98
|
return validate_config(raw_config)
|
|
99
99
|
|
|
100
100
|
|
|
101
|
-
def
|
|
102
|
-
"""
|
|
103
|
-
Validate raw config dict and convert to WupConfig object.
|
|
104
|
-
|
|
105
|
-
Args:
|
|
106
|
-
raw: Raw configuration dictionary from YAML
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
Validated WupConfig object
|
|
110
|
-
|
|
111
|
-
Raises:
|
|
112
|
-
ValueError: If config is invalid
|
|
113
|
-
"""
|
|
114
|
-
# Parse project config
|
|
101
|
+
def _parse_project_config(raw: dict) -> ProjectConfig:
|
|
115
102
|
project_raw = raw.get("project", {})
|
|
116
103
|
if not project_raw.get("name"):
|
|
117
104
|
raise ValueError("Config must contain project.name")
|
|
118
105
|
|
|
119
|
-
|
|
106
|
+
return ProjectConfig(
|
|
120
107
|
name=project_raw["name"],
|
|
121
108
|
description=project_raw.get("description", "")
|
|
122
109
|
)
|
|
123
|
-
|
|
124
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _parse_watch_config(raw: dict) -> WatchConfig:
|
|
125
113
|
watch_raw = raw.get("watch", {})
|
|
126
|
-
|
|
114
|
+
return WatchConfig(
|
|
127
115
|
paths=watch_raw.get("paths", []),
|
|
128
116
|
exclude_patterns=watch_raw.get("exclude_patterns", ["*.md", "*.txt"]),
|
|
129
117
|
file_types=watch_raw.get("file_types", [])
|
|
130
118
|
)
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _parse_services_config(raw: dict) -> List[ServiceConfig]:
|
|
133
122
|
services_raw = raw.get("services", [])
|
|
134
123
|
services = []
|
|
135
124
|
for svc_raw in services_raw:
|
|
@@ -161,18 +150,20 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
161
150
|
)
|
|
162
151
|
)
|
|
163
152
|
services.append(service)
|
|
164
|
-
|
|
165
|
-
|
|
153
|
+
return services
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _parse_strategy_config(raw: dict) -> TestStrategyConfig:
|
|
166
157
|
strategy_raw = raw.get("test_strategy", {})
|
|
167
|
-
|
|
158
|
+
return TestStrategyConfig(
|
|
168
159
|
quick=strategy_raw.get("quick", {"debounce_s": 2, "max_queue": 5, "timeout_s": 10}),
|
|
169
160
|
detail=strategy_raw.get("detail", {"debounce_s": 10, "max_queue": 1, "timeout_s": 30})
|
|
170
161
|
)
|
|
171
|
-
|
|
172
|
-
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _parse_testql_config(raw: dict) -> TestQLConfig:
|
|
173
165
|
testql_raw = raw.get("testql", {})
|
|
174
166
|
extra_args_raw = testql_raw.get("extra_args", ["--timeout", "10"])
|
|
175
|
-
extra_args = []
|
|
176
167
|
if isinstance(extra_args_raw, str):
|
|
177
168
|
extra_args_raw = extra_args_raw.split()
|
|
178
169
|
elif isinstance(extra_args_raw, list):
|
|
@@ -215,7 +206,7 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
215
206
|
normalized_extra_args.append(arg)
|
|
216
207
|
i += 1
|
|
217
208
|
|
|
218
|
-
|
|
209
|
+
return TestQLConfig(
|
|
219
210
|
scenario_dir=testql_raw.get("scenario_dir", "scenarios/tests"),
|
|
220
211
|
smoke_scenario=testql_raw.get("smoke_scenario", "smoke.testql.toon.yaml"),
|
|
221
212
|
output_format=testql_raw.get("output_format", "json"),
|
|
@@ -233,7 +224,8 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
233
224
|
endpoints_by_service=testql_raw.get("endpoints_by_service", {})
|
|
234
225
|
)
|
|
235
226
|
|
|
236
|
-
|
|
227
|
+
|
|
228
|
+
def _parse_visual_diff_config(raw: dict) -> VisualDiffConfig:
|
|
237
229
|
vd_raw = raw.get("visual_diff", {})
|
|
238
230
|
env_visual_enabled = os.environ.get("WUP_VISUAL_DIFF_ENABLED")
|
|
239
231
|
env_visual_delay = os.environ.get("WUP_VISUAL_DIFF_DELAY_SECONDS")
|
|
@@ -268,7 +260,7 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
268
260
|
env_visual_pages_from_endpoints.strip().lower() in {"1", "true", "yes", "on"}
|
|
269
261
|
)
|
|
270
262
|
|
|
271
|
-
|
|
263
|
+
return VisualDiffConfig(
|
|
272
264
|
enabled=visual_enabled,
|
|
273
265
|
base_url=vd_raw.get("base_url", ""),
|
|
274
266
|
base_url_env=vd_raw.get("base_url_env", "WUP_BASE_URL"),
|
|
@@ -291,11 +283,13 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
291
283
|
"[class*='error'][class*='container']",
|
|
292
284
|
]),
|
|
293
285
|
headless=vd_raw.get("headless", True),
|
|
286
|
+
run_on_periodic_probe=bool(vd_raw.get("run_on_periodic_probe", False)),
|
|
294
287
|
)
|
|
295
288
|
|
|
296
|
-
|
|
289
|
+
|
|
290
|
+
def _parse_web_config(raw: dict) -> WebConfig:
|
|
297
291
|
web_raw = raw.get("web", {})
|
|
298
|
-
|
|
292
|
+
return WebConfig(
|
|
299
293
|
enabled=web_raw.get("enabled", False),
|
|
300
294
|
endpoint=web_raw.get("endpoint", ""),
|
|
301
295
|
endpoint_env=web_raw.get("endpoint_env", "WUPBRO_ENDPOINT"),
|
|
@@ -303,7 +297,8 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
303
297
|
api_key=web_raw.get("api_key", ""),
|
|
304
298
|
)
|
|
305
299
|
|
|
306
|
-
|
|
300
|
+
|
|
301
|
+
def _parse_planfile_config(raw: dict) -> PlanfileConfig:
|
|
307
302
|
planfile_raw = raw.get("planfile", {})
|
|
308
303
|
env_planfile_enabled = os.environ.get("WUP_PLANFILE_ENABLED")
|
|
309
304
|
if env_planfile_enabled is None:
|
|
@@ -313,7 +308,7 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
313
308
|
|
|
314
309
|
labels_raw = planfile_raw.get("labels", ["koru", "llm-ready", "wup", "auto-diag"])
|
|
315
310
|
labels = [str(label) for label in labels_raw] if isinstance(labels_raw, list) else []
|
|
316
|
-
|
|
311
|
+
return PlanfileConfig(
|
|
317
312
|
enabled=planfile_enabled,
|
|
318
313
|
command=planfile_raw.get("command", "planfile"),
|
|
319
314
|
sprint=planfile_raw.get("sprint", "current"),
|
|
@@ -323,15 +318,29 @@ def validate_config(raw: dict) -> WupConfig:
|
|
|
323
318
|
labels=labels or ["koru", "llm-ready", "wup", "auto-diag"],
|
|
324
319
|
)
|
|
325
320
|
|
|
321
|
+
|
|
322
|
+
def validate_config(raw: dict) -> WupConfig:
|
|
323
|
+
"""
|
|
324
|
+
Validate raw config dict and convert to WupConfig object.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
raw: Raw configuration dictionary from YAML
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Validated WupConfig object
|
|
331
|
+
|
|
332
|
+
Raises:
|
|
333
|
+
ValueError: If config is invalid
|
|
334
|
+
"""
|
|
326
335
|
return WupConfig(
|
|
327
|
-
project=
|
|
328
|
-
watch=
|
|
329
|
-
services=
|
|
330
|
-
test_strategy=
|
|
331
|
-
testql=
|
|
332
|
-
visual_diff=
|
|
333
|
-
web=
|
|
334
|
-
planfile=
|
|
336
|
+
project=_parse_project_config(raw),
|
|
337
|
+
watch=_parse_watch_config(raw),
|
|
338
|
+
services=_parse_services_config(raw),
|
|
339
|
+
test_strategy=_parse_strategy_config(raw),
|
|
340
|
+
testql=_parse_testql_config(raw),
|
|
341
|
+
visual_diff=_parse_visual_diff_config(raw),
|
|
342
|
+
web=_parse_web_config(raw),
|
|
343
|
+
planfile=_parse_planfile_config(raw),
|
|
335
344
|
)
|
|
336
345
|
|
|
337
346
|
|
|
@@ -696,6 +696,35 @@ class TestQLWatcher(WupWatcher):
|
|
|
696
696
|
)
|
|
697
697
|
return True
|
|
698
698
|
|
|
699
|
+
async def _run_quick_test_no_scenarios(self, service: str, merged_endpoints: List[str]) -> bool:
|
|
700
|
+
self.console.print(
|
|
701
|
+
f"[yellow]⚠ No TestQL scenarios found for {service} — running visual diff only[/yellow]"
|
|
702
|
+
)
|
|
703
|
+
self._record_health_transition(service=service, status="up", stage="quick", message="Probes passed (no scenarios)")
|
|
704
|
+
if self.web_client.is_active:
|
|
705
|
+
await self.web_client.send_pass(service=service, stage="quick")
|
|
706
|
+
if self.visual_differ and self.visual_differ.cfg.enabled:
|
|
707
|
+
visual_endpoints = self._get_config_endpoints_for_service(service) or merged_endpoints
|
|
708
|
+
visual_results = await self.visual_differ.run_for_service(service, visual_endpoints)
|
|
709
|
+
visual_issues = [
|
|
710
|
+
item for item in visual_results
|
|
711
|
+
if item.get("diff", {}).get("status") == "issue"
|
|
712
|
+
]
|
|
713
|
+
if visual_issues:
|
|
714
|
+
issue_text = "; ".join(
|
|
715
|
+
", ".join(item.get("diff", {}).get("issues", []) or ["visual page issue"])
|
|
716
|
+
for item in visual_issues
|
|
717
|
+
)
|
|
718
|
+
self._record_health_transition(
|
|
719
|
+
service=service,
|
|
720
|
+
status="down",
|
|
721
|
+
stage="visual",
|
|
722
|
+
message=issue_text or "visual page issue",
|
|
723
|
+
track_file="",
|
|
724
|
+
)
|
|
725
|
+
await self._publish_visual_events(service, visual_results)
|
|
726
|
+
return True
|
|
727
|
+
|
|
699
728
|
async def run_quick_test(self, service: str, endpoints: List[str]) -> bool:
|
|
700
729
|
merged_endpoints = self._merge_endpoints(service, endpoints)
|
|
701
730
|
|
|
@@ -709,33 +738,7 @@ class TestQLWatcher(WupWatcher):
|
|
|
709
738
|
scenarios = scenarios[:limit]
|
|
710
739
|
|
|
711
740
|
if not scenarios:
|
|
712
|
-
self.
|
|
713
|
-
f"[yellow]⚠ No TestQL scenarios found for {service} — running visual diff only[/yellow]"
|
|
714
|
-
)
|
|
715
|
-
self._record_health_transition(service=service, status="up", stage="quick", message="Probes passed (no scenarios)")
|
|
716
|
-
if self.web_client.is_active:
|
|
717
|
-
await self.web_client.send_pass(service=service, stage="quick")
|
|
718
|
-
if self.visual_differ and self.visual_differ.cfg.enabled:
|
|
719
|
-
visual_endpoints = self._get_config_endpoints_for_service(service) or merged_endpoints
|
|
720
|
-
visual_results = await self.visual_differ.run_for_service(service, visual_endpoints)
|
|
721
|
-
visual_issues = [
|
|
722
|
-
item for item in visual_results
|
|
723
|
-
if item.get("diff", {}).get("status") == "issue"
|
|
724
|
-
]
|
|
725
|
-
if visual_issues:
|
|
726
|
-
issue_text = "; ".join(
|
|
727
|
-
", ".join(item.get("diff", {}).get("issues", []) or ["visual page issue"])
|
|
728
|
-
for item in visual_issues
|
|
729
|
-
)
|
|
730
|
-
self._record_health_transition(
|
|
731
|
-
service=service,
|
|
732
|
-
status="down",
|
|
733
|
-
stage="visual",
|
|
734
|
-
message=issue_text or "visual page issue",
|
|
735
|
-
track_file="",
|
|
736
|
-
)
|
|
737
|
-
await self._publish_visual_events(service, visual_results)
|
|
738
|
-
return True
|
|
741
|
+
return await self._run_quick_test_no_scenarios(service, merged_endpoints)
|
|
739
742
|
|
|
740
743
|
self.console.print(
|
|
741
744
|
f"[cyan]🧪 Quick TestQL for {service} "
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.49
|
|
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
|
+
  
|
|
36
36
|
|
|
37
|
-
- 🤖 **LLM usage:** $3.
|
|
38
|
-
- 👤 **Human dev:** ~$
|
|
37
|
+
- 🤖 **LLM usage:** $3.1175 (62 commits)
|
|
38
|
+
- 👤 **Human dev:** ~$2574 (25.7h @ $100/h, 30min dedup)
|
|
39
39
|
|
|
40
40
|
Generated on 2026-05-24 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
|
|
|
@@ -512,6 +512,26 @@ python3 -m pytest tests/test_testql_watcher.py -v
|
|
|
512
512
|
python3 -m pytest tests/ --cov=wup
|
|
513
513
|
```
|
|
514
514
|
|
|
515
|
+
### Goal wrapper (local `.venv`)
|
|
516
|
+
|
|
517
|
+
When `goal` is installed globally, it may inherit another project's `VIRTUAL_ENV`.
|
|
518
|
+
Use the local wrapper to force `wup/.venv` before running `goal` commands:
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
# Default: runs goal -a
|
|
522
|
+
bash scripts/goal-local
|
|
523
|
+
|
|
524
|
+
# Explicit arguments
|
|
525
|
+
bash scripts/goal-local -a
|
|
526
|
+
bash scripts/goal-local --dry-run
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
If needed, point to a specific `goal` binary:
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
GOAL_BIN=/home/tom/.local/bin/goal bash scripts/goal-local -a
|
|
533
|
+
```
|
|
534
|
+
|
|
515
535
|
### Examples
|
|
516
536
|
|
|
517
537
|
```bash
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|