From 1a726ebbe13c5aacc4d029cb2be0d5aaed3a2f47 Mon Sep 17 00:00:00 2001 From: Sivori Date: Sat, 13 Sep 2025 12:20:55 -0500 Subject: [PATCH] feat: add work item status command --- README.md | 16 +++++++++ src/commands/workitem.ts | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/README.md b/README.md index bec071f..70b5f07 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ The CLI uses Azure DevOps Personal Access Tokens (PAT) for authentication: - `ado workitem close ` - Close a work item - `ado workitem reopen ` - Reopen a work item - `ado workitem comment ` - List or add comments on a work item +- `ado workitem status` - Show work items involving the current user ### Pull Requests - `ado pr list --repository ` - List pull requests @@ -127,6 +128,18 @@ ado workitem edit 123 --title "New title" --state "In Progress" ado workitem edit 123 --add-label "urgent,frontend" --area "MyTeam\\UI" ``` +#### Work Item Status +```bash +# Show counts of items involving you +ado workitem status + +# Show detailed table of related items +ado workitem status --table + +# Limit results +ado workitem status --limit 50 +``` + ## Global Options - `-R, --repo ` - Target specific organization/project @@ -139,6 +152,9 @@ ado workitem edit 123 --add-label "urgent,frontend" --area "MyTeam\\UI" # List your assigned work items ado workitem list --assignee @me +# Check work items that mention you or are assigned to you +ado workitem status + # Create a bug with high priority ado workitem create --title "Critical login issue" --type Bug --priority 1 --assignee @me diff --git a/src/commands/workitem.ts b/src/commands/workitem.ts index 8a90454..52a6c0a 100644 --- a/src/commands/workitem.ts +++ b/src/commands/workitem.ts @@ -47,6 +47,28 @@ export function createWorkItemCommand(configManager: ConfigManager): Command { } }); + command + .command('status') + .description('Show work items assigned to, created by, or mentioning the current user') + .option('-L, --limit ', 'Maximum number of items to fetch', '30') + .option('--table', 'Show results in a table instead of grouped counts') + .option('--full', 'Show full titles (no truncation)') + .option('--web', 'Open work items in browser when clicked') + .option('-R, --repo ', 'Target organization/project') + .action(async (options) => { + try { + if (options.repo) { + configManager.setRepository(options.repo); + } + + await authManager.ensureAuthenticated(); + await statusWorkItems(configManager, options); + } catch (error) { + console.error(chalk.red(`Error: ${error}`)); + process.exit(1); + } + }); + command .command('create') .description('Create a new work item') @@ -217,6 +239,50 @@ async function listWorkItems(configManager: ConfigManager, options: ListWorkItem } } +async function statusWorkItems(configManager: ConfigManager, options: any): Promise { + const spinner = ora('Fetching work items...').start(); + + try { + const client = new AdoApiClient(configManager); + const project = configManager.getProject(); + if (!project) { + throw new Error('Project not configured. Use -R organization/project or set default repository.'); + } + + const wiql = buildStatusWiqlQuery(project); + const limit = parseInt(options.limit?.toString() || '30'); + + spinner.text = 'Executing query...'; + const workItems = await client.getWorkItems(wiql, limit); + + spinner.succeed(`Found ${workItems.length} work items`); + + if (workItems.length === 0) { + console.log(chalk.yellow('No work items found matching the criteria.')); + return; + } + + if (options.table) { + displayWorkItems(workItems, options); + } else { + const counts: Record = {}; + workItems.forEach(wi => { + const state = wi.fields['System.State'] || 'Unknown'; + counts[state] = (counts[state] || 0) + 1; + }); + + console.log(''); + console.log(chalk.cyan('Work Item Counts by State:')); + Object.entries(counts).forEach(([state, count]) => { + console.log(`${getStateWithColor(state.toUpperCase())}: ${count}`); + }); + } + } catch (error) { + spinner.fail('Failed to fetch work items'); + throw error; + } +} + function buildWiqlQuery(options: ListWorkItemsOptions, project: string): string { let whereClause = `[System.TeamProject] = '${project}'`; @@ -255,6 +321,11 @@ function buildWiqlQuery(options: ListWorkItemsOptions, project: string): string return `SELECT [System.Id], [System.Title], [System.WorkItemType], [System.State], [System.AssignedTo], [System.CreatedDate] FROM WorkItems WHERE ${whereClause} ORDER BY ${orderBy}`; } +function buildStatusWiqlQuery(project: string): string { + const whereClause = `[System.TeamProject] = '${project}' AND ([System.AssignedTo] = @Me OR [System.CreatedBy] = @Me OR [System.History] CONTAINS @Me)`; + return `SELECT [System.Id], [System.Title], [System.WorkItemType], [System.State], [System.AssignedTo], [System.CreatedDate] FROM WorkItems WHERE ${whereClause} ORDER BY [System.ChangedDate] DESC`; +} + function getOrderByClause(sort: string, order: string): string { const fieldMap: Record = { created: '[System.CreatedDate]',