| import sys |
| import os |
| import requests |
| from typing import Dict, List, Optional, Tuple |
| import base64 |
| from dotenv import load_dotenv |
|
|
|
|
| def _get_github_api( |
| endpoint: str, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> Tuple[bool, Optional[Dict]]: |
| """Make a GET request to GitHub API and return (success, response).""" |
| url = f"https://api.github.com/repos/{org}/{repo}/{endpoint}" |
| try: |
| response = requests.get(url, headers=headers) |
| if response.status_code == 200: |
| return True, response.json() |
| elif response.status_code == 404: |
| return False, None |
| else: |
| print(f"API error for {endpoint}: {response.status_code}", file=sys.stderr) |
| return False, None |
| except Exception as e: |
| print(f"Exception for {endpoint}: {e}", file=sys.stderr) |
| return False, None |
|
|
|
|
| def _check_branch_exists( |
| branch_name: str, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> bool: |
| """Verify that a branch exists in the repository.""" |
| success, _ = _get_github_api(f"branches/{branch_name}", headers, org, repo) |
| return success |
|
|
|
|
| def _get_file_content( |
| file_path: str, |
| headers: Dict[str, str], |
| org: str, |
| repo: str = "claude-code", |
| ref: str = "main", |
| ) -> Optional[str]: |
| """Get the content of a file from the repository.""" |
| success, result = _get_github_api( |
| f"contents/{file_path}?ref={ref}", headers, org, repo |
| ) |
| if not success or not result: |
| return None |
|
|
| try: |
| content = base64.b64decode(result.get("content", "")).decode("utf-8") |
| return content |
| except Exception as e: |
| print(f"Content decode error for {file_path}: {e}", file=sys.stderr) |
| return None |
|
|
|
|
| def _find_issue_by_title_keyword( |
| keyword: str, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> Optional[Dict]: |
| """Find an issue by title keyword and return the issue data.""" |
| |
| for state in ["open", "closed"]: |
| success, issues = _get_github_api( |
| f"issues?state={state}&per_page=100", headers, org, repo |
| ) |
| if success and issues: |
| for issue in issues: |
| if keyword.lower() in issue.get("title", "").lower(): |
| return issue |
| return None |
|
|
|
|
| def _find_pr_by_title_keyword( |
| keyword: str, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> Optional[Dict]: |
| """Find a PR by title keyword and return the PR data.""" |
| |
| for state in ["open", "closed"]: |
| success, prs = _get_github_api( |
| f"pulls?state={state}&per_page=100", headers, org, repo |
| ) |
| if success and prs: |
| for pr in prs: |
| if keyword.lower() in pr.get("title", "").lower(): |
| return pr |
| return None |
|
|
|
|
| def _get_pr_by_number( |
| pr_number: int, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> Optional[Dict]: |
| """Get a specific PR by number.""" |
| success, pr = _get_github_api(f"pulls/{pr_number}", headers, org, repo) |
| if success: |
| return pr |
| return None |
|
|
|
|
| def _check_issue_references(text: str, reference_numbers: List[str]) -> bool: |
| """Check if text contains references to specified issue numbers.""" |
| if not text: |
| return False |
|
|
| return all(f"#{ref}" in text for ref in reference_numbers) |
|
|
|
|
| def _check_addresses_pattern(pr_body: str, issue_numbers: List[str]) -> bool: |
| """Check if PR body contains 'Addresses #X' pattern for specified issues.""" |
| if not pr_body: |
| return False |
|
|
| return all( |
| f"Addresses #{num}" in pr_body or f"addresses #{num}" in pr_body |
| for num in issue_numbers |
| ) |
|
|
|
|
| def _get_issue_comments( |
| issue_number: int, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> List[Dict]: |
| """Get all comments for an issue.""" |
| success, comments = _get_github_api( |
| f"issues/{issue_number}/comments", headers, org, repo |
| ) |
| if success and comments: |
| return comments |
| return [] |
|
|
|
|
| def _get_pr_reviews( |
| pr_number: int, headers: Dict[str, str], org: str, repo: str = "claude-code" |
| ) -> List[Dict]: |
| """Get all reviews for a PR.""" |
| success, reviews = _get_github_api(f"pulls/{pr_number}/reviews", headers, org, repo) |
| if success and reviews: |
| return reviews |
| return [] |
|
|
|
|
| def _check_title_keywords(title: str, required_keywords: List[str]) -> bool: |
| """Check if title contains all required keywords.""" |
| return all(keyword.lower() in title.lower() for keyword in required_keywords) |
|
|
|
|
| def _check_headings_and_keywords( |
| body: str, headings: List[str], keywords: List[str] |
| ) -> bool: |
| """Check if body contains required headings and keywords.""" |
| has_headings = all(heading in body for heading in headings) |
| has_keywords = all(keyword.lower() in body.lower() for keyword in keywords) |
| return has_headings and has_keywords |
|
|
|
|
| def _check_exact_file_content(content: str, expected_sections: List[str]) -> bool: |
| """Check if file content contains expected sections.""" |
| return all(section in content for section in expected_sections) |
|
|
|
|
| def verify() -> bool: |
| """ |
| Programmatically verify that the critical issue hotfix workflow meets the |
| requirements described in description.md. |
| """ |
| |
| HOTFIX_BRANCH_NAME = "hotfix/memory-optimization-v1.0.72" |
| TRACKING_ISSUE_KEYWORD = "Memory and Context Management Issues" |
| HOTFIX_PR_KEYWORD = "HOTFIX: Critical memory optimization" |
|
|
| |
| MEMORY_DOC_SECTIONS = [ |
| "# Memory Optimization Guide for Claude Code v1.0.72", |
| "## Overview", |
| "### Context Auto-Compact Problem (Issue #49)", |
| "### JavaScript Heap Exhaustion (Issue #46)", |
| "## Optimization Strategies", |
| "### Immediate Fixes", |
| "### Configuration Options", |
| "## Related Issues", |
| ] |
|
|
| |
| TRACKING_ISSUE_TITLE_KEYWORDS = [ |
| "CRITICAL", |
| "Memory", |
| "Context Management", |
| "Hotfix Tracking", |
| ] |
| TRACKING_ISSUE_REFERENCE_NUMBERS = ["49", "46", "47"] |
| TRACKING_ISSUE_HEADINGS = [ |
| "## Critical Issues", |
| "## Impact Assessment", |
| "## Resolution Strategy", |
| ] |
| TRACKING_ISSUE_KEYWORDS = [ |
| "memory exhaustion", |
| "context auto-compact", |
| "JavaScript heap", |
| "hotfix priority", |
| ] |
|
|
| |
| HOTFIX_PR_TITLE_KEYWORDS = [ |
| "HOTFIX", |
| "Critical memory optimization", |
| "issues #49", |
| "#46", |
| ] |
| HOTFIX_PR_ADDRESSES_NUMBERS = ["49", "46"] |
| HOTFIX_PR_HEADINGS = [ |
| "## Summary", |
| "## Critical Issues Addressed", |
| "## Documentation Changes", |
| ] |
| HOTFIX_PR_KEYWORDS = [ |
| "memory optimization", |
| "context management", |
| "heap exhaustion", |
| "v1.0.72 hotfix", |
| ] |
|
|
| |
| PR51_UPDATE_KEYWORDS = [ |
| "Technical Implementation", |
| "event logging integration", |
| "workflow enhancement", |
| ] |
|
|
| |
| ISSUE_COMMENT_KEYWORDS = [ |
| "context buffer management", |
| "streaming optimization", |
| "progressive cleanup", |
| ] |
|
|
| |
| load_dotenv(".mcp_env") |
|
|
| |
| github_token = os.environ.get("MCP_GITHUB_TOKEN") |
| github_org = os.environ.get("GITHUB_EVAL_ORG") |
|
|
| if not github_token: |
| print("Error: MCP_GITHUB_TOKEN environment variable not set", file=sys.stderr) |
| return False |
|
|
| if not github_org: |
| print("Error: GITHUB_EVAL_ORG environment variable not set", file=sys.stderr) |
| return False |
|
|
| headers = { |
| "Authorization": f"Bearer {github_token}", |
| "Accept": "application/vnd.github.v3+json", |
| } |
|
|
| |
| print("Verifying critical issue hotfix workflow completion...") |
|
|
| |
| print("1. Verifying hotfix branch exists...") |
| if not _check_branch_exists(HOTFIX_BRANCH_NAME, headers, github_org): |
| print(f"Error: Branch '{HOTFIX_BRANCH_NAME}' not found", file=sys.stderr) |
| return False |
| print("✓ Hotfix branch created") |
|
|
| |
| print("2. Verifying MEMORY_OPTIMIZATION.md documentation...") |
| memory_doc_content = _get_file_content( |
| "docs/MEMORY_OPTIMIZATION.md", |
| headers, |
| github_org, |
| "claude-code", |
| HOTFIX_BRANCH_NAME, |
| ) |
| if not memory_doc_content: |
| print( |
| "Error: docs/MEMORY_OPTIMIZATION.md not found in hotfix branch", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| if not _check_exact_file_content(memory_doc_content, MEMORY_DOC_SECTIONS): |
| print( |
| "Error: MEMORY_OPTIMIZATION.md missing required sections or content", |
| file=sys.stderr, |
| ) |
| return False |
| print("✓ Memory optimization documentation created with correct content") |
|
|
| |
| print("3. Verifying tracking issue creation and content...") |
| tracking_issue = _find_issue_by_title_keyword( |
| TRACKING_ISSUE_KEYWORD, headers, github_org |
| ) |
| if not tracking_issue: |
| print( |
| f"Error: Tracking issue with keyword '{TRACKING_ISSUE_KEYWORD}' not found", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| tracking_issue_number = tracking_issue.get("number") |
| tracking_issue_title = tracking_issue.get("title", "") |
| tracking_issue_body = tracking_issue.get("body", "") |
|
|
| |
| if not _check_title_keywords(tracking_issue_title, TRACKING_ISSUE_TITLE_KEYWORDS): |
| print("Error: Tracking issue title missing required keywords", file=sys.stderr) |
| return False |
|
|
| |
| if not _check_headings_and_keywords( |
| tracking_issue_body, TRACKING_ISSUE_HEADINGS, TRACKING_ISSUE_KEYWORDS |
| ): |
| print( |
| "Error: Tracking issue missing required headings or keywords", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| if not _check_issue_references( |
| tracking_issue_body, TRACKING_ISSUE_REFERENCE_NUMBERS |
| ): |
| print( |
| "Error: Tracking issue does not reference required issues #49, #46, #47", |
| file=sys.stderr, |
| ) |
| return False |
| print("✓ Tracking issue created with correct content and references") |
|
|
| |
| print("4. Verifying hotfix pull request creation and content...") |
| hotfix_pr = _find_pr_by_title_keyword(HOTFIX_PR_KEYWORD, headers, github_org) |
| if not hotfix_pr: |
| print( |
| f"Error: Hotfix PR with keyword '{HOTFIX_PR_KEYWORD}' not found", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| hotfix_pr_number = hotfix_pr.get("number") |
| hotfix_pr_title = hotfix_pr.get("title", "") |
| hotfix_pr_body = hotfix_pr.get("body", "") |
|
|
| |
| if not _check_title_keywords(hotfix_pr_title, HOTFIX_PR_TITLE_KEYWORDS): |
| print("Error: Hotfix PR title missing required keywords", file=sys.stderr) |
| return False |
|
|
| |
| if not _check_headings_and_keywords( |
| hotfix_pr_body, HOTFIX_PR_HEADINGS, HOTFIX_PR_KEYWORDS |
| ): |
| print("Error: Hotfix PR missing required headings or keywords", file=sys.stderr) |
| return False |
|
|
| |
| if not _check_addresses_pattern(hotfix_pr_body, HOTFIX_PR_ADDRESSES_NUMBERS): |
| print( |
| "Error: Hotfix PR does not properly address issues #49 and #46", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| |
| if f"#{tracking_issue_number}" not in hotfix_pr_body: |
| print( |
| f"Error: Hotfix PR does not reference tracking issue #{tracking_issue_number}", |
| file=sys.stderr, |
| ) |
| return False |
| print("✓ Hotfix PR created with correct content and references") |
|
|
| |
| print("5. Verifying PR #51 update and merge...") |
| pr51 = _get_pr_by_number(51, headers, github_org) |
| if not pr51: |
| print("Error: PR #51 not found", file=sys.stderr) |
| return False |
|
|
| pr51_body = pr51.get("body", "") |
| pr51_state = pr51.get("state", "") |
|
|
| |
| if not _check_headings_and_keywords( |
| pr51_body, ["## Technical Implementation"], PR51_UPDATE_KEYWORDS |
| ): |
| print( |
| "Error: PR #51 missing updated technical implementation section", |
| file=sys.stderr, |
| ) |
| return False |
|
|
| |
| if pr51_state != "closed" or not pr51.get("merged_at"): |
| print("Error: PR #51 has not been merged", file=sys.stderr) |
| return False |
| print("✓ PR #51 updated and merged successfully") |
|
|
| |
| print("6. Verifying tracking issue implementation comment...") |
| tracking_issue_comments = _get_issue_comments( |
| tracking_issue_number, headers, github_org |
| ) |
|
|
| has_implementation_comment = False |
| for comment in tracking_issue_comments: |
| body = comment.get("body", "") |
| has_pr_ref = f"PR #{hotfix_pr_number}" in body |
| has_pr51_ref = "PR #51" in body |
| has_keywords = all( |
| keyword.lower() in body.lower() for keyword in ISSUE_COMMENT_KEYWORDS |
| ) |
| if has_pr_ref and has_pr51_ref and has_keywords: |
| has_implementation_comment = True |
| break |
|
|
| if not has_implementation_comment: |
| print( |
| f"Error: Tracking issue #{tracking_issue_number} missing implementation comment with required references and keywords", |
| file=sys.stderr, |
| ) |
| return False |
| print("✓ Tracking issue has implementation comment with PR references") |
|
|
| |
| print("7. Verifying tracking issue closure...") |
| if tracking_issue.get("state") != "closed": |
| print( |
| f"Error: Tracking issue #{tracking_issue_number} is not closed", |
| file=sys.stderr, |
| ) |
| return False |
| print("✓ Tracking issue closed successfully") |
|
|
| print("\n✅ All verification checks passed!") |
| print("Critical issue hotfix workflow completed successfully:") |
| print(f" - Tracking Issue #{tracking_issue_number}: {tracking_issue.get('title')}") |
| print(f" - Hotfix PR #{hotfix_pr_number}: {hotfix_pr.get('title')}") |
| print(f" - Branch: {HOTFIX_BRANCH_NAME}") |
| print(" - PR #51 merged: ✓") |
| print(" - Memory optimization documentation: ✓") |
|
|
| return True |
|
|
|
|
| if __name__ == "__main__": |
| success = verify() |
| sys.exit(0 if success else 1) |
|
|