wup 0.2.24__tar.gz → 0.2.25__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.24/wup.egg-info → wup-0.2.25}/PKG-INFO +7 -7
- {wup-0.2.24 → wup-0.2.25}/README.md +6 -6
- {wup-0.2.24 → wup-0.2.25}/pyproject.toml +1 -1
- {wup-0.2.24 → wup-0.2.25}/wup/__init__.py +1 -1
- {wup-0.2.24 → wup-0.2.25}/wup/core.py +61 -32
- {wup-0.2.24 → wup-0.2.25/wup.egg-info}/PKG-INFO +7 -7
- {wup-0.2.24 → wup-0.2.25}/LICENSE +0 -0
- {wup-0.2.24 → wup-0.2.25}/setup.cfg +0 -0
- {wup-0.2.24 → wup-0.2.25}/tests/test_e2e.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/tests/test_testql_watcher.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/tests/test_web_client.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/tests/test_wup.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/_ast_detector.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/_hash_detector.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/_yaml_detector.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/anomaly_detector.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/anomaly_models.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/assistant.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/cli.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/config.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/dependency_mapper.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/models/__init__.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/models/config.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/testql_discovery.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/testql_watcher.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/visual_diff.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup/web_client.py +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup.egg-info/SOURCES.txt +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup.egg-info/dependency_links.txt +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup.egg-info/entry_points.txt +0 -0
- {wup-0.2.24 → wup-0.2.25}/wup.egg-info/requires.txt +0 -0
- {wup-0.2.24 → wup-0.2.25}/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.25
|
|
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
|
|
@@ -29,17 +29,17 @@ Dynamic: license-file
|
|
|
29
29
|
|
|
30
30
|
## AI Cost Tracking
|
|
31
31
|
|
|
32
|
-
     
|
|
33
|
+
  
|
|
34
34
|
|
|
35
|
-
- 🤖 **LLM usage:** $1.
|
|
36
|
-
- 👤 **Human dev:** ~$
|
|
35
|
+
- 🤖 **LLM usage:** $1.8622 (35 commits)
|
|
36
|
+
- 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
|
|
37
37
|
|
|
38
|
-
Generated on 2026-05-
|
|
38
|
+
Generated on 2026-05-15 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
-
    
|
|
43
43
|
|
|
44
44
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
45
45
|
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
     
|
|
7
|
+
  
