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.
Files changed (37) hide show
  1. package/.github/dependabot.yml +10 -30
  2. package/.github/workflows/claude-md-validation.yml +5 -7
  3. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  4. package/.github/workflows/quality.yml +26 -12
  5. package/.github/workflows/release.yml +2 -1
  6. package/.github/workflows/stale-prs.yml +42 -0
  7. package/.github/workflows/weekly-gitleaks-verification.yml +6 -4
  8. package/LICENSE +3 -3
  9. package/README.md +19 -20
  10. package/config/quality-config.schema.json +1 -1
  11. package/docs/CI-COST-ANALYSIS.md +8 -8
  12. package/docs/DEPLOYMENT.md +1 -1
  13. package/docs/DEVELOPMENT-WORKFLOW.md +2 -2
  14. package/docs/TURBOREPO-SUPPORT.md +3 -3
  15. package/docs/dev_guide/CONVENTIONS.md +132 -0
  16. package/eslint.config.cjs +25 -0
  17. package/lib/blob-storage.js +57 -0
  18. package/lib/commands/analyze-ci.js +267 -27
  19. package/lib/commands/deps.js +5 -5
  20. package/lib/commands/license-commands.js +2 -2
  21. package/lib/commands/maturity-check.js +20 -2
  22. package/lib/dependency-monitoring-basic.js +4 -4
  23. package/lib/dependency-monitoring-premium.js +5 -5
  24. package/lib/license-validator.js +1 -1
  25. package/lib/licensing.js +3 -3
  26. package/lib/smart-strategy-generator.js +1 -1
  27. package/lib/validation/documentation.js +2 -0
  28. package/lib/workflow-config.js +106 -62
  29. package/package.json +51 -21
  30. package/scripts/deploy-consumers.sh +369 -0
  31. package/scripts/pattern-check.sh +607 -0
  32. package/scripts/run-semgrep.sh +244 -0
  33. package/scripts/smart-test-strategy.sh +1 -1
  34. package/setup.js +62 -32
  35. package/templates/CLAUDE_WORKFLOW_POLICY.md +3 -3
  36. package/templates/scripts/smart-test-strategy.sh +1 -1
  37. package/.github/workflows/auto-release.yml +0 -39
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # deploy-consumers.sh — Auto-discover and update ALL consumer repos with staged rollout
5
+ #
6
+ # Usage:
7
+ # ./scripts/deploy-consumers.sh # Dry run (validate only)
8
+ # ./scripts/deploy-consumers.sh --canary-only --push # Deploy ONLY to canary, wait for CI
9
+ # ./scripts/deploy-consumers.sh --push # Full rollout: canary first, then rest
10
+ # ./scripts/deploy-consumers.sh --skip-canary --push # Emergency: bypass canary (use with caution)
11
+ #
12
+ # Staged Rollout Process:
13
+ # 1. Deploy to canary repo (buildproven) first
14
+ # 2. Wait for CI to complete on canary (up to 10 minutes)
15
+ # 3. If CI passes, deploy to remaining repos
16
+ # 4. If CI fails, abort rollout (prevents cascading failures)
17
+ #
18
+ # Auto-discovers repos by scanning ~/Projects for .github/workflows/quality.yml
19
+ # files that contain the WORKFLOW_MODE marker from qa-architect.
20
+
21
+ PROJECTS_DIR="$HOME/Projects"
22
+ QA_ARCHITECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
23
+ CANARY_REPO="buildproven"
24
+ PUSH=false
25
+ TIER="minimal"
26
+ VERBOSE=false
27
+ CANARY_ONLY=false
28
+ SKIP_CANARY=false
29
+ CI_TIMEOUT=600 # 10 minutes in seconds
30
+ CI_POLL_INTERVAL=15 # Check every 15 seconds
31
+
32
+ # Parse args
33
+ while [[ $# -gt 0 ]]; do
34
+ case "$1" in
35
+ --push) PUSH=true; shift ;;
36
+ --tier) TIER="$2"; shift 2 ;;
37
+ --verbose) VERBOSE=true; shift ;;
38
+ --canary-only) CANARY_ONLY=true; shift ;;
39
+ --skip-canary) SKIP_CANARY=true; shift ;;
40
+ --help|-h)
41
+ cat <<EOF
42
+ Usage: deploy-consumers.sh [OPTIONS]
43
+
44
+ OPTIONS:
45
+ --push Commit and push changes (default: dry run)
46
+ --canary-only Deploy ONLY to canary repo, wait for CI green
47
+ --skip-canary Skip canary validation (emergency use only)
48
+ --tier <tier> Workflow tier to apply (default: minimal)
49
+ --verbose Show detailed output
50
+ --help, -h Show this help
51
+
52
+ STAGED ROLLOUT:
53
+ Default behavior (--push):
54
+ 1. Deploy to canary (buildproven)
55
+ 2. Wait for CI to pass (up to 10 minutes)
56
+ 3. Deploy to remaining repos
57
+
58
+ Canary-only mode (--canary-only --push):
59
+ Deploy to canary only, validate CI passes
60
+
61
+ Skip canary (--skip-canary --push):
62
+ Deploy to all repos simultaneously (emergency only)
63
+
64
+ EXAMPLES:
65
+ # Dry run (no changes)
66
+ ./scripts/deploy-consumers.sh
67
+
68
+ # Canary validation
69
+ ./scripts/deploy-consumers.sh --canary-only --push
70
+
71
+ # Full rollout (staged)
72
+ ./scripts/deploy-consumers.sh --push
73
+
74
+ # Emergency bypass (use with caution)
75
+ ./scripts/deploy-consumers.sh --skip-canary --push
76
+ EOF
77
+ exit 0
78
+ ;;
79
+ *) echo "Unknown option: $1"; exit 1 ;;
80
+ esac
81
+ done
82
+
83
+ echo "=== QA Architect Consumer Deployment ==="
84
+ echo "Mode: $([ "$PUSH" = true ] && echo "PUSH (will commit + push)" || echo "DRY RUN (validate only)")"
85
+ echo "Tier: $TIER"
86
+ echo "Canary repo: $CANARY_REPO"
87
+ if [ "$CANARY_ONLY" = true ]; then
88
+ echo "⚠️ CANARY-ONLY mode: will deploy to $CANARY_REPO only"
89
+ elif [ "$SKIP_CANARY" = true ]; then
90
+ echo "⚠️ SKIP-CANARY mode: bypassing canary validation (emergency use)"
91
+ else
92
+ echo "Staged rollout: canary first, then remaining repos"
93
+ fi
94
+ echo ""
95
+
96
+ # Discover consumer repos: any repo with quality.yml containing WORKFLOW_MODE marker
97
+ # Excludes qa-architect itself
98
+ CONSUMERS=()
99
+ CANARY_DIR=""
100
+ for workflow in "$PROJECTS_DIR"/*/".github/workflows/quality.yml"; do
101
+ [ -f "$workflow" ] || continue
102
+ repo_dir="$(dirname "$(dirname "$(dirname "$workflow")")")"
103
+ repo_name="$(basename "$repo_dir")"
104
+
105
+ # Skip qa-architect itself (compare basenames to avoid case/symlink issues)
106
+ [ "$(basename "$repo_dir")" = "$(basename "$QA_ARCHITECT_DIR")" ] && continue
107
+
108
+ # Check for WORKFLOW_MODE marker (proves it was generated by qa-architect)
109
+ if grep -q "WORKFLOW_MODE:" "$workflow" 2>/dev/null; then
110
+ if [ "$repo_name" = "$CANARY_REPO" ]; then
111
+ CANARY_DIR="$repo_dir"
112
+ else
113
+ CONSUMERS+=("$repo_dir")
114
+ fi
115
+ fi
116
+ done
117
+
118
+ # Ensure canary was found
119
+ if [ -z "$CANARY_DIR" ]; then
120
+ echo "❌ ERROR: Canary repo '$CANARY_REPO' not found or doesn't have WORKFLOW_MODE marker"
121
+ exit 1
122
+ fi
123
+
124
+ # In canary-only mode, only process canary
125
+ if [ "$CANARY_ONLY" = true ]; then
126
+ echo "Canary-only mode: processing $CANARY_REPO only"
127
+ CONSUMERS=()
128
+ else
129
+ echo "Discovered canary repo: $CANARY_REPO"
130
+ echo "Discovered ${#CONSUMERS[@]} additional consumer repos:"
131
+ for dir in "${CONSUMERS[@]}"; do
132
+ echo " - $(basename "$dir")"
133
+ done
134
+ fi
135
+ echo ""
136
+
137
+ # Function to wait for CI to complete on a repo
138
+ # Args: $1 = repo_dir, $2 = repo_name
139
+ wait_for_ci() {
140
+ local repo_dir="$1"
141
+ local repo_name="$2"
142
+
143
+ echo " Waiting for CI to complete on $repo_name..."
144
+
145
+ # Check if gh CLI is installed
146
+ if ! command -v gh &>/dev/null; then
147
+ echo " ⚠️ WARNING: gh CLI not installed, cannot check CI status"
148
+ echo " Install with: brew install gh"
149
+ echo " Proceeding without CI validation..."
150
+ return 0
151
+ fi
152
+
153
+ # Get the repo owner/name for gh CLI
154
+ local remote_url
155
+ remote_url=$(cd "$repo_dir" && git remote get-url origin 2>/dev/null || echo "")
156
+ if [ -z "$remote_url" ]; then
157
+ echo " ⚠️ WARNING: No git remote found, cannot check CI status"
158
+ return 0
159
+ fi
160
+
161
+ # Extract owner/repo from URL (handles both HTTPS and SSH)
162
+ local repo_slug
163
+ repo_slug=$(echo "$remote_url" | sed -E 's|^.*[:/]([^/]+/[^/]+)(\.git)?$|\1|')
164
+
165
+ # Get the current branch
166
+ local branch
167
+ branch=$(cd "$repo_dir" && git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
168
+
169
+ echo " Checking CI status for $repo_slug on branch $branch..."
170
+
171
+ local elapsed=0
172
+ local status=""
173
+
174
+ while [ $elapsed -lt $CI_TIMEOUT ]; do
175
+ # Get latest workflow run status for quality.yml on this branch
176
+ status=$(gh run list --repo "$repo_slug" --workflow quality.yml --branch "$branch" --limit 1 --json status,conclusion --jq '.[0].status + ":" + (.[0].conclusion // "")' 2>/dev/null || echo "")
177
+
178
+ if [ -z "$status" ]; then
179
+ echo " ⚠️ No CI runs found yet (elapsed: ${elapsed}s)"
180
+ elif [[ "$status" == "completed:success" ]]; then
181
+ echo " ✅ CI PASSED on $repo_name (elapsed: ${elapsed}s)"
182
+ return 0
183
+ elif [[ "$status" == "completed:failure" ]] || [[ "$status" == "completed:cancelled" ]]; then
184
+ echo " ❌ CI FAILED on $repo_name (status: $status)"
185
+ return 1
186
+ else
187
+ echo " ⏳ CI in progress on $repo_name (status: $status, elapsed: ${elapsed}s)"
188
+ fi
189
+
190
+ sleep $CI_POLL_INTERVAL
191
+ elapsed=$((elapsed + CI_POLL_INTERVAL))
192
+ done
193
+
194
+ echo " ⏰ TIMEOUT: CI did not complete within ${CI_TIMEOUT}s"
195
+ return 1
196
+ }
197
+
198
+ # Function to deploy to a single repo
199
+ # Args: $1 = repo_dir, $2 = is_canary (true/false)
200
+ deploy_to_repo() {
201
+ local repo_dir="$1"
202
+ local is_canary="${2:-false}"
203
+ local repo_name="$(basename "$repo_dir")"
204
+
205
+ echo "--- $repo_name $([ "$is_canary" = true ] && echo "(CANARY)" || echo "") ---"
206
+
207
+ # Check if repo has package.json (needed for npx)
208
+ if [ ! -f "$repo_dir/package.json" ]; then
209
+ echo " SKIP: No package.json"
210
+ return 2 # Return code 2 = skipped
211
+ fi
212
+
213
+ # Detect the existing tier from the workflow
214
+ local existing_tier="$TIER"
215
+ if grep -q "WORKFLOW_MODE: standard" "$repo_dir/.github/workflows/quality.yml" 2>/dev/null; then
216
+ existing_tier="standard"
217
+ elif grep -q "WORKFLOW_MODE: comprehensive" "$repo_dir/.github/workflows/quality.yml" 2>/dev/null; then
218
+ existing_tier="comprehensive"
219
+ elif grep -q "WORKFLOW_MODE: minimal" "$repo_dir/.github/workflows/quality.yml" 2>/dev/null; then
220
+ existing_tier="minimal"
221
+ fi
222
+
223
+ # Regenerate workflow (must cd to consumer dir — setup.js uses process.cwd())
224
+ echo " Regenerating workflow (tier: $existing_tier)..."
225
+ if (cd "$repo_dir" && QAA_DEVELOPER=true node "$QA_ARCHITECT_DIR/setup.js" --update "--workflow-${existing_tier}" \
226
+ 2>&1 | { [ "$VERBOSE" = true ] && cat || tail -1; }); then
227
+ :
228
+ else
229
+ echo " FAIL: Workflow generation failed"
230
+ return 1
231
+ fi
232
+
233
+ local workflow_file="$repo_dir/.github/workflows/quality.yml"
234
+
235
+ # Validate: no node_modules/create-qa-architect references
236
+ if grep -q "node_modules/create-qa-architect" "$workflow_file"; then
237
+ echo " FAIL: Contains node_modules/create-qa-architect references"
238
+ return 1
239
+ fi
240
+
241
+ # Validate: no section markers leaked
242
+ if grep -qE '\{\{(QA_ARCHITECT_ONLY|FULL_DETECTION|FULL_REPORT)_(BEGIN|END)\}\}' "$workflow_file"; then
243
+ echo " FAIL: Contains section markers"
244
+ return 1
245
+ fi
246
+
247
+ # Validate: valid YAML (requires node + js-yaml)
248
+ if ! node -e "require('$QA_ARCHITECT_DIR/node_modules/js-yaml').load(require('fs').readFileSync('$workflow_file','utf8'))" 2>/dev/null; then
249
+ echo " FAIL: Invalid YAML"
250
+ return 1
251
+ fi
252
+
253
+ # Remove stale devDep if present
254
+ if grep -q '"create-qa-architect"' "$repo_dir/package.json" 2>/dev/null; then
255
+ echo " Removing stale create-qa-architect devDependency..."
256
+ if [ "$PUSH" = true ]; then
257
+ (cd "$repo_dir" && npm uninstall create-qa-architect 2>/dev/null || true)
258
+ else
259
+ echo " (dry run - would remove devDep)"
260
+ fi
261
+ fi
262
+
263
+ echo " PASS: Validated"
264
+
265
+ # Commit and push if --push
266
+ if [ "$PUSH" = true ]; then
267
+ (
268
+ cd "$repo_dir"
269
+ if git diff --quiet .github/workflows/quality.yml package.json 2>/dev/null; then
270
+ echo " No changes to commit"
271
+ else
272
+ git add .github/workflows/quality.yml package.json package-lock.json 2>/dev/null || true
273
+ git commit -m "chore: regenerate qa-architect workflow (${existing_tier} tier)
274
+
275
+ Staged rollout: $([ "$is_canary" = true ] && echo "canary deployment" || echo "validated via canary")
276
+ Fixes node_modules/create-qa-architect fallback paths.
277
+ Consumers use npx create-qa-architect@latest instead of devDep." 2>/dev/null || true
278
+ git push 2>/dev/null && echo " Pushed" || echo " Push failed (check remote)"
279
+ fi
280
+ )
281
+ fi
282
+
283
+ echo ""
284
+ return 0
285
+ }
286
+
287
+ # Validation counters
288
+ PASS=0
289
+ FAIL=0
290
+ SKIPPED=0
291
+
292
+ # STAGE 1: Deploy to canary (unless --skip-canary)
293
+ if [ "$SKIP_CANARY" = false ]; then
294
+ echo "=== STAGE 1: Canary Deployment ==="
295
+ echo ""
296
+
297
+ if deploy_to_repo "$CANARY_DIR" true; then
298
+ PASS=$((PASS + 1))
299
+
300
+ # Wait for CI if in push mode
301
+ if [ "$PUSH" = true ]; then
302
+ if ! wait_for_ci "$CANARY_DIR" "$CANARY_REPO"; then
303
+ echo ""
304
+ echo "❌ ROLLOUT ABORTED: Canary CI failed or timed out"
305
+ echo " Fix the issue on $CANARY_REPO before rolling out to other repos"
306
+ exit 1
307
+ fi
308
+ fi
309
+ else
310
+ ret=$?
311
+ if [ $ret -eq 2 ]; then
312
+ SKIPPED=$((SKIPPED + 1))
313
+ else
314
+ FAIL=$((FAIL + 1))
315
+ echo ""
316
+ echo "❌ ROLLOUT ABORTED: Canary deployment failed"
317
+ exit 1
318
+ fi
319
+ fi
320
+
321
+ echo ""
322
+ echo "✅ Canary deployment successful"
323
+ echo ""
324
+ fi
325
+
326
+ # Exit early if canary-only mode
327
+ if [ "$CANARY_ONLY" = true ]; then
328
+ echo "=== Summary (Canary-Only) ==="
329
+ echo " Pass: $PASS"
330
+ echo " Fail: $FAIL"
331
+ echo " Skipped: $SKIPPED"
332
+ echo ""
333
+ echo "✅ Canary deployment complete. Review CI results before full rollout."
334
+ exit 0
335
+ fi
336
+
337
+ # STAGE 2: Deploy to remaining repos
338
+ if [ ${#CONSUMERS[@]} -gt 0 ]; then
339
+ echo "=== STAGE 2: Remaining Repos Deployment ==="
340
+ echo ""
341
+
342
+ for repo_dir in "${CONSUMERS[@]}"; do
343
+ if deploy_to_repo "$repo_dir" false; then
344
+ PASS=$((PASS + 1))
345
+ else
346
+ ret=$?
347
+ if [ $ret -eq 2 ]; then
348
+ SKIPPED=$((SKIPPED + 1))
349
+ else
350
+ FAIL=$((FAIL + 1))
351
+ fi
352
+ fi
353
+ done
354
+ fi
355
+
356
+ echo "=== Summary ==="
357
+ echo " Pass: $PASS"
358
+ echo " Fail: $FAIL"
359
+ echo " Skipped: $SKIPPED"
360
+ echo " Total: $((${#CONSUMERS[@]} + 1))" # +1 for canary
361
+
362
+ if [ "$FAIL" -gt 0 ]; then
363
+ echo ""
364
+ echo "⚠️ Some repos failed validation. Review output above."
365
+ exit 1
366
+ fi
367
+
368
+ echo ""
369
+ echo "✅ Deployment complete!"