zephyr-enterprise-tools 1.3.0 → 1.3.2

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
@@ -1,21 +1,11 @@
1
1
  # Zephyr Enterprise Tools
2
2
 
3
- Comprehensive tools for Zephyr Enterprise — Release Readiness, Project Health, Test Analytics & More.
3
+ Comprehensive tools for Zephyr Enterprise — Project Health, Test Analytics & More.
4
4
 
5
5
  ---
6
6
 
7
7
  ## 🛠️ Available Tools
8
8
 
9
- ### 🚦 Release Readiness (Quality Gates)
10
-
11
- | Tool | Description | Thresholds |
12
- |------|-------------|------------|
13
- | `release-readiness` | Run all 4 quality gates | Combined assessment |
14
- | `requirement-coverage` | Are requirements covered by tests? | ≥70% = GO |
15
- | `test-plan` | Are tests planned and assigned? | <80% = NO GO, 80–90% = CONDITIONAL, ≥90% = GO |
16
- | `test-execution` | Have tests been executed? | <90% = NO GO, 90–97% = CONDITIONAL, ≥97% = GO |
17
- | `defect-quality` | Are critical defects resolved? | Blocker > 0 = NO GO, High-risk > 10 = NO GO |
18
-
19
9
  ### 📊 Analytics & Insights
20
10
 
21
11
  | Tool | Description |
@@ -28,7 +18,10 @@ Comprehensive tools for Zephyr Enterprise — Release Readiness, Project Health,
28
18
  | `search-tests` | Search test cases by keyword query |
29
19
  | `user-activity` | User activity and productivity metrics |
30
20
  | `user-trend` | Full audit log history for a user — every action across the system, filterable by date range, entity type, and operation |
21
+ | `execution-burnup` | Day-by-day execution burnup (cumulative executed vs ideal and total scope), supports optional date range filtering |
31
22
  | `execution-burndown` | Day-by-day execution burndown (remaining vs ideal), supports optional date range filtering |
23
+ | `list-cycles` | List all test cycles for a release, including phases and execution status counts |
24
+ | `get-cycle` | Get full details for a single test cycle |
32
25
 
33
26
  ---
34
27
 
@@ -65,11 +58,6 @@ Use `zephyr-enterprise-tools` as an MCP (Model Context Protocol) server with you
65
58
  |------|-----------|-------------|
66
59
  | `list_projects` | _(none)_ | List all Zephyr projects |
67
60
  | `list_releases` | `projectId` | List releases for a project |
68
- | `release_readiness` | `projectId`, `releaseId` | Run all 4 quality gates |
69
- | `requirement_coverage` | `projectId`, `releaseId` | Check requirement coverage |
70
- | `test_plan_analysis` | `projectId`, `releaseId`, `query?` _(ZQL)_ | Analyze test planning status — supports ZQL filter e.g. `priority = "P1"` |
71
- | `test_execution` | `projectId`, `releaseId` | Check test execution progress |
72
- | `defect_quality` | `projectId`, `releaseId` | Analyze defect status |
73
61
  | `project_health` | `projectId`, `releaseId` | Get project health score |
74
62
  | `test_coverage` | `projectId`, `releaseId` | Get test coverage details |
75
63
  | `failed_tests` | `projectId`, `releaseId`, `limit?` | List failed tests |
@@ -77,13 +65,16 @@ Use `zephyr-enterprise-tools` as an MCP (Model Context Protocol) server with you
77
65
  | `search_test_cases` | `projectId`, `releaseId`, `query?`, `limit?` | Search test cases by keyword |
78
66
  | `user_activity` | `projectId`, `releaseId`, `days?` | Get user activity metrics |
79
67
  | `user_trend` | `userName`*, `fromDate?`, `toDate?`, `entity?`, `operation?`, `pageSize?`, `offset?` | Full audit log history for a user |
68
+ | `execution_burnup` | `projectId`, `releaseId`, `startDate?`, `endDate?` | Day-by-day burnup chart data with cumulative executed, ideal, and scope counts |
80
69
  | `execution_burndown` | `projectId`, `releaseId`, `startDate?`, `endDate?` | Day-by-day burndown chart data |
70
+ | `list_cycles` | `releaseId` | List all test cycles for a release, including phases and execution status counts |
71
+ | `get_cycle` | `cycleId` | Get full details for a single test cycle, including phases |
81
72
 
82
73
  > **\* `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
74
 
84
- > **`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.
75
+ > **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.
85
76
 
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.
77
+ > **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
78
 
88
79
  ---
89
80
 
@@ -162,9 +153,6 @@ Add to your `mcp.json` configuration:
162
153
  The CLI binary is `zephyr-enterprise-tools`:
163
154
 
