diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..fd8d21f4 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,18 @@ +# Linux dev environment matching the CI runner (ubuntu, bash 5, Node 22, Go 1.26). +# Keep the versions in step with .github/workflows/deploy.yml (node-version, GO_VERSION). +FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 + +# sqlite3 CLI + fuser (psmisc): used when seeding the E2E fixture DB and freeing the test port. +RUN apt-get update && apt-get install -y --no-install-recommends sqlite3 psmisc \ + && rm -rf /var/lib/apt/lists/* + +ARG NODE_MAJOR=22 +ARG GO_VERSION=1.26.0 + +RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \ + && apt-get install -y --no-install-recommends nodejs \ + && rm -rf /var/lib/apt/lists/* + +RUN ARCH="$(dpkg --print-architecture)" \ + && curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" | tar -C /usr/local -xz +ENV PATH="/usr/local/go/bin:${PATH}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..113313e4 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +{ + "name": "CoreScope (CI parity)", + "build": { + "dockerfile": "Dockerfile" + }, + "postCreateCommand": "npm ci --production=false && npx playwright install --with-deps chromium", + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "golang.go" + ] + } + }, + "remoteEnv": { + "CI": "true" + } +} diff --git a/scripts/e2e-local.sh b/scripts/e2e-local.sh new file mode 100644 index 00000000..664d980b --- /dev/null +++ b/scripts/e2e-local.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# usage: bash scripts/e2e-local.sh tests/e2e/.js [more tests...] +set -euo pipefail +cd "$(dirname "$0")/.." + +PORT="${E2E_PORT:-13581}" +WORK="$(mktemp -d)" +DB="$WORK/e2e-fixture.db" +SERVER_PID="" +cleanup() { [ -n "$SERVER_PID" ] && kill "$SERVER_PID" 2>/dev/null || true; rm -rf "$WORK"; } +trap cleanup EXIT + +[ "$#" -ge 1 ] || { echo "usage: $0 tests/e2e/.js [more tests...]" >&2; exit 2; } +for t in "$@"; do [ -f "$t" ] || { echo "no such test: $t" >&2; exit 2; }; done +command -v sqlite3 >/dev/null || { echo "sqlite3 CLI is required" >&2; exit 2; } + +go build -o "$WORK/corescope-server" ./cmd/server +go build -o "$WORK/corescope-migrate" ./cmd/migrate + +cp test-fixtures/e2e-fixture.db "$DB" +bash tools/freshen-fixture.sh "$DB" +"$WORK/corescope-migrate" -db "$DB" -baseline-stamp-migrate + +WF=.github/workflows/deploy.yml +grep -E "sqlite3 test-fixtures/e2e-fixture.db \"UPDATE observers" "$WF" \ + | sed -E 's/^ *run: *//; s#test-fixtures/e2e-fixture.db#'"$DB"'#' | bash +awk '/sqlite3 test-fixtures\/e2e-fixture.db <<.SQL.$/{f=1;next} /^ *SQL$/{f=0} f' "$WF" | sqlite3 "$DB" + +fuser -k "$PORT"/tcp 2>/dev/null || true +"$WORK/corescope-server" -port "$PORT" -db "$DB" -public public >"$WORK/server.log" 2>&1 & +SERVER_PID=$! +for i in $(seq 1 120); do + if curl -sf "http://localhost:$PORT/api/healthz" 2>/dev/null | grep -q '"ready":true'; then echo "server ready after ${i}s"; break; fi + kill -0 "$SERVER_PID" 2>/dev/null || { echo "server exited:"; tail -50 "$WORK/server.log"; exit 1; } + [ "$i" -eq 120 ] && { echo "server not ready after 120s:"; tail -50 "$WORK/server.log"; exit 1; } + sleep 1 +done + +rc=0 +for t in "$@"; do + echo "== $t" + CHROMIUM_REQUIRE=1 BASE_URL="http://localhost:$PORT" node "$t" || rc=1 +done +[ "$rc" -eq 0 ] || { echo "== server log tail"; tail -30 "$WORK/server.log"; } +exit "$rc" \ No newline at end of file