diff --git a/robot/coverage_threshold.robot b/robot/coverage_threshold.robot index 7d081bffc..b7d6d5ce4 100644 --- a/robot/coverage_threshold.robot +++ b/robot/coverage_threshold.robot @@ -9,7 +9,7 @@ Suite Teardown Cleanup Test Environment *** Test Cases *** Noxfile Contains Coverage Threshold Constant [Documentation] Verify COVERAGE_THRESHOLD = 97 is defined in noxfile.py - [Tags] coverage config tdd_issue tdd_issue_4305 tdd_expected_fail + [Tags] coverage config ${content}= Get File ${WORKSPACE}/noxfile.py Should Contain ${content} COVERAGE_THRESHOLD = 97 diff --git a/scripts/validate_automation_tracking.py b/scripts/validate_automation_tracking.py index c53c16e30..ff4783de8 100755 --- a/scripts/validate_automation_tracking.py +++ b/scripts/validate_automation_tracking.py @@ -7,32 +7,33 @@ defined in docs/development/automation-tracking.md. Usage: python scripts/validate_automation_tracking.py --repo owner/repo - python scripts/validate_automation_tracking.py --title "[AUTO-SESSION] Checkpoint (Cycle 15)" + python scripts/validate_automation_tracking.py \ + --title "[AUTO-SESSION] Checkpoint (Cycle 15)" python scripts/validate_automation_tracking.py --validate-all """ -import re import argparse +import re import sys -from typing import List, Dict, Any, Optional, Tuple +from typing import Any # Standard agent prefixes and their expected types -AGENT_PREFIXES = { +AGENT_PREFIXES: dict[str, list[str]] = { "SESSION": ["Checkpoint"], - "IMP-POOL": ["Health Report", "Status Update"], + "IMP-POOL": ["Health Report", "Status Update"], "WATCHDOG": ["System Health", "Alert"], "GROOMER": ["Grooming Report", "Scope Alert"], "LIAISON": ["Status Update", "Human Activity Summary"], } # Title format patterns -TRACKING_TITLE_PATTERN = re.compile(r'^\[AUTO-([A-Z-]+)\] (.+) \(Cycle (\d+)\)$') -ANNOUNCEMENT_TITLE_PATTERN = re.compile(r'^\[AUTO-([A-Z-]+)\] Announce: (.+)$') +TRACKING_TITLE_PATTERN = re.compile(r"^\[AUTO-([A-Z-]+)\] (.+) \(Cycle (\d+)\)$") +ANNOUNCEMENT_TITLE_PATTERN = re.compile(r"^\[AUTO-([A-Z-]+)\] Announce: (.+)$") + + +def validate_tracking_title(title: str) -> tuple[bool, str]: + """Validate a tracking issue title format. -def validate_tracking_title(title: str) -> Tuple[bool, str]: - """ - Validate a tracking issue title format. - Returns: (is_valid, error_message) """ @@ -41,27 +42,37 @@ def validate_tracking_title(title: str) -> Tuple[bool, str]: if announce_match: prefix, message = announce_match.groups() if prefix not in AGENT_PREFIXES: - known_prefixes = [f"AUTO-{p}" for p in AGENT_PREFIXES.keys()] - return False, f"Unknown agent prefix 'AUTO-{prefix}'. Known prefixes: {known_prefixes}" + known = [f"AUTO-{p}" for p in AGENT_PREFIXES] + return ( + False, + f"Unknown agent prefix 'AUTO-{prefix}'. Known prefixes: {known}", + ) if not message.strip(): return False, "Announcement message cannot be empty" return True, "Valid announcement title" - + # Check for tracking format track_match = TRACKING_TITLE_PATTERN.match(title) if track_match: prefix, issue_type, cycle_str = track_match.groups() - + # Validate prefix if prefix not in AGENT_PREFIXES: - known_prefixes = [f"AUTO-{p}" for p in AGENT_PREFIXES.keys()] - return False, f"Unknown agent prefix 'AUTO-{prefix}'. Known prefixes: {known_prefixes}" - + known = [f"AUTO-{p}" for p in AGENT_PREFIXES] + return ( + False, + f"Unknown agent prefix 'AUTO-{prefix}'. Known prefixes: {known}", + ) + # Validate type valid_types = AGENT_PREFIXES[prefix] if issue_type not in valid_types: - return False, f"Invalid type '{issue_type}' for prefix 'AUTO-{prefix}'. Valid types: {valid_types}" - + return ( + False, + f"Invalid type '{issue_type}' for prefix " + f"'AUTO-{prefix}'. Valid types: {valid_types}", + ) + # Validate cycle number try: cycle_num = int(cycle_str) @@ -69,129 +80,164 @@ def validate_tracking_title(title: str) -> Tuple[bool, str]: return False, "Cycle number must be positive" except ValueError: return False, f"Invalid cycle number '{cycle_str}'" - - return True, "Valid tracking title" - - return False, "Title does not match expected format: '[AUTO-] (Cycle )' or '[AUTO-] Announce: '" -def validate_automation_tracking_issue(issue_data: Dict[str, Any]) -> List[str]: - """ - Validate a complete automation tracking issue. - + return True, "Valid tracking title" + + return ( + False, + "Title does not match expected format: " + "'[AUTO-] (Cycle )' or " + "'[AUTO-] Announce: '", + ) + + +def validate_automation_tracking_issue( + issue_data: dict[str, Any], +) -> list[str]: + """Validate a complete automation tracking issue. + Args: issue_data: Dictionary containing issue data (title, labels, etc.) - + Returns: List of validation errors (empty if valid) """ - errors = [] - + errors: list[str] = [] + # Validate title - title = issue_data.get('title', '') + title = issue_data.get("title", "") is_valid, message = validate_tracking_title(title) if not is_valid: errors.append(f"Title format error: {message}") - + # Validate labels - labels = issue_data.get('labels', []) - label_names = [label.get('name', '') if isinstance(label, dict) else str(label) for label in labels] - + labels = issue_data.get("labels", []) + label_names = [ + label.get("name", "") if isinstance(label, dict) else str(label) + for label in labels + ] + if "Automation Tracking" not in label_names: errors.append("Missing required 'Automation Tracking' label") - + # Validate body content (basic checks) - body = issue_data.get('body', '') + body = issue_data.get("body", "") if not body.strip(): errors.append("Issue body cannot be empty") - + # Check for common required elements in body - if '**Automated by CleverAgents Bot**' not in body: + if "**Automated by CleverAgents Bot**" not in body: errors.append("Missing automation signature in body") - + return errors -def get_tracking_issues_from_repo(owner: str, repo: str) -> List[Dict[str, Any]]: - """ - Fetch automation tracking issues from repository. - - Note: This is a stub - in real usage, you would integrate with Forgejo API + +def get_tracking_issues_from_repo( + owner: str, + repo: str, +) -> list[dict[str, Any]]: + """Fetch automation tracking issues from repository. + + Note: This is a stub — in real usage, integrate with the Forgejo API. """ print(f"Note: Repository validation for {owner}/{repo} requires API integration") print("This is a demonstration of the validation logic.") return [] -def main(): - parser = argparse.ArgumentParser(description='Validate automation tracking issues') - parser.add_argument('--title', help='Validate a single title string') - parser.add_argument('--repo', help='Validate issues from repository (owner/repo)') - parser.add_argument('--validate-all', action='store_true', - help='Run comprehensive validation examples') - + +def _run_validate_all() -> int: + """Run comprehensive validation examples and report results.""" + print("Running comprehensive validation examples...") + + # Test cases + test_cases = [ + # Valid cases + ("[AUTO-SESSION] Checkpoint (Cycle 15)", True), + ("[AUTO-IMP-POOL] Health Report (Cycle 42)", True), + ("[AUTO-WATCHDOG] System Health (Cycle 8)", True), + ("[AUTO-GROOMER] Grooming Report (Cycle 23)", True), + ("[AUTO-LIAISON] Status Update (Cycle 67)", True), + ( + "[AUTO-SESSION] Announce: Emergency system restart required", + True, + ), + # Invalid cases + ("[AUTO-UNKNOWN] Test (Cycle 1)", False), + ("[AUTO-SESSION] Invalid Type (Cycle 1)", False), + ("[AUTO-SESSION] Checkpoint (Cycle 0)", False), + ("[AUTO-SESSION] Checkpoint", False), + ("Regular issue title", False), + ("[AUTO-SESSION] Announce:", False), + ] + + print("\nTitle Validation Test Results:") + print("-" * 50) + + all_passed = True + for title, expected_valid in test_cases: + is_valid, message = validate_tracking_title(title) + status = "\u2713" if is_valid == expected_valid else "\u2717" + result = "VALID" if is_valid else "INVALID" + + print(f"{status} {title}") + expected_str = "VALID" if expected_valid else "INVALID" + print(f" Expected: {expected_str}, Got: {result}") + print(f" Message: {message}") + print() + + if is_valid != expected_valid: + all_passed = False + + verdict = "\u2713 ALL PASSED" if all_passed else "\u2717 SOME FAILED" + print(f"Overall test result: {verdict}") + return 0 if all_passed else 1 + + +def main() -> int: + """Entry point for automation tracking validation.""" + parser = argparse.ArgumentParser( + description="Validate automation tracking issues", + ) + parser.add_argument( + "--title", + help="Validate a single title string", + ) + parser.add_argument( + "--repo", + help="Validate issues from repository (owner/repo)", + ) + parser.add_argument( + "--validate-all", + action="store_true", + help="Run comprehensive validation examples", + ) + args = parser.parse_args() - + if args.title: is_valid, message = validate_tracking_title(args.title) print(f"Title: {args.title}") - print(f"Result: {'✓ VALID' if is_valid else '✗ INVALID'}") + valid_str = "\u2713 VALID" if is_valid else "\u2717 INVALID" + print(f"Result: {valid_str}") print(f"Message: {message}") return 0 if is_valid else 1 - - elif args.repo: + + if args.repo: try: - owner, repo_name = args.repo.split('/', 1) - issues = get_tracking_issues_from_repo(owner, repo_name) - # Validation logic would go here + owner, repo_name = args.repo.split("/", 1) + get_tracking_issues_from_repo(owner, repo_name) print(f"Repository validation for {args.repo} completed") return 0 except ValueError: print("Error: Repository must be in format 'owner/repo'") return 1 - - elif args.validate_all: - print("Running comprehensive validation examples...") - - # Test cases - test_cases = [ - # Valid cases - ("[AUTO-SESSION] Checkpoint (Cycle 15)", True), - ("[AUTO-IMP-POOL] Health Report (Cycle 42)", True), - ("[AUTO-WATCHDOG] System Health (Cycle 8)", True), - ("[AUTO-GROOMER] Grooming Report (Cycle 23)", True), - ("[AUTO-LIAISON] Status Update (Cycle 67)", True), - ("[AUTO-SESSION] Announce: Emergency system restart required", True), - - # Invalid cases - ("[AUTO-UNKNOWN] Test (Cycle 1)", False), # Unknown prefix - ("[AUTO-SESSION] Invalid Type (Cycle 1)", False), # Invalid type - ("[AUTO-SESSION] Checkpoint (Cycle 0)", False), # Invalid cycle - ("[AUTO-SESSION] Checkpoint", False), # Missing cycle - ("Regular issue title", False), # Wrong format - ("[AUTO-SESSION] Announce:", False), # Empty announcement - ] - - print("\nTitle Validation Test Results:") - print("-" * 50) - - all_passed = True - for title, expected_valid in test_cases: - is_valid, message = validate_tracking_title(title) - status = "✓" if is_valid == expected_valid else "✗" - result = "VALID" if is_valid else "INVALID" - - print(f"{status} {title}") - print(f" Expected: {'VALID' if expected_valid else 'INVALID'}, Got: {result}") - print(f" Message: {message}") - print() - - if is_valid != expected_valid: - all_passed = False - - print(f"Overall test result: {'✓ ALL PASSED' if all_passed else '✗ SOME FAILED'}") - return 0 if all_passed else 1 - - else: - parser.print_help() - return 1 -if __name__ == '__main__': + if args.validate_all: + return _run_validate_all() + + parser.print_help() + return 1 + + +if __name__ == "__main__": sys.exit(main())