164
155
  ```bash
165
- # Run all quality gates (release readiness)
166
- zephyr-enterprise-tools -p <projectId> -r <releaseId>
167
-
168
156
  # Run a specific tool
169
157
  zephyr-enterprise-tools -p 364 -r 4312 -t project-health
170
158
  zephyr-enterprise-tools -p 364 -r 4312 -t failed-tests
@@ -173,12 +161,18 @@ zephyr-enterprise-tools -p 364 -r 4312 -t user-activity
173
161
  # Search test cases by keyword
174
162
  zephyr-enterprise-tools -p 364 -r 4312 -t search-tests -q "login"
175
163
 
176
- # Test plan analysis filtered to P1 priority (ZQL)
177
- zephyr-enterprise-tools -p 364 -r 4312 -t test-plan -q 'priority = "P1"'
178
-
179
164
  # Get trends for last 14 days
180
165
  zephyr-enterprise-tools -p 364 -r 4312 -t test-trends -d 14
181
166
 
167
+ # Get execution burnup chart data
168
+ zephyr-enterprise-tools -p 364 -r 4312 -t execution-burnup --start-date 2026-07-22 --end-date 2026-08-27
169
+
170
+ # List all cycles and phase details for a release
171
+ zephyr-enterprise-tools -p 364 -r 4312 -t list-cycles
172
+
173
+ # Get one cycle by ID
174
+ zephyr-enterprise-tools -p 364 -r 4312 -t get-cycle -c 98765
175
+
182
176
  # Get user audit log (full email required)
183
177
  zephyr-enterprise-tools -t user-trend --user jane.doe@yourcompany.com --page-size 1000
184
178
 
@@ -195,10 +189,11 @@ zephyr-enterprise-tools --help
195
189
  |--------|-------------|
196
190
  | `-p, --project <id>` | Project ID (required for most tools) |
197
191
  | `-r, --release <id>` | Release ID (required for most tools) |
198
- | `-t, --tool <name>` | Tool to run (default: `release-readiness`) |
199
- | `-q, --query <text>` | Keyword query (for `search-tests`) or ZQL expression (for `test-plan`) |
192
+ | `-t, --tool <name>` | Tool to run (default: `project-health`) |
193
+ | `-q, --query <text>` | Keyword query for `search-tests` |
200
194
  | `-d, --days <n>` | Days for trends/activity (default: 30) |
201
195
  | `-l, --limit <n>` | Max results (default: 50) |
196
+ | `-c, --cycle <id>` | Cycle ID for `get-cycle` |
202
197
  | `--user <email>` | Full email address for `user-trend` |
203
198
  | `--page-size <n>` | Records per page for `user-trend` (max: 1000) |
204
199
  | `--start-date <YYYY-MM-DD>` | Start date for `execution-burndown` |
@@ -226,17 +221,6 @@ const tools = new ZephyrEnterpriseTools({
226
221
  token: 'your-api-token',
227
222
  });
228
223
 
229
- // ── Release Readiness ──────────────────────────────────────
230
- const report = await tools.runAllGates(364, 4312);
231
- console.log(report.overallStatus); // "GO" | "CONDITIONAL GO" | "NO GO"
232
-
233
- // Individual gates
234
- const coverage = await tools.requirementCoverageGate(364, 4312);
235
- const planning = await tools.testPlanAnalysisGate(364, 4312);
236
- const planningP1 = await tools.testPlanAnalysisGate(364, 4312, { query: 'priority = "P1"' });
237
- const execution = await tools.testExecutionGate(364, 4312);
238
- const defects = await tools.defectQualityGate(364, 4312);
239
-
240
224
  // ── Analytics & Insights ───────────────────────────────────
241
225
  const health = await tools.getProjectHealth(364, 4312);
242
226
  console.log(health.healthScore); // 0–100
@@ -247,6 +231,14 @@ const reqCoverage = await tools.getRequirementCoverage(364, 4312);
247
231
  const trends = await tools.getTestCaseTrends(364, 4312, { days: 14 });
248
232
  const results = await tools.searchTestCases(364, 4312, { query: 'login' });
249
233
  const activity = await tools.getUserActivity(364, 4312, { days: 30 });
234
+ const cycles = await tools.listCycles(4312);
235
+ const cycle = await tools.getCycle(98765);
236
+
237
+ // Burnup with optional date range
238
+ const burnup = await tools.getExecutionBurnup(364, 4312, {
239
+ startDate: '2026-07-22',
240
+ endDate: '2026-08-27',
241
+ });
250
242
 
251
243
  // User audit log — full email address required; pageSize up to 1000
252
244
  const auditLog = await tools.getUserTrend({
@@ -267,27 +259,6 @@ const burndown = await tools.getExecutionBurndown(364, 4312, {
267
259
 
268
260
  ## 📊 Sample Outputs
269
261
 
270
- ### Release Readiness Report
271
-
272
- ```
273
- ════════════════════════════════════════════════════════════════════════════════
274
- RELEASE READINESS REPORT
275
- ════════════════════════════════════════════════════════════════════════════════
276
- Project: 364 | Release: 4312 | 2026-08-12T10:30:00.000Z
277
- ────────────────────────────────────────────────────────────────────────────────
278
-
279
- ┌─────────────────────────┬──────────┬──────────────────┬─────────────────────────┐
280
- │ Gate │ Score │ Status │ Threshold │
281
- ├─────────────────────────┼──────────┼──────────────────┼─────────────────────────┤
282
- │ Requirement Coverage │ 37.04% │ 🔴 NO GO │ ≥70% coverage │
283
- │ Test Plan Analysis │ 19.53% │ 🔴 NO GO │ ≥90% planned & assigned │
284
- │ Test Execution │ 80% │ 🔴 NO GO │ ≥97% executed │
285
- │ Defect Quality │ 0B / 0H │ 🟢 GO │ 0 blockers, ≤10 high │
286
- └─────────────────────────┴──────────┴──────────────────┴─────────────────────────┘
287
-
288
- OVERALL: 🔴 NO GO (1/4 passed, 3 failed, 0 conditional)
289
- ```
290
-
291
262
  ### Project Health
292
263
 
293
264
  ```
@@ -331,60 +302,6 @@ Health Score: 🟡 65/100 (MODERATE)
331
302
 
332
303
  ## 🔧 CI/CD Integration
333
304
 
334
- ### GitHub Actions
335
-
336
- ```yaml
337
- - name: Check Release Readiness
338
- env:
339
- ZEPHYR_BASE_URL: ${{ secrets.ZEPHYR_BASE_URL }}
340
- ZEPHYR_TOKEN: ${{ secrets.ZEPHYR_TOKEN }}
341
- run: |
342
- npx zephyr-enterprise-tools -p ${{ vars.PROJECT_ID }} -r ${{ vars.RELEASE_ID }} --json > report.json
343
- cat report.json
344
- ```
345
-
346
- ### Jenkins
347
-
348
- ```groovy
349
- stage('Quality Gates') {
350
- environment {
351
- ZEPHYR_BASE_URL = credentials('zephyr-base-url')
352
- ZEPHYR_TOKEN = credentials('zephyr-token')
353
- }
354
- steps {
355
- sh 'npx zephyr-enterprise-tools -p ${PROJECT_ID} -r ${RELEASE_ID}'
356
- }
357
- }
358
- ```
359
-
360
- ---
361
-
362
- ## 📝 Customizing Thresholds
363
-
364
- Edit `quality-gates.js`:
365
-
366
- ```javascript
367
- export const THRESHOLDS = {
368
- requirementCoverage: {
369
- go: 70, // Raise to 80 for stricter coverage requirements
370
- },
371
- testPlanAnalysis: {
372
- noGo: 80,
373
- conditionalGo: 90,
374
- },
375
- testExecution: {
376
- noGo: 90,
377
- conditionalGo: 97,
378
- },
379
- defectQuality: {
380
- blockerLimit: 0,
381
- highRiskLimit: 10, // Lower to 5 for a stricter defect policy
382
- }
383
- };
384
- ```
385
-
386
- ---
387
-
388
305
  ## 🐛 Common Issues
