zephyr-enterprise-tools 1.3.0 → 1.3.1

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
@@ -11,6 +11,7 @@ Comprehensive tools for Zephyr Enterprise — Release Readiness, Project Health,
11
11
  | Tool | Description | Thresholds |
12
12
  |------|-------------|------------|
13
13
  | `release-readiness` | Run all 4 quality gates | Combined assessment |
14
+ | `compare-releases` | Compare readiness across two releases | MCP/programmatic API |
14
15
  | `requirement-coverage` | Are requirements covered by tests? | ≥70% = GO |
15
16
  | `test-plan` | Are tests planned and assigned? | <80% = NO GO, 80–90% = CONDITIONAL, ≥90% = GO |
16
17
  | `test-execution` | Have tests been executed? | <90% = NO GO, 90–97% = CONDITIONAL, ≥97% = GO |
@@ -28,7 +29,10 @@ Comprehensive tools for Zephyr Enterprise — Release Readiness, Project Health,
28
29
  | `search-tests` | Search test cases by keyword query |
29
30
  | `user-activity` | User activity and productivity metrics |
30
31
  | `user-trend` | Full audit log history for a user — every action across the system, filterable by date range, entity type, and operation |
32
+ | `execution-burnup` | Day-by-day execution burnup (cumulative executed vs ideal and total scope), supports optional date range filtering |
31
33
  | `execution-burndown` | Day-by-day execution burndown (remaining vs ideal), supports optional date range filtering |
34
+ | `list-cycles` | List all test cycles for a release, including phases and execution status counts |
35
+ | `get-cycle` | Get full details for a single test cycle |
32
36
 
33
37
  ---
34
38
 
@@ -66,6 +70,7 @@ Use `zephyr-enterprise-tools` as an MCP (Model Context Protocol) server with you
66
70
  | `list_projects` | _(none)_ | List all Zephyr projects |
67
71
  | `list_releases` | `projectId` | List releases for a project |
68
72
  | `release_readiness` | `projectId`, `releaseId` | Run all 4 quality gates |
73
+ | `compare_releases` | `projectId`, `releaseId1`, `releaseId2`, `query?` _(ZQL)_ | Compare readiness between two releases in the same project |
69
74
  | `requirement_coverage` | `projectId`, `releaseId` | Check requirement coverage |
70
75
  | `test_plan_analysis` | `projectId`, `releaseId`, `query?` _(ZQL)_ | Analyze test planning status — supports ZQL filter e.g. `priority = "P1"` |
71
76
  | `test_execution` | `projectId`, `releaseId` | Check test execution progress |
@@ -77,13 +82,18 @@ Use `zephyr-enterprise-tools` as an MCP (Model Context Protocol) server with you
77
82
  | `search_test_cases` | `projectId`, `releaseId`, `query?`, `limit?` | Search test cases by keyword |
78
83
  | `user_activity` | `projectId`, `releaseId`, `days?` | Get user activity metrics |
79
84
  | `user_trend` | `userName`*, `fromDate?`, `toDate?`, `entity?`, `operation?`, `pageSize?`, `offset?` | Full audit log history for a user |
85
+ | `execution_burnup` | `projectId`, `releaseId`, `startDate?`, `endDate?` | Day-by-day burnup chart data with cumulative executed, ideal, and scope counts |
80
86
  | `execution_burndown` | `projectId`, `releaseId`, `startDate?`, `endDate?` | Day-by-day burndown chart data |
87
+ | `list_cycles` | `releaseId` | List all test cycles for a release, including phases and execution status counts |
88
+ | `get_cycle` | `cycleId` | Get full details for a single test cycle, including phases |
81
89
 
82
90
  > **\* `user_trend` — `userName` must be the user's full email address** (e.g. `jane.doe@yourcompany.com`). Short names or display names will return 0 results. `pageSize` supports up to 1000 records per request.
83
91
 
84
92
  > **`test_plan_analysis` ZQL filter** — Use the `query` parameter to scope results to a specific priority, e.g. `priority = "P1"`. This is the recommended way to filter test plan metrics by priority. Note: `search_test_cases` accepts keyword queries but does not support ZQL priority filtering.
85
93
 
