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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Run Semgrep - Defensive Pattern Security Scan
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Runs Semgrep with defensive pattern rules. Falls back to LLM analysis
|
|
6
|
+
# if Semgrep is not installed.
|
|
7
|
+
#
|
|
8
|
+
# Part of CS-090: Semgrep Integration for Patterns
|
|
9
|
+
#
|
|
10
|
+
# USAGE:
|
|
11
|
+
# ./scripts/run-semgrep.sh # Scan current directory
|
|
12
|
+
# ./scripts/run-semgrep.sh --install # Install semgrep
|
|
13
|
+
# ./scripts/run-semgrep.sh --ci # CI mode (exit codes)
|
|
14
|
+
# ./scripts/run-semgrep.sh src/ # Scan specific directory
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
# Colors
|
|
20
|
+
RED='\033[0;31m'
|
|
21
|
+
GREEN='\033[0;32m'
|
|
22
|
+
YELLOW='\033[1;33m'
|
|
23
|
+
BLUE='\033[0;34m'
|
|
24
|
+
NC='\033[0m'
|
|
25
|
+
|
|
26
|
+
# Configuration
|
|
27
|
+
SEMGREP_CONFIG=".semgrep/defensive-patterns.yaml"
|
|
28
|
+
CI_MODE=false
|
|
29
|
+
INSTALL_MODE=false
|
|
30
|
+
SCAN_DIR="."
|
|
31
|
+
OUTPUT_FORMAT="text"
|
|
32
|
+
OUTPUT_FILE=""
|
|
33
|
+
|
|
34
|
+
# Get script directory
|
|
35
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
36
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
37
|
+
|
|
38
|
+
# Parse arguments
|
|
39
|
+
while [[ $# -gt 0 ]]; do
|
|
40
|
+
case "$1" in
|
|
41
|
+
--install)
|
|
42
|
+
INSTALL_MODE=true
|
|
43
|
+
shift
|
|
44
|
+
;;
|
|
45
|
+
--ci)
|
|
46
|
+
CI_MODE=true
|
|
47
|
+
OUTPUT_FORMAT="json"
|
|
48
|
+
shift
|
|
49
|
+
;;
|
|
50
|
+
--json)
|
|
51
|
+
OUTPUT_FORMAT="json"
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--sarif)
|
|
55
|
+
OUTPUT_FORMAT="sarif"
|
|
56
|
+
shift
|
|
57
|
+
;;
|
|
58
|
+
--output|-o)
|
|
59
|
+
OUTPUT_FILE="$2"
|
|
60
|
+
shift 2
|
|
61
|
+
;;
|
|
62
|
+
--config|-c)
|
|
63
|
+
SEMGREP_CONFIG="$2"
|
|
64
|
+
shift 2
|
|
65
|
+
;;
|
|
66
|
+
--help|-h)
|
|
67
|
+
echo "Usage: run-semgrep.sh [OPTIONS] [DIRECTORY]"
|
|
68
|
+
echo ""
|
|
69
|
+
echo "Options:"
|
|
70
|
+
echo " --install Install semgrep via pip"
|
|
71
|
+
echo " --ci CI mode (json output, proper exit codes)"
|
|
72
|
+
echo " --json Output as JSON"
|
|
73
|
+
echo " --sarif Output as SARIF (for GitHub Security)"
|
|
74
|
+
echo " --output Write output to file"
|
|
75
|
+
echo " --config Custom semgrep config (default: .semgrep/defensive-patterns.yaml)"
|
|
76
|
+
echo " --help Show this help message"
|
|
77
|
+
echo ""
|
|
78
|
+
echo "Examples:"
|
|
79
|
+
echo " run-semgrep.sh # Scan current dir"
|
|
80
|
+
echo " run-semgrep.sh --install # Install semgrep"
|
|
81
|
+
echo " run-semgrep.sh --ci --output report.json"
|
|
82
|
+
exit 0
|
|
83
|
+
;;
|
|
84
|
+
-*)
|
|
85
|
+
echo -e "${RED}Unknown option: $1${NC}"
|
|
86
|
+
exit 1
|
|
87
|
+
;;
|
|
88
|
+
*)
|
|
89
|
+
SCAN_DIR="$1"
|
|
90
|
+
shift
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# Install semgrep if requested
|
|
96
|
+
if [[ "$INSTALL_MODE" == "true" ]]; then
|
|
97
|
+
echo -e "${BLUE}Installing Semgrep...${NC}"
|
|
98
|
+
|
|
99
|
+
if command -v pip3 &> /dev/null; then
|
|
100
|
+
pip3 install semgrep
|
|
101
|
+
elif command -v pip &> /dev/null; then
|
|
102
|
+
pip install semgrep
|
|
103
|
+
elif command -v brew &> /dev/null; then
|
|
104
|
+
brew install semgrep
|
|
105
|
+
else
|
|
106
|
+
echo -e "${RED}Error: No package manager found (pip3, pip, or brew)${NC}"
|
|
107
|
+
echo "Install manually: https://semgrep.dev/docs/getting-started/"
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo -e "${GREEN}✓ Semgrep installed${NC}"
|
|
112
|
+
exit 0
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Check if semgrep is installed
|
|
116
|
+
check_semgrep() {
|
|
117
|
+
if ! command -v semgrep &> /dev/null; then
|
|
118
|
+
return 1
|
|
119
|
+
fi
|
|
120
|
+
return 0
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Find the config file
|
|
124
|
+
find_config() {
|
|
125
|
+
# Check local project first
|
|
126
|
+
if [[ -f "$SEMGREP_CONFIG" ]]; then
|
|
127
|
+
echo "$SEMGREP_CONFIG"
|
|
128
|
+
return 0
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Check claude-setup
|
|
132
|
+
local setup_config="$PROJECT_ROOT/.semgrep/defensive-patterns.yaml"
|
|
133
|
+
if [[ -f "$setup_config" ]]; then
|
|
134
|
+
echo "$setup_config"
|
|
135
|
+
return 0
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# Check home directory
|
|
139
|
+
local home_config="$HOME/.claude/.semgrep/defensive-patterns.yaml"
|
|
140
|
+
if [[ -f "$home_config" ]]; then
|
|
141
|
+
echo "$home_config"
|
|
142
|
+
return 0
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
return 1
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Run semgrep scan
|
|
149
|
+
run_semgrep() {
|
|
150
|
+
local config_path="$1"
|
|
151
|
+
local scan_path="$2"
|
|
152
|
+
|
|
153
|
+
echo -e "${BLUE}🔍 Running Semgrep Security Scan${NC}"
|
|
154
|
+
echo "═══════════════════════════════════════════════════════════"
|
|
155
|
+
echo ""
|
|
156
|
+
echo "Config: $config_path"
|
|
157
|
+
echo "Scanning: $scan_path"
|
|
158
|
+
echo ""
|
|
159
|
+
|
|
160
|
+
local semgrep_args=(
|
|
161
|
+
"--config" "$config_path"
|
|
162
|
+
"--exclude" "node_modules"
|
|
163
|
+
"--exclude" "dist"
|
|
164
|
+
"--exclude" "build"
|
|
165
|
+
"--exclude" ".next"
|
|
166
|
+
"--exclude" "coverage"
|
|
167
|
+
"--exclude" "*.min.js"
|
|
168
|
+
"--exclude" "*.bundle.js"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Add output format
|
|
172
|
+
case "$OUTPUT_FORMAT" in
|
|
173
|
+
json)
|
|
174
|
+
semgrep_args+=("--json")
|
|
175
|
+
;;
|
|
176
|
+
sarif)
|
|
177
|
+
semgrep_args+=("--sarif")
|
|
178
|
+
;;
|
|
179
|
+
esac
|
|
180
|
+
|
|
181
|
+
# Add output file
|
|
182
|
+
if [[ -n "$OUTPUT_FILE" ]]; then
|
|
183
|
+
semgrep_args+=("--output" "$OUTPUT_FILE")
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Run semgrep
|
|
187
|
+
local exit_code=0
|
|
188
|
+
semgrep "${semgrep_args[@]}" "$scan_path" || exit_code=$?
|
|
189
|
+
|
|
190
|
+
echo ""
|
|
191
|
+
|
|
192
|
+
if [[ $exit_code -eq 0 ]]; then
|
|
193
|
+
echo -e "${GREEN}✅ No security issues found${NC}"
|
|
194
|
+
elif [[ $exit_code -eq 1 ]]; then
|
|
195
|
+
echo -e "${YELLOW}⚠️ Security findings detected${NC}"
|
|
196
|
+
if [[ "$CI_MODE" == "true" ]]; then
|
|
197
|
+
echo "Review findings above and fix before merging."
|
|
198
|
+
fi
|
|
199
|
+
else
|
|
200
|
+
echo -e "${RED}❌ Semgrep scan failed (exit code: $exit_code)${NC}"
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
return $exit_code
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Fallback LLM analysis when semgrep not available
|
|
207
|
+
fallback_llm_analysis() {
|
|
208
|
+
echo -e "${YELLOW}⚠️ Semgrep not installed - using LLM-based analysis${NC}"
|
|
209
|
+
echo ""
|
|
210
|
+
echo "For faster, more reliable scans, install Semgrep:"
|
|
211
|
+
echo " ./scripts/run-semgrep.sh --install"
|
|
212
|
+
echo ""
|
|
213
|
+
echo "Falling back to pattern-check.sh..."
|
|
214
|
+
echo ""
|
|
215
|
+
|
|
216
|
+
# Run the grep-based pattern checker
|
|
217
|
+
if [[ -f "$SCRIPT_DIR/pattern-check.sh" ]]; then
|
|
218
|
+
bash "$SCRIPT_DIR/pattern-check.sh" --all
|
|
219
|
+
return $?
|
|
220
|
+
else
|
|
221
|
+
echo -e "${RED}Error: pattern-check.sh not found${NC}"
|
|
222
|
+
return 1
|
|
223
|
+
fi
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Main
|
|
227
|
+
main() {
|
|
228
|
+
if ! check_semgrep; then
|
|
229
|
+
fallback_llm_analysis
|
|
230
|
+
return $?
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
local config_path
|
|
234
|
+
if ! config_path=$(find_config); then
|
|
235
|
+
echo -e "${RED}Error: Semgrep config not found at $SEMGREP_CONFIG${NC}"
|
|
236
|
+
echo ""
|
|
237
|
+
echo "Create .semgrep/defensive-patterns.yaml or specify with --config"
|
|
238
|
+
exit 1
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
run_semgrep "$config_path" "$SCAN_DIR"
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
main
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Smart Test Strategy - create-qa-architect
|
|
3
3
|
# Generated by create-qa-architect (Pro/Team/Enterprise feature)
|
|
4
|
-
# https://
|
|
4
|
+
# https://buildproven.ai/qa-architect
|
|
5
5
|
set -e
|
|
6
6
|
|
|
7
7
|
echo "🧠 Analyzing changes for optimal test strategy..."
|
package/setup.js
CHANGED
|
@@ -701,9 +701,9 @@ SETUP OPTIONS:
|
|
|
701
701
|
--dry-run Preview changes without modifying files
|
|
702
702
|
|
|
703
703
|
WORKFLOW TIERS (GitHub Actions optimization):
|
|
704
|
-
--workflow-minimal Minimal CI (default) - Single Node version,
|
|
705
|
-
|
|
706
|
-
--workflow-standard Standard CI - Matrix testing on main,
|
|
704
|
+
--workflow-minimal Minimal CI (default) - Single Node version, monthly security
|
|
705
|
+
Budget-first mode: detection-only CI (target <1000 min/month)
|
|
706
|
+
--workflow-standard Standard CI - Matrix testing on main, monthly security
|
|
707
707
|
~15-20 min/commit, ~$5-20/mo for typical projects
|
|
708
708
|
--workflow-comprehensive Comprehensive CI - Matrix on every push, security inline
|
|
709
709
|
~50-100 min/commit, ~$100-350/mo for typical projects
|
|
@@ -1161,7 +1161,7 @@ HELP:
|
|
|
1161
1161
|
if (!repoCheck.allowed) {
|
|
1162
1162
|
console.error(`\n❌ ${repoCheck.reason}`)
|
|
1163
1163
|
console.error(
|
|
1164
|
-
' Upgrade to Pro for unlimited repos: https://
|
|
1164
|
+
' Upgrade to Pro for unlimited repos: https://buildproven.ai/qa-architect'
|
|
1165
1165
|
)
|
|
1166
1166
|
process.exit(1)
|
|
1167
1167
|
}
|
|
@@ -1531,7 +1531,7 @@ HELP:
|
|
|
1531
1531
|
console.error(` • Detected maturity: ${detectedMaturity}`)
|
|
1532
1532
|
console.error(` • Error count: ${validationResult.errors.length}`)
|
|
1533
1533
|
console.error(
|
|
1534
|
-
` • https://github.com/
|
|
1534
|
+
` • https://github.com/buildproven/qa-architect/issues/new\n`
|
|
1535
1535
|
)
|
|
1536
1536
|
|
|
1537
1537
|
// Don't continue - this is a bug in the tool itself
|
|
@@ -1717,6 +1717,14 @@ HELP:
|
|
|
1717
1717
|
})
|
|
1718
1718
|
|
|
1719
1719
|
fs.writeFileSync(workflowFile, templateWorkflow)
|
|
1720
|
+
if (workflowMode === 'minimal') {
|
|
1721
|
+
console.log(
|
|
1722
|
+
'⚠️ Minimal mode disables tests and security scans in CI (detection-only).'
|
|
1723
|
+
)
|
|
1724
|
+
console.log(
|
|
1725
|
+
' Use --workflow-standard to re-enable full CI checks.'
|
|
1726
|
+
)
|
|
1727
|
+
}
|
|
1720
1728
|
console.log(
|
|
1721
1729
|
`♻️ Updated GitHub Actions workflow to ${workflowMode} mode`
|
|
1722
1730
|
)
|
|
@@ -1948,7 +1956,7 @@ try {
|
|
|
1948
1956
|
const CAP = 50
|
|
1949
1957
|
if (usage.prePushRuns >= CAP) {
|
|
1950
1958
|
console.error('❌ Free tier limit reached: ' + usage.prePushRuns + '/' + CAP + ' pre-push runs this month')
|
|
1951
|
-
console.error(' Upgrade to Pro, Team, or Enterprise: https://
|
|
1959
|
+
console.error(' Upgrade to Pro, Team, or Enterprise: https://buildproven.ai/qa-architect')
|
|
1952
1960
|
process.exit(1)
|
|
1953
1961
|
}
|
|
1954
1962
|
|
|
@@ -2167,32 +2175,6 @@ echo "✅ Pre-push validation passed!"
|
|
|
2167
2175
|
: '✅ Added Shell CI GitHub Actions workflow'
|
|
2168
2176
|
)
|
|
2169
2177
|
}
|
|
2170
|
-
|
|
2171
|
-
// Copy/update Shell Quality workflow
|
|
2172
|
-
const shellQualityWorkflowFile = path.join(
|
|
2173
|
-
githubWorkflowDir,
|
|
2174
|
-
'shell-quality.yml'
|
|
2175
|
-
)
|
|
2176
|
-
if (!fs.existsSync(shellQualityWorkflowFile) || isUpdateMode) {
|
|
2177
|
-
const templateShellQualityWorkflow =
|
|
2178
|
-
templateLoader.getTemplate(
|
|
2179
|
-
templates,
|
|
2180
|
-
path.join('config', 'shell-quality.yml')
|
|
2181
|
-
) ||
|
|
2182
|
-
fs.readFileSync(
|
|
2183
|
-
path.join(__dirname, 'config/shell-quality.yml'),
|
|
2184
|
-
'utf8'
|
|
2185
|
-
)
|
|
2186
|
-
fs.writeFileSync(
|
|
2187
|
-
shellQualityWorkflowFile,
|
|
2188
|
-
templateShellQualityWorkflow
|
|
2189
|
-
)
|
|
2190
|
-
console.log(
|
|
2191
|
-
isUpdateMode
|
|
2192
|
-
? '🔄 Updated Shell Quality GitHub Actions workflow'
|
|
2193
|
-
: '✅ Added Shell Quality GitHub Actions workflow'
|
|
2194
|
-
)
|
|
2195
|
-
}
|
|
2196
2178
|
}
|
|
2197
2179
|
|
|
2198
2180
|
// Create a basic README if it doesn't exist
|
|
@@ -2250,6 +2232,54 @@ Quality checks are automated via GitHub Actions:
|
|
|
2250
2232
|
fs.unlinkSync(shellQualityWf)
|
|
2251
2233
|
staleWorkflows.push('shell-quality.yml')
|
|
2252
2234
|
}
|
|
2235
|
+
} else {
|
|
2236
|
+
// Consolidate shell CI into a single workflow to avoid duplicate runs.
|
|
2237
|
+
const shellQualityWf = path.join(
|
|
2238
|
+
githubWorkflowDir,
|
|
2239
|
+
'shell-quality.yml'
|
|
2240
|
+
)
|
|
2241
|
+
if (fs.existsSync(shellQualityWf)) {
|
|
2242
|
+
fs.unlinkSync(shellQualityWf)
|
|
2243
|
+
staleWorkflows.push('shell-quality.yml')
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
// Remove known duplicate CI workflow names that overlap quality.yml,
|
|
2248
|
+
// but ONLY if they were generated by qa-architect (contain a marker).
|
|
2249
|
+
const duplicateCiWorkflows = [
|
|
2250
|
+
'ci.yml',
|
|
2251
|
+
'ci.yaml',
|
|
2252
|
+
'test.yml',
|
|
2253
|
+
'test.yaml',
|
|
2254
|
+
'tests.yml',
|
|
2255
|
+
'tests.yaml',
|
|
2256
|
+
'quality-legacy.yml',
|
|
2257
|
+
'quality-legacy.yaml',
|
|
2258
|
+
]
|
|
2259
|
+
const skippedWorkflows = []
|
|
2260
|
+
for (const duplicateName of duplicateCiWorkflows) {
|
|
2261
|
+
const duplicatePath = path.join(githubWorkflowDir, duplicateName)
|
|
2262
|
+
if (fs.existsSync(duplicatePath)) {
|
|
2263
|
+
const content = fs.readFileSync(duplicatePath, 'utf8')
|
|
2264
|
+
const isQaaGenerated =
|
|
2265
|
+
content.includes('create-qa-architect') ||
|
|
2266
|
+
content.includes('qa-architect') ||
|
|
2267
|
+
content.includes('WORKFLOW_MODE:')
|
|
2268
|
+
if (isQaaGenerated) {
|
|
2269
|
+
fs.unlinkSync(duplicatePath)
|
|
2270
|
+
staleWorkflows.push(duplicateName)
|
|
2271
|
+
} else {
|
|
2272
|
+
skippedWorkflows.push(duplicateName)
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
if (skippedWorkflows.length > 0) {
|
|
2277
|
+
console.log(
|
|
2278
|
+
`⚠️ Found potential duplicate workflows: ${skippedWorkflows.join(', ')}`
|
|
2279
|
+
)
|
|
2280
|
+
console.log(
|
|
2281
|
+
' These were not created by qa-architect — review manually and remove if redundant with quality.yml'
|
|
2282
|
+
)
|
|
2253
2283
|
}
|
|
2254
2284
|
if (staleWorkflows.length > 0) {
|
|
2255
2285
|
console.log(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## ⚠️ CRITICAL: Do Not Create Additional Workflows
|
|
4
4
|
|
|
5
|
-
This project uses **qa-architect** for quality automation with **minimal workflow mode** (
|
|
5
|
+
This project uses **qa-architect** for quality automation with **minimal workflow mode** (budget-first: <1000 min/month target).
|
|
6
6
|
|
|
7
7
|
### What This Means for AI Assistants (Claude, Copilot, etc.)
|
|
8
8
|
|
|
@@ -25,13 +25,13 @@ This project uses **qa-architect** for quality automation with **minimal workflo
|
|
|
25
25
|
|
|
26
26
|
- **Mode:** Minimal (~$0-5/mo per project)
|
|
27
27
|
- **Path filters:** Skip docs/config changes (60% fewer runs)
|
|
28
|
-
- **Security:**
|
|
28
|
+
- **Security:** Monthly schedule (not every commit)
|
|
29
29
|
- **Node version:** Single version (22)
|
|
30
30
|
|
|
31
31
|
### Why This Matters
|
|
32
32
|
|
|
33
33
|
- **Cost control:** Prevents $20-350/mo per-project bloat
|
|
34
|
-
- **Efficiency:** Path filters +
|
|
34
|
+
- **Efficiency:** Path filters + monthly security = 60-90% CI savings
|
|
35
35
|
- **Standards:** Consistent automation across all projects
|
|
36
36
|
|
|
37
37
|
### Upgrading CI (User Decision Only)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Smart Test Strategy - {{PROJECT_NAME}}
|
|
3
3
|
# Generated by create-qa-architect (Pro/Team/Enterprise feature)
|
|
4
|
-
# https://
|
|
4
|
+
# https://buildproven.ai/qa-architect
|
|
5
5
|
set -e
|
|
6
6
|
|
|
7
7
|
echo "🧠 Analyzing changes for optimal test strategy..."
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
name: Auto Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*'
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
release:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v4
|
|
16
|
-
with:
|
|
17
|
-
fetch-depth: 0
|
|
18
|
-
|
|
19
|
-
- name: Get previous tag
|
|
20
|
-
id: prev_tag
|
|
21
|
-
run: |
|
|
22
|
-
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
|
23
|
-
echo "tag=$PREV_TAG" >> $GITHUB_OUTPUT
|
|
24
|
-
|
|
25
|
-
- name: Generate release notes
|
|
26
|
-
run: |
|
|
27
|
-
TAG=${GITHUB_REF#refs/tags/}
|
|
28
|
-
PREV_TAG=${{ steps.prev_tag.outputs.tag }}
|
|
29
|
-
if [ -n "$PREV_TAG" ]; then
|
|
30
|
-
echo "## Changes since $PREV_TAG" > notes.md
|
|
31
|
-
git log ${PREV_TAG}..${TAG} --pretty=format:"- %s" >> notes.md
|
|
32
|
-
echo -e "\n\n**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${TAG}" >> notes.md
|
|
33
|
-
else
|
|
34
|
-
echo "Initial release" > notes.md
|
|
35
|
-
fi
|
|
36
|
-
|
|
37
|
-
- uses: softprops/action-gh-release@v2
|
|
38
|
-
with:
|
|
39
|
-
body_path: notes.md
|