389
306
 
390
307
  | Problem | Cause | Fix |
package/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * Zephyr Enterprise Tools CLI
5
5
  *
6
- * Run release readiness checks and analytics from the command line.
6
+ * Run Zephyr analytics from the command line.
7
7
  *
8
8
  * Usage:
9
9
  * export ZEPHYR_BASE_URL="https://your-zephyr.com/flex/services/rest/latest"
@@ -35,14 +35,15 @@ function parseArgs() {
35
35
  const options = {
36
36
  projectId: null,
37
37
  releaseId: null,
38
- tool: 'release-readiness',
39
- gate: null, // Legacy support
38
+ tool: 'project-health',
40
39
  format: 'table',
41
40
  help: false,
42
41
  query: '',
43
42
  days: 30,
44
43
  limit: 50,
45
44
  cycleId: null,
45
+ startDate: null,
46
+ endDate: null,
46
47
  };
47
48
 
48
49
  for (let i = 0; i < args.length; i++) {
@@ -60,11 +61,6 @@ function parseArgs() {
60
61
  case '--tool':
61
62
  options.tool = args[++i];
62
63
  break;
63
- case '-g':
64
- case '--gate':
65
- // Legacy support - map to tool
66
- options.gate = args[++i];
67
- break;
68
64
  case '-q':
69
65
  case '--query':
70
66
  options.query = args[++i] || '';
@@ -81,6 +77,12 @@ function parseArgs() {
81
77
  case '--cycle':
82
78
  options.cycleId = Number(args[++i]);
83
79
  break;
80
+ case '--start-date':
81
+ options.startDate = args[++i] || null;
82
+ break;
83
+ case '--end-date':
84
+ options.endDate = args[++i] || null;
85
+ break;
84
86
  case '--json':
85
87
  options.format = 'json';
86
88
  break;
@@ -94,11 +96,6 @@ function parseArgs() {
94
96
  }
95
97
  }
96
98
 
97
- // Legacy gate support
98
- if (options.gate) {
99
- options.tool = options.gate === 'all' ? 'release-readiness' : options.gate;
100
- }
101
-
102
99
  return options;
103
100
  }
104
101
 
@@ -118,7 +115,7 @@ REQUIRED:
118
115
  -r, --release <id> Release ID
119
116
 
120
117
  OPTIONS:
121
- -t, --tool <name> Tool to run (default: release-readiness)
118
+ -t, --tool <name> Tool to run (default: project-health)
122
119
  -q, --query <text> Search query (for search-tests)
123
120
  -d, --days <n> Number of days for trends/activity (default: 30)
124
121
  -l, --limit <n> Max results to return (default: 50)
@@ -129,15 +126,7 @@ OPTIONS:
129
126
 
130
127
  AVAILABLE TOOLS:
131
128
  ┌─────────────────────────────────────────────────────────────────────────────┐
132
- │ RELEASE READINESS (Quality Gates) │
133
- ├─────────────────────────────────────────────────────────────────────────────┤
134
- │ release-readiness Run all 4 quality gates (default) │
135
- │ requirement-coverage Requirement coverage gate only │
136
- │ test-plan Test plan analysis gate only │
137
- │ test-execution Test execution gate only │
138
- │ defect-quality Defect quality gate only │
139
- ├─────────────────────────────────────────────────────────────────────────────┤
140
- │ ANALYTICS & INSIGHTS │
129
+ │ AVAILABLE ANALYTICS │
141
130
  ├─────────────────────────────────────────────────────────────────────────────┤
142
131
  │ project-health Overall project health score and metrics │
143
132
  │ test-coverage Detailed test coverage analysis │
@@ -146,6 +135,8 @@ AVAILABLE TOOLS:
146
135
  │ test-trends Test execution trends over time │
147
136
  │ search-tests Search test cases by query │
148
137
  │ user-activity User activity and productivity metrics │
138
+ │ execution-burnup Day-by-day execution burnup chart │
139
+ │ execution-burndown Day-by-day execution burndown chart │
149
140
  │ list-cycles List all cycles for a release with phase details │
150
141
  │ get-cycle Get full details for one cycle (-c <cycleId>) │
151
142
  └─────────────────────────────────────────────────────────────────────────────┘
@@ -155,9 +146,6 @@ ENVIRONMENT VARIABLES:
155
146
  ZEPHYR_TOKEN API token for authentication (required)
156
147
 
157
148
  EXAMPLES:
158
- # Run all quality gates (release readiness)
159
- zephyr-tools -p 364 -r 4312
160
-
161
149
  # Check project health
162
150
  zephyr-tools -p 364 -r 4312 -t project-health
163
151
 
@@ -173,89 +161,18 @@ EXAMPLES:
173
161
  # Get user activity report
174
162
  zephyr-tools -p 364 -r 4312 -t user-activity
175
163
 
164
+ # Get execution burnup chart data
165
+ zephyr-tools -p 364 -r 4312 -t execution-burnup --start-date 2026-07-22 --end-date 2026-08-27
166
+
176
167
  # List all cycles and phase details for a release
177
168
  zephyr-tools -p 364 -r 4312 -t list-cycles
178
169
 
179
170
  # Get a single cycle detail
180
171
  zephyr-tools -p 364 -r 4312 -t get-cycle -c 98765
181
172
 
182
- QUALITY GATE THRESHOLDS:
183
- Requirement Coverage: ≥70% = GO
184
- Test Plan Analysis: <80% = NO GO, 80-90% = CONDITIONAL, ≥90% = GO
185
- Test Execution: <90% = NO GO, 90-97% = CONDITIONAL, ≥97% = GO
186
- Defect Quality: Blocker >0 = NO GO, High-risk >10 = NO GO
187
173
  `);
188
174
  }
189
175
 
190
- // ─── Formatters ───────────────────────────────────────────────────────────────
191
-
192
- function formatTable(report) {
193
- const { gates, overallStatus, summary, recommendation } = report;
194
-
195
- const statusIcon = (s) => s === 'GO' ? '🟢' : s === 'CONDITIONAL GO' ? '🟡' : s === 'NO GO' ? '🔴' : '⚪';
196
-
197
- console.log('\n' + '═'.repeat(80));
198
- console.log(' RELEASE READINESS REPORT');
199
- console.log('═'.repeat(80));
200
- console.log(`Project: ${report.projectId} | Release: ${report.releaseId} | ${report.timestamp}`);
201
- console.log('─'.repeat(80));
202
-
203
- console.log('\n┌─────────────────────────┬──────────┬───────────┬─────────────────────────┐');
204
- console.log('│ Gate │ Score │ Status │ Threshold │');
205
- console.log('├─────────────────────────┼──────────┼───────────┼─────────────────────────┤');
206
-
207
- // Gate 1
208
- const g1 = gates.requirementCoverage;
209
- console.log(`│ Requirement Coverage │ ${String(g1.coveragePercentage + '%').padEnd(8)} │ ${statusIcon(g1.status)} ${g1.status.padEnd(7)} │ ≥70% coverage │`);
210
-
211
- // Gate 2
212
- const g2 = gates.testPlanAnalysis;
213
- console.log(`│ Test Plan Analysis │ ${String(g2.overallPlanningPercentage + '%').padEnd(8)} │ ${statusIcon(g2.status)} ${g2.status.padEnd(7)} │ ≥90% planned & assigned │`);
214
-
215
- // Gate 3
216
- const g3 = gates.testExecution;
217
- console.log(`│ Test Execution │ ${String(g3.executionPercentage + '%').padEnd(8)} │ ${statusIcon(g3.status)} ${g3.status.padEnd(7)} │ ≥97% executed │`);
218
-
219
- // Gate 4
220
- const g4 = gates.defectQuality;
221
- const defectScore = `${g4.breakdown?.blocker?.count || 0}B/${g4.breakdown?.highRisk?.count || 0}H`;
222
- console.log(`│ Defect Quality │ ${defectScore.padEnd(8)} │ ${statusIcon(g4.status)} ${g4.status.padEnd(7)} │ 0 blocker, ≤10 high │`);
223
-
224
- console.log('└─────────────────────────┴──────────┴───────────┴─────────────────────────┘');
225
-
226
- console.log('\n' + '─'.repeat(80));
227
- console.log(`OVERALL: ${statusIcon(overallStatus)} ${overallStatus} (${summary.passed}/4 passed, ${summary.failed} failed, ${summary.conditional} conditional)`);
228
- console.log('─'.repeat(80));
229
- console.log('\n' + recommendation);
230
- console.log('\n' + '═'.repeat(80) + '\n');
231
- }
232
-
233
- function formatSingleGate(result) {
234
- const statusIcon = (s) => s === 'GO' ? '🟢' : s === 'CONDITIONAL GO' ? '🟡' : s === 'NO GO' ? '🔴' : '⚪';
235
-
236
- console.log('\n' + '─'.repeat(60));
237
- console.log(`${result.gate.toUpperCase()} GATE`);
238
- console.log('─'.repeat(60));
239
- console.log(`Status: ${statusIcon(result.status)} ${result.status}`);
240
- console.log(`Message: ${result.statusMessage}`);
241
-
242
- if (result.coveragePercentage !== undefined) {
243
- console.log(`Coverage: ${result.coveragePercentage}% (${result.coveredRequirements}/${result.totalRequirements})`);
244
- }
245
- if (result.overallPlanningPercentage !== undefined) {
246
- console.log(`Planning: ${result.overallPlanningPercentage}%`);
247
- }
248
- if (result.executionPercentage !== undefined) {
249
- console.log(`Execution: ${result.executionPercentage}% (${result.completedTests}/${result.totalPlannedTests})`);
250
- const b = result.breakdown;
251
- console.log(`Breakdown: ✅${b.passed} ❌${b.failed} ⏸️${b.blocked} 🔄${b.wip} ⏳${b.notExecuted}`);
252
- }
253
- if (result.breakdown?.blocker !== undefined) {
254
- console.log(`Defects: ${result.breakdown.blocker.count} blocker, ${result.breakdown.highRisk.count} high-risk, ${result.breakdown.lowRisk.count} low-risk`);
255
- }
256
- console.log('─'.repeat(60) + '\n');
257
- }
258
-
259
176
  // ─── Generic Result Formatter ─────────────────────────────────────────────────
260
177
 
261
178
  function formatGenericResult(result) {
@@ -427,6 +344,17 @@ function formatGenericResult(result) {
427
344
  console.log(' └────────────┴───────┴────────┴────────┴─────────┘');
428
345
  }
429
346
 
347
+ if (result.dailyBurnup && result.dailyBurnup.length > 0) {
348
+ console.log('\n📈 DAILY BURNUP (last 10 days):');
349
+ console.log(' ┌────────────┬────────┬────────────┬───────┬───────┐');
350
+ console.log(' │ Date │ Today │ Cumulative │ Ideal │ Scope │');
351
+ console.log(' ├────────────┼────────┼────────────┼───────┼───────┤');
352
+ for (const day of result.dailyBurnup.slice(-10)) {
353
+ console.log(` │ ${day.date} │ ${String(day.executedToday).padEnd(6)} │ ${String(day.cumulativeExecuted).padEnd(10)} │ ${String(day.ideal).padEnd(5)} │ ${String(day.scope).padEnd(5)} │`);
354
+ }
355
+ console.log(' └────────────┴────────┴────────────┴───────┴───────┘');
356
+ }
357
+
430
358
  // Cycles list/detail
431
359
  if (result.cycles && result.cycles.length > 0) {
432
360
  console.log(`\n🔁 CYCLES (${result.total || result.cycles.length}):`);
@@ -528,25 +456,6 @@ async function main() {
528
456
  const { projectId, releaseId, tool, query, days, limit } = options;
529
457
 
530
458
  switch (tool) {
531
- // Quality Gates (Release Readiness)
532
- case 'release-readiness':
533
- case 'all':
534
- result = await tools.runAllGates(projectId, releaseId);
535
- break;
536
- case 'requirement-coverage':
537
- result = await tools.requirementCoverageGate(projectId, releaseId);
538
- break;
539
- case 'test-plan':
540
- result = await tools.testPlanAnalysisGate(projectId, releaseId);
541
- break;
542
- case 'test-execution':
543
- result = await tools.testExecutionGate(projectId, releaseId);
544
- break;
545
- case 'defect-quality':
546
- result = await tools.defectQualityGate(projectId, releaseId);
547
- break;
548
-
549
- // Analytics & Insights
550
459
  case 'project-health':
551
460
  result = await tools.getProjectHealth(projectId, releaseId);
552
461
  break;
@@ -568,6 +477,18 @@ async function main() {
568
477
  case 'user-activity':
569
478
  result = await tools.getUserActivity(projectId, releaseId, { days });
570
479
  break;
480
+ case 'execution-burnup':
481
+ result = await tools.getExecutionBurnup(projectId, releaseId, {
482
+ startDate: options.startDate,
483
+ endDate: options.endDate,
484
+ });
485
+ break;
486
+ case 'execution-burndown':
487
+ result = await tools.getExecutionBurndown(projectId, releaseId, {
488
+ startDate: options.startDate,
489
+ endDate: options.endDate,
490
+ });
491
+ break;
571
492
  case 'list-cycles':
572
493
  result = await tools.listCycles(releaseId);
573
494
  break;
@@ -584,18 +505,10 @@ async function main() {
584
505
  console.error('Use --help to see available tools.');
585
506
  process.exit(1);
586
507
  }
587
-
588
508
  if (options.format === 'json') {
589
509
  console.log(JSON.stringify(result, null, 2));
590
510
  } else {
591
- // Use appropriate formatter
592
- if (tool === 'release-readiness' || tool === 'all') {
593
- formatTable(result);
594
- } else if (['requirement-coverage', 'test-plan', 'test-execution', 'defect-quality'].includes(tool)) {
595
- formatSingleGate(result);
596
- } else {
597
- formatGenericResult(result);
598
- }
511
+ formatGenericResult(result);
599
512
  }
600
513
 
601
514
  // Exit code based on status
package/mcp-server.js CHANGED
@@ -18,82 +18,6 @@ import QualityGates from './zephyr-enterprise-tools.js';
18
18
  // ─── Tool Definitions ─────────────────────────────────────────────────────────
19
19
 
20
20
  const TOOLS = [
21
- {
22
- name: 'release_readiness',
23
- description: 'Run all 4 quality gates with calculation details and action items. Optionally scope Test Plan Analysis to a Zephyr ZQL expression. Returns GO, CONDITIONAL GO, or NO GO status.',
24
- inputSchema: {
25
- type: 'object',
26
- properties: {
27
- projectId: { type: 'number', description: 'Zephyr project ID' },
28
- releaseId: { type: 'number', description: 'Zephyr release ID' },
29
- query: { type: 'string', description: 'Optional Zephyr ZQL expression for Test Plan Analysis, e.g. priority = "P1"' },
30
- },
31
- required: ['projectId', 'releaseId'],
32
- },
33
- },
34
- {
35
- name: 'compare_releases',
36
- description: 'Run release readiness for two releases in the same project and return a side-by-side diff across all 4 gates, including which gate statuses changed and their metric deltas.',
37
- inputSchema: {
38
- type: 'object',
39
- properties: {
40
- projectId: { type: 'number', description: 'Zephyr project ID' },
41
- releaseId1: { type: 'number', description: 'First (baseline) Zephyr release ID' },
42
- releaseId2: { type: 'number', description: 'Second (comparison) Zephyr release ID' },
43
- query: { type: 'string', description: 'Optional Zephyr ZQL expression for Test Plan Analysis, e.g. priority = "P1"' },
44
- },
45
- required: ['projectId', 'releaseId1', 'releaseId2'],
46
- },
47
- },
48
- {
49
- name: 'requirement_coverage',
50
- description: 'Check if requirements are covered by test cases. Threshold: ≥70% = GO.',
51
- inputSchema: {
52
- type: 'object',
53
- properties: {
54
- projectId: { type: 'number', description: 'Zephyr project ID' },
55
- releaseId: { type: 'number', description: 'Zephyr release ID' },
56
- },
57
- required: ['projectId', 'releaseId'],
58
- },
59
- },
60
- {
61
- name: 'test_plan_analysis',
62
- description: 'Analyze test planning status, optionally scoped to testcase IDs returned by a Zephyr ZQL expression. Threshold: <80% = NO GO, 80-90% = CONDITIONAL, ≥90% = GO.',
63
- inputSchema: {
64
- type: 'object',
65
- properties: {
66
- projectId: { type: 'number', description: 'Zephyr project ID' },
67
- releaseId: { type: 'number', description: 'Zephyr release ID' },
68
- query: { type: 'string', description: 'Optional Zephyr ZQL expression, e.g. priority = "P1"' },
69
- },
70
- required: ['projectId', 'releaseId'],
71
- },
72
- },
73
- {
74
- name: 'test_execution',
75
- description: 'Check test execution progress. Threshold: <90% = NO GO, 90-97% = CONDITIONAL, ≥97% = GO.',
76
- inputSchema: {
77
- type: 'object',
78
- properties: {
79
- projectId: { type: 'number', description: 'Zephyr project ID' },
80
- releaseId: { type: 'number', description: 'Zephyr release ID' },
81
- },
82
- required: ['projectId', 'releaseId'],
83
- },
84
- },
85
- {
86
- name: 'defect_quality',
87
- description: 'Analyze defect status. Threshold: Blocker >0 = NO GO, High-risk >10 = NO GO.',
88
- inputSchema: {
89
- type: 'object',
90
- properties: {
91
- projectId: { type: 'number', description: 'Zephyr project ID' },
92
- releaseId: { type: 'number', description: 'Zephyr release ID' },
93
- },
94
- required: ['projectId', 'releaseId'],
95
- },
96
- },
97
21
  {
98
22
  name: 'project_health',
99
23
  description: 'Get overall project health score (0-100) with metrics, team info, releases, and recommendations.',
@@ -197,6 +121,20 @@ const TOOLS = [
197
121
  required: ['projectId', 'releaseId'],
198
122
  },
199
123
  },
124
+ {
125
+ name: 'execution_burnup',
126
+ 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.',
127
+ inputSchema: {
128
+ type: 'object',
129
+ properties: {
130
+ projectId: { type: 'number', description: 'Zephyr project ID' },
131
+ releaseId: { type: 'number', description: 'Zephyr release ID' },
132
+ startDate: { type: 'string', description: 'Burnup start date YYYY-MM-DD (default: earliest execution date)' },
133
+ endDate: { type: 'string', description: 'Burnup end date YYYY-MM-DD (default: today)' },
134
+ },
135
+ required: ['projectId', 'releaseId'],
136
+ },
137
+ },
200
138
  {
201
139
  name: 'user_trend',
202
140
  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).',
@@ -312,30 +250,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
312
250
  const releaseId = args.releaseId;
313
251
 
314
252
  switch (name) {
315
- case 'release_readiness':
316
- result = await tools.runAllGates(projectId, releaseId, { query: args.query });
317
- break;
318
-
319
- case 'compare_releases':
320
- result = await tools.compareReleases(projectId, args.releaseId1, args.releaseId2, { query: args.query });
321
- break;
322
-
323
- case 'requirement_coverage':
324
- result = await tools.requirementCoverageGate(projectId, releaseId);
325
- break;
326
-
327
- case 'test_plan_analysis':
328
- result = await tools.testPlanAnalysisGate(projectId, releaseId, { query: args.query });
329
- break;
330
-
331
- case 'test_execution':
332
- result = await tools.testExecutionGate(projectId, releaseId);
333
- break;
334
-
335
- case 'defect_quality':
336
- result = await tools.defectQualityGate(projectId, releaseId);
337
- break;
338
-
339
253
  case 'project_health':
340
254
  result = await tools.getProjectHealth(projectId, releaseId);
341
255
  break;
@@ -374,6 +288,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
374
288
  });
375
289
  break;
376
290
 
291
+ case 'execution_burnup':
292
+ result = await tools.getExecutionBurnup(projectId, releaseId, {
293
+ startDate: args.startDate || null,
294
+ endDate: args.endDate || null,
295
+ });
296
+ break;
297
+
377
298
  case 'user_trend':
378
299
  result = await tools.getUserTrend({
379
300
  userName: args.userName,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zephyr-enterprise-tools",
3
- "version": "1.3.0",
4
- "description": "Comprehensive Zephyr Enterprise Tools - Release Readiness, Project Health, Test Analytics & More",
3
+ "version": "1.3.2",
4
+ "description": "Comprehensive Zephyr Enterprise Tools - Project Health, Test Analytics & More",
5
5
  "main": "zephyr-enterprise-tools.js",
6
6
  "types": "zephyr-enterprise-tools.d.ts",
7
7
  "exports": {
@@ -29,8 +29,6 @@
29
29
  "keywords": [
30
30
  "zephyr",
31
31
  "zephyr-enterprise",
32
- "quality-gates",
33
- "release-readiness",
34
32
  "testing",
35
33
  "qa",
36
34
  "test-management",
@@ -7,111 +7,8 @@ export interface ZephyrConfig {
7
7
  token?: string;
8
8
  }
9
9
 
10
- export interface ThresholdConfig {
11
- requirementCoverage: { go: number; description: string };
12
- testPlanAnalysis: { noGo: number; conditionalGo: number; description: string };
13
- testExecution: { noGo: number; conditionalGo: number; description: string };
14
- defectQuality: { blockerLimit: number; highRiskLimit: number; description: string };
15
- }
16
-
17
- export type GateStatus = "GO" | "CONDITIONAL GO" | "NO GO";
18
10
  export type HealthStatus = "HEALTHY" | "MODERATE" | "AT RISK" | "CRITICAL";
19
11
 
20
- export interface GateResult {
21
- gate: string;
22
- status: GateStatus;
23
- statusMessage: string;
24
- [key: string]: unknown;
25
- }
26
-
27
- export interface RequirementCoverageResult extends GateResult {
28
- coveragePercentage: number;
29
- coveredRequirements: number;
30
- notCoveredRequirements: number;
31
- totalRequirements: number;
32
- }
33
-
34
- export interface TestPlanResult extends GateResult {
35
- overallPlanningPercentage: number;
36
- totalTests: number;
37
- plannedTests: number;
38
- assignedTests: number;
39
- }
40
-
41
- export interface TestPlanOptions {
42
- /** Optional Zephyr ZQL expression, e.g. `priority = "P1"`. */
43
- query?: string;
44
- }
45
-
46
- export interface TestExecutionResult extends GateResult {
47
- executionPercentage: number;
48
- completedTests: number;
49
- totalPlannedTests: number;
50
- breakdown: {
51
- passed: number;
52
- failed: number;
53
- blocked: number;
54
- wip: number;
55
- notExecuted: number;
56
- };
57
- }
58
-
59
- export interface DefectQualityResult extends GateResult {
60
- totalDefects: number;
61
- breakdown: {
62
- blocker: { count: number; defects: unknown[] };
63
- highRisk: { count: number; defects: unknown[] };
64
- lowRisk: { count: number; defects: unknown[] };
65
- resolved: { count: number };
66
- };
67
- }
68
-
69
- export interface ReleaseReadinessResult {
70
- projectId: number;
71
- releaseId: number;
72
- timestamp: string;
73
- report: {
74
- projectName: string;
75
- releaseName: string;
76
- generatedAt: string;
77
- fileName: string;
78
- };
79
- overallStatus: GateStatus;
80
- summary: { passed: number; failed: number; conditional: number };
81
- details: Record<string, unknown>;
82
- recommendation: string;
83
- gates: {
84
- requirementCoverage: RequirementCoverageResult;
85
- testPlanAnalysis: TestPlanResult;
86
- testExecution: TestExecutionResult;
87
- defectQuality: DefectQualityResult;
88
- };
89
- }
90
-
91
- export interface GateComparison {
92
- metric: string;
93
- releaseA: { status: GateStatus; value: number };
94
- releaseB: { status: GateStatus; value: number };
95
- delta: number;
96
- statusChanged: boolean;
97
- trend: 'improved' | 'regressed' | 'unchanged';
98
- }
99
-
100
- export interface CompareReleasesResult {
101
- projectId: number;
102
- timestamp: string;
103
- query?: string;
104
- releaseA: { releaseId: number; projectName: string; releaseName: string; generatedAt: string; fileName: string; overallStatus: GateStatus };
105
- releaseB: { releaseId: number; projectName: string; releaseName: string; generatedAt: string; fileName: string; overallStatus: GateStatus };
106
- overallStatusChanged: boolean;
107
- gates: {
108
- requirementCoverage: GateComparison;
109
- testPlanAnalysis: GateComparison;
110
- testExecution: GateComparison;
111
- defectQuality: GateComparison;
112
- };
113
- }
114
-
115
12
  export interface ProjectHealthResult {
116
13
  tool: string;
117
14
  projectId: number;
@@ -221,6 +118,34 @@ export interface ListUsersOptions {
221
118
  pageSize?: number;
222
119
  }
223
120
 
121
+ export interface ExecutionChartOptions {
122
+ startDate?: string | null;
123
+ endDate?: string | null;
124
+ }
125
+
126
+ export interface ExecutionBurnupDay {
127
+ date: string;
128
+ executedToday: number;
129
+ cumulativeExecuted: number;
130
+ remaining: number;
131
+ completionPct: number;
132
+ ideal: number;
133
+ scope: number;
134
+ }
135
+
136
+ export interface ExecutionBurnupResult {
137
+ tool: string;
138
+ projectId: number;
139
+ releaseId: number;
140
+ timestamp: string;
141
+ dateRange?: { from: string; to: string };
142
+ total: number;
143
+ totalPlanned: number;
144
+ summary?: Record<string, unknown>;
145
+ message?: string;
146
+ dailyBurnup: ExecutionBurnupDay[];
147
+ }
148
+
224
149
  export interface ZephyrUser {
225
150
  id: number;
226
151
  fullName: string;
@@ -307,14 +232,6 @@ export interface GetCycleResult {
307
232
  export declare class QualityGates {
308
233
  constructor(config: ZephyrConfig);
309
234
 
310
- // Quality Gates (Release Readiness)
311
- requirementCoverageGate(projectId: number, releaseId: number): Promise<RequirementCoverageResult>;
312
- testPlanAnalysisGate(projectId: number, releaseId: number, options?: TestPlanOptions): Promise<TestPlanResult>;
313
- testExecutionGate(projectId: number, releaseId: number): Promise<TestExecutionResult>;
314
- defectQualityGate(projectId: number, releaseId: number): Promise<DefectQualityResult>;
315
- runAllGates(projectId: number, releaseId: number, options?: TestPlanOptions): Promise<ReleaseReadinessResult>;
316
- compareReleases(projectId: number, releaseId1: number, releaseId2: number, options?: TestPlanOptions): Promise<CompareReleasesResult>;
317
-
318
235
  // Analytics & Insights
319
236
  getProjectHealth(projectId: number, releaseId: number): Promise<ProjectHealthResult>;
320
237
  getTestCoverage(projectId: number, releaseId: number): Promise<TestCoverageResult>;
@@ -323,17 +240,13 @@ export declare class QualityGates {
323
240
  getTestCaseTrends(projectId: number, releaseId: number, options?: TrendsOptions): Promise<TestTrendsResult>;
324
241
  searchTestCases(projectId: number, releaseId: number, options?: SearchTestCasesOptions): Promise<SearchTestCasesResult>;
325
242
  getUserActivity(projectId: number, releaseId: number, options?: UserActivityOptions): Promise<UserActivityResult>;
243
+ getExecutionBurndown(projectId: number, releaseId: number, options?: ExecutionChartOptions): Promise<Record<string, unknown>>;
244
+ getExecutionBurnup(projectId: number, releaseId: number, options?: ExecutionChartOptions): Promise<ExecutionBurnupResult>;
326
245
  listUsers(projectId: number, options?: ListUsersOptions): Promise<ListUsersResult>;
327
246
  listCycles(releaseId: number): Promise<ListCyclesResult>;
328
247
  getCycle(cycleId: number): Promise<GetCycleResult>;
329
248
  }
330
249
 
331
- export declare const THRESHOLDS: ThresholdConfig;
332
- export declare const RESOLVED_STATUSES: string[];
333
- export declare const BLOCKER_PRIORITIES: string[];
334
- export declare const HIGH_RISK_PRIORITIES: string[];
335
- export declare const LOW_RISK_PRIORITIES: string[];
336
-
337
250
  /** Alias for QualityGates — kept for backward compatibility */
338
251
  export { QualityGates as ZephyrTools };
339
252
  export default QualityGates;
@@ -3,12 +3,6 @@
3
3
  *
4
4
  * Provides comprehensive tools for Zephyr Enterprise:
5
5
  *
6
- * RELEASE READINESS (Quality Gates):
7
- * 1. Requirement Coverage Gate - Are requirements covered by tests?
8
- * 2. Test Plan Analysis Gate - Are tests planned and assigned?
9
- * 3. Test Execution Gate - Have tests been executed?
10
- * 4. Defect Quality Gate - Are critical defects resolved?
11
- *
12
6
  * ANALYTICS & INSIGHTS:
13
7
  * 5. Project Health - Overall project health metrics
14
8
  * 6. Test Coverage - Detailed test coverage analysis
@@ -21,13 +15,12 @@
21
15
  * Usage:
22
16
  * import { ZephyrTools } from './quality-gates.js';
23
17
  * const tools = new ZephyrTools({ baseUrl, username, password });
24
- * const report = await tools.runAllGates(projectId, releaseId);
25
18
  * const health = await tools.getProjectHealth(projectId, releaseId);
26
19
  */
27
20
 
28
- // ─── Configuration & Thresholds ───────────────────────────────────────────────
21
+ // ─── Configuration ────────────────────────────────────────────────────────────
29
22
 
30
- export const THRESHOLDS = {
23
+ const THRESHOLDS = {
31
24
  requirementCoverage: {
32
25
  go: 70,
33
26
  description: "≥70% coverage = GO, <70% = NO GO"
@@ -1803,6 +1796,123 @@ export class QualityGates {
1803
1796
  };
1804
1797
  }
1805
1798
 
1799
+ async getExecutionBurnup(projectId, releaseId, options = {}) {
1800
+ const { startDate = null, endDate = null } = options;
1801
+ const statusMap = await this.getTestResultStatusMap();
1802
+
1803
+ const executionsById = new Map();
1804
+ let currentOffset = 0;
1805
+ const pageSize = 10000;
1806
+
1807
+ while (true) {
1808
+ const executionData = await this.GET('/execution', {
1809
+ releaseid: releaseId,
1810
+ offset: currentOffset,
1811
+ pagesize: pageSize,
1812
+ includeanyoneuser: true,
1813
+ });
1814
+ const page = executionData.results || executionData || [];
1815
+
1816
+ if (!Array.isArray(page) || page.length === 0) break;
1817
+
1818
+ const sizeBefore = executionsById.size;
1819
+ for (const exec of page) executionsById.set(exec.id, exec);
1820
+ currentOffset += page.length;
1821
+
1822
+ if (executionsById.size === sizeBefore) break;
1823
+ }
1824
+
1825
+ const executions = [...executionsById.values()];
1826
+ const total = executions.length;
1827
+ const totalPlanned = total;
1828
+
1829
+ if (total === 0) {
1830
+ return {
1831
+ tool: 'Execution Burnup',
1832
+ projectId,
1833
+ releaseId,
1834
+ timestamp: new Date().toISOString(),
1835
+ total: 0,
1836
+ totalPlanned: 0,
1837
+ message: 'No executions found for this release.',
1838
+ dailyBurnup: [],
1839
+ };
1840
+ }
1841
+
1842
+ const allDates = executions
1843
+ .map(e => e.lastModifiedOn || e.createDatetime)
1844
+ .filter(Boolean)
1845
+ .map(d => new Date(d).toISOString().split('T')[0]);
1846
+
1847
+ const rangeStart = startDate || allDates.reduce((a, b) => (a < b ? a : b));
1848
+ const rangeEnd = endDate || new Date().toISOString().split('T')[0];
1849
+
1850
+ const executedByDate = {};
1851
+ for (const exec of executions) {
1852
+ const rawDate = exec.lastModifiedOn || exec.createDatetime;
1853
+ if (!rawDate) continue;
1854
+ const dateKey = new Date(rawDate).toISOString().split('T')[0];
1855
+ if (dateKey < rangeStart || dateKey > rangeEnd) continue;
1856
+ if (!this.isExecutionStatus(exec, statusMap, "unexecuted")) {
1857
+ executedByDate[dateKey] = (executedByDate[dateKey] || 0) + 1;
1858
+ }
1859
+ }
1860
+
1861
+ const days = [];
1862
+ let current = new Date(rangeStart);
1863
+ const end = new Date(rangeEnd);
1864
+ let cumulativeExecuted = 0;
1865
+
1866
+ while (current <= end) {
1867
+ const dateKey = current.toISOString().split('T')[0];
1868
+ const executedToday = executedByDate[dateKey] || 0;
1869
+ cumulativeExecuted += executedToday;
1870
+
1871
+ days.push({
1872
+ date: dateKey,
1873
+ executedToday,
1874
+ cumulativeExecuted,
1875
+ remaining: Math.max(0, total - cumulativeExecuted),
1876
+ completionPct: Math.round((cumulativeExecuted / total) * 100),
1877
+ });
1878
+
1879
+ current.setDate(current.getDate() + 1);
1880
+ }
1881
+
1882
+ const totalDays = days.length;
1883
+ const idealDailyBurnup = totalDays > 1 ? total / (totalDays - 1) : total;
1884
+ const dailyBurnup = days.map((day, i) => ({
1885
+ ...day,
1886
+ ideal: Math.min(total, Math.round(idealDailyBurnup * i)),
1887
+ scope: total,
1888
+ }));
1889
+
1890
+ const lastDay = dailyBurnup[dailyBurnup.length - 1];
1891
+ const behindBy = lastDay.ideal - lastDay.cumulativeExecuted;
1892
+
1893
+ return {
1894
+ tool: 'Execution Burnup',
1895
+ projectId,
1896
+ releaseId,
1897
+ timestamp: new Date().toISOString(),
1898
+ dateRange: { from: rangeStart, to: rangeEnd },
1899
+ total,
1900
+ totalPlanned,
1901
+ summary: {
1902
+ totalExecutions: total,
1903
+ executed: lastDay.cumulativeExecuted,
1904
+ remaining: lastDay.remaining,
1905
+ completionPct: lastDay.completionPct,
1906
+ status: behindBy > 0
1907
+ ? `⚠️ Behind ideal by ${behindBy} tests`
1908
+ : behindBy < 0
1909
+ ? `✅ Ahead of schedule by ${Math.abs(behindBy)} tests`
1910
+ : '✅ On track',
1911
+ },
1912
+ dailyBurnup,
1913
+ };
1914
+ }
1915
+
1806
1916
  // ─── User Trend (Audit Logs) ─────────────────────────────────────────────────
1807
1917
 
1808
1918
  async getUserTrend(options = {}) {