qa360 2.2.6 → 2.2.9
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.
Potentially problematic release.
This version of qa360 might be problematic. Click here for more details.
- package/CHANGELOG.md +28 -0
- package/README.md +79 -0
- package/cli/dist/core/ai/ollama-provider.js +15 -3
- package/cli/dist/core/pack-v2/migrator.d.ts +1 -0
- package/cli/dist/core/pack-v2/migrator.js +25 -0
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/cli/dist/core/core/coverage/analyzer.d.ts +0 -101
- package/cli/dist/core/core/coverage/analyzer.js +0 -415
- package/cli/dist/core/core/coverage/collector.d.ts +0 -74
- package/cli/dist/core/core/coverage/collector.js +0 -459
- package/cli/dist/core/core/coverage/config.d.ts +0 -37
- package/cli/dist/core/core/coverage/config.js +0 -156
- package/cli/dist/core/core/coverage/index.d.ts +0 -11
- package/cli/dist/core/core/coverage/index.js +0 -15
- package/cli/dist/core/core/coverage/types.d.ts +0 -267
- package/cli/dist/core/core/coverage/types.js +0 -6
- package/cli/dist/core/core/coverage/vault.d.ts +0 -95
- package/cli/dist/core/core/coverage/vault.js +0 -405
- package/cli/dist/core/schemas/pack.schema.json +0 -236
- package/cli/dist/schemas/pack.schema.json +0 -236
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to QA360 will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ⚠️ BROKEN VERSIONS - DO NOT USE
|
|
11
|
+
|
|
12
|
+
| Version | Status | Issue | Fixed In |
|
|
13
|
+
|---------|--------|-------|----------|
|
|
14
|
+
| **2.2.4** | 🔴 BROKEN | Published without CI check (CI was failing) | 2.2.6 |
|
|
15
|
+
| **2.2.5** | 🔴 BROKEN | Published without bundle script - missing `cli/dist/core/` | 2.2.6 |
|
|
16
|
+
|
|
17
|
+
**Use version 2.2.6 or later instead.**
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## [2.2.6] - 2025-01-18
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **Critical bundle fix**: Re-ran bundle script correctly before publication
|
|
25
|
+
- `cli/dist/core/` now contains the bundled core engine
|
|
26
|
+
- Imports correctly use `../core/index.js` instead of `qa360-core`
|
|
27
|
+
- Package installation now works correctly
|
|
28
|
+
- **Recovery**: This version fixes the broken 2.2.4 and 2.2.5 releases
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **npm Publication Workflow section** in README with mandatory checklist
|
|
32
|
+
- Documented fatal mistakes from 2.2.4 and 2.2.5 to prevent recurrence
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
8
36
|
## Versioning Convention
|
|
9
37
|
|
|
10
38
|
QA360 uses **Node.js-style versioning** (Major.Minor.Patch).
|
package/README.md
CHANGED
|
@@ -215,6 +215,85 @@ QA360 Core is developed in structured phases:
|
|
|
215
215
|
- **Phase 8**: ✅ TUI & Dashboard (COMPLETE)
|
|
216
216
|
- **Phase 9**: ⏳ Parallel CI → consolidated proof
|
|
217
217
|
|
|
218
|
+
## 🚢 npm Publication Workflow (CRITICAL)
|
|
219
|
+
|
|
220
|
+
> **⚠️ WARNING: Publishing broken packages damages user trust permanently.**
|
|
221
|
+
|
|
222
|
+
### Mandatory Pre-Publication Checklist
|
|
223
|
+
|
|
224
|
+
**NEVER skip these steps - versions 2.2.4 and 2.2.5 were broken due to skipping these:**
|
|
225
|
+
|
|
226
|
+
1. ✅ **CI MUST be green** on both `develop` AND `main`
|
|
227
|
+
2. ✅ **Run bundle script**: `cd cli && bash scripts/bundle-for-npm.sh`
|
|
228
|
+
3. ✅ **Test with npm pack**: `npm pack && tar -tzf qa360-*.tgz | grep "cli/dist/core/index.js"`
|
|
229
|
+
4. ✅ **Test installation**: `cd /tmp && npm install -g ./qa360-*.tgz && qa360 --version`
|
|
230
|
+
5. ✅ **Get EXPLICIT authorization** from maintainer before publishing
|
|
231
|
+
6. ✅ **Publish from MAIN branch only** - NEVER from `develop`
|
|
232
|
+
|
|
233
|
+
### The Fatal Mistakes (DO NOT REPEAT)
|
|
234
|
+
|
|
235
|
+
| Version | Mistake | Result |
|
|
236
|
+
|---------|---------|--------|
|
|
237
|
+
| **2.2.4** | Published without CI check | CI was failing - broken package |
|
|
238
|
+
| **2.2.5** | Published without bundle script | Missing `cli/dist/core/` - completely broken |
|
|
239
|
+
| **2.2.6** | Followed full checklist | ✅ Working package |
|
|
240
|
+
|
|
241
|
+
### Correct Publication Workflow
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# 1. Verify CI is green
|
|
245
|
+
gh run list --branch develop --limit 1
|
|
246
|
+
gh run list --branch main --limit 1
|
|
247
|
+
|
|
248
|
+
# 2. Merge develop to main
|
|
249
|
+
git checkout main
|
|
250
|
+
git merge develop --no-ff
|
|
251
|
+
git push origin main
|
|
252
|
+
|
|
253
|
+
# 3. Wait for CI to pass on main
|
|
254
|
+
gh run watch --branch main
|
|
255
|
+
|
|
256
|
+
# 4. CREATE THE BUNDLE (THIS IS CRITICAL)
|
|
257
|
+
cd cli
|
|
258
|
+
bash scripts/bundle-for-npm.sh
|
|
259
|
+
cd ..
|
|
260
|
+
|
|
261
|
+
# 5. Verify bundle was created
|
|
262
|
+
ls -la cli/dist/core/index.js # Must exist
|
|
263
|
+
grep "from '../core/index.js'" cli/dist/commands/ai.js # Must show this, NOT qa360-core
|
|
264
|
+
|
|
265
|
+
# 6. Test the package locally
|
|
266
|
+
npm pack
|
|
267
|
+
tar -tzf qa360-*.tgz | grep "cli/dist/core/index.js" # Must exist
|
|
268
|
+
cd /tmp && npm install -g /path/to/qa360-*.tgz && qa360 --version
|
|
269
|
+
|
|
270
|
+
# 7. ONLY AFTER ALL TESTS PASS: Get authorization, then publish
|
|
271
|
+
npm version patch # or minor/major
|
|
272
|
+
npm publish --access public
|
|
273
|
+
git push origin main --tags
|
|
274
|
+
|
|
275
|
+
# 8. ALWAYS return to develop
|
|
276
|
+
git checkout develop
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Why the Bundle Script Is Critical
|
|
280
|
+
|
|
281
|
+
The bundle script (`cli/scripts/bundle-for-npm.sh`) does:
|
|
282
|
+
1. Copies `core/src/*` into `cli/src/core/`
|
|
283
|
+
2. Changes imports from `'qa360-core'` to `'../core/index.js'`
|
|
284
|
+
3. Builds TypeScript → `cli/dist/`
|
|
285
|
+
4. **Result**: `cli/dist/core/` contains the bundled core engine
|
|
286
|
+
|
|
287
|
+
**Without this step**: The CLI imports `'qa360-core'` which doesn't exist in the npm package → **COMPLETELY BROKEN**
|
|
288
|
+
|
|
289
|
+
### Recovery from Broken Publication
|
|
290
|
+
|
|
291
|
+
If a broken version is published:
|
|
292
|
+
1. **Fix the issue** on `develop`
|
|
293
|
+
2. **Follow the FULL checklist** above
|
|
294
|
+
3. **Publish a patch version** (e.g., 2.2.5 → 2.2.6)
|
|
295
|
+
4. **Add a warning** in CHANGELOG about broken versions
|
|
296
|
+
|
|
218
297
|
## 🛠️ Technology Stack
|
|
219
298
|
|
|
220
299
|
- **Runtime**: Node.js 18+ with TypeScript 5+
|
|
@@ -32,16 +32,28 @@ export class OllamaProvider {
|
|
|
32
32
|
}
|
|
33
33
|
async isAvailable() {
|
|
34
34
|
try {
|
|
35
|
-
// Use timeout
|
|
35
|
+
// Use a longer timeout (15 seconds) to accommodate slower systems
|
|
36
|
+
// Ollama can take time to respond, especially on first run or with many models
|
|
36
37
|
const controller = new AbortController();
|
|
37
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
38
|
+
const timeoutId = setTimeout(() => controller.abort(), 15000);
|
|
38
39
|
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
39
40
|
signal: controller.signal,
|
|
40
41
|
});
|
|
41
42
|
clearTimeout(timeoutId);
|
|
42
43
|
return response.ok;
|
|
43
44
|
}
|
|
44
|
-
catch {
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Log the error for debugging (will be visible in verbose mode)
|
|
47
|
+
if (error instanceof Error) {
|
|
48
|
+
if (error.name === 'AbortError') {
|
|
49
|
+
// Timeout - Ollama is slow to respond
|
|
50
|
+
console.debug(`[Ollama] Connection to ${this.baseUrl} timed out after 15s`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Other error (ECONNREFUSED, ENOTFOUND, etc.)
|
|
54
|
+
console.debug(`[Ollama] Connection error: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
45
57
|
return false;
|
|
46
58
|
}
|
|
47
59
|
}
|
|
@@ -424,8 +424,33 @@ export class PackMigrator {
|
|
|
424
424
|
}
|
|
425
425
|
/**
|
|
426
426
|
* Sanitize gate name for v2 format
|
|
427
|
+
* Handles both strings and objects (from YAML parsing edge cases)
|
|
427
428
|
*/
|
|
428
429
|
sanitizeGateName(gate) {
|
|
430
|
+
// Handle edge case where gate might be an object from YAML parsing
|
|
431
|
+
if (typeof gate !== 'string') {
|
|
432
|
+
// If gate is an object, try to extract a name
|
|
433
|
+
if (gate && typeof gate === 'object') {
|
|
434
|
+
// Try common property names
|
|
435
|
+
const possibleName = gate.name || gate.id || gate.gate;
|
|
436
|
+
if (typeof possibleName === 'string') {
|
|
437
|
+
gate = possibleName;
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
// Fallback: stringify the object keys
|
|
441
|
+
const keys = Object.keys(gate);
|
|
442
|
+
if (keys.length === 1) {
|
|
443
|
+
gate = keys[0];
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
throw new Error(`Invalid gate format: expected string, got object with keys: ${keys.join(', ')}`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
throw new Error(`Invalid gate format: expected string, got ${typeof gate}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
429
454
|
// Map v1 gate names to v2 conventions
|
|
430
455
|
const nameMap = {
|
|
431
456
|
'api_smoke': 'smoke',
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Coverage Analyzer
|
|
3
|
-
*
|
|
4
|
-
* Analyzes coverage data to provide insights, trends, and recommendations.
|
|
5
|
-
*/
|
|
6
|
-
import type { FileCoverage, CoverageMetrics, CoverageResult, CoverageTrend, CoverageGap, CoverageComparison, CoverageThreshold, CoverageType, CoverageReport } from './types.js';
|
|
7
|
-
/**
|
|
8
|
-
* Historical coverage data point
|
|
9
|
-
*/
|
|
10
|
-
interface HistoricalCoverage {
|
|
11
|
-
runId: string;
|
|
12
|
-
timestamp: number;
|
|
13
|
-
metrics: CoverageMetrics;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Coverage Analyzer class
|
|
17
|
-
*/
|
|
18
|
-
export declare class CoverageAnalyzer {
|
|
19
|
-
private history;
|
|
20
|
-
/**
|
|
21
|
-
* Analyze coverage and generate insights
|
|
22
|
-
*/
|
|
23
|
-
analyze(result: CoverageResult, threshold?: CoverageThreshold): CoverageReport;
|
|
24
|
-
/**
|
|
25
|
-
* Check if coverage meets thresholds
|
|
26
|
-
*/
|
|
27
|
-
checkThresholds(metrics: CoverageMetrics, threshold?: CoverageThreshold): boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Check if a single file meets thresholds
|
|
30
|
-
*/
|
|
31
|
-
checkFileThresholds(file: FileCoverage, threshold?: CoverageThreshold): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Find coverage gaps
|
|
34
|
-
*/
|
|
35
|
-
findGaps(files: Record<string, FileCoverage>, threshold?: CoverageThreshold): CoverageGap[];
|
|
36
|
-
/**
|
|
37
|
-
* Calculate priority for covering a file
|
|
38
|
-
*/
|
|
39
|
-
private calculatePriority;
|
|
40
|
-
/**
|
|
41
|
-
* Estimate effort to cover a file
|
|
42
|
-
*/
|
|
43
|
-
private estimateEffort;
|
|
44
|
-
/**
|
|
45
|
-
* Generate test suggestions for a file
|
|
46
|
-
*/
|
|
47
|
-
private generateSuggestions;
|
|
48
|
-
/**
|
|
49
|
-
* Group consecutive numbers into ranges
|
|
50
|
-
*/
|
|
51
|
-
private groupConsecutiveNumbers;
|
|
52
|
-
/**
|
|
53
|
-
* Get top and bottom files by coverage
|
|
54
|
-
*/
|
|
55
|
-
getTopFiles(files: Record<string, FileCoverage>, limit?: number): Array<{
|
|
56
|
-
path: string;
|
|
57
|
-
coverage: number;
|
|
58
|
-
type: 'best' | 'worst';
|
|
59
|
-
}>;
|
|
60
|
-
/**
|
|
61
|
-
* Compare two coverage results
|
|
62
|
-
*/
|
|
63
|
-
compare(baseResult: CoverageResult, compareResult: CoverageResult): CoverageComparison;
|
|
64
|
-
/**
|
|
65
|
-
* Add historical coverage data
|
|
66
|
-
*/
|
|
67
|
-
addHistory(key: string, data: HistoricalCoverage): void;
|
|
68
|
-
/**
|
|
69
|
-
* Get coverage trends
|
|
70
|
-
*/
|
|
71
|
-
getTrends(key: string, type?: CoverageType, limit?: number): CoverageTrend[];
|
|
72
|
-
/**
|
|
73
|
-
* Calculate trend direction
|
|
74
|
-
*/
|
|
75
|
-
getTrendDirection(trends: CoverageTrend[]): 'improving' | 'stable' | 'declining';
|
|
76
|
-
/**
|
|
77
|
-
* Predict future coverage based on trends
|
|
78
|
-
*/
|
|
79
|
-
predictCoverage(key: string, type: CoverageType | undefined, targetCoverage: number): {
|
|
80
|
-
predictedReach: number | null;
|
|
81
|
-
projectedCoverage: number;
|
|
82
|
-
confidence: 'high' | 'medium' | 'low';
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Generate coverage summary text
|
|
86
|
-
*/
|
|
87
|
-
generateSummary(metrics: CoverageMetrics): string;
|
|
88
|
-
/**
|
|
89
|
-
* Format coverage percentage with color indicator
|
|
90
|
-
*/
|
|
91
|
-
formatCoverage(percentage: number, threshold?: number): string;
|
|
92
|
-
/**
|
|
93
|
-
* Clear history
|
|
94
|
-
*/
|
|
95
|
-
clearHistory(key?: string): void;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Create a coverage analyzer
|
|
99
|
-
*/
|
|
100
|
-
export declare function createCoverageAnalyzer(): CoverageAnalyzer;
|
|
101
|
-
export {};
|