Repository navigation
Expand file tree
/
Copy pathtest.sh
More file actions
executable file
·192 lines (163 loc) · 7.67 KB
/
Copy pathtest.sh
File metadata and controls
executable file
·192 lines (163 loc) · 7.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env bash
set -euo pipefail
# Trawl — local test runner.
#
# This mirrors .github/workflows/ci.yml step for step, so that a green run here
# means a green run there. If you add a gate to CI, add it here too; a local
# check that is weaker than the remote one is worse than no local check,
# because it tells you that you are done when you are not.
#
# Usage:
# ./test.sh # everything except the Docker image build
# ./test.sh --docker # also build and smoke-test the server image
# ./test.sh --desktop # also build the Wails desktop application
# ./test.sh --quick # skip the production bundle build (the slow step)
WITH_DOCKER=false
WITH_DESKTOP=false
QUICK=false
for arg in "$@"; do
case "${arg}" in
--docker) WITH_DOCKER=true ;;
--desktop) WITH_DESKTOP=true ;;
--quick) QUICK=true ;;
-h|--help)
sed -n '3,15p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*) echo "Unknown option: ${arg}" >&2; exit 1 ;;
esac
done
STEP=0
step() {
STEP=$((STEP + 1))
echo ""
echo "──────────────────────────────────────────────────────────────"
echo " [${STEP}] $1"
echo "──────────────────────────────────────────────────────────────"
}
echo "============================================================"
echo " Trawl — Local Test Runner "
echo "============================================================"
# ─── Go engine ────────────────────────────────────────────────────────────────
# ./... is deliberately not used: the root package embeds the built dashboard
# via go:embed, so it cannot compile without a prior Angular build.
step "Go — formatting"
if [ -n "$(gofmt -l ./pkg ./cmd)" ]; then
echo "The following files are not formatted. Run: gofmt -w ./pkg ./cmd" >&2
gofmt -l ./pkg ./cmd >&2
exit 1
fi
echo "✔ gofmt clean"
step "Go — vet"
go vet ./pkg/... ./cmd/...
echo "✔ vet clean"
step "Go — build"
go build ./pkg/... ./cmd/...
echo "✔ engine builds"
# -race is not optional here: the job queue is claimed concurrently by multiple
# workers, and its exclusivity test spawns goroutines to prove it.
step "Go — tests (race detector enabled)"
go test -race -count=1 ./pkg/... ./cmd/...
# ─── Frontend ─────────────────────────────────────────────────────────────────
step "TypeScript — typecheck"
npm run typecheck
step "Frontend — unit tests"
npm test
step "Dependency gate — classifier tests"
npm run test:classifier
# The same check the pre-push hook runs. Having it here too means a dependency
# that becomes vulnerable is reported by the ordinary development loop rather
# than discovered at the moment of pushing, when the intent is to be finished.
step "Dependencies — vulnerability gate"
./scripts/check-vulns.sh
# ─── Specifications ───────────────────────────────────────────────────────────
# The ledger is this project's central argument, and it has twice been broken
# by ordinary housekeeping: a change archived with `git mv` recreated at its
# old path by an editor buffer, and a tasks.md truncated to nothing behind a
# proposal still citing its phases. Neither is visible on inspection.
step "Specifications — ledger reconciliation"
go run ./cmd/specledger --check
# House style: em dashes are for the prose in this repository, not for the
# product. They render unpredictably in terminals and in the plain-text half of
# an email report, and they are awkward enough to type that they drift into
# inconsistency. This checks only strings a user reads, never comments.
step "Prose — em dashes in user-visible text"
go run ./cmd/prosecheck
# ─── Deployment ───────────────────────────────────────────────────────────────
step "Compose — manifest validation"
docker compose -f deploy/compose/docker-compose.yml config -q
docker compose -f deploy/compose/docker-compose.dev.yml config -q
echo "✔ compose manifests valid"
# Packaging defects are invisible locally, invisible in CI, and discovered by a
# user on a platform nobody here owns, hours after a tag was pushed. The cheap
# subset of those checks is worth running on every commit rather than only at
# release time.
step "Packaging — manifest validation"
./scripts/validate-packaging.sh
if [ "${QUICK}" = false ]; then
step "Angular — production bundle"
npm run build > /dev/null
echo "✔ production bundle builds"
else
echo ""
echo " (skipping production bundle build — --quick)"
fi
if [ "${WITH_DOCKER}" = true ]; then
step "Server image — build and smoke test"
docker build -q -f deploy/compose/Dockerfile.server -t trawl-server:local . > /dev/null
docker rm -f trawl-local > /dev/null 2>&1 || true
docker run -d --name trawl-local -p 8099:8080 trawl-server:local > /dev/null
trap 'docker rm -f trawl-local > /dev/null 2>&1 || true' EXIT
HEALTHY=false
for _ in $(seq 1 30); do
if curl -sf http://127.0.0.1:8099/healthz > /dev/null; then HEALTHY=true; break; fi
sleep 1
done
if [ "${HEALTHY}" = false ]; then
echo "FAIL: server did not become healthy within 30s" >&2
docker logs trawl-local >&2
exit 1
fi
# Round-trip a job through the queue: enqueue, claim, then confirm the queue
# reports empty rather than erroring.
curl -sf -X POST http://127.0.0.1:8099/api/jobs \
-H 'Content-Type: application/json' \
-d '{"type":"scan","targets":["example.com"]}' > /dev/null
CLAIMED=$(curl -sf "http://127.0.0.1:8099/api/jobs/pop?type=scan")
echo "${CLAIMED}" | grep -q '"status":"running"' \
|| { echo "FAIL: claimed job was not marked running: ${CLAIMED}" >&2; exit 1; }
EMPTY=$(curl -sf "http://127.0.0.1:8099/api/jobs/pop?type=scan")
[ "${EMPTY}" = "{}" ] \
|| { echo "FAIL: drained queue returned '${EMPTY}', expected {}" >&2; exit 1; }
echo "✔ server image healthy; job round-trips through the queue"
else
echo ""
echo " (skipping server image build — pass --docker to include it)"
fi
if [ "${WITH_DESKTOP}" = true ]; then
step "Wails — desktop application build"
export PATH="${PATH}:$(go env GOPATH)/bin"
if ! command -v wails > /dev/null; then
echo "FAIL: wails CLI not found. Install with:" >&2
echo " go install github.com/wailsapp/wails/v2/cmd/wails@latest" >&2
exit 1
fi
wails build > /dev/null
echo "✔ desktop application builds"
# Regenerated bindings that differ from the committed ones mean the frontend
# is calling a backend surface that no longer matches. Catch it here rather
# than as a runtime "method not found" in the packaged app.
if ! git diff --quiet -- app/wailsjs; then
echo "FAIL: Wails bindings in app/wailsjs are stale — commit the regenerated files:" >&2
git diff --stat -- app/wailsjs >&2
exit 1
fi
echo "✔ committed Wails bindings match the bound Go methods"
else
echo ""
echo " (skipping desktop build — pass --desktop to include it)"
fi
echo ""
echo "============================================================"
echo " ✔ ALL CHECKS PASSED — READY TO COMMIT"
echo "============================================================"