xp-gate 0.5.1
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/adapter-common.sh +192 -0
- package/adapters/cpp.sh +76 -0
- package/adapters/dart.sh +41 -0
- package/adapters/flutter.sh +41 -0
- package/adapters/go.sh +59 -0
- package/adapters/iac.sh +189 -0
- package/adapters/java.sh +191 -0
- package/adapters/kotlin.sh +77 -0
- package/adapters/objectivec.sh +38 -0
- package/adapters/powershell.sh +138 -0
- package/adapters/python.sh +104 -0
- package/adapters/shell.sh +55 -0
- package/adapters/swift.sh +44 -0
- package/adapters/typescript.sh +61 -0
- package/bin/xp-gate.js +157 -0
- package/hooks/adapter-common.sh +192 -0
- package/hooks/pre-commit +1667 -0
- package/hooks/pre-push +395 -0
- package/lib/__tests__/detect-deps.test.js +209 -0
- package/lib/__tests__/doctor.test.js +448 -0
- package/lib/__tests__/download-skill.test.js +281 -0
- package/lib/__tests__/init.test.js +327 -0
- package/lib/__tests__/install-skill.test.js +326 -0
- package/lib/__tests__/migrate.test.js +212 -0
- package/lib/__tests__/rollback.test.js +183 -0
- package/lib/__tests__/ui-detector.test.ts +200 -0
- package/lib/__tests__/uninstall-skill.test.js +189 -0
- package/lib/__tests__/uninstall.test.js +589 -0
- package/lib/__tests__/update-skill.test.js +276 -0
- package/lib/detect-deps.js +157 -0
- package/lib/doctor.js +370 -0
- package/lib/download-skill.js +96 -0
- package/lib/init.js +367 -0
- package/lib/install-skill.js +184 -0
- package/lib/migrate.js +120 -0
- package/lib/rollback.js +78 -0
- package/lib/ui-detector.ts +99 -0
- package/lib/uninstall-skill.js +69 -0
- package/lib/uninstall.js +401 -0
- package/lib/update-skill.js +90 -0
- package/package.json +39 -0
- package/plugins/claude-code/.claude-plugin/plugin.json +21 -0
- package/plugins/claude-code/bin/delphi-review-guard.sh +68 -0
- package/plugins/claude-code/bin/xp-gate-check +47 -0
- package/plugins/claude-code/hooks/hooks.json +37 -0
- package/skills/delphi-review/.delphi-config.json.example +45 -0
- package/skills/delphi-review/AGENTS.md +54 -0
- package/skills/delphi-review/INSTALL.md +152 -0
- package/skills/delphi-review/SKILL.md +371 -0
- package/skills/delphi-review/evals/evals.json +82 -0
- package/skills/delphi-review/opencode.json.delphi.example +56 -0
- package/skills/delphi-review/references/code-walkthrough.md +486 -0
- package/skills/ralph-loop/SKILL.md +330 -0
- package/skills/ralph-loop/evals/evals.json +311 -0
- package/skills/ralph-loop/evolution-history.json +59 -0
- package/skills/ralph-loop/evolution-log.md +16 -0
- package/skills/ralph-loop/references/components/memory.md +55 -0
- package/skills/ralph-loop/references/components/middleware.md +54 -0
- package/skills/ralph-loop/references/components/skill-invocations.md +39 -0
- package/skills/ralph-loop/references/components/system-prompt.md +24 -0
- package/skills/ralph-loop/references/components/tool-descriptions.md +32 -0
- package/skills/ralph-loop/references/phase-2-build-ralph.md +89 -0
- package/skills/ralph-loop/templates/progress-log.md +36 -0
- package/skills/sprint-flow/SKILL.md +600 -0
- package/skills/sprint-flow/evals/evals.json +78 -0
- package/skills/sprint-flow/evolution-history.json +39 -0
- package/skills/sprint-flow/evolution-log.md +23 -0
- package/skills/sprint-flow/references/components/memory.md +87 -0
- package/skills/sprint-flow/references/components/middleware.md +72 -0
- package/skills/sprint-flow/references/components/skill-invocations.md +104 -0
- package/skills/sprint-flow/references/components/system-prompt.md +27 -0
- package/skills/sprint-flow/references/components/tool-descriptions.md +96 -0
- package/skills/sprint-flow/references/phase-0-think.md +115 -0
- package/skills/sprint-flow/references/phase-1-plan.md +178 -0
- package/skills/sprint-flow/references/phase-2-build.md +198 -0
- package/skills/sprint-flow/references/phase-3-review.md +213 -0
- package/skills/sprint-flow/references/phase-4-uat.md +125 -0
- package/skills/sprint-flow/references/phase-5-feedback.md +100 -0
- package/skills/sprint-flow/references/phase-6-ship.md +193 -0
- package/skills/sprint-flow/references/phase-7-land.md +140 -0
- package/skills/sprint-flow/references/phase-8-cleanup.md +192 -0
- package/skills/sprint-flow/templates/emergent-issues-template.md +120 -0
- package/skills/sprint-flow/templates/pain-document-template.md +115 -0
- package/skills/sprint-flow/templates/sprint-summary-template.md +120 -0
- package/skills/test-specification-alignment/AGENTS.md +59 -0
- package/skills/test-specification-alignment/SKILL.md +605 -0
- package/skills/test-specification-alignment/evals/evals.json +75 -0
- package/skills/test-specification-alignment/references/alignment-verification-algorithm.md +493 -0
- package/skills/test-specification-alignment/references/phase2-constraint-enforcement.md +431 -0
- package/skills/test-specification-alignment/references/specification-format.md +348 -0
package/adapters/java.sh
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
4
|
+
# Plugin directory
|
|
5
|
+
PLUGIN_DIR="$SCRIPT_DIR/plugins/p3c-java"
|
|
6
|
+
WHALECLOUD_PLUGIN_DIR="$SCRIPT_DIR/plugins/whalecloud-java"
|
|
7
|
+
|
|
8
|
+
_is_whalecloud_enabled() {
|
|
9
|
+
# Check if whalecloud-java plugin is enabled
|
|
10
|
+
[ -d "$WHALECLOUD_PLUGIN_DIR" ] && \
|
|
11
|
+
([ -f "config/pmd/whalecloud-ruleset.xml" ] || \
|
|
12
|
+
grep -q 'xp-gate-whalecloud-java\|xp-gateWhalecloudCheck' pom.xml build.gradle build.gradle.kts 2>/dev/null)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_detect_java_build() {
|
|
16
|
+
if [ -f "pom.xml" ]; then
|
|
17
|
+
echo "maven"
|
|
18
|
+
elif [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
19
|
+
echo "gradle"
|
|
20
|
+
else
|
|
21
|
+
echo "none"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
run_static_analysis() {
|
|
26
|
+
local build_system
|
|
27
|
+
build_system=$(_detect_java_build)
|
|
28
|
+
|
|
29
|
+
if [ "$build_system" = "maven" ]; then
|
|
30
|
+
mvn compile -q 2>&1 | grep -i "error\|fail" | head -5
|
|
31
|
+
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
|
|
32
|
+
echo "❌ Maven compilation failed"
|
|
33
|
+
return 1
|
|
34
|
+
fi
|
|
35
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
36
|
+
gradle compileJava --quiet 2>&1 | grep -i "error\|fail" | head -5
|
|
37
|
+
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
|
|
38
|
+
echo "❌ Gradle compilation failed"
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# CheckStyle with Google style (legacy fallback)
|
|
44
|
+
if command -v checkstyle &>/dev/null; then
|
|
45
|
+
checkstyle -c /google_checks.xml . 2>&1 | head -20
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# PMD error detection (legacy fallback)
|
|
49
|
+
if command -v pmd &>/dev/null; then
|
|
50
|
+
pmd check -d . -R category/java/errorprone.xml 2>&1 | head -20
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# p3c-pmd check (Alibaba coding guidelines) — primary Java quality gate
|
|
54
|
+
_run_p3c_check "$build_system"
|
|
55
|
+
|
|
56
|
+
# WhaleCloud Java Coding Standards — overlay on top of p3c-pmd
|
|
57
|
+
_run_whalecloud_check "$build_system"
|
|
58
|
+
|
|
59
|
+
return 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
run_lint() {
|
|
63
|
+
run_static_analysis
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
run_tests() {
|
|
67
|
+
local build_system
|
|
68
|
+
build_system=$(_detect_java_build)
|
|
69
|
+
|
|
70
|
+
if [ "$build_system" = "maven" ]; then
|
|
71
|
+
mvn test -q 2>&1 | tail -15
|
|
72
|
+
return "${PIPESTATUS[0]}"
|
|
73
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
74
|
+
gradle test --quiet 2>&1 | tail -15
|
|
75
|
+
return "${PIPESTATUS[0]}"
|
|
76
|
+
else
|
|
77
|
+
echo "No Maven/Gradle project detected"
|
|
78
|
+
return 1
|
|
79
|
+
fi
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
run_coverage() {
|
|
83
|
+
local build_system
|
|
84
|
+
build_system=$(_detect_java_build)
|
|
85
|
+
|
|
86
|
+
if [ "$build_system" = "maven" ]; then
|
|
87
|
+
mvn test jacoco:report -q 2>&1 | tail -10
|
|
88
|
+
return "${PIPESTATUS[0]}"
|
|
89
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
90
|
+
gradle jacocoTestReport --quiet 2>&1 | tail -10
|
|
91
|
+
return "${PIPESTATUS[0]}"
|
|
92
|
+
else
|
|
93
|
+
echo "No Maven/Gradle project detected"
|
|
94
|
+
return 1
|
|
95
|
+
fi
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
run_p3c_check() {
|
|
99
|
+
_run_p3c_check "$(_detect_java_build)"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_run_p3c_check() {
|
|
103
|
+
local build_system="$1"
|
|
104
|
+
|
|
105
|
+
echo " Running p3c-pmd Alibaba Coding Guidelines check..."
|
|
106
|
+
|
|
107
|
+
if [ "$build_system" = "maven" ]; then
|
|
108
|
+
if grep -q '<id>xp-gate-p3c</id>' pom.xml 2>/dev/null; then
|
|
109
|
+
# Profile already installed — use it
|
|
110
|
+
mvn pmd:check -P xp-gate-p3c -Dpmd.failOnViolation=true 2>&1 | tail -30
|
|
111
|
+
return "${PIPESTATUS[0]}"
|
|
112
|
+
else
|
|
113
|
+
# Profile not installed — run inline with p3c-pmd dependency
|
|
114
|
+
if command -v mvn &>/dev/null; then
|
|
115
|
+
mvn pmd:check \
|
|
116
|
+
-Dpmd.rulesets="/rulesets/java/ali-comment.xml,/rulesets/java/ali-concurrent.xml,/rulesets/java/ali-constant.xml,/rulesets/java/ali-exception.xml,/rulesets/java/ali-flowcontrol.xml,/rulesets/java/ali-naming.xml,/rulesets/java/ali-oop.xml,/rulesets/java/ali-orm.xml,/rulesets/java/ali-other.xml,/rulesets/java/ali-set.xml" \
|
|
117
|
+
-Dpmd.failOnViolation=true \
|
|
118
|
+
-DprintFailingErrors=true \
|
|
119
|
+
2>&1 | tail -30
|
|
120
|
+
local result="${PIPESTATUS[0]}"
|
|
121
|
+
|
|
122
|
+
if [ "$result" -ne 0 ]; then
|
|
123
|
+
echo ""
|
|
124
|
+
echo " ⚠️ p3c-pmd check FAILED — Alibaba Coding Guidelines violations found"
|
|
125
|
+
echo " To permanently enable: bash $PLUGIN_DIR/scripts/install-maven-p3c.sh"
|
|
126
|
+
return 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
echo " ✅ p3c-pmd check passed"
|
|
130
|
+
return 0
|
|
131
|
+
else
|
|
132
|
+
echo " ℹ️ Maven not available — Skipping p3c-pmd"
|
|
133
|
+
return 0
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
138
|
+
if grep -q 'xp-gateP3cCheck\|p3c-pmd' build.gradle 2>/dev/null || \
|
|
139
|
+
grep -q 'xp-gateP3cCheck\|p3c-pmd' build.gradle.kts 2>/dev/null; then
|
|
140
|
+
gradle xp-gateP3cCheck --quiet 2>&1 | tail -20
|
|
141
|
+
return "${PIPESTATUS[0]}"
|
|
142
|
+
else
|
|
143
|
+
echo " ℹ️ p3c-pmd not configured in Gradle build"
|
|
144
|
+
echo " To enable: bash $PLUGIN_DIR/scripts/install-gradle-p3c.sh"
|
|
145
|
+
return 0
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo " ℹ️ No Maven/Gradle project — Skipping p3c-pmd"
|
|
150
|
+
return 0
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_run_whalecloud_check() {
|
|
154
|
+
local build_system="$1"
|
|
155
|
+
|
|
156
|
+
if ! _is_whalecloud_enabled; then
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
echo " Running WhaleCloud Java Coding Standards check..."
|
|
161
|
+
|
|
162
|
+
if [ "$build_system" = "maven" ]; then
|
|
163
|
+
if grep -q '<id>xp-gate-whalecloud-java</id>' pom.xml 2>/dev/null; then
|
|
164
|
+
mvn pmd:check checkstyle:check spotbugs:check \
|
|
165
|
+
-P xp-gate-whalecloud-java -Dpmd.failOnViolation=true \
|
|
166
|
+
2>&1 | tail -30
|
|
167
|
+
return "${PIPESTATUS[0]}"
|
|
168
|
+
else
|
|
169
|
+
echo " ⚠️ whalecloud-java profile not installed in pom.xml"
|
|
170
|
+
echo " To enable: bash $WHALECLOUD_PLUGIN_DIR/scripts/install-maven-whalecloud.sh"
|
|
171
|
+
return 0
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
175
|
+
if grep -q 'xp-gateWhalecloudCheck' build.gradle 2>/dev/null || \
|
|
176
|
+
grep -q 'xp-gateWhalecloudCheck' build.gradle.kts 2>/dev/null; then
|
|
177
|
+
gradle xp-gateWhalecloudCheck --quiet 2>&1 | tail -20
|
|
178
|
+
return "${PIPESTATUS[0]}"
|
|
179
|
+
else
|
|
180
|
+
echo " ⚠️ whalecloud-java not configured in Gradle build"
|
|
181
|
+
echo " To enable: bash $WHALECLOUD_PLUGIN_DIR/scripts/install-gradle-whalecloud.sh"
|
|
182
|
+
return 0
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
return 0
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
run_whalecloud_check() {
|
|
190
|
+
_run_whalecloud_check "$(_detect_java_build)"
|
|
191
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
_detect_kotlin_build() {
|
|
4
|
+
if [ -f "pom.xml" ]; then
|
|
5
|
+
echo "maven"
|
|
6
|
+
elif [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
7
|
+
echo "gradle"
|
|
8
|
+
else
|
|
9
|
+
echo "none"
|
|
10
|
+
fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run_static_analysis() {
|
|
14
|
+
local build_system
|
|
15
|
+
build_system=$(_detect_kotlin_build)
|
|
16
|
+
|
|
17
|
+
if [ "$build_system" = "maven" ]; then
|
|
18
|
+
mvn compile -q 2>&1 | grep -i "error\|fail" | head -5
|
|
19
|
+
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
|
20
|
+
echo "❌ Maven compilation failed"
|
|
21
|
+
return 1
|
|
22
|
+
fi
|
|
23
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
24
|
+
gradle compileKotlin --quiet 2>&1 | grep -i "error\|fail" | head -5
|
|
25
|
+
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
|
26
|
+
echo "❌ Gradle compilation failed"
|
|
27
|
+
return 1
|
|
28
|
+
fi
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
if command -v ktlint &>/dev/null; then
|
|
32
|
+
ktlint "**/*.kt" 2>&1 | head -20
|
|
33
|
+
return $?
|
|
34
|
+
elif command -v detekt &>/dev/null; then
|
|
35
|
+
detekt --input . 2>&1 | head -20
|
|
36
|
+
return $?
|
|
37
|
+
else
|
|
38
|
+
echo "No Kotlin lint tools (ktlint/detekt)"
|
|
39
|
+
return 0
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
run_lint() {
|
|
44
|
+
run_static_analysis
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
run_tests() {
|
|
48
|
+
local build_system
|
|
49
|
+
build_system=$(_detect_kotlin_build)
|
|
50
|
+
|
|
51
|
+
if [ "$build_system" = "maven" ]; then
|
|
52
|
+
mvn test -q 2>&1 | tail -15
|
|
53
|
+
return ${PIPESTATUS[0]}
|
|
54
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
55
|
+
gradle test --quiet 2>&1 | tail -15
|
|
56
|
+
return ${PIPESTATUS[0]}
|
|
57
|
+
else
|
|
58
|
+
echo "No build system detected"
|
|
59
|
+
return 1
|
|
60
|
+
fi
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
run_coverage() {
|
|
64
|
+
local build_system
|
|
65
|
+
build_system=$(_detect_kotlin_build)
|
|
66
|
+
|
|
67
|
+
if [ "$build_system" = "maven" ]; then
|
|
68
|
+
mvn test jacoco:report -q 2>&1 | tail -10
|
|
69
|
+
return ${PIPESTATUS[0]}
|
|
70
|
+
elif [ "$build_system" = "gradle" ]; then
|
|
71
|
+
gradle jacocoTestReport --quiet 2>&1 | tail -10
|
|
72
|
+
return ${PIPESTATUS[0]}
|
|
73
|
+
else
|
|
74
|
+
echo "No build system detected"
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
run_static_analysis() {
|
|
4
|
+
if command -v oclint &>/dev/null; then
|
|
5
|
+
oclint-json-compilation-database 2>&1 | head -30
|
|
6
|
+
return $?
|
|
7
|
+
elif command -v clang-tidy &>/dev/null; then
|
|
8
|
+
find . -name "*.m" -o -name "*.mm" -o -name "*.h" | head -20 | xargs clang-tidy 2>&1 | head -30
|
|
9
|
+
return $?
|
|
10
|
+
else
|
|
11
|
+
echo "No Objective-C analysis tools available (oclint/clang-tidy)"
|
|
12
|
+
return 1
|
|
13
|
+
fi
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
run_lint() {
|
|
17
|
+
run_static_analysis
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
run_tests() {
|
|
21
|
+
if [ -f "*.xcodeproj" ] || [ -f "*.xcworkspace" ]; then
|
|
22
|
+
echo "Xcode project detected — use xcodebuild for tests"
|
|
23
|
+
return 1
|
|
24
|
+
else
|
|
25
|
+
echo "No Objective-C test framework detected"
|
|
26
|
+
return 1
|
|
27
|
+
fi
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
run_coverage() {
|
|
31
|
+
if command -v xccov &>/dev/null; then
|
|
32
|
+
xccov view --report 2>&1 | tail -10
|
|
33
|
+
return $?
|
|
34
|
+
else
|
|
35
|
+
echo "No Objective-C coverage tools available"
|
|
36
|
+
return 1
|
|
37
|
+
fi
|
|
38
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# PowerShell adapter for quality gates
|
|
4
|
+
#
|
|
5
|
+
# Tool requirements:
|
|
6
|
+
# - PSScriptAnalyzer: Install-Module PSScriptAnalyzer -Scope CurrentUser
|
|
7
|
+
# - Pester: Install-Module Pester -Scope CurrentUser
|
|
8
|
+
#
|
|
9
|
+
# Notes:
|
|
10
|
+
# - Gate 2 (Duplicate Code): No PowerShell-native duplicate detector exists.
|
|
11
|
+
# jscpd and lizard do not support .ps1. SKIP for now.
|
|
12
|
+
# - Gate 3 (Cyclomatic Complexity): lizard does not analyze .ps1.
|
|
13
|
+
# SKIP for now.
|
|
14
|
+
# - Gate 4 (Principles Checker): No PowerShell principles checker.
|
|
15
|
+
# SKIP for now.
|
|
16
|
+
# - Gate 6 (Architecture): No PowerShell architecture tooling.
|
|
17
|
+
# SKIP for now.
|
|
18
|
+
|
|
19
|
+
# Detect PowerShell executable (prefer pwsh 7+, fallback to powershell.exe 5.1)
|
|
20
|
+
_detect_pwsh() {
|
|
21
|
+
if command -v pwsh &>/dev/null 2>&1; then
|
|
22
|
+
echo "pwsh"
|
|
23
|
+
elif command -v powershell.exe &>/dev/null 2>&1; then
|
|
24
|
+
echo "powershell.exe"
|
|
25
|
+
elif command -v powershell &>/dev/null 2>&1; then
|
|
26
|
+
echo "powershell"
|
|
27
|
+
else
|
|
28
|
+
echo ""
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
run_static_analysis() {
|
|
33
|
+
local PWSH
|
|
34
|
+
PWSH=$(_detect_pwsh)
|
|
35
|
+
if [ -n "$PWSH" ]; then
|
|
36
|
+
echo "Running PSScriptAnalyzer static analysis on PowerShell scripts..."
|
|
37
|
+
# Recursively analyze all .ps1 files from repo root
|
|
38
|
+
# Exit with non-zero if Error or Warning severity issues found
|
|
39
|
+
"$PWSH" -NoProfile -Command "
|
|
40
|
+
\$results = Invoke-ScriptAnalyzer -Path . -Recurse -Severity Error,Warning
|
|
41
|
+
if (\$results) {
|
|
42
|
+
\$results | Format-Table -AutoSize
|
|
43
|
+
exit 1
|
|
44
|
+
}
|
|
45
|
+
exit 0
|
|
46
|
+
"
|
|
47
|
+
return $?
|
|
48
|
+
else
|
|
49
|
+
echo "PowerShell not available, skipping PowerShell static analysis"
|
|
50
|
+
return 0
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
run_lint() {
|
|
55
|
+
# PSScriptAnalyzer covers both static analysis and linting
|
|
56
|
+
run_static_analysis
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
run_tests() {
|
|
60
|
+
local PWSH
|
|
61
|
+
PWSH=$(_detect_pwsh)
|
|
62
|
+
if [ -z "$PWSH" ]; then
|
|
63
|
+
echo "PowerShell not available, skipping PowerShell tests"
|
|
64
|
+
return 0
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Check if Pester tests exist in common locations
|
|
68
|
+
local test_paths=""
|
|
69
|
+
if [ -d "tests" ]; then
|
|
70
|
+
test_paths="tests/"
|
|
71
|
+
elif [ -d "test" ]; then
|
|
72
|
+
test_paths="test/"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [ -n "$test_paths" ] && find "$test_paths" -name "*.Tests.ps1" -type f 2>/dev/null | head -1 | grep -q "."; then
|
|
76
|
+
echo "Running Pester tests..."
|
|
77
|
+
"$PWSH" -NoProfile -Command "
|
|
78
|
+
\$results = Invoke-Pester -Path '$test_paths' -PassThru
|
|
79
|
+
if (\$results.FailedCount -gt 0) {
|
|
80
|
+
Write-Host \"FAILED: \$(\$results.FailedCount) test(s)\"
|
|
81
|
+
exit 1
|
|
82
|
+
}
|
|
83
|
+
Write-Host \"PASSED: \$(\$results.PassedCount) test(s)\"
|
|
84
|
+
exit 0
|
|
85
|
+
"
|
|
86
|
+
return $?
|
|
87
|
+
elif find . -maxdepth 2 -name "*.Tests.ps1" -type f 2>/dev/null | head -1 | grep -q "."; then
|
|
88
|
+
echo "Running Pester tests in current directory..."
|
|
89
|
+
"$PWSH" -NoProfile -Command "
|
|
90
|
+
\$results = Invoke-Pester -CI -PassThru
|
|
91
|
+
if (\$results.FailedCount -gt 0) {
|
|
92
|
+
Write-Host \"FAILED: \$(\$results.FailedCount) test(s)\"
|
|
93
|
+
exit 1
|
|
94
|
+
}
|
|
95
|
+
Write-Host \"PASSED: \$(\$results.PassedCount) test(s)\"
|
|
96
|
+
exit 0
|
|
97
|
+
"
|
|
98
|
+
return $?
|
|
99
|
+
else
|
|
100
|
+
echo "No Pester tests found"
|
|
101
|
+
return 0
|
|
102
|
+
fi
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
run_coverage() {
|
|
106
|
+
local PWSH
|
|
107
|
+
PWSH=$(_detect_pwsh)
|
|
108
|
+
if [ -z "$PWSH" ]; then
|
|
109
|
+
echo "PowerShell not available, skipping PowerShell coverage"
|
|
110
|
+
return 0
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
local test_paths=""
|
|
114
|
+
if [ -d "tests" ]; then
|
|
115
|
+
test_paths="tests/"
|
|
116
|
+
elif [ -d "test" ]; then
|
|
117
|
+
test_paths="test/"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
if [ -n "$test_paths" ] || find . -maxdepth 2 -name "*.Tests.ps1" -type f 2>/dev/null | head -1 | grep -q "."; then
|
|
121
|
+
echo "Running Pester with code coverage..."
|
|
122
|
+
local path_arg="${test_paths:-.}"
|
|
123
|
+
"$PWSH" -NoProfile -Command "
|
|
124
|
+
\$results = Invoke-Pester -Path '$path_arg' -CodeCoverage @(Get-ChildItem -Path . -Filter *.ps1 -Recurse -Exclude *.Tests.ps1) -PassThru
|
|
125
|
+
\$pct = [math]::Round(\$results.CodeCoverage.CoveragePercent, 1)
|
|
126
|
+
Write-Host \"Coverage: \$pct%\"
|
|
127
|
+
if (\$pct -lt 80) {
|
|
128
|
+
Write-Host \"WARNING: Coverage \$pct% is below 80% threshold\"
|
|
129
|
+
exit 0
|
|
130
|
+
}
|
|
131
|
+
exit 0
|
|
132
|
+
" 2>&1
|
|
133
|
+
return $?
|
|
134
|
+
else
|
|
135
|
+
echo "No Pester tests found for coverage measurement"
|
|
136
|
+
return 0
|
|
137
|
+
fi
|
|
138
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Python adapter for quality gates
|
|
4
|
+
# Tools: mypy, ruff/flake8, pytest, import-linter (architecture)
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
source "$SCRIPT_DIR/../adapter-common.sh" 2>/dev/null || true
|
|
8
|
+
|
|
9
|
+
run_static_analysis() {
|
|
10
|
+
require_tool mypy "mypy" || return 1
|
|
11
|
+
|
|
12
|
+
echo "Running Python static analysis (mypy)..."
|
|
13
|
+
mypy .
|
|
14
|
+
return $?
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
run_lint() {
|
|
18
|
+
if command -v ruff >/dev/null 2>&1; then
|
|
19
|
+
echo "Running Python linting (ruff)..."
|
|
20
|
+
ruff check .
|
|
21
|
+
return $?
|
|
22
|
+
elif command -v flake8 >/dev/null 2>&1; then
|
|
23
|
+
echo "Running Python linting (flake8)..."
|
|
24
|
+
flake8 .
|
|
25
|
+
return $?
|
|
26
|
+
else
|
|
27
|
+
echo "⚠ No Python linter available (ruff or flake8 required)"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
run_architecture() {
|
|
33
|
+
if [ ! -f ".import-linter.yml" ] && [ ! -f "import_linter_config.yml" ]; then
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
require_tool lint-imports "import-linter" || return 0
|
|
38
|
+
|
|
39
|
+
echo "Running Python architecture checks (import-linter)..."
|
|
40
|
+
lint-imports
|
|
41
|
+
return $?
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
run_tests() {
|
|
45
|
+
require_tool pytest "pytest" || return 1
|
|
46
|
+
|
|
47
|
+
echo "Running Python tests..."
|
|
48
|
+
PYTEST_OUTPUT=$(pytest --exitfirst --tb=short 2>&1)
|
|
49
|
+
PYTEST_EXIT=$?
|
|
50
|
+
echo "$PYTEST_OUTPUT" | tail -30
|
|
51
|
+
|
|
52
|
+
# Check for collection errors (ModuleNotFoundError / ImportError)
|
|
53
|
+
if echo "$PYTEST_OUTPUT" | grep -qi "ModuleNotFoundError\|ImportError"; then
|
|
54
|
+
echo "❌ Python test collection errors detected — modules not importable"
|
|
55
|
+
echo " Fix: Run 'pip install -e .' or set PYTHONPATH=."
|
|
56
|
+
return 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Check if no tests were actually collected
|
|
60
|
+
if echo "$PYTEST_OUTPUT" | grep -q "collected 0 items\|no tests ran"; then
|
|
61
|
+
echo "❌ No tests were collected — nothing actually ran"
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Check for errors in summary line (e.g. "3 errors")
|
|
66
|
+
ERROR_COUNT=$(echo "$PYTEST_OUTPUT" | grep -oP '\d+ error' | grep -oP '\d+' | head -1)
|
|
67
|
+
if [ -n "$ERROR_COUNT" ] && [ "$ERROR_COUNT" -gt 0 ]; then
|
|
68
|
+
echo "❌ $ERROR_COUNT test collection/execution errors detected"
|
|
69
|
+
return 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
return $PYTEST_EXIT
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
run_coverage() {
|
|
76
|
+
require_tool pytest "pytest" || return 1
|
|
77
|
+
|
|
78
|
+
echo "Running Python coverage..."
|
|
79
|
+
PYTEST_OUTPUT=$(pytest --exitfirst --tb=short --cov=. --cov-fail-under=80 2>&1)
|
|
80
|
+
PYTEST_EXIT=$?
|
|
81
|
+
echo "$PYTEST_OUTPUT" | tail -30
|
|
82
|
+
|
|
83
|
+
# Check for collection errors (ModuleNotFoundError / ImportError)
|
|
84
|
+
if echo "$PYTEST_OUTPUT" | grep -qi "ModuleNotFoundError\|ImportError"; then
|
|
85
|
+
echo "❌ Python test collection errors detected — modules not importable"
|
|
86
|
+
echo " Fix: Run 'pip install -e .' or set PYTHONPATH=."
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# Check if no tests were actually collected
|
|
91
|
+
if echo "$PYTEST_OUTPUT" | grep -q "collected 0 items\|no tests ran"; then
|
|
92
|
+
echo "❌ No tests were collected — nothing actually ran"
|
|
93
|
+
return 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Check for errors in summary line (e.g. "3 errors")
|
|
97
|
+
ERROR_COUNT=$(echo "$PYTEST_OUTPUT" | grep -oP '\d+ error' | grep -oP '\d+' | head -1)
|
|
98
|
+
if [ -n "$ERROR_COUNT" ] && [ "$ERROR_COUNT" -gt 0 ]; then
|
|
99
|
+
echo "❌ $ERROR_COUNT test collection/execution errors detected"
|
|
100
|
+
return 1
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
return $PYTEST_EXIT
|
|
104
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Shell adapter for quality gates
|
|
4
|
+
|
|
5
|
+
run_static_analysis() {
|
|
6
|
+
if command -v shellcheck >/dev/null 2>&1; then
|
|
7
|
+
echo "Running Shell static analysis..."
|
|
8
|
+
shellcheck ./*.sh
|
|
9
|
+
return $?
|
|
10
|
+
else
|
|
11
|
+
echo "shellcheck not available, skipping Shell linting"
|
|
12
|
+
return 0
|
|
13
|
+
fi
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
run_lint() {
|
|
17
|
+
if command -v shellcheck >/dev/null 2>&1; then
|
|
18
|
+
echo "Running Shell linting..."
|
|
19
|
+
shellcheck ./*.sh ./**/**/*.sh
|
|
20
|
+
return $?
|
|
21
|
+
else
|
|
22
|
+
echo "shellcheck not available, skipping Shell linting"
|
|
23
|
+
return 0
|
|
24
|
+
fi
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
run_tests() {
|
|
28
|
+
# Look for and run shell test files
|
|
29
|
+
if [[ -d "tests" ]] && [[ -n "$(find tests -name "*.sh" -type f | head -n 1)" ]]; then
|
|
30
|
+
echo "Running Shell tests..."
|
|
31
|
+
for test_file in tests/*.sh; do
|
|
32
|
+
if [[ -x "$test_file" ]]; then
|
|
33
|
+
"$test_file"
|
|
34
|
+
local exit_code=$?
|
|
35
|
+
if [[ $exit_code -ne 0 ]]; then
|
|
36
|
+
return $exit_code
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
return 0
|
|
41
|
+
elif command -v shunit2 >/dev/null 2>&1; then
|
|
42
|
+
echo "Checking for shunit2 tests..."
|
|
43
|
+
# Skip - shunit2 requires properly formatted tests, just run any script if available
|
|
44
|
+
return 0
|
|
45
|
+
else
|
|
46
|
+
echo "No shell tests detected or shunit2 available"
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
run_coverage() {
|
|
52
|
+
# Shell does not typically have standardized coverage tools
|
|
53
|
+
echo "Shell coverage not available"
|
|
54
|
+
return 0
|
|
55
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
run_static_analysis() {
|
|
4
|
+
if command -v swiftlint &>/dev/null; then
|
|
5
|
+
swiftlint lint 2>&1 | head -30
|
|
6
|
+
return $?
|
|
7
|
+
else
|
|
8
|
+
echo "SwiftLint not available"
|
|
9
|
+
return 1
|
|
10
|
+
fi
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
run_lint() {
|
|
14
|
+
if command -v swiftlint &>/dev/null; then
|
|
15
|
+
swiftlint lint --strict 2>&1 | head -30
|
|
16
|
+
return $?
|
|
17
|
+
else
|
|
18
|
+
echo "SwiftLint not available"
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
run_tests() {
|
|
24
|
+
if command -v swift &>/dev/null && [ -f "Package.swift" ]; then
|
|
25
|
+
swift test 2>&1 | tail -20
|
|
26
|
+
return $?
|
|
27
|
+
elif [ -f "*.xcodeproj" ] || [ -f "*.xcworkspace" ]; then
|
|
28
|
+
echo "Xcode project detected — use xcodebuild for tests"
|
|
29
|
+
return 1
|
|
30
|
+
else
|
|
31
|
+
echo "No Swift test framework detected"
|
|
32
|
+
return 1
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
run_coverage() {
|
|
37
|
+
if command -v swift &>/dev/null && [ -f "Package.swift" ]; then
|
|
38
|
+
swift test --enable-code-coverage 2>&1 | tail -10
|
|
39
|
+
return $?
|
|
40
|
+
else
|
|
41
|
+
echo "No Swift test framework detected"
|
|
42
|
+
return 1
|
|
43
|
+
fi
|
|
44
|
+
}
|