claude-devkit-cli 1.0.0

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.
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env bash
2
+ # build-test.sh — Universal test runner with auto-detection
3
+ # Detects project language/framework and runs the appropriate test command.
4
+ #
5
+ # Usage:
6
+ # bash scripts/build-test.sh # run all tests
7
+ # bash scripts/build-test.sh --filter "Auth" # filter by pattern
8
+ # bash scripts/build-test.sh --list # show detected project type
9
+ # bash scripts/build-test.sh --ci # machine-readable output
10
+ #
11
+ # Supports: Swift (SPM/Xcode), Node (Vitest/Jest), Python (pytest/unittest),
12
+ # Rust (cargo), Go, Java (Gradle/Maven), C# (.NET), Ruby (RSpec/Minitest)
13
+ #
14
+ # Exit codes:
15
+ # 0 — all tests passed
16
+ # 1 — tests failed
17
+ # 2 — no project detected or missing tooling
18
+
19
+ set -euo pipefail
20
+
21
+ # ─── Argument parsing ───────────────────────────────────────────────
22
+
23
+ FILTER=""
24
+ CI_MODE=false
25
+ LIST_ONLY=false
26
+
27
+ while [[ $# -gt 0 ]]; do
28
+ case "$1" in
29
+ --filter) FILTER="${2:-}"; shift 2 ;;
30
+ --ci) CI_MODE=true; shift ;;
31
+ --list) LIST_ONLY=true; shift ;;
32
+ --help|-h) sed -n '2,16p' "$0"; exit 0 ;;
33
+ *) FILTER="$1"; shift ;; # bare arg = filter
34
+ esac
35
+ done
36
+
37
+ # ─── Output helpers ─────────────────────────────────────────────────
38
+
39
+ info() { echo "[INFO] $*"; }
40
+ pass() { echo "[PASS] $*"; }
41
+ fail() { echo "[FAIL] $*"; }
42
+ skip() { echo "[SKIP] $*"; }
43
+
44
+ # ─── Language detectors ─────────────────────────────────────────────
45
+ # Each function returns 0 if detected, 1 otherwise.
46
+ # Sets LANG_NAME and TEST_CMD as side effects.
47
+
48
+ detect_swift_spm() {
49
+ [[ -f "Package.swift" ]] || return 1
50
+ LANG_NAME="Swift (SPM)"
51
+ if [[ -n "$FILTER" ]]; then
52
+ TEST_CMD="swift test --filter '$FILTER'"
53
+ else
54
+ TEST_CMD="swift test"
55
+ fi
56
+ }
57
+
58
+ detect_swift_xcode() {
59
+ local project=""
60
+ local flag=""
61
+
62
+ if compgen -G "*.xcworkspace" > /dev/null 2>&1; then
63
+ project=$(compgen -G "*.xcworkspace" | head -1)
64
+ flag="-workspace"
65
+ elif compgen -G "*.xcodeproj" > /dev/null 2>&1; then
66
+ project=$(compgen -G "*.xcodeproj" | head -1)
67
+ flag="-project"
68
+ else
69
+ return 1
70
+ fi
71
+
72
+ local scheme
73
+ scheme=$(xcodebuild "$flag" "$project" -list 2>/dev/null \
74
+ | sed -n '/Schemes:/,/^$/p' | tail -n +2 | head -1 | xargs) || return 1
75
+
76
+ [[ -z "$scheme" ]] && return 1
77
+
78
+ LANG_NAME="Swift (Xcode: $scheme)"
79
+ TEST_CMD="xcodebuild test $flag '$project' -scheme '$scheme' -destination 'platform=macOS,arch=arm64'"
80
+ if [[ -n "$FILTER" ]]; then
81
+ TEST_CMD="$TEST_CMD -only-testing:'$FILTER'"
82
+ fi
83
+ }
84
+
85
+ detect_node() {
86
+ [[ -f "package.json" ]] || return 1
87
+
88
+ # Detect package manager
89
+ local runner="npx"
90
+ [[ -f "pnpm-lock.yaml" ]] && runner="pnpm exec"
91
+ [[ -f "bun.lockb" || -f "bun.lock" ]] && runner="bunx"
92
+
93
+ if [[ -f "vitest.config.ts" || -f "vitest.config.js" || -f "vitest.config.mts" ]] \
94
+ || grep -q '"vitest"' package.json 2>/dev/null; then
95
+ LANG_NAME="Node (Vitest)"
96
+ if [[ -n "$FILTER" ]]; then
97
+ TEST_CMD="$runner vitest run '$FILTER'"
98
+ else
99
+ TEST_CMD="$runner vitest run"
100
+ fi
101
+ elif [[ -f "jest.config.ts" || -f "jest.config.js" || -f "jest.config.mjs" ]] \
102
+ || grep -q '"jest"' package.json 2>/dev/null; then
103
+ LANG_NAME="Node (Jest)"
104
+ if [[ -n "$FILTER" ]]; then
105
+ TEST_CMD="$runner jest '$FILTER' --no-cache"
106
+ else
107
+ TEST_CMD="$runner jest --no-cache"
108
+ fi
109
+ elif grep -q '"test"' package.json 2>/dev/null; then
110
+ LANG_NAME="Node (npm test)"
111
+ TEST_CMD="npm test"
112
+ else
113
+ return 1
114
+ fi
115
+ }
116
+
117
+ detect_python() {
118
+ [[ -f "pyproject.toml" || -f "setup.py" || -f "pytest.ini" || -f "setup.cfg" ]] \
119
+ || { [[ -d "tests" && -f "requirements.txt" ]]; } \
120
+ || return 1
121
+
122
+ if command -v pytest &>/dev/null || python3 -m pytest --version &>/dev/null 2>&1; then
123
+ LANG_NAME="Python (pytest)"
124
+ if [[ -n "$FILTER" ]]; then
125
+ TEST_CMD="python3 -m pytest -xvs -k '$FILTER'"
126
+ else
127
+ TEST_CMD="python3 -m pytest -x"
128
+ fi
129
+ else
130
+ LANG_NAME="Python (unittest)"
131
+ TEST_CMD="python3 -m unittest discover -s tests"
132
+ fi
133
+ }
134
+
135
+ detect_rust() {
136
+ [[ -f "Cargo.toml" ]] || return 1
137
+ LANG_NAME="Rust (cargo)"
138
+ if [[ -n "$FILTER" ]]; then
139
+ TEST_CMD="cargo test '$FILTER'"
140
+ else
141
+ TEST_CMD="cargo test"
142
+ fi
143
+ }
144
+
145
+ detect_go() {
146
+ [[ -f "go.mod" ]] || return 1
147
+ LANG_NAME="Go"
148
+ if [[ -n "$FILTER" ]]; then
149
+ TEST_CMD="go test -race -run '$FILTER' ./..."
150
+ else
151
+ TEST_CMD="go test -race ./..."
152
+ fi
153
+ }
154
+
155
+ detect_gradle() {
156
+ [[ -f "build.gradle" || -f "build.gradle.kts" ]] || return 1
157
+ LANG_NAME="Java/Kotlin (Gradle)"
158
+ if [[ -n "$FILTER" ]]; then
159
+ TEST_CMD="./gradlew test --tests '$FILTER'"
160
+ else
161
+ TEST_CMD="./gradlew test"
162
+ fi
163
+ }
164
+
165
+ detect_maven() {
166
+ [[ -f "pom.xml" ]] || return 1
167
+ LANG_NAME="Java (Maven)"
168
+ if [[ -n "$FILTER" ]]; then
169
+ TEST_CMD="mvn test -Dtest='$FILTER'"
170
+ else
171
+ TEST_CMD="mvn test"
172
+ fi
173
+ }
174
+
175
+ detect_dotnet() {
176
+ compgen -G "*.sln" > /dev/null 2>&1 || compgen -G "*.csproj" > /dev/null 2>&1 || return 1
177
+ LANG_NAME="C# (.NET)"
178
+ if [[ -n "$FILTER" ]]; then
179
+ TEST_CMD="dotnet test --filter '$FILTER'"
180
+ else
181
+ TEST_CMD="dotnet test"
182
+ fi
183
+ }
184
+
185
+ detect_ruby() {
186
+ [[ -f "Gemfile" ]] || return 1
187
+ if grep -q 'rspec' Gemfile 2>/dev/null; then
188
+ LANG_NAME="Ruby (RSpec)"
189
+ if [[ -n "$FILTER" ]]; then
190
+ TEST_CMD="bundle exec rspec --tag '$FILTER'"
191
+ else
192
+ TEST_CMD="bundle exec rspec"
193
+ fi
194
+ else
195
+ LANG_NAME="Ruby (Minitest)"
196
+ TEST_CMD="bundle exec rake test"
197
+ fi
198
+ }
199
+
200
+ # ─── Detection order (first match wins) ────────────────────────────
201
+
202
+ DETECTORS=(
203
+ detect_swift_spm
204
+ detect_swift_xcode
205
+ detect_node
206
+ detect_python
207
+ detect_rust
208
+ detect_go
209
+ detect_gradle
210
+ detect_maven
211
+ detect_dotnet
212
+ detect_ruby
213
+ )
214
+
215
+ LANG_NAME=""
216
+ TEST_CMD=""
217
+
218
+ for detector in "${DETECTORS[@]}"; do
219
+ if $detector; then
220
+ break
221
+ fi
222
+ done
223
+
224
+ # ─── No project detected ───────────────────────────────────────────
225
+
226
+ if [[ -z "$LANG_NAME" ]]; then
227
+ fail "No supported project detected in $(pwd)"
228
+ info "Supported: Swift (SPM/Xcode), Node (Vitest/Jest), Python (pytest),"
229
+ info " Rust (cargo), Go, Java (Gradle/Maven), C# (.NET), Ruby"
230
+ exit 2
231
+ fi
232
+
233
+ # ─── List mode ──────────────────────────────────────────────────────
234
+
235
+ if $LIST_ONLY; then
236
+ if $CI_MODE; then
237
+ echo "$LANG_NAME"
238
+ else
239
+ info "Detected: $LANG_NAME"
240
+ info "Command: $TEST_CMD"
241
+ fi
242
+ exit 0
243
+ fi
244
+
245
+ # ─── Run tests ──────────────────────────────────────────────────────
246
+
247
+ info "Detected: $LANG_NAME"
248
+ info "Running: $TEST_CMD"
249
+ echo ""
250
+
251
+ if eval "$TEST_CMD"; then
252
+ echo ""
253
+ pass "All tests passed ($LANG_NAME)"
254
+ exit 0
255
+ else
256
+ STATUS=$?
257
+ echo ""
258
+ fail "Tests failed ($LANG_NAME, exit code: $STATUS)"
259
+ exit 1
260
+ fi