86
- > **`execution_burndown` date range** — Use `startDate` and `endDate` (format: `YYYY-MM-DD`) to scope the burndown to a specific period within the release window.
94
+ > **Execution chart date range** — Use `startDate` and `endDate` (format: `YYYY-MM-DD`) to scope `execution_burnup` and `execution_burndown` to a specific period within the release window.
95
+
96
+ > **Execution status IDs** — Test execution, failed tests, trends, user activity, burnup, burndown, and cycle status counts resolve status IDs from Zephyr v4 system preferences using `testresult.testresultStatus.LOV` from `/admin/preference/all/system`. Built-in IDs are used only as a fallback when the preference cannot be loaded or parsed.
87
97
 
88
98
  ---
89
99
 
@@ -179,6 +189,15 @@ zephyr-enterprise-tools -p 364 -r 4312 -t test-plan -q 'priority = "P1"'
179
189
  # Get trends for last 14 days
180
190
  zephyr-enterprise-tools -p 364 -r 4312 -t test-trends -d 14
181
191
 
192
+ # Get execution burnup chart data
193
+ zephyr-enterprise-tools -p 364 -r 4312 -t execution-burnup --start-date 2026-07-22 --end-date 2026-08-27
194
+
195
+ # List all cycles and phase details for a release
196
+ zephyr-enterprise-tools -p 364 -r 4312 -t list-cycles
197
+
198
+ # Get one cycle by ID
199
+ zephyr-enterprise-tools -p 364 -r 4312 -t get-cycle -c 98765
200
+
182
201
  # Get user audit log (full email required)
183
202
  zephyr-enterprise-tools -t user-trend --user jane.doe@yourcompany.com --page-size 1000
184
203
 
@@ -199,6 +218,7 @@ zephyr-enterprise-tools --help
199
218
  | `-q, --query <text>` | Keyword query (for `search-tests`) or ZQL expression (for `test-plan`) |
200
219
  | `-d, --days <n>` | Days for trends/activity (default: 30) |
201
220
  | `-l, --limit <n>` | Max results (default: 50) |
221
+ | `-c, --cycle <id>` | Cycle ID for `get-cycle` |
202
222
  | `--user <email>` | Full email address for `user-trend` |
203
223
  | `--page-size <n>` | Records per page for `user-trend` (max: 1000) |
204
224
  | `--start-date <YYYY-MM-DD>` | Start date for `execution-burndown` |
