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 +29 -112
- package/cli.js +41 -128
- package/mcp-server.js +21 -100
- package/package.json +2 -4
- package/zephyr-enterprise-tools.d.ts +30 -117
- package/zephyr-enterprise-tools.js +119 -9
package/README.md
CHANGED
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
# Zephyr Enterprise Tools
|
|
2
2
|
|
|
3
|
-
Comprehensive tools for Zephyr Enterprise —
|
|
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
|
-
>
|
|
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
|
-
>
|
|
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: `
|
|
199
|
-
| `-q, --query <text>` | Keyword query
|
|
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
|
|
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: '
|
|
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:
|
|
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
|
-
│
|
|
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
|
-
|
|
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.
|
|
4
|
-
"description": "Comprehensive Zephyr Enterprise Tools -
|
|
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
|
|
21
|
+
// ─── Configuration ────────────────────────────────────────────────────────────
|
|
29
22
|
|
|
30
|
-
|
|
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 = {}) {
|