crackerjack 0.33.11__py3-none-any.whl → 0.34.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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/cli/options.py +4 -4
- crackerjack/core/phase_coordinator.py +6 -2
- crackerjack/core/workflow_orchestrator.py +120 -0
- crackerjack/dynamic_config.py +83 -3
- crackerjack/managers/publish_manager.py +87 -3
- crackerjack/managers/test_manager_backup.py +2 -2
- crackerjack/services/config.py +10 -2
- crackerjack/services/performance_benchmarks.py +24 -2
- crackerjack/services/performance_cache.py +1 -1
- crackerjack/tools/validate_regex_patterns.py +3 -3
- {crackerjack-0.33.11.dist-info → crackerjack-0.34.0.dist-info}/METADATA +1 -1
- {crackerjack-0.33.11.dist-info → crackerjack-0.34.0.dist-info}/RECORD +15 -15
- {crackerjack-0.33.11.dist-info → crackerjack-0.34.0.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.11.dist-info → crackerjack-0.34.0.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.11.dist-info → crackerjack-0.34.0.dist-info}/licenses/LICENSE +0 -0
crackerjack/cli/options.py
CHANGED
|
@@ -110,7 +110,7 @@ class Options(BaseModel):
|
|
|
110
110
|
accept_version: bool = False
|
|
111
111
|
|
|
112
112
|
# Intelligent features
|
|
113
|
-
smart_commit: bool =
|
|
113
|
+
smart_commit: bool = True # Default enabled for advanced services integration
|
|
114
114
|
|
|
115
115
|
# Analytics and visualization features
|
|
116
116
|
heatmap: bool = False
|
|
@@ -733,9 +733,9 @@ CLI_OPTIONS = {
|
|
|
733
733
|
help="Automatically accept version bump recommendation without confirmation.",
|
|
734
734
|
),
|
|
735
735
|
"smart_commit": typer.Option(
|
|
736
|
-
|
|
737
|
-
"--smart-commit",
|
|
738
|
-
help="Generate intelligent commit messages
|
|
736
|
+
True, # Now enabled by default for advanced services integration
|
|
737
|
+
"--smart-commit/--basic-commit",
|
|
738
|
+
help="Generate intelligent commit messages using AI analysis (default: enabled). Use --basic-commit for simple messages.",
|
|
739
739
|
),
|
|
740
740
|
"heatmap": typer.Option(
|
|
741
741
|
False,
|
|
@@ -474,8 +474,12 @@ class PhaseCoordinator(ErrorHandlingMixin):
|
|
|
474
474
|
changed_files: list[str],
|
|
475
475
|
options: OptionsProtocol,
|
|
476
476
|
) -> str:
|
|
477
|
-
#
|
|
478
|
-
if
|
|
477
|
+
# Smart commit is now enabled by default for all commit operations
|
|
478
|
+
# Use basic commit messages only if explicitly disabled
|
|
479
|
+
use_smart_commit = getattr(options, "smart_commit", True)
|
|
480
|
+
disable_smart_commit = getattr(options, "basic_commit", False)
|
|
481
|
+
|
|
482
|
+
if use_smart_commit and not disable_smart_commit:
|
|
479
483
|
try:
|
|
480
484
|
from crackerjack.services.intelligent_commit import (
|
|
481
485
|
CommitMessageGenerator,
|
|
@@ -19,11 +19,16 @@ from crackerjack.services.logging import (
|
|
|
19
19
|
setup_structured_logging,
|
|
20
20
|
)
|
|
21
21
|
from crackerjack.services.memory_optimizer import get_memory_optimizer, memory_optimized
|
|
22
|
+
from crackerjack.services.performance_benchmarks import PerformanceBenchmarkService
|
|
22
23
|
from crackerjack.services.performance_cache import get_performance_cache
|
|
23
24
|
from crackerjack.services.performance_monitor import (
|
|
24
25
|
get_performance_monitor,
|
|
25
26
|
phase_monitor,
|
|
26
27
|
)
|
|
28
|
+
from crackerjack.services.quality_baseline_enhanced import (
|
|
29
|
+
EnhancedQualityBaselineService,
|
|
30
|
+
)
|
|
31
|
+
from crackerjack.services.quality_intelligence import QualityIntelligenceService
|
|
27
32
|
|
|
28
33
|
from .phase_coordinator import PhaseCoordinator
|
|
29
34
|
from .session_coordinator import SessionCoordinator
|
|
@@ -60,6 +65,25 @@ class WorkflowPipeline:
|
|
|
60
65
|
self._memory_optimizer = get_memory_optimizer()
|
|
61
66
|
self._cache = get_performance_cache()
|
|
62
67
|
|
|
68
|
+
# Initialize quality intelligence for advanced decision making
|
|
69
|
+
try:
|
|
70
|
+
quality_baseline = EnhancedQualityBaselineService(console, pkg_path)
|
|
71
|
+
self._quality_intelligence = QualityIntelligenceService(
|
|
72
|
+
quality_baseline, console
|
|
73
|
+
)
|
|
74
|
+
except Exception:
|
|
75
|
+
# Fallback gracefully if quality intelligence is not available
|
|
76
|
+
self._quality_intelligence = None
|
|
77
|
+
|
|
78
|
+
# Initialize performance benchmarking for workflow analysis
|
|
79
|
+
try:
|
|
80
|
+
self._performance_benchmarks = PerformanceBenchmarkService(
|
|
81
|
+
console, pkg_path
|
|
82
|
+
)
|
|
83
|
+
except Exception:
|
|
84
|
+
# Fallback gracefully if benchmarking is not available
|
|
85
|
+
self._performance_benchmarks = None
|
|
86
|
+
|
|
63
87
|
@property
|
|
64
88
|
def debugger(self) -> AIAgentDebugger | NoOpDebugger:
|
|
65
89
|
if self._debugger is None:
|
|
@@ -297,6 +321,9 @@ class WorkflowPipeline:
|
|
|
297
321
|
duration = time.time() - start_time
|
|
298
322
|
self._log_workflow_completion(success, duration)
|
|
299
323
|
self._log_workflow_completion_debug(success, duration)
|
|
324
|
+
await self._generate_performance_benchmark_report(
|
|
325
|
+
workflow_id, duration, success
|
|
326
|
+
)
|
|
300
327
|
|
|
301
328
|
return success
|
|
302
329
|
|
|
@@ -318,6 +345,50 @@ class WorkflowPipeline:
|
|
|
318
345
|
duration=duration,
|
|
319
346
|
)
|
|
320
347
|
|
|
348
|
+
async def _generate_performance_benchmark_report(
|
|
349
|
+
self, workflow_id: str, duration: float, success: bool
|
|
350
|
+
) -> None:
|
|
351
|
+
"""Generate and display performance benchmark report for workflow execution."""
|
|
352
|
+
if not self._performance_benchmarks:
|
|
353
|
+
return
|
|
354
|
+
|
|
355
|
+
try:
|
|
356
|
+
# Gather performance metrics from the workflow execution
|
|
357
|
+
{
|
|
358
|
+
"workflow_id": workflow_id,
|
|
359
|
+
"total_duration": duration,
|
|
360
|
+
"success": success,
|
|
361
|
+
"cache_metrics": self._cache.get_stats() if self._cache else {},
|
|
362
|
+
"memory_metrics": self._memory_optimizer.get_stats()
|
|
363
|
+
if hasattr(self._memory_optimizer, "get_stats")
|
|
364
|
+
else {},
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
# Generate benchmark comparison
|
|
368
|
+
benchmark_results = await self._performance_benchmarks.run_benchmark_suite()
|
|
369
|
+
|
|
370
|
+
# Display compact performance summary
|
|
371
|
+
if benchmark_results:
|
|
372
|
+
self.console.print("\n[cyan]📊 Performance Benchmark Summary[/cyan]")
|
|
373
|
+
self.console.print(f"Workflow Duration: [bold]{duration:.2f}s[/bold]")
|
|
374
|
+
|
|
375
|
+
# Show key performance improvements if available
|
|
376
|
+
for result in benchmark_results.results[:3]: # Top 3 results
|
|
377
|
+
if result.time_improvement_percentage > 0:
|
|
378
|
+
self.console.print(
|
|
379
|
+
f"[green]⚡[/green] {result.test_name}: {result.time_improvement_percentage:.1f}% faster"
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
if result.cache_hit_ratio > 0:
|
|
383
|
+
self.console.print(
|
|
384
|
+
f"[blue]🎯[/blue] Cache efficiency: {result.cache_hit_ratio:.0%}"
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
except Exception as e:
|
|
388
|
+
self.console.print(
|
|
389
|
+
f"[dim]⚠️ Performance benchmark failed: {str(e)[:50]}...[/dim]"
|
|
390
|
+
)
|
|
391
|
+
|
|
321
392
|
if self.debugger.enabled:
|
|
322
393
|
self.debugger.print_debug_summary()
|
|
323
394
|
|
|
@@ -391,6 +462,13 @@ class WorkflowPipeline:
|
|
|
391
462
|
async def _execute_quality_phase(
|
|
392
463
|
self, options: OptionsProtocol, workflow_id: str
|
|
393
464
|
) -> bool:
|
|
465
|
+
# Use quality intelligence to make informed decisions about quality phase
|
|
466
|
+
if self._quality_intelligence:
|
|
467
|
+
quality_decision = await self._make_quality_intelligence_decision(options)
|
|
468
|
+
self.console.print(
|
|
469
|
+
f"[dim]🧠 Quality Intelligence: {quality_decision}[/dim]"
|
|
470
|
+
)
|
|
471
|
+
|
|
394
472
|
if hasattr(options, "fast") and options.fast:
|
|
395
473
|
return await self._run_fast_hooks_phase_monitored(options, workflow_id)
|
|
396
474
|
if hasattr(options, "comp") and options.comp:
|
|
@@ -403,6 +481,48 @@ class WorkflowPipeline:
|
|
|
403
481
|
options, workflow_id
|
|
404
482
|
)
|
|
405
483
|
|
|
484
|
+
async def _make_quality_intelligence_decision(
|
|
485
|
+
self, options: OptionsProtocol
|
|
486
|
+
) -> str:
|
|
487
|
+
"""Use quality intelligence to make informed decisions about workflow execution."""
|
|
488
|
+
try:
|
|
489
|
+
if not self._quality_intelligence:
|
|
490
|
+
return "Quality intelligence not available"
|
|
491
|
+
|
|
492
|
+
# Analyze recent quality trends and anomalies
|
|
493
|
+
anomalies = await self._quality_intelligence.detect_anomalies()
|
|
494
|
+
patterns = await self._quality_intelligence.identify_patterns()
|
|
495
|
+
|
|
496
|
+
# Make intelligent recommendations based on current state
|
|
497
|
+
recommendations = []
|
|
498
|
+
if anomalies:
|
|
499
|
+
high_severity_anomalies = [
|
|
500
|
+
a for a in anomalies if a.severity.name in ["CRITICAL", "HIGH"]
|
|
501
|
+
]
|
|
502
|
+
if high_severity_anomalies:
|
|
503
|
+
recommendations.append(
|
|
504
|
+
"comprehensive analysis recommended due to quality anomalies"
|
|
505
|
+
)
|
|
506
|
+
else:
|
|
507
|
+
recommendations.append("standard quality checks sufficient")
|
|
508
|
+
|
|
509
|
+
if patterns:
|
|
510
|
+
improving_patterns = [
|
|
511
|
+
p for p in patterns if p.trend_direction.name == "IMPROVING"
|
|
512
|
+
]
|
|
513
|
+
if improving_patterns:
|
|
514
|
+
recommendations.append("quality trending upward")
|
|
515
|
+
else:
|
|
516
|
+
recommendations.append("quality monitoring active")
|
|
517
|
+
|
|
518
|
+
if not recommendations:
|
|
519
|
+
recommendations.append("baseline quality analysis active")
|
|
520
|
+
|
|
521
|
+
return "; ".join(recommendations)
|
|
522
|
+
|
|
523
|
+
except Exception as e:
|
|
524
|
+
return f"Quality intelligence analysis failed: {str(e)[:50]}..."
|
|
525
|
+
|
|
406
526
|
async def _execute_test_workflow(
|
|
407
527
|
self, options: OptionsProtocol, workflow_id: str
|
|
408
528
|
) -> bool:
|
crackerjack/dynamic_config.py
CHANGED
|
@@ -457,8 +457,55 @@ PRE_COMMIT_TEMPLATE = """repos:
|
|
|
457
457
|
|
|
458
458
|
|
|
459
459
|
class DynamicConfigGenerator:
|
|
460
|
-
def __init__(self) -> None:
|
|
460
|
+
def __init__(self, package_directory: str | None = None) -> None:
|
|
461
461
|
self.template = jinja2.Template(PRE_COMMIT_TEMPLATE)
|
|
462
|
+
self.package_directory = package_directory or self._detect_package_directory()
|
|
463
|
+
|
|
464
|
+
def _detect_package_directory(self) -> str:
|
|
465
|
+
"""Detect the package directory name for the current project."""
|
|
466
|
+
import os
|
|
467
|
+
from pathlib import Path
|
|
468
|
+
|
|
469
|
+
# Check if we're in the crackerjack project itself
|
|
470
|
+
current_dir = Path(os.getcwd())
|
|
471
|
+
if (current_dir / "crackerjack").exists() and (
|
|
472
|
+
current_dir / "pyproject.toml"
|
|
473
|
+
).exists():
|
|
474
|
+
# Check if this is actually the crackerjack project
|
|
475
|
+
try:
|
|
476
|
+
import tomllib
|
|
477
|
+
|
|
478
|
+
with (current_dir / "pyproject.toml").open("rb") as f:
|
|
479
|
+
data = tomllib.load(f)
|
|
480
|
+
if data.get("project", {}).get("name") == "crackerjack":
|
|
481
|
+
return "crackerjack"
|
|
482
|
+
except Exception:
|
|
483
|
+
pass
|
|
484
|
+
|
|
485
|
+
# Try to read package name from pyproject.toml
|
|
486
|
+
pyproject_path = current_dir / "pyproject.toml"
|
|
487
|
+
if pyproject_path.exists():
|
|
488
|
+
try:
|
|
489
|
+
import tomllib
|
|
490
|
+
|
|
491
|
+
with pyproject_path.open("rb") as f:
|
|
492
|
+
data = tomllib.load(f)
|
|
493
|
+
|
|
494
|
+
if "project" in data and "name" in data["project"]:
|
|
495
|
+
package_name = str(data["project"]["name"])
|
|
496
|
+
# Check if package directory exists
|
|
497
|
+
if (current_dir / package_name).exists():
|
|
498
|
+
return package_name
|
|
499
|
+
except Exception:
|
|
500
|
+
pass
|
|
501
|
+
|
|
502
|
+
# Fallback to common patterns
|
|
503
|
+
for possible_name in ("src", current_dir.name):
|
|
504
|
+
if (current_dir / possible_name).exists():
|
|
505
|
+
return possible_name
|
|
506
|
+
|
|
507
|
+
# Default fallback
|
|
508
|
+
return "src"
|
|
462
509
|
|
|
463
510
|
def _should_include_hook(
|
|
464
511
|
self,
|
|
@@ -486,10 +533,40 @@ class DynamicConfigGenerator:
|
|
|
486
533
|
for category_hooks in HOOKS_REGISTRY.values():
|
|
487
534
|
for hook in category_hooks:
|
|
488
535
|
if self._should_include_hook(hook, config, enabled_experimental):
|
|
489
|
-
|
|
536
|
+
# Create a copy and update package-specific configurations
|
|
537
|
+
updated_hook = self._update_hook_for_package(hook.copy())
|
|
538
|
+
filtered_hooks.append(updated_hook)
|
|
490
539
|
|
|
491
540
|
return filtered_hooks
|
|
492
541
|
|
|
542
|
+
def _update_hook_for_package(self, hook: HookMetadata) -> HookMetadata:
|
|
543
|
+
"""Update hook configuration to use the detected package directory."""
|
|
544
|
+
# Update skylos hook
|
|
545
|
+
if hook["id"] == "skylos" and hook["args"]:
|
|
546
|
+
hook["args"] = [self.package_directory]
|
|
547
|
+
|
|
548
|
+
# Update zuban hook
|
|
549
|
+
elif hook["id"] == "zuban" and hook["args"]:
|
|
550
|
+
# Replace the hardcoded "./crackerjack" with the dynamic package directory
|
|
551
|
+
updated_args = []
|
|
552
|
+
for arg in hook["args"]:
|
|
553
|
+
if arg == "./crackerjack":
|
|
554
|
+
updated_args.append(f"./{self.package_directory}")
|
|
555
|
+
else:
|
|
556
|
+
updated_args.append(arg)
|
|
557
|
+
hook["args"] = updated_args
|
|
558
|
+
|
|
559
|
+
# Update other hooks that use hardcoded "crackerjack" patterns
|
|
560
|
+
elif hook["files"] and "crackerjack" in hook["files"]:
|
|
561
|
+
hook["files"] = hook["files"].replace("crackerjack", self.package_directory)
|
|
562
|
+
|
|
563
|
+
elif hook["exclude"] and "crackerjack" in hook["exclude"]:
|
|
564
|
+
hook["exclude"] = hook["exclude"].replace(
|
|
565
|
+
"crackerjack", self.package_directory
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return hook
|
|
569
|
+
|
|
493
570
|
def group_hooks_by_repo(
|
|
494
571
|
self,
|
|
495
572
|
hooks: list[HookMetadata],
|
|
@@ -580,8 +657,11 @@ class DynamicConfigGenerator:
|
|
|
580
657
|
def generate_config_for_mode(
|
|
581
658
|
mode: str,
|
|
582
659
|
enabled_experimental: list[str] | None = None,
|
|
660
|
+
package_directory: str | None = None,
|
|
583
661
|
) -> Path:
|
|
584
|
-
return DynamicConfigGenerator().create_temp_config(
|
|
662
|
+
return DynamicConfigGenerator(package_directory).create_temp_config(
|
|
663
|
+
mode, enabled_experimental
|
|
664
|
+
)
|
|
585
665
|
|
|
586
666
|
|
|
587
667
|
def get_available_modes() -> list[str]:
|
|
@@ -122,8 +122,18 @@ class PublishManagerImpl:
|
|
|
122
122
|
raise ValueError(msg)
|
|
123
123
|
self.console.print(f"[cyan]📦[/ cyan] Current version: {current_version}")
|
|
124
124
|
|
|
125
|
+
# Get intelligent version analysis and recommendation
|
|
126
|
+
recommendation = self._get_version_recommendation()
|
|
127
|
+
if recommendation and version_type not in ["interactive"]:
|
|
128
|
+
self._display_version_analysis(recommendation)
|
|
129
|
+
if version_type == "auto":
|
|
130
|
+
version_type = recommendation.bump_type.value
|
|
131
|
+
self.console.print(
|
|
132
|
+
f"[green]🎯[/green] Using AI-recommended bump type: {version_type}"
|
|
133
|
+
)
|
|
134
|
+
|
|
125
135
|
if version_type == "interactive":
|
|
126
|
-
version_type = self._prompt_for_version_type()
|
|
136
|
+
version_type = self._prompt_for_version_type(recommendation)
|
|
127
137
|
|
|
128
138
|
try:
|
|
129
139
|
new_version = self._calculate_next_version(current_version, version_type)
|
|
@@ -146,14 +156,21 @@ class PublishManagerImpl:
|
|
|
146
156
|
self.console.print(f"[red]❌[/ red] Version bump failed: {e}")
|
|
147
157
|
raise
|
|
148
158
|
|
|
149
|
-
def _prompt_for_version_type(self) -> str:
|
|
159
|
+
def _prompt_for_version_type(self, recommendation=None) -> str:
|
|
150
160
|
try:
|
|
151
161
|
from rich.prompt import Prompt
|
|
152
162
|
|
|
163
|
+
default_type = "patch"
|
|
164
|
+
if recommendation:
|
|
165
|
+
default_type = recommendation.bump_type.value
|
|
166
|
+
self.console.print(
|
|
167
|
+
f"[dim]AI recommendation: {default_type} (confidence: {recommendation.confidence:.0%})[/dim]"
|
|
168
|
+
)
|
|
169
|
+
|
|
153
170
|
return Prompt.ask(
|
|
154
171
|
"[cyan]📦[/ cyan] Select version bump type",
|
|
155
172
|
choices=["patch", "minor", "major"],
|
|
156
|
-
default=
|
|
173
|
+
default=default_type,
|
|
157
174
|
)
|
|
158
175
|
except ImportError:
|
|
159
176
|
self.console.print(
|
|
@@ -161,6 +178,73 @@ class PublishManagerImpl:
|
|
|
161
178
|
)
|
|
162
179
|
return "patch"
|
|
163
180
|
|
|
181
|
+
def _get_version_recommendation(self):
|
|
182
|
+
"""Get AI-powered version bump recommendation based on git history."""
|
|
183
|
+
try:
|
|
184
|
+
import asyncio
|
|
185
|
+
|
|
186
|
+
from crackerjack.services.git import GitService
|
|
187
|
+
from crackerjack.services.version_analyzer import VersionAnalyzer
|
|
188
|
+
|
|
189
|
+
# Initialize services
|
|
190
|
+
git_service = GitService(self.console, self.pkg_path)
|
|
191
|
+
version_analyzer = VersionAnalyzer(self.console, git_service)
|
|
192
|
+
|
|
193
|
+
# Get recommendation asynchronously
|
|
194
|
+
try:
|
|
195
|
+
# Try to get existing event loop
|
|
196
|
+
loop = asyncio.get_event_loop()
|
|
197
|
+
if loop.is_running():
|
|
198
|
+
# Create a new event loop in a thread if one is already running
|
|
199
|
+
import concurrent.futures
|
|
200
|
+
|
|
201
|
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
202
|
+
future = executor.submit(
|
|
203
|
+
asyncio.run, version_analyzer.recommend_version_bump()
|
|
204
|
+
)
|
|
205
|
+
recommendation = future.result(timeout=10)
|
|
206
|
+
else:
|
|
207
|
+
recommendation = loop.run_until_complete(
|
|
208
|
+
version_analyzer.recommend_version_bump()
|
|
209
|
+
)
|
|
210
|
+
except RuntimeError:
|
|
211
|
+
# No event loop, create one
|
|
212
|
+
recommendation = asyncio.run(version_analyzer.recommend_version_bump())
|
|
213
|
+
|
|
214
|
+
return recommendation
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
self.console.print(f"[yellow]⚠️[/yellow] Version analysis failed: {e}")
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
def _display_version_analysis(self, recommendation):
|
|
221
|
+
"""Display version analysis in a compact format."""
|
|
222
|
+
if not recommendation:
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
self.console.print("\n[cyan]🎯 AI Version Analysis[/cyan]")
|
|
226
|
+
self.console.print(
|
|
227
|
+
f"Recommended: [bold green]{recommendation.recommended_version}[/bold green] "
|
|
228
|
+
f"({recommendation.bump_type.value.upper()}) - {recommendation.confidence:.0%} confidence"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if recommendation.reasoning:
|
|
232
|
+
self.console.print(f"[dim]→ {recommendation.reasoning[0]}[/dim]")
|
|
233
|
+
|
|
234
|
+
# Show key changes briefly
|
|
235
|
+
if recommendation.breaking_changes:
|
|
236
|
+
self.console.print(
|
|
237
|
+
f"[red]⚠️[/red] {len(recommendation.breaking_changes)} breaking changes detected"
|
|
238
|
+
)
|
|
239
|
+
elif recommendation.new_features:
|
|
240
|
+
self.console.print(
|
|
241
|
+
f"[green]✨[/green] {len(recommendation.new_features)} new features detected"
|
|
242
|
+
)
|
|
243
|
+
elif recommendation.bug_fixes:
|
|
244
|
+
self.console.print(
|
|
245
|
+
f"[blue]🔧[/blue] {len(recommendation.bug_fixes)} bug fixes detected"
|
|
246
|
+
)
|
|
247
|
+
|
|
164
248
|
def validate_auth(self) -> bool:
|
|
165
249
|
auth_methods = self._collect_auth_methods()
|
|
166
250
|
return self._report_auth_status(auth_methods)
|
|
@@ -71,7 +71,7 @@ class TestProgress:
|
|
|
71
71
|
border_style="yellow",
|
|
72
72
|
title_style="bold yellow",
|
|
73
73
|
expand=True,
|
|
74
|
-
min_width=
|
|
74
|
+
min_width=74,
|
|
75
75
|
)
|
|
76
76
|
|
|
77
77
|
table.add_column("Type", style="cyan", ratio=1)
|
|
@@ -106,7 +106,7 @@ class TestProgress:
|
|
|
106
106
|
border_style="cyan",
|
|
107
107
|
title_style="bold cyan",
|
|
108
108
|
expand=True,
|
|
109
|
-
min_width=
|
|
109
|
+
min_width=74,
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
table.add_column("Metric", style="cyan", ratio=1)
|
crackerjack/services/config.py
CHANGED
|
@@ -12,12 +12,20 @@ class ConfigurationService:
|
|
|
12
12
|
def __init__(self, console: Console, pkg_path: Path) -> None:
|
|
13
13
|
self.console = console
|
|
14
14
|
self.pkg_path = pkg_path
|
|
15
|
-
|
|
15
|
+
# Extract package directory name from the pkg_path
|
|
16
|
+
package_directory = pkg_path.name if pkg_path != Path.cwd() else None
|
|
17
|
+
self.config_generator = DynamicConfigGenerator(package_directory)
|
|
16
18
|
|
|
17
19
|
def update_precommit_config(self, options: OptionsProtocol) -> bool:
|
|
18
20
|
try:
|
|
19
21
|
mode = self._determine_config_mode(options)
|
|
20
|
-
|
|
22
|
+
# Extract package directory name from the pkg_path
|
|
23
|
+
package_directory = (
|
|
24
|
+
self.pkg_path.name if self.pkg_path != Path.cwd() else None
|
|
25
|
+
)
|
|
26
|
+
config_temp_path = generate_config_for_mode(
|
|
27
|
+
mode, package_directory=package_directory
|
|
28
|
+
)
|
|
21
29
|
if not config_temp_path:
|
|
22
30
|
self.console.print("[yellow]⚠️ No configuration generated[/ yellow]")
|
|
23
31
|
return False
|
|
@@ -130,7 +130,7 @@ class PerformanceBenchmarker:
|
|
|
130
130
|
obj = {
|
|
131
131
|
"data": f"heavy_data_{i}" * 100,
|
|
132
132
|
"metadata": {"created": time.time(), "index": i},
|
|
133
|
-
"payload": list
|
|
133
|
+
"payload": list(range(100)),
|
|
134
134
|
}
|
|
135
135
|
heavy_objects.append(obj)
|
|
136
136
|
|
|
@@ -153,7 +153,7 @@ class PerformanceBenchmarker:
|
|
|
153
153
|
return {
|
|
154
154
|
"data": f"heavy_data_{index}" * 100,
|
|
155
155
|
"metadata": {"created": time.time(), "index": index},
|
|
156
|
-
"payload": list
|
|
156
|
+
"payload": list(range(100)),
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
lazy_obj = LazyLoader(create_heavy_object, f"heavy_object_{i}")
|
|
@@ -298,5 +298,27 @@ class PerformanceBenchmarker:
|
|
|
298
298
|
self._logger.info(f"Exported benchmark results to {output_path}")
|
|
299
299
|
|
|
300
300
|
|
|
301
|
+
class PerformanceBenchmarkService:
|
|
302
|
+
"""Service wrapper for performance benchmarking in workflow orchestration."""
|
|
303
|
+
|
|
304
|
+
def __init__(self, console, pkg_path):
|
|
305
|
+
self._console = console
|
|
306
|
+
self._pkg_path = pkg_path
|
|
307
|
+
self._benchmarker = PerformanceBenchmarker()
|
|
308
|
+
self._logger = get_logger("crackerjack.benchmark_service")
|
|
309
|
+
|
|
310
|
+
async def run_benchmark_suite(self) -> BenchmarkSuite | None:
|
|
311
|
+
"""Run comprehensive benchmark suite and return results."""
|
|
312
|
+
try:
|
|
313
|
+
return await self._benchmarker.run_comprehensive_benchmark()
|
|
314
|
+
except Exception as e:
|
|
315
|
+
self._logger.warning(f"Benchmark suite failed: {e}")
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
def export_results(self, suite: BenchmarkSuite, output_path: Path) -> None:
|
|
319
|
+
"""Export benchmark results to file."""
|
|
320
|
+
self._benchmarker.export_benchmark_results(suite, output_path)
|
|
321
|
+
|
|
322
|
+
|
|
301
323
|
def get_benchmarker() -> PerformanceBenchmarker:
|
|
302
324
|
return PerformanceBenchmarker()
|
|
@@ -140,7 +140,7 @@ class PerformanceCache:
|
|
|
140
140
|
ttl_seconds: int | None = None,
|
|
141
141
|
invalidation_keys: builtins.set[str] | None = None,
|
|
142
142
|
) -> None:
|
|
143
|
-
self.set
|
|
143
|
+
self.set(key, value, ttl_seconds, invalidation_keys)
|
|
144
144
|
|
|
145
145
|
def invalidate(self, invalidation_key: str) -> int:
|
|
146
146
|
with self._lock:
|
|
@@ -166,15 +166,15 @@ def main(file_paths: list[str]) -> int:
|
|
|
166
166
|
if exit_code == 0:
|
|
167
167
|
print("✅ All regex patterns validated successfully!")
|
|
168
168
|
else:
|
|
169
|
-
print("\n" + "=" *
|
|
169
|
+
print("\n" + "=" * 74)
|
|
170
170
|
print("REGEX VALIDATION FAILED")
|
|
171
|
-
print("=" *
|
|
171
|
+
print("=" * 74)
|
|
172
172
|
print("To fix these issues: ")
|
|
173
173
|
print("1. Use patterns from crackerjack.services.regex_patterns")
|
|
174
174
|
print("2. Add new patterns to SAFE_PATTERNS with comprehensive tests")
|
|
175
175
|
print("3. Use '# REGEX OK: reason' comment for legitimate exceptions")
|
|
176
176
|
print("4. Fix \\g<1> replacement syntax (no spaces)")
|
|
177
|
-
print("=" *
|
|
177
|
+
print("=" * 74)
|
|
178
178
|
|
|
179
179
|
return exit_code
|
|
180
180
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crackerjack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.34.0
|
|
4
4
|
Summary: Crackerjack Python project management tool
|
|
5
5
|
Project-URL: documentation, https://github.com/lesleslie/crackerjack
|
|
6
6
|
Project-URL: homepage, https://github.com/lesleslie/crackerjack
|
|
@@ -2,7 +2,7 @@ crackerjack/__init__.py,sha256=k8_Ev_3fWdjFtGNSJdSOvyaSLW54y3j484d3a8k_Ob4,1396
|
|
|
2
2
|
crackerjack/__main__.py,sha256=zSZyImAZrHvOvGQT7-QHXqJPW8IQLH2c6QU5Awvy1eU,52552
|
|
3
3
|
crackerjack/api.py,sha256=hXWqk9qLxYley6NiIIz9RemYhxC67cwwbktQdV1IPPY,21550
|
|
4
4
|
crackerjack/code_cleaner.py,sha256=M1zVaq31uW0nOkPneKR8kfR3892gyyVx0VhFgRaxsj4,44338
|
|
5
|
-
crackerjack/dynamic_config.py,sha256=
|
|
5
|
+
crackerjack/dynamic_config.py,sha256=DOfq5Qjkfcww7qW9Q-MDOCn-TSUu6sZWMpZ4rbaFn40,21564
|
|
6
6
|
crackerjack/errors.py,sha256=yYbZ92kn_y6acEWgQvEPvozAYs2HT65uLwAXrtXxGsE,10049
|
|
7
7
|
crackerjack/interactive.py,sha256=QXFZrnbY0nc8rFJcivFAVFNgUTHXqLCu3FFv5bmq_eI,21634
|
|
8
8
|
crackerjack/adapters/__init__.py,sha256=k-8ajMDL9DS9hV2FYOu694nmNQg3HkudJRuNcXmx8N4,451
|
|
@@ -34,7 +34,7 @@ crackerjack/cli/cache_handlers_enhanced.py,sha256=6X5rYSo1l-rj9eb7eB8mpA-6BlUagy
|
|
|
34
34
|
crackerjack/cli/facade.py,sha256=e4_oB04awqEijI3yqiYAZGc6x09uMBa4ih0SsXpgMuY,3751
|
|
35
35
|
crackerjack/cli/handlers.py,sha256=mYhwMLUKid6mQLff0ScpcnhP0yUS9IzOIMdM7VLkUCc,17178
|
|
36
36
|
crackerjack/cli/interactive.py,sha256=bGOMXHYyuselHh2b4khbDGJ4tX9yI2rVN3SZ1oSDOaM,16988
|
|
37
|
-
crackerjack/cli/options.py,sha256=
|
|
37
|
+
crackerjack/cli/options.py,sha256=g1OcUXA6a59dLQfNw-84HQt66zQR9QRBGnVvlbrbVwI,34010
|
|
38
38
|
crackerjack/cli/utils.py,sha256=XC7dT8GNidhORjUe2p2hQOpZgCi2KvVCNu6g3azzgqY,584
|
|
39
39
|
crackerjack/config/__init__.py,sha256=b0481N2f_JvGufMPcbo5IXu2VjYd111r1BHw0oD3x7o,330
|
|
40
40
|
crackerjack/config/global_lock_config.py,sha256=PyonoA2__HKEEvn6SD-gEYh9iD7xIAdts2C3lNoTWhw,1996
|
|
@@ -47,14 +47,14 @@ crackerjack/core/enhanced_container.py,sha256=0rN9aDm5WfcH-g3D_dj7byc1aZK6dLKthK
|
|
|
47
47
|
crackerjack/core/file_lifecycle.py,sha256=W0A0Bk3XTds1Za-h4gASAUdUrMozbq2XvGi-BjrnkGc,15149
|
|
48
48
|
crackerjack/core/performance.py,sha256=ZVpDydd5BDycxwwZLOUG1tzwejwVvjJvFFSiKbDHpVQ,7606
|
|
49
49
|
crackerjack/core/performance_monitor.py,sha256=5fMDcn8mSDAEJNm6DfNNLDt_NTcRwDHcbKx_eyqHeTs,13303
|
|
50
|
-
crackerjack/core/phase_coordinator.py,sha256=
|
|
50
|
+
crackerjack/core/phase_coordinator.py,sha256=Ubx1CchB3dQ-2GxlMgm_86O7GKyvmnodE5e4wBaw-8M,31366
|
|
51
51
|
crackerjack/core/proactive_workflow.py,sha256=DcmQnOvP4uge5O13t0bfXfBI4K4EjD8fnJPQmlYMO5U,9774
|
|
52
52
|
crackerjack/core/resource_manager.py,sha256=gFQ629Ves5vwd0KNSVCqDp4H57e7-342yRCWL4xRHD8,12797
|
|
53
53
|
crackerjack/core/service_watchdog.py,sha256=Ttj1imOxvUea4Tkf5JO1e2dQtGIK7D-bX1xOsHTa-Kc,15688
|
|
54
54
|
crackerjack/core/session_coordinator.py,sha256=TgoGE9DfXe2x-OkH93Ld9dX9ROjx2_mZFkGXen-z5YI,15680
|
|
55
55
|
crackerjack/core/timeout_manager.py,sha256=_sbEsfYDwWx7y0Pn89QCoAZ5DpWIbCdtR9qkG_Kqj5E,15013
|
|
56
56
|
crackerjack/core/websocket_lifecycle.py,sha256=74kn6ugu6FLlDQhCNSPgqguCFwRoT1WFOvtl8G2OyFc,12860
|
|
57
|
-
crackerjack/core/workflow_orchestrator.py,sha256=
|
|
57
|
+
crackerjack/core/workflow_orchestrator.py,sha256=NgvOn6pTVV8aULxe-bbwT6GeIELRc-KNXU7bYKroGV8,70162
|
|
58
58
|
crackerjack/docs/INDEX.md,sha256=a6CGFEeL5DX_FRft_JFWd0nOxoBmCSSp-QHIC3B7ato,342
|
|
59
59
|
crackerjack/docs/generated/api/API_REFERENCE.md,sha256=mWoqImZA7AhDvRqqF1MhUo70g_pnZr3NoBeZQRotqN8,155816
|
|
60
60
|
crackerjack/docs/generated/api/CLI_REFERENCE.md,sha256=ikuG0hO5EjIiQlJtAUnvEuAhXDa-JHPULPXNNmUwvk4,2805
|
|
@@ -84,11 +84,11 @@ crackerjack/intelligence/integration.py,sha256=vVaC2Fp5RbbABpaohCePzGw1XANuRztGl
|
|
|
84
84
|
crackerjack/managers/__init__.py,sha256=PFWccXx4hDQA76T02idAViOLVD-aPeVpgjdfSkh_Dmk,298
|
|
85
85
|
crackerjack/managers/async_hook_manager.py,sha256=c0HFR98sFwfk0uZ3NmAe_6OVZpBrq9I570V8A2DoIxw,5129
|
|
86
86
|
crackerjack/managers/hook_manager.py,sha256=_FT0ngwPwujqg0KZGpLz-pP07mwDmptJ5pVkiy5yS8k,7820
|
|
87
|
-
crackerjack/managers/publish_manager.py,sha256=
|
|
87
|
+
crackerjack/managers/publish_manager.py,sha256=Jn0XqGjZNfLNiq3-XaQWGU950TRbDWW-5WMEn7jJ6ag,21373
|
|
88
88
|
crackerjack/managers/test_command_builder.py,sha256=1TlPzddNcDDxRORH6UvAudcbRc6hKwFyknSEVLkiWAo,3459
|
|
89
89
|
crackerjack/managers/test_executor.py,sha256=2837Ti4OaNsmLxnmELjbQ18hmfL0-Z2EW-W2UeFSDcE,13871
|
|
90
90
|
crackerjack/managers/test_manager.py,sha256=BRPBWXx4flPDK0w96xyHhg-9dmUca1vpKQRM2VofSlI,13158
|
|
91
|
-
crackerjack/managers/test_manager_backup.py,sha256=
|
|
91
|
+
crackerjack/managers/test_manager_backup.py,sha256=CR8D7WZ68ZrTADFqYJtVDUWnlznJXJNriPIdsp6ZB1E,37932
|
|
92
92
|
crackerjack/managers/test_progress.py,sha256=B1013ygUk2nAo37whDXNA7n-FYdsEO4qj17fuDm_fdg,3058
|
|
93
93
|
crackerjack/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
94
94
|
crackerjack/mcp/cache.py,sha256=uq5XVeRjNyARfaAyN9DsaPURU_OHdBId5UfDvXbfSos,11974
|
|
@@ -157,7 +157,7 @@ crackerjack/services/backup_service.py,sha256=0e8AAo9svSBtbsbI9vwnAVSilB2fjph61l
|
|
|
157
157
|
crackerjack/services/bounded_status_operations.py,sha256=mrBkUQwgtYjkbp-Y-5MdrU2A3rp3ZLVgOJv9vLdnJ8k,18763
|
|
158
158
|
crackerjack/services/cache.py,sha256=FutQKxItKSdQFzOlWQaQzVBEfn6lbPXCDdvNnz3NCDQ,14536
|
|
159
159
|
crackerjack/services/changelog_automation.py,sha256=KUeXCYLihRfLR0mUIRiI2aRQdCfe-45GnbB2gYNJJQE,14095
|
|
160
|
-
crackerjack/services/config.py,sha256=
|
|
160
|
+
crackerjack/services/config.py,sha256=fF3EpPfIxFBmZ9oTr7V64zCMBmxHWCmD_649qr0dgsI,13590
|
|
161
161
|
crackerjack/services/config_integrity.py,sha256=Ac6-c7WuupsyrP2dxx_ijgjzpNnx9G0NWsXB-SZjelg,2904
|
|
162
162
|
crackerjack/services/config_merge.py,sha256=FPh4u4J68JkNVf0AT1paNeEy2MjusSbYu9kN72LzR9w,18825
|
|
163
163
|
crackerjack/services/config_template.py,sha256=RgSYFVNBxdBfMitlRqz7bzkEHaQhEWMm3pUMS7maRFU,18035
|
|
@@ -188,8 +188,8 @@ crackerjack/services/metrics.py,sha256=0_tiaK2-lBY0Y5MrS3Rrzyxft_JziGEEPgUXW486r
|
|
|
188
188
|
crackerjack/services/parallel_executor.py,sha256=cwKj8KKzaANn6zLmvPRr1v_nije_VqF6O6jSprBFDdM,13604
|
|
189
189
|
crackerjack/services/pattern_cache.py,sha256=fdD-HPoImUnd07rlGuDfyFWG86teWpNVr2LacJkCZ5Q,11097
|
|
190
190
|
crackerjack/services/pattern_detector.py,sha256=soB9zXsjsNFo5pzMpFhFehNOemPTCQh-ARdKlHi46U0,18032
|
|
191
|
-
crackerjack/services/performance_benchmarks.py,sha256=
|
|
192
|
-
crackerjack/services/performance_cache.py,sha256=
|
|
191
|
+
crackerjack/services/performance_benchmarks.py,sha256=HPH86UM9IArkWQgXm71abAhuGuriUza4i6_zyJNOGPc,11326
|
|
192
|
+
crackerjack/services/performance_cache.py,sha256=d_sREaPQAdxFPKgLCgLMC4Iz-DdDc1QDYCbhvNYmUGQ,11858
|
|
193
193
|
crackerjack/services/performance_monitor.py,sha256=cDu6FoiUX2VpslA3vG4JL6YQyIk1JzDcD4g5zR8NdjI,20214
|
|
194
194
|
crackerjack/services/predictive_analytics.py,sha256=OcZYP0p2_zZuyWqbqzLHDoHTxVfrPm3VtiY-Yq9y7xc,17843
|
|
195
195
|
crackerjack/services/quality_baseline.py,sha256=ImC1XTFTfrwFIDDDX1F0V7sGquAXI21oVxgjOSYIYFQ,8229
|
|
@@ -221,9 +221,9 @@ crackerjack/slash_commands/run.md,sha256=VEWWset52jPV0m00LnQpjRkHL8g8XRPYAzgOq6B
|
|
|
221
221
|
crackerjack/slash_commands/status.md,sha256=U3qqppVLtIIm2lEiMYaKagaHYLI9UplL7OH1j6SRJGw,3921
|
|
222
222
|
crackerjack/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
223
223
|
crackerjack/tools/validate_input_validator_patterns.py,sha256=NN7smYlXWrHLQXTb-81gRam2vjW-cJav92f1klPA0qA,8234
|
|
224
|
-
crackerjack/tools/validate_regex_patterns.py,sha256=
|
|
225
|
-
crackerjack-0.
|
|
226
|
-
crackerjack-0.
|
|
227
|
-
crackerjack-0.
|
|
228
|
-
crackerjack-0.
|
|
229
|
-
crackerjack-0.
|
|
224
|
+
crackerjack/tools/validate_regex_patterns.py,sha256=9ejFb7Tw1js_oydzuEeeeXvrU5ipHUEX9ATBfkLCCE8,5811
|
|
225
|
+
crackerjack-0.34.0.dist-info/METADATA,sha256=8y1wbYXB1T7_irlTiOilQbI_XQWPKc2aj8Aq7QVhRN4,37942
|
|
226
|
+
crackerjack-0.34.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
227
|
+
crackerjack-0.34.0.dist-info/entry_points.txt,sha256=AJKNft0WXm9xoGUJ3Trl-iXHOWxRAYbagQiza3AILr4,57
|
|
228
|
+
crackerjack-0.34.0.dist-info/licenses/LICENSE,sha256=fDt371P6_6sCu7RyqiZH_AhT1LdN3sN1zjBtqEhDYCk,1531
|
|
229
|
+
crackerjack-0.34.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|