fix(ci): resolve lint errors and remove stale tdd_expected_fail tag #5264
@@ -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
|
||||
|
||||
@@ -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-<PREFIX>] <TYPE> (Cycle <N>)' or '[AUTO-<PREFIX>] Announce: <message>'"
|
||||
|
||||
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-<PREFIX>] <TYPE> (Cycle <N>)' or "
|
||||
"'[AUTO-<PREFIX>] Announce: <message>'",
|
||||
)
|
||||
|
||||
|
||||
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())
|
||||
|
||||
Reference in New Issue
Block a user
TDD Regression Markers Incorrectly Removed
Only
tdd_expected_failshould be removed when a bug is fixed. Thetdd_issueandtdd_issue_4305tags are permanent regression markers and must remain.Current (incorrect):
Required (correct):
Per CONTRIBUTING.md TDD Issue Test Tags: