zephyr-enterprise-tools 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,6 +25,7 @@ Comprehensive tools for Zephyr Enterprise - Release Readiness, Project Health, T
25
25
  | `test-trends` | Test execution trends over time |
26
26
  | `search-tests` | Search test cases by query |
27
27
  | `user-activity` | User activity and productivity metrics |
28
+ | `execution-burndown` | Day-by-day execution burndown (remaining vs ideal) |
28
29
 
29
30
  ---
30
31
 
@@ -72,51 +73,48 @@ Use zephyr-enterprise-tools as an MCP (Model Context Protocol) server with your
72
73
  | `test_trends` | Get execution trends over time |
73
74
  | `search_test_cases` | Search test cases by query |
74
75
  | `user_activity` | Get user activity metrics |
76
+ | `execution_burndown` | Day-by-day execution burndown chart data (remaining vs ideal) |
75
77
 
76
- ### VS Code with GitHub Copilot
78
+ ### Claude Desktop
77
79
 
78
- Create or edit `.vscode/mcp.json` in your workspace:
80
+ Edit your `claude_desktop_config.json` file:
79
81
 
80
82
  ```json
81
83
  {
82
- "servers": {
83
- "zephyr-enterprise": {
84
- "type": "stdio",
84
+ "mcpServers": {
85
+ "zephyr": {
85
86
  "command": "npx",
86
- "args": ["-y", "zephyr-enterprise-tools@latest", "mcp"],
87
+ "args": [
88
+ "-y",
89
+ "--package",
90
+ "zephyr-enterprise-tools@latest",
91
+ "zephyr-mcp"
92
+ ],
87
93
  "env": {
88
- "ZEPHYR_BASE_URL": "${input:zephyr_base_url}",
89
- "ZEPHYR_TOKEN": "${input:zephyr_token}"
94
+ "ZEPHYR_BASE_URL": "https://your-zephyr.com/flex/services/rest/latest",
95
+ "ZEPHYR_TOKEN": "your-api-token"
90
96
  }
91
97
  }
92
- },
93
- "inputs": [
94
- {
95
- "id": "zephyr_base_url",
96
- "type": "promptString",
97
- "description": "Zephyr Enterprise API Base URL (e.g. https://your-zephyr.com/flex/services/rest/latest)",
98
- "password": false
99
- },
100
- {
101
- "id": "zephyr_token",
102
- "type": "promptString",
103
- "description": "Zephyr Enterprise API Token",
104
- "password": true
105
- }
106
- ]
98
+ }
107
99
  }
108
100
  ```
109
101
 
110
- ### Cursor
102
+ ### VS Code with GitHub Copilot
111
103
 
112
- Add to your `mcp.json` configuration:
104
+ Create or edit `.vscode/mcp.json` in your workspace:
113
105
 
114
106
  ```json
115
107
  {
116
- "mcpServers": {
117
- "zephyr-enterprise": {
108
+ "servers": {
109
+ "zephyr": {
110
+ "type": "stdio",
118
111
  "command": "npx",
119
- "args": ["-y", "zephyr-enterprise-tools@latest", "mcp"],
112
+ "args": [
113
+ "-y",
114
+ "--package",
115
+ "zephyr-enterprise-tools",
116
+ "zephyr-mcp"
117
+ ],
120
118
  "env": {
121
119
  "ZEPHYR_BASE_URL": "https://your-zephyr.com/flex/services/rest/latest",
122
120
  "ZEPHYR_TOKEN": "your-api-token"
@@ -126,9 +124,9 @@ Add to your `mcp.json` configuration:
126
124
  }
127
125
  ```
128
126
 
129
- ### Claude Desktop
127
+ ### Cursor
130
128
 
131
- Edit your `claude_desktop_config.json` file:
129
+ Add to your `mcp.json` configuration:
132
130
 
