Coverage for scripts / list_pending_approvals.py: 19%
68 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-25 18:08 -0500
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-25 18:08 -0500
1#!/usr/bin/env python3
2"""
3List all pending approvals for current user (agent queue view).
5This script shows a queue of all pending approvals across requests where
6the current user is an approver, providing an agent-level view of their
7approval workload.
8"""
10import sys
11import argparse
12import json
13from pathlib import Path
14from datetime import datetime
16# Add shared lib to path
17sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / 'shared' / 'scripts' / 'lib'))
19from config_manager import get_jira_client
20from error_handler import handle_errors
23def get_jira_client(profile=None):
24 """Get JIRA client (overridable for testing)."""
25 from config_manager import get_jira_client as _get_client
26 return _get_client(profile)
29def format_pending_approvals_table(approvals: list, user_email: str = None) -> None:
30 """Format pending approvals as table."""
31 if not approvals:
32 print("No pending approvals found.")
33 return
35 user_str = f" for {user_email}" if user_email else ""
36 print(f"\nPending Approvals{user_str} ({len(approvals)} total):\n")
38 print(f"{'Request':<12} {'Summary':<35} {'Approval ID':<12} {'Approval Name':<25} {'Created':<20} {'Action'}")
39 print("─" * 140)
41 for approval in approvals:
42 request_key = approval.get('requestKey', 'Unknown')
43 summary = approval.get('summary', '')[:34]
44 approval_id = approval.get('approvalId', 'Unknown')
45 approval_name = approval.get('approvalName', 'Unknown')[:24]
46 created = approval.get('created', '')
48 # Format date
49 try:
50 created_dt = datetime.fromisoformat(created.replace('Z', '+00:00'))
51 created_str = created_dt.strftime('%Y-%m-%d %H:%M')
52 except:
53 created_str = created[:16] if created else 'Unknown'
55 action = "Approve | Decline"
57 print(f"{request_key:<12} {summary:<35} {approval_id:<12} {approval_name:<25} {created_str:<20} {action}")
59 print("\nTo approve/decline:")
60 print(" python approve_request.py <REQUEST-KEY> --approval-id <APPROVAL-ID>")
61 print(" python decline_request.py <REQUEST-KEY> --approval-id <APPROVAL-ID>")
64@handle_errors
65def main(args=None):
66 """Main function."""
67 parser = argparse.ArgumentParser(
68 description='List all pending approvals (agent queue view)',
69 formatter_class=argparse.RawDescriptionHelpFormatter,
70 epilog="""
71Examples:
72 # All pending approvals for current user
73 %(prog)s
75 # Filter by project
76 %(prog)s --project SD
78 # For specific user (admin only)
79 %(prog)s --user alice@company.com
81 # JSON output
82 %(prog)s --output json
83 """
84 )
86 parser.add_argument('--project',
87 help='Filter by project key')
88 parser.add_argument('--user',
89 help='Show approvals for specific user (admin only)')
90 parser.add_argument('--output', choices=['text', 'json'], default='text',
91 help='Output format (default: text)')
92 parser.add_argument('--profile',
93 help='JIRA profile to use')
95 parsed_args = parser.parse_args(args)
97 # Get JIRA client
98 jira = get_jira_client(parsed_args.profile)
100 # Build JQL to find requests with pending approvals
101 jql_parts = ['status != Resolved']
103 if parsed_args.project:
104 jql_parts.append(f'project = {parsed_args.project}')
106 # Note: User filtering would require additional JQL or post-filtering
107 # For now, we get all pending approvals and filter by canAnswerApproval
109 jql = ' AND '.join(jql_parts)
111 # Search for requests
112 search_result = jira.search_issues(jql, max_results=100)
114 pending_approvals = []
116 # For each request, check for pending approvals
117 for issue in search_result.get('issues', []):
118 issue_key = issue['key']
119 summary = issue.get('fields', {}).get('summary', '')
121 try:
122 approvals_resp = jira.get_request_approvals(issue_key)
123 approvals = approvals_resp.get('values', [])
125 for approval in approvals:
126 if approval.get('finalDecision') == 'pending':
127 # Check if current user can answer this approval
128 if approval.get('canAnswerApproval', False):
129 pending_approvals.append({
130 'requestKey': issue_key,
131 'approvalId': approval.get('id'),
132 'approvalName': approval.get('name'),
133 'created': approval.get('createdDate'),
134 'summary': summary
135 })
136 except Exception:
137 # Skip requests where we can't get approvals (e.g., permissions)
138 continue
140 # Output
141 if parsed_args.output == 'json':
142 print(json.dumps(pending_approvals, indent=2))
143 else:
144 format_pending_approvals_table(pending_approvals, parsed_args.user)
146 return 0
149if __name__ == '__main__':
150 sys.exit(main())