Skip to main content
Glama
ado_client.py6.36 kB
"""Azure DevOps API client wrapper.""" import os from typing import Dict, List, Any, Optional from azure.devops.connection import Connection from azure.devops.v7_1.work_item_tracking import WorkItemTrackingClient from azure.devops.v7_1.work_item_tracking.models import JsonPatchOperation from msrest.authentication import BasicAuthentication class ADOClient: """Client for interacting with Azure DevOps API.""" def __init__(self): """Initialize the ADO client with credentials from environment variables.""" self.organization = os.getenv("ADO_ORGANIZATION") self.project = os.getenv("ADO_PROJECT") pat = os.getenv("ADO_PAT") if not all([self.organization, self.project, pat]): raise ValueError( "Missing required environment variables: ADO_ORGANIZATION, ADO_PROJECT, ADO_PAT" ) # Build organization URL organization_url = f"https://dev.azure.com/{self.organization}" # Create connection credentials = BasicAuthentication("", pat) self.connection = Connection(base_url=organization_url, creds=credentials) # Get work item tracking client self.wit_client: WorkItemTrackingClient = self.connection.clients.get_work_item_tracking_client() def get_work_item(self, work_item_id: int) -> Dict[str, Any]: """ Get detailed information about a work item. Args: work_item_id: The ID of the work item to retrieve Returns: Dictionary containing work item details including: - id: Work item ID - title: Work item title - type: Work item type (Bug, Task, User Story, etc.) - state: Current state/status - description: Work item description (HTML) - assigned_to: Person assigned to the work item - created_date: When the work item was created - changed_date: When the work item was last modified - steps_to_reproduce: Steps to reproduce (if applicable for bugs) - comments: List of comments on the work item """ try: # Get the work item with all fields work_item = self.wit_client.get_work_item( id=work_item_id, project=self.project, expand="All" ) fields = work_item.fields # Extract common fields result = { "id": work_item.id, "title": fields.get("System.Title", ""), "type": fields.get("System.WorkItemType", ""), "state": fields.get("System.State", ""), "description": fields.get("System.Description", ""), "assigned_to": fields.get("System.AssignedTo", {}).get("displayName", "Unassigned") if isinstance(fields.get("System.AssignedTo"), dict) else str(fields.get("System.AssignedTo", "Unassigned")), "created_date": str(fields.get("System.CreatedDate", "")), "changed_date": str(fields.get("System.ChangedDate", "")), "created_by": fields.get("System.CreatedBy", {}).get("displayName", "Unknown") if isinstance(fields.get("System.CreatedBy"), dict) else str(fields.get("System.CreatedBy", "Unknown")), "area_path": fields.get("System.AreaPath", ""), "iteration_path": fields.get("System.IterationPath", ""), "tags": fields.get("System.Tags", ""), } # Add steps to reproduce if it exists (common in bugs) if "Microsoft.VSTS.TCM.ReproSteps" in fields: result["steps_to_reproduce"] = fields["Microsoft.VSTS.TCM.ReproSteps"] # Get comments comments = self.get_work_item_comments(work_item_id) result["comments"] = comments result["comment_count"] = len(comments) return result except Exception as e: raise Exception(f"Failed to get work item {work_item_id}: {str(e)}") def get_work_item_comments(self, work_item_id: int) -> List[Dict[str, Any]]: """ Get all comments for a work item. Args: work_item_id: The ID of the work item Returns: List of comment dictionaries with text, author, and date """ try: comments_result = self.wit_client.get_comments( project=self.project, work_item_id=work_item_id ) comments = [] if comments_result and hasattr(comments_result, 'comments'): for comment in comments_result.comments: comments.append({ "text": comment.text, "created_by": comment.created_by.display_name if comment.created_by else "Unknown", "created_date": str(comment.created_date) if comment.created_date else "", }) return comments except Exception as e: # Some work items might not have comments enabled return [] def update_work_item_state(self, work_item_id: int, new_state: str) -> Dict[str, Any]: """ Update the state/status of a work item. Args: work_item_id: The ID of the work item to update new_state: The new state to set (e.g., "Active", "Closed", "Resolved") Returns: Dictionary containing updated work item details """ try: # Create JSON patch document to update the state patch_document = [ JsonPatchOperation( op="add", path="/fields/System.State", value=new_state ) ] # Update the work item updated_work_item = self.wit_client.update_work_item( document=patch_document, id=work_item_id, project=self.project ) # Return updated work item details return self.get_work_item(work_item_id) except Exception as e: raise Exception(f"Failed to update work item {work_item_id} state to '{new_state}': {str(e)}")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Akshay-Quorum2145/ADO-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server