diff --git a/Makefile b/Makefile index 7438d23..bd3c7a8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,13 @@ SHELL := /bin/bash +GO_TEST_PACKAGE ?= $(shell cd server && go list ./... | grep -Ev 'internal/(store|seed)$$') +GO_TEST_RUN ?= +GO_TEST_ARGS ?= + +ifneq ($(strip $(GO_TEST_RUN)),) +GO_TEST_RUN_FLAG := -run '$(GO_TEST_RUN)' +endif + # Production image knobs. Override at the CLI: # make docker-build PARSAR_IMAGE=parsar PARSAR_IMAGE_TAG=v0.1.0 # PARSAR_IMAGE is intentionally a generic local name — the open-source @@ -8,16 +16,40 @@ SHELL := /bin/bash PARSAR_IMAGE ?= parsar PARSAR_IMAGE_TAG ?= dev -.PHONY: setup dev dev-db check reset-dev clean-dev paths migrate-dev sqlc-generate server web cli devgateway http-runner-once http-runner-loop dev-all smoke e2e-http-agent e2e-feishu-gateway dev-server-up dev-server-down dev-server-log bootstrap docker-build docker-build-no-cache openapi +.PHONY: help setup node-deps dev dev-db check test test-fast test-go test-web typecheck-web lint-web-design lint-web test-cli typecheck reset-dev clean-dev paths migrate-dev sqlc-generate server web cli devgateway http-runner-once http-runner-loop dev-all smoke e2e-http-agent e2e-feishu-gateway dev-server-up dev-server-down dev-server-log bootstrap docker-build docker-build-no-cache openapi + +help: + @printf '%s\n' \ + 'Local development:' \ + ' make dev-all Start Postgres, API, web, and HTTP runner' \ + ' make dev-db Start the development Postgres only' \ + ' make server Run the API in the foreground' \ + ' make web Run the web app in the foreground' \ + '' \ + 'Fast feedback:' \ + ' make test-fast Run Go tests plus frontend/CLI checks' \ + ' make test-go Run all Go tests without integration DB packages' \ + ' make test-go GO_TEST_PACKAGE=./server/internal/api/...' \ + ' make test-go GO_TEST_PACKAGE=./server/internal/api GO_TEST_RUN=TestHealth' \ + ' make test-web Typecheck web and check design-system lint' \ + ' make lint-web Run the full web lint (existing debt may fail)' \ + ' make test-cli Run CLI unit tests' \ + ' make typecheck Typecheck all TypeScript packages' \ + '' \ + 'Before review:' \ + ' make check Run the required full repository gate' setup: ./scripts/setup.sh +node-deps: + @if [[ ! -d node_modules ]]; then pnpm install --frozen-lockfile; fi + paths: ./scripts/setup.sh paths migrate-dev: - cd server && go run ./cmd/migrate + ./scripts/with-dev-env.sh bash -c 'cd server && exec go run ./cmd/migrate' # `make bootstrap` is the operator-side first-owner provisioning # entry point for a freshly-installed Parsar. Required flags must @@ -47,6 +79,36 @@ dev: dev-db check: ./scripts/check.sh +# Fast local feedback. Unlike `make check`, these targets skip setup, +# code-generation drift checks, and database-backed migration tests. +test: test-fast + +test-fast: test-go test-web test-cli + +test-go: + go test $(GO_TEST_PACKAGE) $(GO_TEST_RUN_FLAG) $(GO_TEST_ARGS) + +test-web: typecheck-web lint-web-design + +typecheck-web: node-deps + pnpm --filter @parsar/web typecheck + +lint-web-design: node-deps + @if (cd apps/web && npx eslint src/ 2>&1) | grep -q "no-restricted-syntax"; then \ + echo "Design-system lint violations (arbitrary font sizes or raw palette):" >&2; \ + (cd apps/web && npx eslint src/ 2>&1) | grep "no-restricted-syntax" >&2; \ + exit 1; \ + fi + +lint-web: node-deps + pnpm --filter @parsar/web lint + +test-cli: node-deps + pnpm --filter @parsar/cli test + +typecheck: node-deps + pnpm typecheck + reset-dev: ./scripts/reset-dev.sh @@ -54,7 +116,7 @@ clean-dev: ./scripts/reset-dev.sh --all server: - cd server && go run ./cmd/server + ./scripts/with-dev-env.sh bash -c 'cd server && exec go run ./cmd/server' # Persistent dev server lifecycle. The binary lives at ~/.parsar/bin # and runs inside a tmux session that survives sandbox bash exits and diff --git a/scripts/dev-compose.sh b/scripts/dev-compose.sh new file mode 100755 index 0000000..ac8c45e --- /dev/null +++ b/scripts/dev-compose.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +compose=(docker compose --project-name parsar --file "$ROOT_DIR/docker-compose.dev.yml") + +if docker info >/dev/null 2>&1; then + exec "${compose[@]}" "$@" +fi + +if command -v sudo >/dev/null 2>&1 && sudo -n docker info >/dev/null 2>&1; then + exec sudo -n "${compose[@]}" "$@" +fi + +echo "Docker is unavailable. Start Docker or grant this user access to its socket." >&2 +exit 1 diff --git a/scripts/dev-env.sh b/scripts/dev-env.sh index 44e6906..0d93e4a 100644 --- a/scripts/dev-env.sh +++ b/scripts/dev-env.sh @@ -40,6 +40,17 @@ export PARSAR_WEB_PORT="${PARSAR_WEB_PORT:-5173}" # in prod) — see docs/deploy/config.example.yaml. export PARSAR_DEV_AUTH="${PARSAR_DEV_AUTH:-true}" +# ── Server runtime posture ─────────────────────────────────────────── +# Loopback public_url selects the development validation profile. These +# values are intentionally safe only for local development and remain +# override-friendly for alternate ports or integration setups. +export PARSAR_ADDR="${PARSAR_ADDR:-127.0.0.1:$PARSAR_DEV_SERVER_PORT}" +export PARSAR_PUBLIC_URL="${PARSAR_PUBLIC_URL:-http://127.0.0.1:$PARSAR_DEV_SERVER_PORT}" +export PARSAR_COOKIE_SECURE="${PARSAR_COOKIE_SECURE:-false}" +export PARSAR_MASTER_KEY="${PARSAR_MASTER_KEY:-parsar-dev-master-key-2026}" +export PARSAR_FEISHU_MOCK="${PARSAR_FEISHU_MOCK:-true}" +export PARSAR_AGENT_DAEMON_OWNER_URL="${PARSAR_AGENT_DAEMON_OWNER_URL:-$PARSAR_PUBLIC_URL}" + # Builds the dev DATABASE_URL from the parts above. Optional args let a # caller override host ($1) and port ($2) without touching the creds — # used by dev-all.sh, which picks an ephemeral free port for Postgres. diff --git a/scripts/dev-stack.sh b/scripts/dev-stack.sh index f7b7477..6ce927e 100755 --- a/scripts/dev-stack.sh +++ b/scripts/dev-stack.sh @@ -13,13 +13,32 @@ PARSAR_STATE_DIR="$PARSAR_HOME/state" PARSAR_DEV_DIR="$PARSAR_HOME/dev" mkdir -p "$PARSAR_LOG_DIR" "$PARSAR_STATE_DIR" "$PARSAR_DEV_DIR" -docker compose -f docker-compose.dev.yml up -d postgres +./scripts/dev-compose.sh up -d postgres + +printf 'Waiting for Postgres' +for _ in {1..30}; do + if ./scripts/dev-compose.sh exec -T postgres \ + pg_isready -U "$PARSAR_PG_USER" -d "$PARSAR_PG_DB" >/dev/null 2>&1; then + printf ' ready\n' + break + fi + printf '.' + sleep 1 +done + +if ! ./scripts/dev-compose.sh exec -T postgres \ + pg_isready -U "$PARSAR_PG_USER" -d "$PARSAR_PG_DB" >/dev/null 2>&1; then + printf '\nPostgres did not become ready; inspect logs with:\n' >&2 + printf ' ./scripts/dev-compose.sh logs postgres\n' >&2 + exit 1 +fi + cat <