|
|
8
8
|
|
|
9
|
-
- 🤖 **LLM usage:** $1.
|
|
10
|
-
- 👤 **Human dev:** ~$
|
|
9
|
+
- 🤖 **LLM usage:** $1.8622 (35 commits)
|
|
10
|
+
- 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
|
|
11
11
|
|
|
12
|
-
Generated on 2026-05-
|
|
12
|
+
Generated on 2026-05-15 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.25"
|
|
11
11
|
__author__ = "Tom Sapletta"
|
|
12
12
|
|
|
13
13
|
from .config import load_config, save_config, get_default_config
|
|
@@ -6,6 +6,8 @@ import asyncio
|
|
|
6
6
|
import json
|
|
7
7
|
import subprocess
|
|
8
8
|
import time
|
|
9
|
+
import urllib.error
|
|
10
|
+
import urllib.request
|
|
9
11
|
from collections import defaultdict, deque
|
|
10
12
|
from pathlib import Path
|
|
11
13
|
from typing import Dict, List, Optional, Set, Tuple
|
|
@@ -298,69 +300,96 @@ class WupWatcher:
|
|
|
298
300
|
async def run_quick_test(self, service: str, endpoints: List[str]) -> bool:
|
|
299
301
|
"""
|
|
300
302
|
Run a quick test for a service (smoke test).
|
|
301
|
-
|
|
303
|
+
|
|
302
304
|
Args:
|
|
303
305
|
service: Service name
|
|
304
306
|
endpoints: List of endpoints to test
|
|
305
|
-
|
|
307
|
+
|
|
306
308
|
Returns:
|
|
307
309
|
True if all tests passed, False otherwise
|
|
308
310
|
"""
|
|
309
311
|
self.console.print(f"[cyan]🧪 Quick testing {service} ({len(endpoints)} endpoints)[/cyan]")
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
312
|
+
|
|
313
|
+
if not endpoints:
|
|
314
|
+
self.console.print(f"[yellow]⚠ No endpoints configured for {service}, skipping quick test[/yellow]")
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
passed = True
|
|
318
|
+
for endpoint in endpoints:
|
|
319
|
+
try:
|
|
320
|
+
req = urllib.request.Request(endpoint, method="HEAD")
|
|
321
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
322
|
+
if resp.status >= 400:
|
|
323
|
+
self.console.print(f"[red]✗ {endpoint} → HTTP {resp.status}[/red]")
|
|
324
|
+
passed = False
|
|
325
|
+
else:
|
|
326
|
+
self.console.print(f"[green]✓ {endpoint} → HTTP {resp.status}[/green]")
|
|
327
|
+
except Exception as e:
|
|
328
|
+
self.console.print(f"[red]✗ {endpoint} → {e}[/red]")
|
|
329
|
+
passed = False
|
|
330
|
+
|
|
319
331
|
if passed:
|
|
320
332
|
self.console.print(f"[green]✓ Quick test passed for {service}[/green]")
|
|
321
333
|
else:
|
|
322
334
|
self.console.print(f"[red]✗ Quick test failed for {service}[/red]")
|
|
323
|
-
|
|
335
|
+
|
|
324
336
|
return passed
|
|
325
337
|
|
|
326
338
|
async def run_detail_test(self, service: str, endpoints: List[str]) -> Dict:
|
|
327
339
|
"""
|
|
328
340
|
Run a detailed test for a service with blame report.
|
|
329
|
-
|
|
341
|
+
|
|
330
342
|
Args:
|
|
331
343
|
service: Service name
|
|
332
344
|
endpoints: List of endpoints to test
|
|
333
|
-
|
|
345
|
+
|
|
334
346
|
Returns:
|
|
335
347
|
Dictionary with test results and blame information
|
|
336
348
|
"""
|
|
337
349
|
self.console.print(f"[cyan]🔍 Detail testing {service} ({len(endpoints)} endpoints)[/cyan]")
|
|
338
|
-
|
|
339
|
-
# This is a placeholder - integrate with TestQL or your test framework
|
|
340
|
-
# For now, simulate a test
|
|
341
|
-
await asyncio.sleep(3)
|
|
342
|
-
|
|
343
|
-
# Simulate results
|
|
350
|
+
|
|
344
351
|
results = {
|
|
345
352
|
"service": service,
|
|
346
353
|
"total_endpoints": len(endpoints),
|
|
347
|
-
"passed":
|
|
348
|
-
"failed":
|
|
349
|
-
"failed_endpoint":
|
|
350
|
-
"blame": {
|
|
351
|
-
"file": f"app/{service}/routes.py",
|
|
352
|
-
"line": 42,
|
|
353
|
-
"commit": "abc123",
|
|
354
|
-
"author": "developer"
|
|
355
|
-
}
|
|
354
|
+
"passed": 0,
|
|
355
|
+
"failed": 0,
|
|
356
|
+
"failed_endpoint": None,
|
|
357
|
+
"blame": {},
|
|
356
358
|
}
|
|
357
|
-
|
|
359
|
+
|
|
360
|
+
for endpoint in endpoints:
|
|
361
|
+
try:
|
|
362
|
+
req = urllib.request.Request(endpoint, method="GET")
|
|
363
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
364
|
+
if resp.status >= 400:
|
|
365
|
+
results["failed"] += 1
|
|
366
|
+
self.console.print(f"[red]✗ {endpoint} → HTTP {resp.status}[/red]")
|
|
367
|
+
else:
|
|
368
|
+
results["passed"] += 1
|
|
369
|
+
self.console.print(f"[green]✓ {endpoint} → HTTP {resp.status}[/green]")
|
|
370
|
+
except Exception as e:
|
|
371
|
+
results["failed"] += 1
|
|
372
|
+
self.console.print(f"[red]✗ {endpoint} → {e}[/red]")
|
|
373
|
+
|
|
358
374
|
if results["failed"] > 0:
|
|
375
|
+
results["failed_endpoint"] = endpoints[0] if endpoints else None
|
|
376
|
+
try:
|
|
377
|
+
blame_result = subprocess.run(
|
|
378
|
+
["git", "log", "--oneline", "-5", "--", f"*/{service}/*"],
|
|
379
|
+
cwd=str(self.project_root),
|
|
380
|
+
capture_output=True,
|
|
381
|
+
text=True,
|
|
382
|
+
)
|
|
383
|
+
if blame_result.returncode == 0:
|
|
384
|
+
lines = blame_result.stdout.strip().split("\n")
|
|
385
|
+
if lines and lines[0]:
|
|
386
|
+
results["blame"] = {"recent_commits": lines}
|
|
387
|
+
except Exception:
|
|
388
|
+
pass
|
|
359
389
|
self.console.print(f"[red]✗ Detail test found {results['failed']} regression(s)[/red]")
|
|
360
|
-
self.console.print(f"[red] Blame: {results['blame']['file']}:{results['blame']['line']}[/red]")
|
|
361
390
|
else:
|
|
362
391
|
self.console.print(f"[green]✓ Detail test passed for {service}[/green]")
|
|
363
|
-
|
|
392
|
+
|
|
364
393
|
return results
|
|
365
394
|
|
|
366
395
|
async def test_loop(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.25
|
|
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
|
|
@@ -29,17 +29,17 @@ Dynamic: license-file
|
|
|
29
29
|
|
|
30
30
|
## AI Cost Tracking
|
|
31
31
|
|
|
32
|
-
     
|
|
33
|
+
  
|
|
34
34
|
|
|
35
|
-
- 🤖 **LLM usage:** $1.
|
|
36
|
-
- 👤 **Human dev:** ~$
|
|
35
|
+
- 🤖 **LLM usage:** $1.8622 (35 commits)
|
|
36
|
+
- 👤 **Human dev:** ~$1432 (14.3h @ $100/h, 30min dedup)
|
|
37
37
|
|
|
38
|
-
Generated on 2026-05-
|
|
38
|
+
Generated on 2026-05-15 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
-
    
|
|
43
43
|
|
|
44
44
|
**WUP (What's Up)** - Intelligent file watcher for regression testing in large projects.
|
|
45
45
|
|
|
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
|