create-qa-architect 5.12.1 → 5.13.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/.github/dependabot.yml +10 -30
- package/.github/workflows/claude-md-validation.yml +5 -7
- package/.github/workflows/dependabot-auto-merge.yml +1 -0
- package/.github/workflows/quality.yml +26 -12
- package/.github/workflows/release.yml +2 -1
- package/.github/workflows/stale-prs.yml +42 -0
- package/.github/workflows/weekly-gitleaks-verification.yml +6 -4
- package/LICENSE +3 -3
- package/README.md +19 -20
- package/config/quality-config.schema.json +1 -1
- package/docs/CI-COST-ANALYSIS.md +8 -8
- package/docs/DEPLOYMENT.md +1 -1
- package/docs/DEVELOPMENT-WORKFLOW.md +2 -2
- package/docs/TURBOREPO-SUPPORT.md +3 -3
- package/docs/dev_guide/CONVENTIONS.md +132 -0
- package/eslint.config.cjs +25 -0
- package/lib/blob-storage.js +57 -0
- package/lib/commands/analyze-ci.js +267 -27
- package/lib/commands/deps.js +5 -5
- package/lib/commands/license-commands.js +2 -2
- package/lib/commands/maturity-check.js +20 -2
- package/lib/dependency-monitoring-basic.js +4 -4
- package/lib/dependency-monitoring-premium.js +5 -5
- package/lib/license-validator.js +1 -1
- package/lib/licensing.js +3 -3
- package/lib/smart-strategy-generator.js +1 -1
- package/lib/validation/documentation.js +2 -0
- package/lib/workflow-config.js +106 -62
- package/package.json +51 -21
- package/scripts/deploy-consumers.sh +369 -0
- package/scripts/pattern-check.sh +607 -0
- package/scripts/run-semgrep.sh +244 -0
- package/scripts/smart-test-strategy.sh +1 -1
- package/setup.js +62 -32
- package/templates/CLAUDE_WORKFLOW_POLICY.md +3 -3
- package/templates/scripts/smart-test-strategy.sh +1 -1
- package/.github/workflows/auto-release.yml +0 -39
|
@@ -10,11 +10,29 @@
|
|
|
10
10
|
*/
|
|
11
11
|
function handleMaturityCheck() {
|
|
12
12
|
const { ProjectMaturityDetector } = require('../project-maturity')
|
|
13
|
+
const githubActions = process.argv.includes('--github-actions')
|
|
13
14
|
const detector = new ProjectMaturityDetector({
|
|
14
15
|
projectPath: process.cwd(),
|
|
15
|
-
verbose:
|
|
16
|
+
verbose: !githubActions,
|
|
16
17
|
})
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
if (githubActions) {
|
|
20
|
+
const output = detector.generateGitHubActionsOutput()
|
|
21
|
+
console.log(`maturity=${output.maturity}`)
|
|
22
|
+
console.log(`source-count=${output.sourceCount}`)
|
|
23
|
+
console.log(`test-count=${output.testCount}`)
|
|
24
|
+
console.log(`has-deps=${output.hasDeps}`)
|
|
25
|
+
console.log(`has-docs=${output.hasDocs}`)
|
|
26
|
+
console.log(`has-css=${output.hasCss}`)
|
|
27
|
+
console.log(`has-shell=${output.hasShell}`)
|
|
28
|
+
console.log(`shell-count=${output.shellCount}`)
|
|
29
|
+
console.log(`is-shell-project=${output.isShellProject}`)
|
|
30
|
+
console.log(`required-checks=${output.requiredChecks}`)
|
|
31
|
+
console.log(`optional-checks=${output.optionalChecks}`)
|
|
32
|
+
console.log(`disabled-checks=${output.disabledChecks}`)
|
|
33
|
+
} else {
|
|
34
|
+
detector.printReport()
|
|
35
|
+
}
|
|
18
36
|
process.exit(0)
|
|
19
37
|
}
|
|
20
38
|
|
|
@@ -22,7 +22,7 @@ function hasNpmProject(projectPath) {
|
|
|
22
22
|
function generateBasicDependabotConfig(options = {}) {
|
|
23
23
|
const {
|
|
24
24
|
projectPath = '.',
|
|
25
|
-
schedule = '
|
|
25
|
+
schedule = 'monthly',
|
|
26
26
|
day = 'monday',
|
|
27
27
|
time = '09:00',
|
|
28
28
|
monorepoInfo = null, // Optional monorepo detection result
|
|
@@ -50,7 +50,7 @@ function generateBasicDependabotConfig(options = {}) {
|
|
|
50
50
|
day: day,
|
|
51
51
|
time: time,
|
|
52
52
|
},
|
|
53
|
-
'open-pull-requests-limit':
|
|
53
|
+
'open-pull-requests-limit': 2,
|
|
54
54
|
labels: ['dependencies', 'root'],
|
|
55
55
|
'commit-message': {
|
|
56
56
|
prefix: 'deps(root)',
|
|
@@ -69,7 +69,7 @@ function generateBasicDependabotConfig(options = {}) {
|
|
|
69
69
|
day: day,
|
|
70
70
|
time: time,
|
|
71
71
|
},
|
|
72
|
-
'open-pull-requests-limit':
|
|
72
|
+
'open-pull-requests-limit': 2,
|
|
73
73
|
labels: ['dependencies', pkg.name],
|
|
74
74
|
'commit-message': {
|
|
75
75
|
prefix: `deps(${pkg.name})`,
|
|
@@ -87,7 +87,7 @@ function generateBasicDependabotConfig(options = {}) {
|
|
|
87
87
|
day: day,
|
|
88
88
|
time: time,
|
|
89
89
|
},
|
|
90
|
-
'open-pull-requests-limit':
|
|
90
|
+
'open-pull-requests-limit': 2,
|
|
91
91
|
labels: ['dependencies'],
|
|
92
92
|
'commit-message': {
|
|
93
93
|
prefix: 'deps',
|
|
@@ -1294,7 +1294,7 @@ function generatePremiumDependabotConfig(options = {}) {
|
|
|
1294
1294
|
|
|
1295
1295
|
const {
|
|
1296
1296
|
projectPath = '.',
|
|
1297
|
-
schedule = '
|
|
1297
|
+
schedule = 'monthly',
|
|
1298
1298
|
day = 'monday',
|
|
1299
1299
|
time = '09:00',
|
|
1300
1300
|
} = options
|
|
@@ -1316,7 +1316,7 @@ function generatePremiumDependabotConfig(options = {}) {
|
|
|
1316
1316
|
'package-ecosystem': 'npm',
|
|
1317
1317
|
directory: '/',
|
|
1318
1318
|
schedule: { interval: schedule, day, time },
|
|
1319
|
-
'open-pull-requests-limit':
|
|
1319
|
+
'open-pull-requests-limit': 3,
|
|
1320
1320
|
labels: ['dependencies', 'npm'],
|
|
1321
1321
|
'commit-message': { prefix: 'deps(npm)', include: 'scope' },
|
|
1322
1322
|
...(Object.keys(npmGroups).length > 0 && { groups: npmGroups }),
|
|
@@ -1330,7 +1330,7 @@ function generatePremiumDependabotConfig(options = {}) {
|
|
|
1330
1330
|
'package-ecosystem': 'pip',
|
|
1331
1331
|
directory: '/',
|
|
1332
1332
|
schedule: { interval: schedule, day, time },
|
|
1333
|
-
'open-pull-requests-limit':
|
|
1333
|
+
'open-pull-requests-limit': 3,
|
|
1334
1334
|
labels: ['dependencies', 'python'],
|
|
1335
1335
|
'commit-message': { prefix: 'deps(python)' },
|
|
1336
1336
|
...(Object.keys(pipGroups).length > 0 && { groups: pipGroups }),
|
|
@@ -1344,7 +1344,7 @@ function generatePremiumDependabotConfig(options = {}) {
|
|
|
1344
1344
|
'package-ecosystem': 'cargo',
|
|
1345
1345
|
directory: '/',
|
|
1346
1346
|
schedule: { interval: schedule, day, time },
|
|
1347
|
-
'open-pull-requests-limit':
|
|
1347
|
+
'open-pull-requests-limit': 3,
|
|
1348
1348
|
labels: ['dependencies', 'rust'],
|
|
1349
1349
|
'commit-message': { prefix: 'deps(rust)' },
|
|
1350
1350
|
...(Object.keys(cargoGroups).length > 0 && { groups: cargoGroups }),
|
|
@@ -1358,7 +1358,7 @@ function generatePremiumDependabotConfig(options = {}) {
|
|
|
1358
1358
|
'package-ecosystem': 'bundler',
|
|
1359
1359
|
directory: '/',
|
|
1360
1360
|
schedule: { interval: schedule, day, time },
|
|
1361
|
-
'open-pull-requests-limit':
|
|
1361
|
+
'open-pull-requests-limit': 3,
|
|
1362
1362
|
labels: ['dependencies', 'ruby'],
|
|
1363
1363
|
'commit-message': { prefix: 'deps(ruby)' },
|
|
1364
1364
|
...(Object.keys(bundlerGroups).length > 0 && { groups: bundlerGroups }),
|
package/lib/license-validator.js
CHANGED
|
@@ -85,7 +85,7 @@ class LicenseValidator {
|
|
|
85
85
|
// Allow enterprises to host their own registry
|
|
86
86
|
this.licenseDbUrl =
|
|
87
87
|
process.env.QAA_LICENSE_DB_URL ||
|
|
88
|
-
'https://
|
|
88
|
+
'https://buildproven.ai/api/licenses/qa-architect.json'
|
|
89
89
|
|
|
90
90
|
this.licensePublicKey = loadKeyFromEnv(
|
|
91
91
|
process.env.QAA_LICENSE_PUBLIC_KEY,
|
package/lib/licensing.js
CHANGED
|
@@ -399,7 +399,7 @@ function showUpgradeMessage(feature) {
|
|
|
399
399
|
console.log('')
|
|
400
400
|
console.log(' 🎁 Start 14-day free trial - no credit card required')
|
|
401
401
|
console.log('')
|
|
402
|
-
console.log('🚀 Upgrade: https://
|
|
402
|
+
console.log('🚀 Upgrade: https://buildproven.ai/qa-architect')
|
|
403
403
|
console.log(
|
|
404
404
|
'🔑 Activate: npx create-qa-architect@latest --activate-license'
|
|
405
405
|
)
|
|
@@ -745,7 +745,7 @@ async function promptLicenseActivation() {
|
|
|
745
745
|
console.log(
|
|
746
746
|
' If you purchased this license, please contact support at:'
|
|
747
747
|
)
|
|
748
|
-
console.log(' Email: support@
|
|
748
|
+
console.log(' Email: support@buildproven.ai')
|
|
749
749
|
console.log(
|
|
750
750
|
' Include your license key and purchase email for verification.'
|
|
751
751
|
)
|
|
@@ -1140,7 +1140,7 @@ function showLicenseStatus() {
|
|
|
1140
1140
|
// Show upgrade path
|
|
1141
1141
|
if (license.tier === LICENSE_TIERS.FREE) {
|
|
1142
1142
|
console.log('\n💡 Upgrade to PRO for unlimited access + security scanning')
|
|
1143
|
-
console.log(' → https://
|
|
1143
|
+
console.log(' → https://buildproven.ai/qa-architect')
|
|
1144
1144
|
}
|
|
1145
1145
|
}
|
|
1146
1146
|
|
|
@@ -255,7 +255,7 @@ function generateSmartStrategy(options = {}) {
|
|
|
255
255
|
`Troubleshooting steps:\n` +
|
|
256
256
|
`1. Reinstall the package: npm install -g create-qa-architect@latest\n` +
|
|
257
257
|
`2. Check file permissions: ls -la ${path.dirname(templatePath)}\n` +
|
|
258
|
-
`3. Report issue if problem persists: https://github.com/
|
|
258
|
+
`3. Report issue if problem persists: https://github.com/buildproven/qa-architect/issues/new`
|
|
259
259
|
)
|
|
260
260
|
}
|
|
261
261
|
|
|
@@ -267,6 +267,8 @@ class DocumentationValidator {
|
|
|
267
267
|
'quality-python.yml',
|
|
268
268
|
'ci.yml', // Common workflow name users might have
|
|
269
269
|
'test.yml', // Common workflow name users might have
|
|
270
|
+
'tests.yml', // Common workflow name users might have
|
|
271
|
+
'quality-legacy.yml', // Legacy workflow name referenced in cleanup docs
|
|
270
272
|
// Optional tooling configs
|
|
271
273
|
'.lighthouserc.js',
|
|
272
274
|
'vercel.json',
|
package/lib/workflow-config.js
CHANGED
|
@@ -65,8 +65,80 @@ function detectExistingWorkflowMode(projectPath) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Strip a named section from workflow content.
|
|
70
|
+
* Removes everything between # {{NAME_BEGIN}} and # {{NAME_END}} markers (inclusive).
|
|
71
|
+
* Leaves a single newline to avoid collapsing adjacent YAML blocks.
|
|
72
|
+
* @param {string} content - Workflow content
|
|
73
|
+
* @param {string} sectionName - Section name (e.g. 'QA_ARCHITECT_ONLY', 'FULL_DETECTION')
|
|
74
|
+
* @returns {string} Content with section removed
|
|
75
|
+
*/
|
|
76
|
+
function stripSection(content, sectionName) {
|
|
77
|
+
if (!/^[A-Z_]+$/.test(sectionName)) {
|
|
78
|
+
throw new Error(`Invalid section name: ${sectionName}`)
|
|
79
|
+
}
|
|
80
|
+
// eslint-disable-next-line security/detect-non-literal-regexp -- sectionName validated above
|
|
81
|
+
const pattern = new RegExp(
|
|
82
|
+
`[^\\S\\n]*# \\{\\{${sectionName}_BEGIN\\}\\}[\\s\\S]*?# \\{\\{${sectionName}_END\\}\\}\\n?`,
|
|
83
|
+
'g'
|
|
84
|
+
)
|
|
85
|
+
return content.replace(pattern, '')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Remove a paths-ignore block from a top-level workflow trigger.
|
|
90
|
+
* @param {string} content - Workflow content
|
|
91
|
+
* @param {string} triggerName - Trigger key (e.g. push, pull_request)
|
|
92
|
+
* @returns {string} Updated content
|
|
93
|
+
*/
|
|
94
|
+
function removeTriggerPathsIgnore(content, triggerName) {
|
|
95
|
+
const lines = content.split('\n')
|
|
96
|
+
const output = []
|
|
97
|
+
|
|
98
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
99
|
+
const line = lines[index]
|
|
100
|
+
output.push(line)
|
|
101
|
+
|
|
102
|
+
if (
|
|
103
|
+
line !== ` ${triggerName}:` &&
|
|
104
|
+
!line.startsWith(` ${triggerName}: `)
|
|
105
|
+
) {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let scanIndex = index + 1
|
|
110
|
+
while (scanIndex < lines.length) {
|
|
111
|
+
const nextLine = lines[scanIndex]
|
|
112
|
+
|
|
113
|
+
if (nextLine.startsWith(' ') && !nextLine.startsWith(' ')) {
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (nextLine === ' paths-ignore:') {
|
|
118
|
+
scanIndex += 1
|
|
119
|
+
while (
|
|
120
|
+
scanIndex < lines.length &&
|
|
121
|
+
lines[scanIndex].startsWith(' - ')
|
|
122
|
+
) {
|
|
123
|
+
scanIndex += 1
|
|
124
|
+
}
|
|
125
|
+
index = scanIndex - 1
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
output.push(nextLine)
|
|
130
|
+
index = scanIndex
|
|
131
|
+
scanIndex += 1
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return output.join('\n')
|
|
136
|
+
}
|
|
137
|
+
|
|
68
138
|
/**
|
|
69
139
|
* Inject workflow mode-specific configuration into quality.yml
|
|
140
|
+
* Uses section markers (# {{SECTION_BEGIN/END}}) for reliable content removal
|
|
141
|
+
* instead of fragile structural regex patterns.
|
|
70
142
|
* @param {string} workflowContent - Template content
|
|
71
143
|
* @param {'minimal'|'standard'|'comprehensive'} mode - Selected mode
|
|
72
144
|
* @returns {string} Modified workflow content
|
|
@@ -74,101 +146,72 @@ function detectExistingWorkflowMode(projectPath) {
|
|
|
74
146
|
function injectWorkflowMode(workflowContent, mode) {
|
|
75
147
|
let updated = workflowContent
|
|
76
148
|
|
|
149
|
+
// Set workflow mode marker
|
|
77
150
|
const versionMarker = `# WORKFLOW_MODE: ${mode}`
|
|
78
151
|
if (updated.includes('# WORKFLOW_MODE:')) {
|
|
79
|
-
// Replace existing marker with new mode
|
|
80
152
|
updated = updated.replace(
|
|
81
153
|
/# WORKFLOW_MODE: (minimal|standard|comprehensive)/,
|
|
82
154
|
versionMarker
|
|
83
155
|
)
|
|
84
156
|
} else {
|
|
85
|
-
// Add marker before jobs:
|
|
86
157
|
updated = updated.replace(/(\n\njobs:)/, `\n${versionMarker}\n$1`)
|
|
87
158
|
}
|
|
88
159
|
|
|
89
|
-
//
|
|
90
|
-
|
|
160
|
+
// All consumer workflows: strip qa-architect-only content
|
|
161
|
+
updated = stripSection(updated, 'QA_ARCHITECT_ONLY')
|
|
91
162
|
|
|
92
|
-
//
|
|
163
|
+
// Mode-specific transformations
|
|
93
164
|
if (mode === 'standard') {
|
|
94
165
|
// Standard: Add main branch condition to tests job
|
|
95
|
-
// Handle both single-line and multi-line if: formats
|
|
96
|
-
|
|
97
|
-
// First try multi-line format (if: | block)
|
|
98
166
|
if (
|
|
99
167
|
updated.includes('tests:') &&
|
|
100
168
|
updated.includes('fromJSON(needs.detect-maturity.outputs.test-count)')
|
|
101
169
|
) {
|
|
102
|
-
// Multi-line if: | block - add main branch check at the start
|
|
103
170
|
updated = updated.replace(
|
|
104
171
|
/(tests:\s+runs-on:[^\n]+\s+needs:[^\n]+\s+if: \|\s*\n\s+)fromJSON\(needs\.detect-maturity\.outputs\.test-count\)/,
|
|
105
172
|
"$1github.ref == 'refs/heads/main' &&\n fromJSON(needs.detect-maturity.outputs.test-count)"
|
|
106
173
|
)
|
|
107
|
-
|
|
108
|
-
// Also try single-line format as fallback
|
|
109
174
|
updated = updated.replace(
|
|
110
175
|
/(\s+tests:\s+runs-on:[^\n]+\s+needs:[^\n]+\s+)if: fromJSON\(needs\.detect-maturity\.outputs\.test-count\) > 0/,
|
|
111
176
|
"$1if: github.ref == 'refs/heads/main' && fromJSON(needs.detect-maturity.outputs.test-count) > 0"
|
|
112
177
|
)
|
|
113
178
|
}
|
|
114
|
-
|
|
115
|
-
// Standard: Change matrix to [20, 22]
|
|
116
|
-
updated = updated.replace(/node-version: \[22\]/g, 'node-version: [20, 22]')
|
|
117
179
|
} else if (mode === 'comprehensive') {
|
|
118
|
-
// Comprehensive: Remove paths-ignore blocks
|
|
119
|
-
updated = updated
|
|
120
|
-
|
|
121
|
-
'$1'
|
|
122
|
-
)
|
|
123
|
-
updated = updated.replace(
|
|
124
|
-
/(\s+pull_request:\s+branches:[^\n]+)\s+paths-ignore:\s+- '\*\*\.md'\s+- 'docs\/\*\*'\s+- 'LICENSE'\s+- '\.gitignore'\s+- '\.editorconfig'/g,
|
|
125
|
-
'$1'
|
|
126
|
-
)
|
|
127
|
-
|
|
180
|
+
// Comprehensive: Remove paths-ignore blocks
|
|
181
|
+
updated = removeTriggerPathsIgnore(updated, 'push')
|
|
182
|
+
updated = removeTriggerPathsIgnore(updated, 'pull_request')
|
|
128
183
|
// Comprehensive: Remove schedule trigger (security runs inline)
|
|
129
184
|
updated = updated.replace(/\s+schedule:\s+- cron:[^\n]+[^\n]*\n?/g, '\n')
|
|
130
|
-
|
|
131
185
|
// Comprehensive: Remove schedule condition from security job
|
|
132
186
|
updated = updated.replace(
|
|
133
187
|
/if: \(github\.event_name == 'schedule' \|\| github\.event_name == 'workflow_dispatch'\) && /g,
|
|
134
188
|
'if: '
|
|
135
189
|
)
|
|
136
|
-
|
|
137
|
-
// Comprehensive: Change matrix to [20, 22]
|
|
138
190
|
updated = updated.replace(/node-version: \[22\]/g, 'node-version: [20, 22]')
|
|
139
191
|
}
|
|
140
|
-
// Minimal mode: Remove expensive dependency install and maturity detection steps
|
|
141
|
-
// Keep only: checkout, setup-node, detect-pm, setup-pnpm/bun, simplified report
|
|
142
|
-
if (mode === 'minimal') {
|
|
143
|
-
// 1. Remove "Install dependencies for maturity detection" step
|
|
144
|
-
updated = updated.replace(
|
|
145
|
-
/\s+- name: Install dependencies for maturity detection\s+run: \$\{\{ steps\.detect-pm\.outputs\.install-cmd \}\}\s*\n/,
|
|
146
|
-
'\n'
|
|
147
|
-
)
|
|
148
192
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)
|
|
193
|
+
// Minimal mode: use section markers to strip detection, hardcode outputs
|
|
194
|
+
if (mode === 'minimal') {
|
|
195
|
+
// Strip full detection and report sections via markers
|
|
196
|
+
updated = stripSection(updated, 'FULL_DETECTION')
|
|
197
|
+
updated = stripSection(updated, 'FULL_REPORT')
|
|
154
198
|
|
|
155
|
-
//
|
|
156
|
-
// These sensible defaults allow basic checks to run without expensive detection
|
|
199
|
+
// Hardcode maturity outputs (since we skip detection)
|
|
157
200
|
updated = updated.replace(
|
|
158
201
|
/maturity: \$\{\{ steps\.detect\.outputs\.maturity \}\}/,
|
|
159
202
|
"maturity: 'minimal'"
|
|
160
203
|
)
|
|
161
204
|
updated = updated.replace(
|
|
162
205
|
/source-count: \$\{\{ steps\.detect\.outputs\.source-count \}\}/,
|
|
163
|
-
"source-count: '
|
|
206
|
+
"source-count: '0'"
|
|
164
207
|
)
|
|
165
208
|
updated = updated.replace(
|
|
166
209
|
/test-count: \$\{\{ steps\.detect\.outputs\.test-count \}\}/,
|
|
167
|
-
"test-count: '
|
|
210
|
+
"test-count: '0'"
|
|
168
211
|
)
|
|
169
212
|
updated = updated.replace(
|
|
170
213
|
/has-deps: \$\{\{ steps\.detect\.outputs\.has-deps \}\}/,
|
|
171
|
-
"has-deps: '
|
|
214
|
+
"has-deps: 'false'"
|
|
172
215
|
)
|
|
173
216
|
updated = updated.replace(
|
|
174
217
|
/has-docs: \$\{\{ steps\.detect\.outputs\.has-docs \}\}/,
|
|
@@ -179,30 +222,30 @@ function injectWorkflowMode(workflowContent, mode) {
|
|
|
179
222
|
"has-css: 'false'"
|
|
180
223
|
)
|
|
181
224
|
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
updated = updated.replace(
|
|
185
|
-
/\s+- name: Cache gitleaks binary for real download test[\s\S]*?restore-keys: \|[^\n]*\n[^\n]*\n[^\n]*\n/,
|
|
186
|
-
'\n'
|
|
187
|
-
)
|
|
188
|
-
updated = updated.replace(
|
|
189
|
-
/\s+- name: Run real gitleaks binary verification test[\s\S]*?node tests\/gitleaks-real-binary-test\.js\n/,
|
|
190
|
-
'\n'
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
// 5. Simplify "Display Detection Report" to show only package manager info
|
|
194
|
-
updated = updated.replace(
|
|
195
|
-
/- name: Display Detection Report\s+run: \|[\s\S]*?echo "Has CSS files:[^"]*"/,
|
|
196
|
-
`- name: Display Detection Report
|
|
225
|
+
// Insert simplified detection report after the last setup step
|
|
226
|
+
const minimalReport = ` - name: Display Detection Report
|
|
197
227
|
run: |
|
|
198
228
|
echo "📊 Project Detection Results (Minimal Mode)"
|
|
199
229
|
echo "Package Manager: \${{ steps.detect-pm.outputs.manager }}"
|
|
200
230
|
echo "Install Command: \${{ steps.detect-pm.outputs.install-cmd }}"
|
|
201
231
|
echo "Turborepo: \${{ steps.detect-pm.outputs.is-turborepo }}"
|
|
202
|
-
echo "
|
|
203
|
-
|
|
232
|
+
echo "Mode goal: keep GitHub Actions usage under ~1000 min/month by default"
|
|
233
|
+
echo "Checks: detection-only in CI (tests/security/docs disabled in minimal mode)"
|
|
234
|
+
echo "Use --workflow-standard or --workflow-comprehensive to enable heavier CI checks"`
|
|
235
|
+
|
|
236
|
+
// Insert report before the "Note: Lint/format" comment that follows detect-maturity job
|
|
237
|
+
if (!updated.includes('Display Detection Report')) {
|
|
238
|
+
updated = updated.replace(
|
|
239
|
+
/(\n {2}# Note: Lint\/format jobs REMOVED)/,
|
|
240
|
+
`\n${minimalReport}\n$1`
|
|
241
|
+
)
|
|
242
|
+
}
|
|
204
243
|
}
|
|
205
244
|
|
|
245
|
+
// Strip any remaining section markers from output (belt-and-suspenders)
|
|
246
|
+
// Use [ \t]* (horizontal whitespace only) — \s* would eat newlines and collapse YAML lines
|
|
247
|
+
updated = updated.replace(/[ \t]*# \{\{[A-Z_]+_(BEGIN|END)\}\}\n?/g, '')
|
|
248
|
+
|
|
206
249
|
return updated
|
|
207
250
|
}
|
|
208
251
|
|
|
@@ -243,4 +286,5 @@ module.exports = {
|
|
|
243
286
|
detectExistingWorkflowMode,
|
|
244
287
|
injectWorkflowMode,
|
|
245
288
|
injectMatrix,
|
|
289
|
+
stripSection,
|
|
246
290
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-qa-architect",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.2",
|
|
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": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"validate:comprehensive": "node setup.js --comprehensive --no-markdownlint",
|
|
21
21
|
"validate:all": "npm run validate:comprehensive && npm run security:audit",
|
|
22
22
|
"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",
|
|
23
|
-
"test": "export QAA_DEVELOPER=true && node tests/result-types.test.js && 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/deps-edge-cases.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/workflow-tiers.test.js && node tests/analyze-ci.test.js && node tests/analyze-ci-integration.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 && node tests/lazy-loader.test.js && node tests/template-content-validation.test.js && node tests/ci-environment.test.js && node tests/turborepo-detection.test.js",
|
|
23
|
+
"test": "export QAA_DEVELOPER=true && node tests/result-types.test.js && 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/deps-edge-cases.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/workflow-tiers.test.js && node tests/analyze-ci.test.js && node tests/analyze-ci-integration.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 && node tests/lazy-loader.test.js && node tests/template-content-validation.test.js && node tests/ci-environment.test.js && node tests/turborepo-detection.test.js && node tests/consumer-workflow-integration.test.js",
|
|
24
24
|
"test:unit": "export QAA_DEVELOPER=true && node tests/result-types.test.js && 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/workflow-tiers.test.js && node tests/analyze-ci.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 && node tests/lazy-loader.test.js && node tests/template-content-validation.test.js && node tests/ci-environment.test.js && node tests/turborepo-detection.test.js",
|
|
25
25
|
"test:fast": "npm run test:unit",
|
|
26
26
|
"test:medium": "npm run test:fast && npm run test:patterns && npm run test:commands",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test:comprehensive": "npm run test:patterns && npm test && npm run test:commands && npm run test:e2e && npm run security:audit",
|
|
29
29
|
"test:real-binary": "RUN_REAL_BINARY_TEST=1 node tests/gitleaks-real-binary-test.js",
|
|
30
30
|
"test:commands": "export QAA_DEVELOPER=true && node tests/command-execution.test.js",
|
|
31
|
-
"test:patterns": "
|
|
31
|
+
"test:patterns": "bash scripts/pattern-check.sh --all",
|
|
32
32
|
"test:coverage": "c8 --reporter=html --reporter=text --reporter=lcov npm test",
|
|
33
33
|
"test:e2e": "export QAA_DEVELOPER=true && bash scripts/test-e2e-package.sh",
|
|
34
34
|
"test:all": "npm run test:patterns && npm test && npm run test:commands && npm run test:e2e",
|
|
@@ -52,7 +52,13 @@
|
|
|
52
52
|
"size:why": "size-limit --why",
|
|
53
53
|
"test:a11y": "vitest run tests/accessibility.test.js",
|
|
54
54
|
"test:coverage:check": "vitest run --coverage --coverage.thresholds.lines=70 --coverage.thresholds.functions=70",
|
|
55
|
-
"test:changed": "vitest run --changed HEAD~1 --passWithNoTests"
|
|
55
|
+
"test:changed": "vitest run --changed HEAD~1 --passWithNoTests",
|
|
56
|
+
"dead-code": "knip --no-exit-code || echo \"Dead code found (non-blocking)\"",
|
|
57
|
+
"dead-code:strict": "knip",
|
|
58
|
+
"pattern-check": "bash scripts/pattern-check.sh",
|
|
59
|
+
"security:scan": "bash scripts/run-semgrep.sh",
|
|
60
|
+
"security:scan:ci": "bash scripts/run-semgrep.sh --ci",
|
|
61
|
+
"license:check": "license-checker --onlyAllow \"MIT;ISC;BSD-2-Clause;BSD-3-Clause;Apache-2.0;0BSD;BlueOak-1.0.0;CC0-1.0;CC-BY-3.0;CC-BY-4.0;Unlicense;Python-2.0;MPL-2.0\" --excludePrivatePackages"
|
|
56
62
|
},
|
|
57
63
|
"keywords": [
|
|
58
64
|
"qa-architect",
|
|
@@ -98,12 +104,12 @@
|
|
|
98
104
|
],
|
|
99
105
|
"repository": {
|
|
100
106
|
"type": "git",
|
|
101
|
-
"url": "git+https://github.com/
|
|
107
|
+
"url": "git+https://github.com/buildproven/qa-architect.git"
|
|
102
108
|
},
|
|
103
109
|
"bugs": {
|
|
104
|
-
"url": "https://github.com/
|
|
110
|
+
"url": "https://github.com/buildproven/qa-architect/issues"
|
|
105
111
|
},
|
|
106
|
-
"homepage": "https://
|
|
112
|
+
"homepage": "https://buildproven.ai/qa-architect",
|
|
107
113
|
"engines": {
|
|
108
114
|
"node": ">=20"
|
|
109
115
|
},
|
|
@@ -118,28 +124,33 @@
|
|
|
118
124
|
}
|
|
119
125
|
},
|
|
120
126
|
"devDependencies": {
|
|
127
|
+
"@commitlint/cli": "^19.0.0",
|
|
128
|
+
"@commitlint/config-conventional": "^19.0.0",
|
|
129
|
+
"@lhci/cli": "^0.15.1",
|
|
130
|
+
"@size-limit/file": "^11.0.0",
|
|
121
131
|
"@types/node": "^25",
|
|
132
|
+
"@typescript-eslint/eslint-plugin": "^8.9.0",
|
|
133
|
+
"@typescript-eslint/parser": "^8.9.0",
|
|
134
|
+
"@vercel/blob": "^2.2.0",
|
|
135
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
122
136
|
"actionlint": "^2.0.6",
|
|
123
|
-
"
|
|
137
|
+
"axe-core": "^4.10.0",
|
|
124
138
|
"c8": "^10.1.2",
|
|
139
|
+
"commitlint": "^20.4.1",
|
|
125
140
|
"eslint": "^9.39.2",
|
|
141
|
+
"eslint-plugin-n": "^17.24.0",
|
|
126
142
|
"eslint-plugin-security": "^3.0.1",
|
|
127
143
|
"globals": "^15.9.0",
|
|
128
144
|
"husky": "^9.1.4",
|
|
145
|
+
"knip": "^6.0.1",
|
|
146
|
+
"license-checker": "^25.0.1",
|
|
129
147
|
"lint-staged": "^15.2.10",
|
|
130
148
|
"prettier": "^3.8.0",
|
|
149
|
+
"size-limit": "^11.0.0",
|
|
131
150
|
"stylelint": "^16.26.1",
|
|
132
151
|
"stylelint-config-standard": "^37.0.0",
|
|
133
|
-
"
|
|
134
|
-
"vitest": "^2.1.8"
|
|
135
|
-
"@vitest/coverage-v8": "^2.1.8",
|
|
136
|
-
"@typescript-eslint/eslint-plugin": "^8.9.0",
|
|
137
|
-
"@typescript-eslint/parser": "^8.9.0",
|
|
138
|
-
"size-limit": "^11.0.0",
|
|
139
|
-
"@size-limit/file": "^11.0.0",
|
|
140
|
-
"@commitlint/cli": "^19.0.0",
|
|
141
|
-
"@commitlint/config-conventional": "^19.0.0",
|
|
142
|
-
"axe-core": "^4.10.0"
|
|
152
|
+
"typescript": "^5",
|
|
153
|
+
"vitest": "^2.1.8"
|
|
143
154
|
},
|
|
144
155
|
"volta": {
|
|
145
156
|
"node": "20.11.1",
|
|
@@ -185,11 +196,20 @@
|
|
|
185
196
|
],
|
|
186
197
|
"**/*.{ts,tsx}": [
|
|
187
198
|
"eslint --fix",
|
|
188
|
-
"prettier --write"
|
|
199
|
+
"prettier --write",
|
|
200
|
+
"tsc --noEmit --skipLibCheck"
|
|
189
201
|
],
|
|
190
202
|
"tests/**/*.{ts,tsx,js,jsx}": [
|
|
191
203
|
"eslint --fix",
|
|
192
204
|
"prettier --write"
|
|
205
|
+
],
|
|
206
|
+
"**/*.{js,jsx,ts,tsx,mjs,cjs,html}": [
|
|
207
|
+
"eslint --fix",
|
|
208
|
+
"prettier --write"
|
|
209
|
+
],
|
|
210
|
+
"**/*.{js,jsx,mjs,cjs,html}": [
|
|
211
|
+
"eslint --fix",
|
|
212
|
+
"prettier --write"
|
|
193
213
|
]
|
|
194
214
|
},
|
|
195
215
|
"dependencies": {
|
|
@@ -197,8 +217,18 @@
|
|
|
197
217
|
"ajv": "^8.17.1",
|
|
198
218
|
"ajv-formats": "^3.0.1",
|
|
199
219
|
"js-yaml": "^4.1.0",
|
|
200
|
-
"markdownlint-cli2": "^0.
|
|
220
|
+
"markdownlint-cli2": "^0.21.0",
|
|
201
221
|
"ora": "^8.1.1",
|
|
202
222
|
"tar": "^7.5.7"
|
|
203
|
-
}
|
|
223
|
+
},
|
|
224
|
+
"size-limit": [
|
|
225
|
+
{
|
|
226
|
+
"path": "dist/**/*.js",
|
|
227
|
+
"limit": "250 kB"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"path": "dist/**/*.css",
|
|
231
|
+
"limit": "50 kB"
|
|
232
|
+
}
|
|
233
|
+
]
|
|
204
234
|
}
|