133
131
  ```json
134
132
  {
package/mcp-server.js CHANGED
@@ -167,6 +167,20 @@ const TOOLS = [
167
167
  required: ['projectId', 'releaseId'],
168
168
  },
169
169
  },
170
+ {
171
+ name: 'execution_burndown',
172
+ description: 'Generate a day-by-day execution burndown chart for a release. Returns daily remaining vs ideal counts so an AI or chart tool can visualise test execution progress over time.',
173
+ inputSchema: {
174
+ type: 'object',
175
+ properties: {
176
+ projectId: { type: 'number', description: 'Zephyr project ID' },
177
+ releaseId: { type: 'number', description: 'Zephyr release ID' },
178
+ startDate: { type: 'string', description: 'Burndown start date YYYY-MM-DD (default: earliest execution date)' },
179
+ endDate: { type: 'string', description: 'Burndown end date YYYY-MM-DD (default: today)' },
180
+ },
181
+ required: ['projectId', 'releaseId'],
182
+ },
183
+ },
170
184
  {
171
185
  name: 'user_trend',
172
186
  description: 'Get full audit log activity for a user — every action they performed across the system. Filter by date range and optionally by entity type (project or release).',
@@ -300,6 +314,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
300
314
  result = await tools.getUserActivity(projectId, releaseId, { days: args.days || 30 });
301
315
  break;
302
316
 
317
+ case 'execution_burndown':
318
+ result = await tools.getExecutionBurndown(projectId, releaseId, {
319
+ startDate: args.startDate || null,
320
+ endDate: args.endDate || null,
321
+ });
322
+ break;
323
+
303
324
  case 'user_trend':
304
325
  result = await tools.getUserTrend({
305
326
  userName: args.userName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zephyr-enterprise-tools",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Comprehensive Zephyr Enterprise Tools - Release Readiness, Project Health, Test Analytics & More",
5
5
  "main": "zephyr-enterprise-tools.js",
6
6
  "types": "zephyr-enterprise-tools.d.ts",
@@ -1286,6 +1286,111 @@ export class QualityGates {
1286
1286
  };
1287
1287
  }
1288
1288
 
1289
+ // ─── Execution Burndown Chart ────────────────────────────────────────────────
1290
+
1291
+ async getExecutionBurndown(projectId, releaseId, options = {}) {
1292
+ const { startDate = null, endDate = null } = options;
1293
+
1294
+ // Fetch all executions for the release
1295
+ const executionData = await this.GET('/execution', {
1296
+ projectId,
1297
+ releaseId,
1298
+ maxResults: 10000,
1299
+ });
1300
+ const executions = executionData.results || executionData || [];
1301
+ const total = executions.length;
1302
+
1303
+ if (total === 0) {
1304
+ return {
1305
+ tool: 'Execution Burndown',
1306
+ projectId,
1307
+ releaseId,
1308
+ timestamp: new Date().toISOString(),
1309
+ total: 0,
1310
+ message: 'No executions found for this release.',
1311
+ dailyBurndown: [],
1312
+ };
1313
+ }
1314
+
1315
+ // Determine date range
1316
+ const allDates = executions
1317
+ .map(e => e.lastModifiedOn || e.createDatetime)
1318
+ .filter(Boolean)
1319
+ .map(d => new Date(d).toISOString().split('T')[0]);
1320
+
1321
+ const rangeStart = startDate || allDates.reduce((a, b) => (a < b ? a : b));
1322
+ const rangeEnd = endDate || new Date().toISOString().split('T')[0];
1323
+
1324
+ // Build a map of date → how many tests were executed (status changed from unexecuted) on that day
1325
+ const executedByDate = {};
1326
+ for (const exec of executions) {
1327
+ const rawDate = exec.lastModifiedOn || exec.createDatetime;
1328
+ if (!rawDate) continue;
1329
+ const dateKey = new Date(rawDate).toISOString().split('T')[0];
1330
+ if (dateKey < rangeStart || dateKey > rangeEnd) continue;
1331
+ const status = String(exec.lastTestResult?.executionStatus || exec.status || exec.executionStatus || '0');
1332
+ // Count as "executed" if not unexecuted (status 0)
1333
+ if (status !== '0') {
1334
+ executedByDate[dateKey] = (executedByDate[dateKey] || 0) + 1;
1335
+ }
1336
+ }
1337
+
1338
+ // Build daily burndown series — remaining = total unexecuted tests at end of each day
1339
+ const days = [];
1340
+ let current = new Date(rangeStart);
1341
+ const end = new Date(rangeEnd);
1342
+ let cumulativeExecuted = 0;
1343
+
1344
+ while (current <= end) {
1345
+ const dateKey = current.toISOString().split('T')[0];
1346
+ const executedToday = executedByDate[dateKey] || 0;
1347
+ cumulativeExecuted += executedToday;
1348
+ const remaining = Math.max(0, total - cumulativeExecuted);
1349
+
1350
+ days.push({
1351
+ date: dateKey,
1352
+ executedToday,
1353
+ cumulativeExecuted,
1354
+ remaining,
1355
+ completionPct: Math.round((cumulativeExecuted / total) * 100),
1356
+ });
1357
+
1358
+ current.setDate(current.getDate() + 1);
1359
+ }
1360
+
1361
+ // Ideal burndown line (linear from total → 0)
1362
+ const totalDays = days.length;
1363
+ const idealDailyBurn = totalDays > 1 ? total / (totalDays - 1) : total;
1364
+ const dailyBurndown = days.map((day, i) => ({
1365
+ ...day,
1366
+ ideal: Math.max(0, Math.round(total - idealDailyBurn * i)),
1367
+ }));
1368
+
1369
+ const lastDay = dailyBurndown[dailyBurndown.length - 1];
1370
+ const behindBy = lastDay.remaining - lastDay.ideal;
1371
+
1372
+ return {
1373
+ tool: 'Execution Burndown',
1374
+ projectId,
1375
+ releaseId,
1376
+ timestamp: new Date().toISOString(),
1377
+ dateRange: { from: rangeStart, to: rangeEnd },
1378
+ total,
1379
+ summary: {
1380
+ totalExecutions: total,
1381
+ executed: lastDay.cumulativeExecuted,
1382
+ remaining: lastDay.remaining,
1383
+ completionPct: lastDay.completionPct,
1384
+ status: behindBy > 0
1385
+ ? `⚠️ Behind ideal by ${behindBy} tests`
1386
+ : behindBy < 0
1387
+ ? `✅ Ahead of schedule by ${Math.abs(behindBy)} tests`
1388
+ : '✅ On track',
1389
+ },
1390
+ dailyBurndown,
1391
+ };
1392
+ }
1393
+
1289
1394
  // ─── User Trend (Audit Logs) ─────────────────────────────────────────────────
1290
1395
 
1291
1396
  async getUserTrend(options = {}) {