@@ -230,6 +250,9 @@ const tools = new ZephyrEnterpriseTools({
230
250
  const report = await tools.runAllGates(364, 4312);
231
251
  console.log(report.overallStatus); // "GO" | "CONDITIONAL GO" | "NO GO"
232
252
 
253
+ const comparison = await tools.compareReleases(364, 4312, 4313, { query: 'priority = "P1"' });
254
+ console.log(comparison.overallStatusChanged); // true when release readiness status changed
255
+
233
256
  // Individual gates
234
257
  const coverage = await tools.requirementCoverageGate(364, 4312);
235
258
  const planning = await tools.testPlanAnalysisGate(364, 4312);
@@ -247,6 +270,14 @@ const reqCoverage = await tools.getRequirementCoverage(364, 4312);
247
270
  const trends = await tools.getTestCaseTrends(364, 4312, { days: 14 });
248
271
  const results = await tools.searchTestCases(364, 4312, { query: 'login' });
249
272
  const activity = await tools.getUserActivity(364, 4312, { days: 30 });
273
+ const cycles = await tools.listCycles(4312);
274
+ const cycle = await tools.getCycle(98765);
275
+
276
+ // Burnup with optional date range
277
+ const burnup = await tools.getExecutionBurnup(364, 4312, {
278
+ startDate: '2026-07-22',
279
+ endDate: '2026-08-27',
280
+ });
250
281
 
251
282
  // User audit log — full email address required; pageSize up to 1000
252
283
  const auditLog = await tools.getUserTrend({
package/cli.js CHANGED
@@ -43,6 +43,8 @@ function parseArgs() {
43
43
  days: 30,
44
44
  limit: 50,
45
45
  cycleId: null,
46
+ startDate: null,
47
+ endDate: null,
46
48
  };
47
49
 
48
50
  for (let i = 0; i < args.length; i++) {
@@ -81,6 +83,12 @@ function parseArgs() {
81
83
  case '--cycle':
82
84
  options.cycleId = Number(args[++i]);
83
85
  break;
86
+ case '--start-date':
87
+ options.startDate = args[++i] || null;
88
+ break;
89
+ case '--end-date':
90
+ options.endDate = args[++i] || null;
91
+ break;
84
92
  case '--json':
85
93
  options.format = 'json';
86
94
  break;
@@ -146,6 +154,8 @@ AVAILABLE TOOLS:
146
154
  │ test-trends Test execution trends over time │
147
155
  │ search-tests Search test cases by query │
148
156
  │ user-activity User activity and productivity metrics │
157
+ │ execution-burnup Day-by-day execution burnup chart │
158
+ │ execution-burndown Day-by-day execution burndown chart │
149
159
  │ list-cycles List all cycles for a release with phase details │
150
160
  │ get-cycle Get full details for one cycle (-c <cycleId>) │
151
161
  └─────────────────────────────────────────────────────────────────────────────┘
@@ -173,6 +183,9 @@ EXAMPLES:
173
183
  # Get user activity report
174
184
  zephyr-tools -p 364 -r 4312 -t user-activity
175
185
 
186
+ # Get execution burnup chart data
187
+ zephyr-tools -p 364 -r 4312 -t execution-burnup --start-date 2026-07-22 --end-date 2026-08-27
188
+
176
189
  # List all cycles and phase details for a release
177
190
  zephyr-tools -p 364 -r 4312 -t list-cycles
178
191
 
@@ -427,6 +440,17 @@ function formatGenericResult(result) {
427
440
  console.log(' └────────────┴───────┴────────┴────────┴─────────┘');
428
441
  }
429
442
 
443
+ if (result.dailyBurnup && result.dailyBurnup.length > 0) {
444
+ console.log('\n📈 DAILY BURNUP (last 10 days):');
445
+ console.log(' ┌────────────┬────────┬────────────┬───────┬───────┐');
446
+ console.log(' │ Date │ Today │ Cumulative │ Ideal │ Scope │');
447
+ console.log(' ├────────────┼────────┼────────────┼───────┼───────┤');
448
+ for (const day of result.dailyBurnup.slice(-10)) {
449
+ console.log(` │ ${day.date} │ ${String(day.executedToday).padEnd(6)} │ ${String(day.cumulativeExecuted).padEnd(10)} │ ${String(day.ideal).padEnd(5)} │ ${String(day.scope).padEnd(5)} │`);
450
+ }
451
+ console.log(' └────────────┴────────┴────────────┴───────┴───────┘');
452
+ }
453
+
430
454
  // Cycles list/detail
431
455
  if (result.cycles && result.cycles.length > 0) {
432
456
  console.log(`\n🔁 CYCLES (${result.total || result.cycles.length}):`);
@@ -568,6 +592,18 @@ async function main() {
568
592
  case 'user-activity':
569
593
  result = await tools.getUserActivity(projectId, releaseId, { days });
570
594
  break;
595
+ case 'execution-burnup':
596
+ result = await tools.getExecutionBurnup(projectId, releaseId, {
597
+ startDate: options.startDate,
598
+ endDate: options.endDate,
599
+ });
600
+ break;
601
+ case 'execution-burndown':
602
+ result = await tools.getExecutionBurndown(projectId, releaseId, {
603
+ startDate: options.startDate,
604
+ endDate: options.endDate,
605
+ });
606
+ break;
571
607
  case 'list-cycles':
572
608
  result = await tools.listCycles(releaseId);
573
609
  break;
package/mcp-server.js CHANGED
@@ -197,6 +197,20 @@ const TOOLS = [
197
197
  required: ['projectId', 'releaseId'],
198
198
  },
199
199
  },
200
+ {
201
+ name: 'execution_burnup',
202
+ description: 'Generate a day-by-day execution burnup chart for a release. Returns cumulative executed vs ideal and total scope counts for charting progress over time.',
203
+ inputSchema: {
204
+ type: 'object',
205
+ properties: {
206
+ projectId: { type: 'number', description: 'Zephyr project ID' },
207
+ releaseId: { type: 'number', description: 'Zephyr release ID' },
208
+ startDate: { type: 'string', description: 'Burnup start date YYYY-MM-DD (default: earliest execution date)' },
209
+ endDate: { type: 'string', description: 'Burnup end date YYYY-MM-DD (default: today)' },
210
+ },
211
+ required: ['projectId', 'releaseId'],
212
+ },
213
+ },
200
214
  {
201
215
  name: 'user_trend',
202
216
  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).',
@@ -374,6 +388,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
374
388
  });
375
389
  break;
376
390
 
391
+ case 'execution_burnup':
392
+ result = await tools.getExecutionBurnup(projectId, releaseId, {
393
+ startDate: args.startDate || null,
394
+ endDate: args.endDate || null,
395
+ });
396
+ break;
397
+
377
398
  case 'user_trend':
378
399
  result = await tools.getUserTrend({
379
400
  userName: args.userName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zephyr-enterprise-tools",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
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",
@@ -221,6 +221,34 @@ export interface ListUsersOptions {
221
221
  pageSize?: number;
222
222
  }
223
223
 
224
+ export interface ExecutionChartOptions {
225
+ startDate?: string | null;
226
+ endDate?: string | null;
227
+ }
228
+
229
+ export interface ExecutionBurnupDay {
230
+ date: string;
231
+ executedToday: number;
232
+ cumulativeExecuted: number;
233
+ remaining: number;
234
+ completionPct: number;
235
+ ideal: number;
236
+ scope: number;
237
+ }
238
+
239
+ export interface ExecutionBurnupResult {
240
+ tool: string;
241
+ projectId: number;
242
+ releaseId: number;
243
+ timestamp: string;
244
+ dateRange?: { from: string; to: string };
245
+ total: number;
246
+ totalPlanned: number;
247
+ summary?: Record<string, unknown>;
248
+ message?: string;
249
+ dailyBurnup: ExecutionBurnupDay[];
250
+ }
251
+
224
252
  export interface ZephyrUser {
225
253
  id: number;
226
254
  fullName: string;
@@ -323,6 +351,8 @@ export declare class QualityGates {
323
351
  getTestCaseTrends(projectId: number, releaseId: number, options?: TrendsOptions): Promise<TestTrendsResult>;
324
352
  searchTestCases(projectId: number, releaseId: number, options?: SearchTestCasesOptions): Promise<SearchTestCasesResult>;
325
353
  getUserActivity(projectId: number, releaseId: number, options?: UserActivityOptions): Promise<UserActivityResult>;
354
+ getExecutionBurndown(projectId: number, releaseId: number, options?: ExecutionChartOptions): Promise<Record<string, unknown>>;
355
+ getExecutionBurnup(projectId: number, releaseId: number, options?: ExecutionChartOptions): Promise<ExecutionBurnupResult>;
326
356
  listUsers(projectId: number, options?: ListUsersOptions): Promise<ListUsersResult>;
327
357
  listCycles(releaseId: number): Promise<ListCyclesResult>;
328
358
  getCycle(cycleId: number): Promise<GetCycleResult>;
@@ -1803,6 +1803,123 @@ export class QualityGates {
1803
1803
  };
1804
1804
  }
1805
1805
 
1806
+ async getExecutionBurnup(projectId, releaseId, options = {}) {
1807
+ const { startDate = null, endDate = null } = options;
1808
+ const statusMap = await this.getTestResultStatusMap();
1809
+
1810
+ const executionsById = new Map();
1811
+ let currentOffset = 0;
1812
+ const pageSize = 10000;
1813
+
1814
+ while (true) {
1815
+ const executionData = await this.GET('/execution', {
1816
+ releaseid: releaseId,
1817
+ offset: currentOffset,
1818
+ pagesize: pageSize,
1819
+ includeanyoneuser: true,
1820
+ });
1821
+ const page = executionData.results || executionData || [];
1822
+
1823
+ if (!Array.isArray(page) || page.length === 0) break;
1824
+
1825
+ const sizeBefore = executionsById.size;
1826
+ for (const exec of page) executionsById.set(exec.id, exec);
1827
+ currentOffset += page.length;
1828
+
1829
+ if (executionsById.size === sizeBefore) break;
1830
+ }
1831
+
1832
+ const executions = [...executionsById.values()];
1833
+ const total = executions.length;
1834
+ const totalPlanned = total;
1835
+
1836
+ if (total === 0) {
1837
+ return {
1838
+ tool: 'Execution Burnup',
1839
+ projectId,
1840
+ releaseId,
1841
+ timestamp: new Date().toISOString(),
1842
+ total: 0,
1843
+ totalPlanned: 0,
1844
+ message: 'No executions found for this release.',
1845
+ dailyBurnup: [],
1846
+ };
1847
+ }
1848
+
1849
+ const allDates = executions
1850
+ .map(e => e.lastModifiedOn || e.createDatetime)
1851
+ .filter(Boolean)
1852
+ .map(d => new Date(d).toISOString().split('T')[0]);
1853
+
1854
+ const rangeStart = startDate || allDates.reduce((a, b) => (a < b ? a : b));
1855
+ const rangeEnd = endDate || new Date().toISOString().split('T')[0];
1856
+
1857
+ const executedByDate = {};
1858
+ for (const exec of executions) {
1859
+ const rawDate = exec.lastModifiedOn || exec.createDatetime;
1860
+ if (!rawDate) continue;
1861
+ const dateKey = new Date(rawDate).toISOString().split('T')[0];
1862
+ if (dateKey < rangeStart || dateKey > rangeEnd) continue;
1863
+ if (!this.isExecutionStatus(exec, statusMap, "unexecuted")) {
1864
+ executedByDate[dateKey] = (executedByDate[dateKey] || 0) + 1;
1865
+ }
1866
+ }
1867
+
1868
+ const days = [];
1869
+ let current = new Date(rangeStart);
1870
+ const end = new Date(rangeEnd);
1871
+ let cumulativeExecuted = 0;
1872
+
1873
+ while (current <= end) {
1874
+ const dateKey = current.toISOString().split('T')[0];
1875
+ const executedToday = executedByDate[dateKey] || 0;
1876
+ cumulativeExecuted += executedToday;
1877
+
1878
+ days.push({
1879
+ date: dateKey,
1880
+ executedToday,
1881
+ cumulativeExecuted,
1882
+ remaining: Math.max(0, total - cumulativeExecuted),
1883
+ completionPct: Math.round((cumulativeExecuted / total) * 100),
1884
+ });
1885
+
1886
+ current.setDate(current.getDate() + 1);
1887
+ }
1888
+
1889
+ const totalDays = days.length;
1890
+ const idealDailyBurnup = totalDays > 1 ? total / (totalDays - 1) : total;
1891
+ const dailyBurnup = days.map((day, i) => ({
1892
+ ...day,
1893
+ ideal: Math.min(total, Math.round(idealDailyBurnup * i)),
1894
+ scope: total,
1895
+ }));
1896
+
1897
+ const lastDay = dailyBurnup[dailyBurnup.length - 1];
1898
+ const behindBy = lastDay.ideal - lastDay.cumulativeExecuted;
1899
+
1900
+ return {
1901
+ tool: 'Execution Burnup',
1902
+ projectId,
1903
+ releaseId,
1904
+ timestamp: new Date().toISOString(),
1905
+ dateRange: { from: rangeStart, to: rangeEnd },
1906
+ total,
1907
+ totalPlanned,
1908
+ summary: {
1909
+ totalExecutions: total,
1910
+ executed: lastDay.cumulativeExecuted,
1911
+ remaining: lastDay.remaining,
1912
+ completionPct: lastDay.completionPct,
1913
+ status: behindBy > 0
1914
+ ? `⚠️ Behind ideal by ${behindBy} tests`
1915
+ : behindBy < 0
1916
+ ? `✅ Ahead of schedule by ${Math.abs(behindBy)} tests`
1917
+ : '✅ On track',
1918
+ },
1919
+ dailyBurnup,
1920
+ };
1921
+ }
1922
+
1806
1923
  // ─── User Trend (Audit Logs) ─────────────────────────────────────────────────
1807
1924
 
1808
1925
  async getUserTrend(options = {}) {