create-qa-architect 5.0.1 โ 5.0.6
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/.github/RELEASE_CHECKLIST.md +2 -4
- package/.github/workflows/daily-deploy-check.yml +136 -0
- package/.github/workflows/nightly-gitleaks-verification.yml +1 -1
- package/.github/workflows/release.yml +12 -10
- package/.github/workflows/weekly-audit.yml +173 -0
- package/README.md +4 -4
- package/config/defaults.js +22 -1
- package/config/quality-config.schema.json +1 -1
- package/create-saas-monetization.js +65 -27
- package/docs/ARCHITECTURE.md +0 -1
- package/docs/DEPLOYMENT.md +1 -2
- package/docs/PREFLIGHT_REPORT.md +108 -0
- package/docs/TESTING.md +1 -2
- package/lib/config-validator.js +8 -2
- package/lib/dependency-monitoring-premium.js +21 -19
- package/lib/github-api.js +249 -0
- package/lib/interactive/questions.js +4 -0
- package/lib/license-validator.js +1 -1
- package/lib/licensing.js +9 -9
- package/lib/package-utils.js +9 -8
- package/lib/project-maturity.js +1 -1
- package/lib/template-loader.js +2 -0
- package/lib/ui-helpers.js +2 -1
- package/lib/validation/base-validator.js +5 -1
- package/lib/validation/cache-manager.js +1 -0
- package/lib/validation/config-security.js +5 -4
- package/lib/validation/validation-factory.js +1 -1
- package/lib/yaml-utils.js +15 -10
- package/package.json +12 -9
- package/scripts/check-docs.sh +63 -0
- package/scripts/smart-test-strategy.sh +98 -0
- package/scripts/test-e2e-package.sh +283 -0
- package/scripts/validate-command-patterns.js +112 -0
- package/setup.js +33 -9
- package/templates/scripts/smart-test-strategy.sh +1 -1
package/lib/template-loader.js
CHANGED
|
@@ -126,6 +126,7 @@ class TemplateLoader {
|
|
|
126
126
|
* // Only loads from whitelisted dirs: config/, .github/, lib/
|
|
127
127
|
*/
|
|
128
128
|
async loadTemplates(dir, baseDir = dir, isPackageDir = false) {
|
|
129
|
+
/** @type {Record<string, string>} */
|
|
129
130
|
const templates = {}
|
|
130
131
|
|
|
131
132
|
try {
|
|
@@ -177,6 +178,7 @@ class TemplateLoader {
|
|
|
177
178
|
* @returns {Promise<Object>} Merged template map
|
|
178
179
|
*/
|
|
179
180
|
async mergeTemplates(customDir, defaultsDir) {
|
|
181
|
+
/** @type {Record<string, string>} */
|
|
180
182
|
const merged = {}
|
|
181
183
|
|
|
182
184
|
// Load defaults first (from package directory - restrict to known template dirs)
|
package/lib/ui-helpers.js
CHANGED
|
@@ -55,7 +55,8 @@ function showProgress(message) {
|
|
|
55
55
|
|
|
56
56
|
// Try to use ora for interactive terminals
|
|
57
57
|
try {
|
|
58
|
-
const
|
|
58
|
+
const oraImport = require('ora')
|
|
59
|
+
const ora = /** @type {any} */ (oraImport.default || oraImport)
|
|
59
60
|
return ora(message).start()
|
|
60
61
|
} catch {
|
|
61
62
|
// Fallback if ora not installed (graceful degradation)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Error & {code?: string}} ErrWithCode
|
|
5
|
+
*/
|
|
6
|
+
|
|
3
7
|
/**
|
|
4
8
|
* Base Validator Class
|
|
5
9
|
* Provides common error handling, state management, and validation patterns
|
|
@@ -81,7 +85,7 @@ class BaseValidator {
|
|
|
81
85
|
|
|
82
86
|
/**
|
|
83
87
|
* Format error message for user
|
|
84
|
-
* @param {
|
|
88
|
+
* @param {ErrWithCode} error - The error object
|
|
85
89
|
* @param {string} context - The context
|
|
86
90
|
* @returns {string} Formatted error message
|
|
87
91
|
*/
|
|
@@ -14,6 +14,7 @@ class CacheManager {
|
|
|
14
14
|
options.cacheDir || path.join(process.cwd(), '.create-qa-architect-cache')
|
|
15
15
|
this.ttl = options.ttl || 24 * 60 * 60 * 1000 // Default: 24 hours in milliseconds
|
|
16
16
|
this.enabled = options.enabled !== false // Enable by default
|
|
17
|
+
this.verbose = Boolean(options.verbose)
|
|
17
18
|
|
|
18
19
|
// Ensure cache directory exists
|
|
19
20
|
if (this.enabled) {
|
|
@@ -10,16 +10,17 @@ const { showProgress } = require('../ui-helpers')
|
|
|
10
10
|
|
|
11
11
|
// Pinned gitleaks version for reproducible security scanning
|
|
12
12
|
const GITLEAKS_VERSION = '8.28.0'
|
|
13
|
-
//
|
|
13
|
+
// SHA256 checksums of EXTRACTED BINARIES from gitleaks v8.28.0 release
|
|
14
|
+
// Note: These are checksums of the binary itself, not the tarball/zip archives
|
|
14
15
|
const GITLEAKS_CHECKSUMS = {
|
|
15
16
|
'linux-x64':
|
|
16
|
-
'
|
|
17
|
+
'5fd1b3b0073269484d40078662e921d07427340ab9e6ed526ccd215a565b3298',
|
|
17
18
|
'darwin-x64':
|
|
18
|
-
'
|
|
19
|
+
'cf09ad7a85683d90221db8324f036f23c8c29107145e1fc4a0dffbfa9e89c09a',
|
|
19
20
|
'darwin-arm64':
|
|
20
21
|
'5588b5d942dffa048720f7e6e1d274283219fb5722a2c7564d22e83ba39087d7',
|
|
21
22
|
'win32-x64':
|
|
22
|
-
'
|
|
23
|
+
'54230c22688d19939f316cd3e2e040cd067ece40a3a8c5b684e5110c62ecbf52',
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
package/lib/yaml-utils.js
CHANGED
|
@@ -82,17 +82,22 @@ function convertToYaml(obj, indent = 0) {
|
|
|
82
82
|
if (Array.isArray(obj)) {
|
|
83
83
|
obj.forEach(item => {
|
|
84
84
|
if (typeof item === 'object' && item !== null) {
|
|
85
|
-
// For objects in arrays,
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
yaml +=
|
|
85
|
+
// For objects in arrays, prefix first line with "- " and indent rest
|
|
86
|
+
const entries = Object.entries(item)
|
|
87
|
+
entries.forEach(([key, value], idx) => {
|
|
88
|
+
const safeKey = formatYamlValue(key)
|
|
89
|
+
const prefix = idx === 0 ? `${spaces}- ` : `${spaces} `
|
|
90
|
+
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
yaml += `${prefix}${safeKey}:\n`
|
|
93
|
+
yaml += convertToYaml(value, indent + 4)
|
|
94
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
95
|
+
yaml += `${prefix}${safeKey}:\n`
|
|
96
|
+
yaml += convertToYaml(value, indent + 4)
|
|
97
|
+
} else {
|
|
98
|
+
yaml += `${prefix}${safeKey}: ${formatYamlValue(value)}\n`
|
|
94
99
|
}
|
|
95
|
-
}
|
|
100
|
+
})
|
|
96
101
|
} else {
|
|
97
102
|
yaml += `${spaces}- ${formatYamlValue(item)}\n`
|
|
98
103
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-qa-architect",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.6",
|
|
4
4
|
"description": "QA Architect - Bootstrap quality automation for JavaScript/TypeScript and Python projects with GitHub Actions, pre-commit hooks, linting, formatting, and smart test strategy",
|
|
5
5
|
"main": "setup.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,17 +12,17 @@
|
|
|
12
12
|
"format": "prettier --write .",
|
|
13
13
|
"format:check": "prettier --check .",
|
|
14
14
|
"lint": "eslint . && stylelint \"**/*.{css,scss,sass,less,pcss}\" --allow-empty-input",
|
|
15
|
+
"type-check": "tsc --noEmit",
|
|
15
16
|
"lint:fix": "eslint . --fix && stylelint \"**/*.{css,scss,sass,less,pcss}\" --fix --allow-empty-input",
|
|
16
17
|
"security:audit": "npm audit --audit-level high",
|
|
17
18
|
"security:secrets": "node -e \"const fs=require('fs');const content=fs.readFileSync('package.json','utf8');if(/[\\\"\\'][a-zA-Z0-9+/]{20,}[\\\"\\']/.test(content)){console.error('โ Potential hardcoded secrets in package.json');process.exit(1)}else{console.log('โ
No secrets detected in package.json')}\"",
|
|
18
19
|
"security:config": "node setup.js --security-config",
|
|
19
20
|
"validate:docs": "node setup.js --validate-docs",
|
|
20
|
-
"validate:claude": "node scripts/validate-claude-md.js",
|
|
21
21
|
"validate:comprehensive": "node setup.js --comprehensive --no-markdownlint",
|
|
22
|
-
"validate:all": "npm run validate:comprehensive && npm run security:audit
|
|
22
|
+
"validate:all": "npm run validate:comprehensive && npm run security:audit",
|
|
23
23
|
"validate:pre-push": "npm run test:patterns --if-present && npm run lint && npm run format:check && npm run test:commands --if-present && npm test --if-present",
|
|
24
|
-
"test": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/integration.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/parallel-validation.test.js && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/template-loader.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/real-world-packages.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/real-purchase-flow.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/project-maturity-cli.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-
|
|
25
|
-
"test:unit": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/template-loader.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-
|
|
24
|
+
"test": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/integration.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/parallel-validation.test.js && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/template-loader.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/real-world-packages.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/real-purchase-flow.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/project-maturity-cli.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js && node tests/gitleaks-real-binary-test.js && node tests/tier-enforcement.test.js",
|
|
25
|
+
"test:unit": "export QAA_DEVELOPER=true && node tests/setup.test.js && node tests/error-paths.test.js && node tests/error-messages.test.js && node tests/cache-manager.test.js && node tests/template-loader.test.js && node tests/telemetry.test.js && node tests/error-reporter.test.js && node tests/validation-factory.test.js && node tests/setup-error-coverage.test.js && node tests/licensing.test.js && node tests/security-licensing.test.js && node tests/base-validator.test.js && node tests/dependency-monitoring-basic.test.js && node tests/workflow-validation.test.js && node tests/setup-critical-paths.test.js && node tests/project-maturity.test.js && node tests/package-manager-detection.test.js && node tests/check-docs.test.js && node tests/validate-command-patterns.test.js && node tests/gitleaks-binary-resolution.test.js && node tests/gitleaks-production-checksums.test.js && node tests/gitleaks-checksum-verification.test.js",
|
|
26
26
|
"test:fast": "npm run test:unit",
|
|
27
27
|
"test:medium": "npm run test:fast && npm run test:patterns && npm run test:commands",
|
|
28
28
|
"test:slow": "export QAA_DEVELOPER=true && node tests/python-integration.test.js && node tests/interactive.test.js && node tests/monorepo.test.js && node tests/critical-fixes.test.js && node tests/interactive-routing-fix.test.js && node tests/premium-dependency-monitoring.test.js && node tests/multi-language-dependency-monitoring.test.js && node tests/cli-deps-integration.test.js && node tests/real-world-packages.test.js && node tests/python-detection-sensitivity.test.js && node tests/python-parser-fixes.test.js && node tests/real-purchase-flow.test.js && node tests/project-maturity-cli.test.js && node tests/gitleaks-real-binary-test.js && npm run test:e2e",
|
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
"legal/",
|
|
74
74
|
"marketing/",
|
|
75
75
|
"templates/",
|
|
76
|
+
"scripts/",
|
|
77
|
+
"LICENSE",
|
|
76
78
|
".github/",
|
|
77
79
|
".prettierrc",
|
|
78
80
|
".prettierignore",
|
|
@@ -84,12 +86,12 @@
|
|
|
84
86
|
],
|
|
85
87
|
"repository": {
|
|
86
88
|
"type": "git",
|
|
87
|
-
"url": "git+https://github.com/
|
|
89
|
+
"url": "git+https://github.com/vibebuildlab/qa-architect.git"
|
|
88
90
|
},
|
|
89
91
|
"bugs": {
|
|
90
|
-
"url": "https://github.com/
|
|
92
|
+
"url": "https://github.com/vibebuildlab/qa-architect/issues"
|
|
91
93
|
},
|
|
92
|
-
"homepage": "https://
|
|
94
|
+
"homepage": "https://vibebuildlab.com/tools/qa-architect",
|
|
93
95
|
"engines": {
|
|
94
96
|
"node": ">=20"
|
|
95
97
|
},
|
|
@@ -104,7 +106,9 @@
|
|
|
104
106
|
}
|
|
105
107
|
},
|
|
106
108
|
"devDependencies": {
|
|
109
|
+
"@types/node": "^20",
|
|
107
110
|
"actionlint": "^2.0.6",
|
|
111
|
+
"typescript": "^5",
|
|
108
112
|
"c8": "^10.1.2",
|
|
109
113
|
"eslint": "^9.12.0",
|
|
110
114
|
"eslint-plugin-security": "^3.0.1",
|
|
@@ -121,7 +125,6 @@
|
|
|
121
125
|
},
|
|
122
126
|
"lint-staged": {
|
|
123
127
|
"CLAUDE.md": [
|
|
124
|
-
"node scripts/validate-claude-md.js",
|
|
125
128
|
"prettier --write"
|
|
126
129
|
],
|
|
127
130
|
"config/defaults.js": [
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Documentation consistency checker
|
|
3
|
+
# Run before any release to catch documentation gaps
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "๐ Checking documentation consistency..."
|
|
8
|
+
|
|
9
|
+
# Check version consistency
|
|
10
|
+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
11
|
+
if ! grep -q "## \[$PACKAGE_VERSION\]" CHANGELOG.md; then
|
|
12
|
+
echo "โ CHANGELOG.md missing entry for version $PACKAGE_VERSION"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# Check that setup.js file creation matches README documentation
|
|
17
|
+
echo "๐ Verifying file inventory..."
|
|
18
|
+
|
|
19
|
+
# Extract files created by setup.js
|
|
20
|
+
SETUP_FILES=$(grep -E "writeFileSync.*Path" setup.js | sed -E 's/.*writeFileSync\([^,]+, [^)]+\)//' | wc -l)
|
|
21
|
+
echo "Setup script creates approximately $SETUP_FILES files"
|
|
22
|
+
|
|
23
|
+
# Check for common missing files in README
|
|
24
|
+
MISSING_FILES=()
|
|
25
|
+
|
|
26
|
+
if grep -q "\.nvmrc" setup.js && ! grep -q "\.nvmrc" README.md; then
|
|
27
|
+
MISSING_FILES+=(".nvmrc")
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
if grep -q "\.npmrc" setup.js && ! grep -q "\.npmrc" README.md; then
|
|
31
|
+
MISSING_FILES+=(".npmrc")
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if grep -q "stylelintrc" setup.js && ! grep -q "stylelintrc" README.md; then
|
|
35
|
+
MISSING_FILES+=(".stylelintrc.json")
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if grep -q "lighthouserc" setup.js && ! grep -q "lighthouserc" README.md; then
|
|
39
|
+
MISSING_FILES+=(".lighthouserc.js")
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
if [ ${#MISSING_FILES[@]} -gt 0 ]; then
|
|
43
|
+
echo "โ README.md missing documentation for files:"
|
|
44
|
+
printf ' - %s\n' "${MISSING_FILES[@]}"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Check for Python features if implemented
|
|
49
|
+
if grep -q "Python" setup.js; then
|
|
50
|
+
if ! grep -q "Python" README.md; then
|
|
51
|
+
echo "โ Python features implemented but not documented in README.md"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Security validation is now handled by:
|
|
57
|
+
# - /bs:audit --security command
|
|
58
|
+
# - security-auditor agent
|
|
59
|
+
# - npm audit in CI workflows
|
|
60
|
+
# - gitleaks in pre-push hooks
|
|
61
|
+
echo "๐ Security validation handled by automated tooling (npm audit, gitleaks, CI workflows)"
|
|
62
|
+
|
|
63
|
+
echo "โ
Documentation consistency checks passed!"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Smart Test Strategy - QA Architect
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
echo "๐ง Analyzing changes for optimal test strategy..."
|
|
6
|
+
|
|
7
|
+
# =============================================================================
|
|
8
|
+
# SECURITY: Always run npm audit for critical vulnerabilities (fast, ~2 seconds)
|
|
9
|
+
# =============================================================================
|
|
10
|
+
echo ""
|
|
11
|
+
echo "๐ Running security audit (critical vulnerabilities only)..."
|
|
12
|
+
if npm audit --audit-level=critical --omit=dev 2>/dev/null; then
|
|
13
|
+
echo "โ
No critical vulnerabilities found"
|
|
14
|
+
else
|
|
15
|
+
echo "โ CRITICAL vulnerabilities detected! Fix before pushing."
|
|
16
|
+
echo " Run: npm audit fix"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
# Collect metrics
|
|
22
|
+
CHANGED_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null | wc -l | tr -d ' ')
|
|
23
|
+
CHANGED_LINES=$(git diff --stat HEAD~1..HEAD 2>/dev/null | tail -1 | grep -o '[0-9]* insertions' | grep -o '[0-9]*' || echo "0")
|
|
24
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
25
|
+
HOUR=$(date +%H)
|
|
26
|
+
DAY_OF_WEEK=$(date +%u)
|
|
27
|
+
|
|
28
|
+
# Project-specific high-risk patterns
|
|
29
|
+
HIGH_RISK_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null | grep -E "(setup\.js|lib/.*|templates/.*|config/.*)" || true)
|
|
30
|
+
API_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null | grep -E "api/" || true)
|
|
31
|
+
CONFIG_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null | grep -E "(package\.json|\.env|config)" || true)
|
|
32
|
+
TEST_FILES=$(git diff --name-only HEAD~1..HEAD 2>/dev/null | grep -E "test|spec" || true)
|
|
33
|
+
|
|
34
|
+
# Calculate risk score (0-10)
|
|
35
|
+
RISK_SCORE=0
|
|
36
|
+
|
|
37
|
+
# File-based risk
|
|
38
|
+
[[ -n "$HIGH_RISK_FILES" ]] && RISK_SCORE=$((RISK_SCORE + 4))
|
|
39
|
+
[[ -n "$API_FILES" ]] && RISK_SCORE=$((RISK_SCORE + 2))
|
|
40
|
+
[[ -n "$CONFIG_FILES" ]] && RISK_SCORE=$((RISK_SCORE + 2))
|
|
41
|
+
|
|
42
|
+
# Size-based risk
|
|
43
|
+
[[ $CHANGED_FILES -gt 10 ]] && RISK_SCORE=$((RISK_SCORE + 2))
|
|
44
|
+
[[ $CHANGED_FILES -gt 20 ]] && RISK_SCORE=$((RISK_SCORE + 3))
|
|
45
|
+
[[ $CHANGED_LINES -gt 200 ]] && RISK_SCORE=$((RISK_SCORE + 2))
|
|
46
|
+
|
|
47
|
+
# Branch-based risk
|
|
48
|
+
case $CURRENT_BRANCH in
|
|
49
|
+
main|master|production) RISK_SCORE=$((RISK_SCORE + 3)) ;;
|
|
50
|
+
hotfix/*) RISK_SCORE=$((RISK_SCORE + 4)) ;;
|
|
51
|
+
release/*) RISK_SCORE=$((RISK_SCORE + 2)) ;;
|
|
52
|
+
develop) RISK_SCORE=$((RISK_SCORE + 1)) ;;
|
|
53
|
+
esac
|
|
54
|
+
|
|
55
|
+
# Time pressure adjustment (strip leading zeros)
|
|
56
|
+
HOUR_NUM=$((10#$HOUR))
|
|
57
|
+
if [[ $HOUR_NUM -ge 9 && $HOUR_NUM -le 17 && $DAY_OF_WEEK -le 5 ]]; then
|
|
58
|
+
SPEED_BONUS=true
|
|
59
|
+
else
|
|
60
|
+
SPEED_BONUS=false
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Display analysis
|
|
64
|
+
echo "๐ Analysis Results:"
|
|
65
|
+
echo " ๐ Files: $CHANGED_FILES"
|
|
66
|
+
echo " ๐ Lines: $CHANGED_LINES"
|
|
67
|
+
echo " ๐ฟ Branch: $CURRENT_BRANCH"
|
|
68
|
+
echo " ๐ฏ Risk Score: $RISK_SCORE/10"
|
|
69
|
+
echo " โก Speed Bonus: $SPEED_BONUS"
|
|
70
|
+
echo ""
|
|
71
|
+
|
|
72
|
+
# Decision logic
|
|
73
|
+
# NOTE: test:commands and test:e2e are ALWAYS excluded from pre-push (run in CI only)
|
|
74
|
+
# - test:commands: Takes 60+ seconds, verifies npm scripts work in isolated env
|
|
75
|
+
# - test:e2e: Requires browser/package build, CI has better infrastructure
|
|
76
|
+
# These run in GitHub Actions on every PR and push to main
|
|
77
|
+
|
|
78
|
+
if [[ $RISK_SCORE -ge 7 ]]; then
|
|
79
|
+
echo "๐ด HIGH RISK - Comprehensive validation (pre-push)"
|
|
80
|
+
echo " โข Patterns + unit tests + security audit"
|
|
81
|
+
echo " โข (command + e2e tests run in CI only)"
|
|
82
|
+
npm run test:patterns && npm test && npm run security:audit
|
|
83
|
+
elif [[ $RISK_SCORE -ge 4 ]]; then
|
|
84
|
+
echo "๐ก MEDIUM RISK - Standard validation"
|
|
85
|
+
echo " โข Fast tests + patterns"
|
|
86
|
+
npm run test:patterns && npm run test:fast
|
|
87
|
+
elif [[ $RISK_SCORE -ge 2 || "$SPEED_BONUS" == "false" ]]; then
|
|
88
|
+
echo "๐ข LOW RISK - Fast validation"
|
|
89
|
+
echo " โข Unit tests only"
|
|
90
|
+
npm run test:fast
|
|
91
|
+
else
|
|
92
|
+
echo "โช MINIMAL RISK - Quality checks only"
|
|
93
|
+
echo " โข Lint + format check"
|
|
94
|
+
npm run lint && npm run format:check
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
echo ""
|
|
98
|
+
echo "๐ก Tip: Run 'npm run test:comprehensive' locally for full validation"
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# E2E Package Test - Validates the package works for consumers
|
|
3
|
+
# Catches issues like Codex findings before release
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Use isolated npm cache to avoid permission issues on shared caches
|
|
8
|
+
export npm_config_cache="${npm_config_cache:-$(mktemp -d)}"
|
|
9
|
+
export NPM_CONFIG_CACHE="$npm_config_cache"
|
|
10
|
+
# Disable husky during packaging so pack works in CI/sandboxed environments
|
|
11
|
+
export HUSKY=0
|
|
12
|
+
|
|
13
|
+
echo "๐งช E2E Package Validation Test"
|
|
14
|
+
echo "================================"
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# Colors
|
|
18
|
+
RED='\033[0;31m'
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[1;33m'
|
|
21
|
+
NC='\033[0m' # No Color
|
|
22
|
+
|
|
23
|
+
# Track failures
|
|
24
|
+
FAILURES=0
|
|
25
|
+
|
|
26
|
+
fail() {
|
|
27
|
+
echo -e "${RED}โ $1${NC}"
|
|
28
|
+
FAILURES=$((FAILURES + 1))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pass() {
|
|
32
|
+
echo -e "${GREEN}โ
$1${NC}"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
warn() {
|
|
36
|
+
echo -e "${YELLOW}โ ๏ธ $1${NC}"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# 1. Package Contents Validation
|
|
40
|
+
echo "๐ฆ Step 1: Validating package contents..."
|
|
41
|
+
echo "Running: npm pack (scripts disabled)"
|
|
42
|
+
TARBALL=$(npm pack --ignore-scripts 2>&1 | tail -1)
|
|
43
|
+
|
|
44
|
+
if [ ! -f "$TARBALL" ]; then
|
|
45
|
+
fail "npm pack failed to create tarball"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
pass "Created tarball: $TARBALL"
|
|
50
|
+
|
|
51
|
+
# Extract tarball and check files
|
|
52
|
+
EXTRACT_DIR=$(mktemp -d)
|
|
53
|
+
tar -xzf "$TARBALL" -C "$EXTRACT_DIR"
|
|
54
|
+
PKG_DIR="$EXTRACT_DIR/package"
|
|
55
|
+
|
|
56
|
+
echo " Checking required files in package..."
|
|
57
|
+
REQUIRED_FILES=(
|
|
58
|
+
"setup.js"
|
|
59
|
+
".prettierrc"
|
|
60
|
+
".prettierignore"
|
|
61
|
+
"eslint.config.cjs"
|
|
62
|
+
"eslint.config.ts.cjs"
|
|
63
|
+
".stylelintrc.json"
|
|
64
|
+
".editorconfig"
|
|
65
|
+
".nvmrc"
|
|
66
|
+
"config/defaults.js"
|
|
67
|
+
"lib/validation/index.js"
|
|
68
|
+
".github/workflows/quality.yml"
|
|
69
|
+
)
|
|
70
|
+
# Note: .npmrc is intentionally excluded - npm won't package it anyway (local config only)
|
|
71
|
+
|
|
72
|
+
for file in "${REQUIRED_FILES[@]}"; do
|
|
73
|
+
if [ -f "$PKG_DIR/$file" ] || [ -d "$PKG_DIR/$file" ]; then
|
|
74
|
+
pass " $file"
|
|
75
|
+
else
|
|
76
|
+
fail " Missing required file: $file"
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
# 2. Consumer Installation Simulation
|
|
81
|
+
echo ""
|
|
82
|
+
echo "๐๏ธ Step 2: Simulating consumer installation..."
|
|
83
|
+
TEST_DIR=$(mktemp -d)
|
|
84
|
+
cd "$TEST_DIR"
|
|
85
|
+
|
|
86
|
+
echo " Creating test project..."
|
|
87
|
+
git init -q
|
|
88
|
+
git config user.email "test@example.com"
|
|
89
|
+
git config user.name "Test User"
|
|
90
|
+
|
|
91
|
+
cat > package.json <<'EOF'
|
|
92
|
+
{
|
|
93
|
+
"name": "e2e-test-consumer",
|
|
94
|
+
"version": "1.0.0",
|
|
95
|
+
"description": "E2E test consumer",
|
|
96
|
+
"keywords": ["test"],
|
|
97
|
+
"license": "MIT"
|
|
98
|
+
}
|
|
99
|
+
EOF
|
|
100
|
+
|
|
101
|
+
pass "Test project created"
|
|
102
|
+
|
|
103
|
+
echo " Installing from tarball..."
|
|
104
|
+
npm install "$OLDPWD/$TARBALL" --silent 2>&1 > /dev/null || {
|
|
105
|
+
fail "npm install from tarball failed"
|
|
106
|
+
cd "$OLDPWD"
|
|
107
|
+
rm -rf "$TEST_DIR" "$EXTRACT_DIR"
|
|
108
|
+
rm -f "$TARBALL"
|
|
109
|
+
exit 1
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pass "Package installed"
|
|
113
|
+
|
|
114
|
+
# 3. Run setup
|
|
115
|
+
echo ""
|
|
116
|
+
echo "๐ Step 3: Running setup..."
|
|
117
|
+
SETUP_OUTPUT=$(QAA_DEVELOPER=true node ./node_modules/create-qa-architect/setup.js 2>&1)
|
|
118
|
+
echo "$SETUP_OUTPUT" | grep -q "Setting up Quality Automation" && pass "Setup executed" || fail "Setup failed"
|
|
119
|
+
echo " Setup output:"
|
|
120
|
+
echo "$SETUP_OUTPUT" | head -20
|
|
121
|
+
|
|
122
|
+
# 4. Verify generated files
|
|
123
|
+
echo ""
|
|
124
|
+
echo "๐ Step 4: Verifying generated files..."
|
|
125
|
+
EXPECTED_FILES=(
|
|
126
|
+
".prettierrc"
|
|
127
|
+
".prettierignore"
|
|
128
|
+
"eslint.config.cjs"
|
|
129
|
+
".stylelintrc.json"
|
|
130
|
+
".editorconfig"
|
|
131
|
+
".nvmrc"
|
|
132
|
+
".npmrc"
|
|
133
|
+
".github/workflows/quality.yml"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
for file in "${EXPECTED_FILES[@]}"; do
|
|
137
|
+
if [ -f "$file" ]; then
|
|
138
|
+
pass " Generated: $file"
|
|
139
|
+
else
|
|
140
|
+
fail " Missing generated file: $file"
|
|
141
|
+
fi
|
|
142
|
+
done
|
|
143
|
+
|
|
144
|
+
# 5. Validate package.json modifications
|
|
145
|
+
echo ""
|
|
146
|
+
echo "๐ Step 5: Validating package.json modifications..."
|
|
147
|
+
|
|
148
|
+
if grep -q "\"format\":" package.json; then
|
|
149
|
+
pass " npm scripts added"
|
|
150
|
+
else
|
|
151
|
+
fail " npm scripts not added"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
if grep -q "husky" package.json; then
|
|
155
|
+
pass " devDependencies added"
|
|
156
|
+
else
|
|
157
|
+
fail " devDependencies not added"
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
if grep -q "lint-staged" package.json; then
|
|
161
|
+
pass " lint-staged config added"
|
|
162
|
+
else
|
|
163
|
+
fail " lint-staged config not added"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# 6. Test npm scripts use npx (not node setup.js)
|
|
167
|
+
echo ""
|
|
168
|
+
echo "๐ Step 6: Validating npm scripts use npx..."
|
|
169
|
+
|
|
170
|
+
if grep -q "\"security:config.*npx create-qa-architect" package.json; then
|
|
171
|
+
pass " security:config uses npx"
|
|
172
|
+
else
|
|
173
|
+
fail " security:config doesn't use npx (Codex finding regression!)"
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
if grep -q "\"validate:docs.*npx create-qa-architect" package.json; then
|
|
177
|
+
pass " validate:docs uses npx"
|
|
178
|
+
else
|
|
179
|
+
fail " validate:docs doesn't use npx (Codex finding regression!)"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# 7. Validate workflow doesn't have UNCONDITIONAL setup.js references
|
|
183
|
+
echo ""
|
|
184
|
+
echo "๐ง Step 7: Validating generated workflow..."
|
|
185
|
+
|
|
186
|
+
# The workflow can have conditional references like:
|
|
187
|
+
# if [ -f "setup.js" ]; then
|
|
188
|
+
# node setup.js --something
|
|
189
|
+
# fi
|
|
190
|
+
# But should NOT have unconditional references like the old:
|
|
191
|
+
# node "$GITHUB_WORKSPACE/setup.js"
|
|
192
|
+
#
|
|
193
|
+
# Check for the specific bad pattern we fixed (Codex finding)
|
|
194
|
+
if grep -q 'node "$GITHUB_WORKSPACE/setup.js"' .github/workflows/quality.yml; then
|
|
195
|
+
fail " Workflow has unconditional GITHUB_WORKSPACE setup.js reference (Codex finding regression!)"
|
|
196
|
+
else
|
|
197
|
+
pass " Workflow doesn't have unconditional setup.js references"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
# Conditional references with guards are OK (will fallback in consumer repos)
|
|
201
|
+
|
|
202
|
+
# 8. NEW: Actually run the generated commands (catches broken CLI flags!)
|
|
203
|
+
echo ""
|
|
204
|
+
echo "๐ Step 8: Testing generated commands actually work..."
|
|
205
|
+
echo " This step would have caught the ESLint --ext bug!"
|
|
206
|
+
|
|
207
|
+
# Install devDependencies first
|
|
208
|
+
echo " Installing devDependencies..."
|
|
209
|
+
npm install --silent > /dev/null 2>&1 || {
|
|
210
|
+
fail " npm install failed"
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Create test files for commands to process
|
|
214
|
+
# Use valid code that won't trigger linting errors
|
|
215
|
+
echo "module.exports = { name: 'test' };" > test.js
|
|
216
|
+
echo "body { color: red; }" > test.css
|
|
217
|
+
|
|
218
|
+
# Test format:check - should work (even if files need formatting)
|
|
219
|
+
echo " Testing: npm run format:check"
|
|
220
|
+
# Format the files first so format:check passes
|
|
221
|
+
npm run format >/dev/null 2>&1
|
|
222
|
+
if npm run format:check 2>&1 >/dev/null; then
|
|
223
|
+
pass " format:check works"
|
|
224
|
+
else
|
|
225
|
+
fail " format:check failed (check Prettier flags!)"
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# Test lint (CRITICAL: this would have caught --ext bug!)
|
|
229
|
+
echo " Testing: npm run lint"
|
|
230
|
+
LINT_OUTPUT=$(npm run lint 2>&1)
|
|
231
|
+
if echo "$LINT_OUTPUT" | grep -q "error"; then
|
|
232
|
+
fail " lint failed (check for deprecated flags like --ext!)"
|
|
233
|
+
echo " ESLint error output:"
|
|
234
|
+
echo "$LINT_OUTPUT" | grep -A 5 "error" | head -10
|
|
235
|
+
else
|
|
236
|
+
pass " lint works"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
# Test direct ESLint
|
|
240
|
+
echo " Testing: npx eslint test.js"
|
|
241
|
+
if npx eslint test.js 2>&1 >/dev/null; then
|
|
242
|
+
pass " Direct ESLint works"
|
|
243
|
+
else
|
|
244
|
+
fail " Direct ESLint failed"
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
# Test stylelint
|
|
248
|
+
echo " Testing: npx stylelint test.css"
|
|
249
|
+
if npx stylelint test.css 2>&1 >/dev/null; then
|
|
250
|
+
pass " Stylelint works"
|
|
251
|
+
else
|
|
252
|
+
fail " Stylelint failed"
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# 9. Test --dry-run mode
|
|
256
|
+
echo ""
|
|
257
|
+
echo "๐งช Step 9: Testing --dry-run mode..."
|
|
258
|
+
cd "$OLDPWD"
|
|
259
|
+
if node ./setup.js --dry-run 2>&1 | grep -q "DRY RUN MODE"; then
|
|
260
|
+
pass "--dry-run mode works"
|
|
261
|
+
else
|
|
262
|
+
fail "--dry-run mode doesn't work"
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
# Cleanup
|
|
266
|
+
cd "$OLDPWD"
|
|
267
|
+
rm -rf "$TEST_DIR" "$EXTRACT_DIR"
|
|
268
|
+
rm -f "$TARBALL"
|
|
269
|
+
|
|
270
|
+
# Report
|
|
271
|
+
echo ""
|
|
272
|
+
echo "================================"
|
|
273
|
+
if [ $FAILURES -eq 0 ]; then
|
|
274
|
+
echo -e "${GREEN}โ
All E2E tests passed!${NC}"
|
|
275
|
+
echo ""
|
|
276
|
+
echo "Package is ready for release."
|
|
277
|
+
exit 0
|
|
278
|
+
else
|
|
279
|
+
echo -e "${RED}โ $FAILURES test(s) failed${NC}"
|
|
280
|
+
echo ""
|
|
281
|
+
echo "Fix these issues before releasing."
|
|
282
|
+
exit 1
|
|
283
|
+
fi
|