zephyr-enterprise-tools 1.0.0

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/cli.js ADDED
@@ -0,0 +1,465 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Zephyr Enterprise Tools CLI
5
+ *
6
+ * Run release readiness checks and analytics from the command line.
7
+ *
8
+ * Usage:
9
+ * export ZEPHYR_BASE_URL="https://your-zephyr.com/flex/services/rest/latest"
10
+ * export ZEPHYR_USERNAME="your-username"
11
+ * export ZEPHYR_PASSWORD="your-password"
12
+ *
13
+ * zephyr-tools --project 364 --release 4312
14
+ * zephyr-tools -p 364 -r 4312 -t project-health
15
+ * zephyr-tools -p 364 -r 4312 -t search-tests -q "login"
16
+ */
17
+
18
+ import QualityGates from './zephyr-enterprise-tools.js';
19
+
20
+ // ─── Parse Arguments ──────────────────────────────────────────────────────────
21
+
22
+ function parseArgs() {
23
+ const args = process.argv.slice(2);
24
+ const options = {
25
+ projectId: null,
26
+ releaseId: null,
27
+ tool: 'release-readiness',
28
+ gate: null, // Legacy support
29
+ format: 'table',
30
+ help: false,
31
+ query: '',
32
+ days: 30,
33
+ limit: 50,
34
+ };
35
+
36
+ for (let i = 0; i < args.length; i++) {
37
+ const arg = args[i];
38
+ switch (arg) {
39
+ case '-p':
40
+ case '--project':
41
+ options.projectId = Number(args[++i]);
42
+ break;
43
+ case '-r':
44
+ case '--release':
45
+ options.releaseId = Number(args[++i]);
46
+ break;
47
+ case '-t':
48
+ case '--tool':
49
+ options.tool = args[++i];
50
+ break;
51
+ case '-g':
52
+ case '--gate':
53
+ // Legacy support - map to tool
54
+ options.gate = args[++i];
55
+ break;
56
+ case '-q':
57
+ case '--query':
58
+ options.query = args[++i] || '';
59
+ break;
60
+ case '-d':
61
+ case '--days':
62
+ options.days = parseInt(args[++i], 10) || 30;
63
+ break;
64
+ case '-l':
65
+ case '--limit':
66
+ options.limit = parseInt(args[++i], 10) || 50;
67
+ break;
68
+ case '--json':
69
+ options.format = 'json';
70
+ break;
71
+ case '--table':
72
+ options.format = 'table';
73
+ break;
74
+ case '-h':
75
+ case '--help':
76
+ options.help = true;
77
+ break;
78
+ }
79
+ }
80
+
81
+ // Legacy gate support
82
+ if (options.gate) {
83
+ options.tool = options.gate === 'all' ? 'release-readiness' : options.gate;
84
+ }
85
+
86
+ return options;
87
+ }
88
+
89
+ // ─── Help ─────────────────────────────────────────────────────────────────────
90
+
91
+ function showHelp() {
92
+ console.log(`
93
+ ╔══════════════════════════════════════════════════════════════════════════════╗
94
+ ║ ZEPHYR ENTERPRISE TOOLS CLI v1.0.0 ║
95
+ ╚══════════════════════════════════════════════════════════════════════════════╝
96
+
97
+ USAGE:
98
+ zephyr-tools -p <projectId> -r <releaseId> [options]
99
+
100
+ REQUIRED:
101
+ -p, --project <id> Project ID
102
+ -r, --release <id> Release ID
103
+
104
+ OPTIONS:
105
+ -t, --tool <name> Tool to run (default: release-readiness)
106
+ -q, --query <text> Search query (for search-tests)
107
+ -d, --days <n> Number of days for trends/activity (default: 30)
108
+ -l, --limit <n> Max results to return (default: 50)
109
+ --json Output as JSON
110
+ --table Output as table (default)
111
+ -h, --help Show this help
112
+
113
+ AVAILABLE TOOLS:
114
+ ┌─────────────────────────────────────────────────────────────────────────────┐
115
+ │ RELEASE READINESS (Quality Gates) │
116
+ ├─────────────────────────────────────────────────────────────────────────────┤
117
+ │ release-readiness Run all 4 quality gates (default) │
118
+ │ requirement-coverage Requirement coverage gate only │
119
+ │ test-plan Test plan analysis gate only │
120
+ │ test-execution Test execution gate only │
121
+ │ defect-quality Defect quality gate only │
122
+ ├─────────────────────────────────────────────────────────────────────────────┤
123
+ │ ANALYTICS & INSIGHTS │
124
+ ├─────────────────────────────────────────────────────────────────────────────┤
125
+ │ project-health Overall project health score and metrics │
126
+ │ test-coverage Detailed test coverage analysis │
127
+ │ failed-tests List and analyze failed tests │
128
+ │ req-coverage Requirements with/without test coverage │
129
+ │ test-trends Test execution trends over time │
130
+ │ search-tests Search test cases by query │
131
+ │ user-activity User activity and productivity metrics │
132
+ └─────────────────────────────────────────────────────────────────────────────┘
133
+
134
+ ENVIRONMENT VARIABLES:
135
+ ZEPHYR_BASE_URL Zephyr API base URL (required)
136
+ ZEPHYR_USERNAME Username for Basic auth
137
+ ZEPHYR_PASSWORD Password for Basic auth
138
+ ZEPHYR_TOKEN Bearer token (alternative to username/password)
139
+
140
+ EXAMPLES:
141
+ # Run all quality gates (release readiness)
142
+ zephyr-tools -p 364 -r 4312
143
+
144
+ # Check project health
145
+ zephyr-tools -p 364 -r 4312 -t project-health
146
+
147
+ # Get failed tests as JSON
148
+ zephyr-tools -p 364 -r 4312 -t failed-tests --json
149
+
150
+ # Search for test cases containing "login"
151
+ zephyr-tools -p 364 -r 4312 -t search-tests -q "login"
152
+
153
+ # Get test trends for last 14 days
154
+ zephyr-tools -p 364 -r 4312 -t test-trends -d 14
155
+
156
+ # Get user activity report
157
+ zephyr-tools -p 364 -r 4312 -t user-activity
158
+
159
+ QUALITY GATE THRESHOLDS:
160
+ Requirement Coverage: ≥70% = GO
161
+ Test Plan Analysis: <80% = NO GO, 80-90% = CONDITIONAL, ≥90% = GO
162
+ Test Execution: <90% = NO GO, 90-97% = CONDITIONAL, ≥97% = GO
163
+ Defect Quality: Blocker >0 = NO GO, High-risk >10 = NO GO
164
+ `);
165
+ }
166
+
167
+ // ─── Formatters ───────────────────────────────────────────────────────────────
168
+
169
+ function formatTable(report) {
170
+ const { gates, overallStatus, summary, recommendation } = report;
171
+
172
+ const statusIcon = (s) => s === 'GO' ? '🟢' : s === 'CONDITIONAL GO' ? '🟡' : s === 'NO GO' ? '🔴' : '⚪';
173
+
174
+ console.log('\n' + '═'.repeat(80));
175
+ console.log(' RELEASE READINESS REPORT');
176
+ console.log('═'.repeat(80));
177
+ console.log(`Project: ${report.projectId} | Release: ${report.releaseId} | ${report.timestamp}`);
178
+ console.log('─'.repeat(80));
179
+
180
+ console.log('\n┌─────────────────────────┬──────────┬───────────┬─────────────────────────┐');
181
+ console.log('│ Gate │ Score │ Status │ Threshold │');
182
+ console.log('├─────────────────────────┼──────────┼───────────┼─────────────────────────┤');
183
+
184
+ // Gate 1
185
+ const g1 = gates.requirementCoverage;
186
+ console.log(`│ Requirement Coverage │ ${String(g1.coveragePercentage + '%').padEnd(8)} │ ${statusIcon(g1.status)} ${g1.status.padEnd(7)} │ ≥70% coverage │`);
187
+
188
+ // Gate 2
189
+ const g2 = gates.testPlanAnalysis;
190
+ console.log(`│ Test Plan Analysis │ ${String(g2.overallPlanningPercentage + '%').padEnd(8)} │ ${statusIcon(g2.status)} ${g2.status.padEnd(7)} │ ≥90% planned & assigned │`);
191
+
192
+ // Gate 3
193
+ const g3 = gates.testExecution;
194
+ console.log(`│ Test Execution │ ${String(g3.executionPercentage + '%').padEnd(8)} │ ${statusIcon(g3.status)} ${g3.status.padEnd(7)} │ ≥97% executed │`);
195
+
196
+ // Gate 4
197
+ const g4 = gates.defectQuality;
198
+ const defectScore = `${g4.breakdown?.blocker?.count || 0}B/${g4.breakdown?.highRisk?.count || 0}H`;
199
+ console.log(`│ Defect Quality │ ${defectScore.padEnd(8)} │ ${statusIcon(g4.status)} ${g4.status.padEnd(7)} │ 0 blocker, ≤10 high │`);
200
+
201
+ console.log('└─────────────────────────┴──────────┴───────────┴─────────────────────────┘');
202
+
203
+ console.log('\n' + '─'.repeat(80));
204
+ console.log(`OVERALL: ${statusIcon(overallStatus)} ${overallStatus} (${summary.passed}/4 passed, ${summary.failed} failed, ${summary.conditional} conditional)`);
205
+ console.log('─'.repeat(80));
206
+ console.log('\n' + recommendation);
207
+ console.log('\n' + '═'.repeat(80) + '\n');
208
+ }
209
+
210
+ function formatSingleGate(result) {
211
+ const statusIcon = (s) => s === 'GO' ? '🟢' : s === 'CONDITIONAL GO' ? '🟡' : s === 'NO GO' ? '🔴' : '⚪';
212
+
213
+ console.log('\n' + '─'.repeat(60));
214
+ console.log(`${result.gate.toUpperCase()} GATE`);
215
+ console.log('─'.repeat(60));
216
+ console.log(`Status: ${statusIcon(result.status)} ${result.status}`);
217
+ console.log(`Message: ${result.statusMessage}`);
218
+
219
+ if (result.coveragePercentage !== undefined) {
220
+ console.log(`Coverage: ${result.coveragePercentage}% (${result.coveredRequirements}/${result.totalRequirements})`);
221
+ }
222
+ if (result.overallPlanningPercentage !== undefined) {
223
+ console.log(`Planning: ${result.overallPlanningPercentage}%`);
224
+ }
225
+ if (result.executionPercentage !== undefined) {
226
+ console.log(`Execution: ${result.executionPercentage}% (${result.completedTests}/${result.totalPlannedTests})`);
227
+ const b = result.breakdown;
228
+ console.log(`Breakdown: ✅${b.passed} ❌${b.failed} ⏸️${b.blocked} 🔄${b.wip} ⏳${b.notExecuted}`);
229
+ }
230
+ if (result.breakdown?.blocker !== undefined) {
231
+ console.log(`Defects: ${result.breakdown.blocker.count} blocker, ${result.breakdown.highRisk.count} high-risk, ${result.breakdown.lowRisk.count} low-risk`);
232
+ }
233
+ console.log('─'.repeat(60) + '\n');
234
+ }
235
+
236
+ // ─── Generic Result Formatter ─────────────────────────────────────────────────
237
+
238
+ function formatGenericResult(result) {
239
+ const tool = result.tool || 'Result';
240
+ console.log('\n' + '═'.repeat(70));
241
+ console.log(` ${tool.toUpperCase()}`);
242
+ console.log('═'.repeat(70));
243
+ console.log(`Project: ${result.projectId} | Release: ${result.releaseId} | ${result.timestamp}`);
244
+ console.log('─'.repeat(70));
245
+
246
+ // Health score display
247
+ if (result.healthScore !== undefined) {
248
+ const icon = result.healthStatus === 'HEALTHY' ? '🟢' :
249
+ result.healthStatus === 'MODERATE' ? '🟡' :
250
+ result.healthStatus === 'AT RISK' ? '🟠' : '🔴';
251
+ console.log(`\nHealth Score: ${icon} ${result.healthScore}/100 (${result.healthStatus})`);
252
+ }
253
+
254
+ // Summary section
255
+ if (result.summary) {
256
+ console.log('\n📊 SUMMARY:');
257
+ for (const [key, value] of Object.entries(result.summary)) {
258
+ if (typeof value === 'object') continue;
259
+ console.log(` ${formatKey(key)}: ${value}`);
260
+ }
261
+ }
262
+
263
+ // Metrics section
264
+ if (result.metrics) {
265
+ console.log('\n📈 METRICS:');
266
+ for (const [category, metrics] of Object.entries(result.metrics)) {
267
+ console.log(` ${formatKey(category)}:`);
268
+ for (const [key, value] of Object.entries(metrics)) {
269
+ console.log(` ${formatKey(key)}: ${value}`);
270
+ }
271
+ }
272
+ }
273
+
274
+ // Team summary
275
+ if (result.teamSummary) {
276
+ console.log('\n👥 TEAM SUMMARY:');
277
+ for (const [key, value] of Object.entries(result.teamSummary)) {
278
+ console.log(` ${formatKey(key)}: ${value}`);
279
+ }
280
+ }
281
+
282
+ // Users list
283
+ if (result.users && result.users.length > 0) {
284
+ console.log('\n👤 USERS:');
285
+ console.log(' ┌─────────────────────────┬────────┬────────┬────────┬────────┐');
286
+ console.log(' │ User │ Assign │ Exec │ Pass% │ Comp% │');
287
+ console.log(' ├─────────────────────────┼────────┼────────┼────────┼────────┤');
288
+ for (const user of result.users.slice(0, 10)) {
289
+ const name = (user.name || 'Unknown').substring(0, 21).padEnd(23);
290
+ console.log(` │ ${name} │ ${String(user.assigned).padEnd(6)} │ ${String(user.executed).padEnd(6)} │ ${String(user.passRate + '%').padEnd(6)} │ ${String(user.completionRate + '%').padEnd(6)} │`);
291
+ }
292
+ console.log(' └─────────────────────────┴────────┴────────┴────────┴────────┘');
293
+ if (result.users.length > 10) console.log(` ... and ${result.users.length - 10} more users`);
294
+ }
295
+
296
+ // Failed tests list
297
+ if (result.failedTests && result.failedTests.length > 0) {
298
+ console.log('\n❌ FAILED TESTS:');
299
+ for (const test of result.failedTests.slice(0, 15)) {
300
+ console.log(` • [${test.testcaseKey || test.testcaseId}] ${test.testcaseName}`);
301
+ if (test.executedBy) console.log(` Tester: ${test.executedBy}`);
302
+ }
303
+ if (result.failedTests.length > 15) console.log(` ... and ${result.failedTests.length - 15} more failed tests`);
304
+ }
305
+
306
+ // Search results
307
+ if (result.results && Array.isArray(result.results)) {
308
+ console.log(`\n🔍 RESULTS (${result.returned || result.results.length} of ${result.totalMatches || result.results.length}):`);
309
+ for (const item of result.results.slice(0, 15)) {
310
+ console.log(` • [${item.key || item.id}] ${item.name}`);
311
+ if (item.status) console.log(` Status: ${item.status}`);
312
+ }
313
+ if (result.results.length > 15) console.log(` ... and ${result.results.length - 15} more results`);
314
+ }
315
+
316
+ // Daily trends
317
+ if (result.dailyTrends && result.dailyTrends.length > 0) {
318
+ console.log('\n📅 DAILY TRENDS (last 10 days):');
319
+ console.log(' ┌────────────┬───────┬────────┬────────┬─────────┐');
320
+ console.log(' │ Date │ Total │ Passed │ Failed │ Blocked │');
321
+ console.log(' ├────────────┼───────┼────────┼────────┼─────────┤');
322
+ for (const day of result.dailyTrends.slice(-10)) {
323
+ console.log(` │ ${day.date} │ ${String(day.total).padEnd(5)} │ ${String(day.passed).padEnd(6)} │ ${String(day.failed).padEnd(6)} │ ${String(day.blocked).padEnd(7)} │`);
324
+ }
325
+ console.log(' └────────────┴───────┴────────┴────────┴─────────┘');
326
+ }
327
+
328
+ // Recommendations
329
+ if (result.recommendations) {
330
+ console.log('\n💡 RECOMMENDATIONS:');
331
+ for (const rec of result.recommendations) {
332
+ console.log(` • ${rec}`);
333
+ }
334
+ }
335
+
336
+ // Insight
337
+ if (result.insight) {
338
+ console.log(`\n💡 INSIGHT: ${result.insight}`);
339
+ }
340
+
341
+ // Message
342
+ if (result.message) {
343
+ console.log(`\n📝 ${result.message}`);
344
+ }
345
+
346
+ // Status
347
+ if (result.status && !result.healthStatus) {
348
+ const icon = result.status === 'GO' || result.status === 'ADEQUATE' ? '🟢' :
349
+ result.status === 'CONDITIONAL GO' || result.status === 'PARTIAL' ? '🟡' : '🔴';
350
+ console.log(`\nStatus: ${icon} ${result.status}`);
351
+ }
352
+
353
+ console.log('\n' + '═'.repeat(70) + '\n');
354
+ }
355
+
356
+ function formatKey(key) {
357
+ return key
358
+ .replace(/([A-Z])/g, ' $1')
359
+ .replace(/_/g, ' ')
360
+ .replace(/^\w/, c => c.toUpperCase())
361
+ .trim();
362
+ }
363
+
364
+ // ─── Main ─────────────────────────────────────────────────────────────────────
365
+
366
+ async function main() {
367
+ const options = parseArgs();
368
+
369
+ if (options.help) {
370
+ showHelp();
371
+ process.exit(0);
372
+ }
373
+
374
+ if (!options.projectId || !options.releaseId) {
375
+ console.error('Error: --project and --release are required.\n');
376
+ showHelp();
377
+ process.exit(1);
378
+ }
379
+
380
+ try {
381
+ const tools = new QualityGates({
382
+ baseUrl: process.env.ZEPHYR_BASE_URL,
383
+ username: process.env.ZEPHYR_USERNAME,
384
+ password: process.env.ZEPHYR_PASSWORD,
385
+ token: process.env.ZEPHYR_TOKEN,
386
+ });
387
+
388
+ let result;
389
+ const { projectId, releaseId, tool, query, days, limit } = options;
390
+
391
+ switch (tool) {
392
+ // Quality Gates (Release Readiness)
393
+ case 'release-readiness':
394
+ case 'all':
395
+ result = await tools.runAllGates(projectId, releaseId);
396
+ break;
397
+ case 'requirement-coverage':
398
+ result = await tools.requirementCoverageGate(projectId, releaseId);
399
+ break;
400
+ case 'test-plan':
401
+ result = await tools.testPlanAnalysisGate(projectId, releaseId);
402
+ break;
403
+ case 'test-execution':
404
+ result = await tools.testExecutionGate(projectId, releaseId);
405
+ break;
406
+ case 'defect-quality':
407
+ result = await tools.defectQualityGate(projectId, releaseId);
408
+ break;
409
+
410
+ // Analytics & Insights
411
+ case 'project-health':
412
+ result = await tools.getProjectHealth(projectId, releaseId);
413
+ break;
414
+ case 'test-coverage':
415
+ result = await tools.getTestCoverage(projectId, releaseId);
416
+ break;
417
+ case 'failed-tests':
418
+ result = await tools.getFailedTests(projectId, releaseId, { limit });
419
+ break;
420
+ case 'req-coverage':
421
+ result = await tools.getRequirementCoverage(projectId, releaseId);
422
+ break;
423
+ case 'test-trends':
424
+ result = await tools.getTestCaseTrends(projectId, releaseId, { days });
425
+ break;
426
+ case 'search-tests':
427
+ result = await tools.searchTestCases(projectId, releaseId, { query, limit });
428
+ break;
429
+ case 'user-activity':
430
+ result = await tools.getUserActivity(projectId, releaseId, { days });
431
+ break;
432
+
433
+ default:
434
+ console.error(`Unknown tool: ${tool}`);
435
+ console.error('Use --help to see available tools.');
436
+ process.exit(1);
437
+ }
438
+
439
+ if (options.format === 'json') {
440
+ console.log(JSON.stringify(result, null, 2));
441
+ } else {
442
+ // Use appropriate formatter
443
+ if (tool === 'release-readiness' || tool === 'all') {
444
+ formatTable(result);
445
+ } else if (['requirement-coverage', 'test-plan', 'test-execution', 'defect-quality'].includes(tool)) {
446
+ formatSingleGate(result);
447
+ } else {
448
+ formatGenericResult(result);
449
+ }
450
+ }
451
+
452
+ // Exit code based on status
453
+ const status = result.overallStatus || result.status || result.healthStatus;
454
+ if (status === 'NO GO' || status === 'CRITICAL') process.exit(2);
455
+ if (status === 'CONDITIONAL GO' || status === 'AT RISK') process.exit(1);
456
+ process.exit(0);
457
+
458
+ } catch (err) {
459
+ console.error(`Error: ${err.message}`);
460
+ if (process.env.DEBUG) console.error(err.stack);
461
+ process.exit(1);
462
+ }
463
+ }
464
+
465
+ main();
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "zephyr-enterprise-tools",
3
+ "version": "1.0.0",
4
+ "description": "Comprehensive Zephyr Enterprise Tools - Release Readiness, Project Health, Test Analytics & More",
5
+ "main": "zephyr-enterprise-tools.js",
6
+ "exports": {
7
+ ".": "./zephyr-enterprise-tools.js",
8
+ "./cli": "./cli.js"
9
+ },
10
+ "bin": {
11
+ "zephyr-gates": "cli.js",
12
+ "zephyr-tools": "cli.js"
13
+ },
14
+ "type": "module",
15
+ "scripts": {
16
+ "start": "node cli.js",
17
+ "test": "node cli.js --help"
18
+ },
19
+ "keywords": [
20
+ "zephyr",
21
+ "zephyr-enterprise",
22
+ "quality-gates",
23
+ "release-readiness",
24
+ "testing",
25
+ "qa",
26
+ "test-management",
27
+ "test-analytics",
28
+ "project-health",
29
+ "test-coverage",
30
+ "ci-cd",
31
+ "devops",
32
+ "mcp"
33
+ ],
34
+ "author": "Govind Drolia",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/govind1072/zephyr-Enterprise-tools.git"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/govind1072/zephyr-Enterprise-tools/issues"
42
+ },
43
+ "homepage": "https://github.com/govind1072/zephyr-Enterprise-tools#readme",
44
+ "engines": {
45
+ "node": ">=18.0.0"
46
+ },
47
+ "files": [
48
+ "zephyr-enterprise-tools.js",
49
+ "cli.js",
50
+ "README.md",
51
+ "LICENSE"
52
+ ]
53
+ }