feat: add one-command environment setup script#809
feat: add one-command environment setup script#809LaphoqueRC wants to merge 8 commits intoSolFoundry:mainfrom
Conversation
Closes SolFoundry#491 Adds `scripts/dev-setup.sh` — a single command to set up the entire SolFoundry development environment. ## Usage ```bash ./scripts/dev-setup.sh # Full setup (Docker) ./scripts/dev-setup.sh --no-docker # Manual setup ./scripts/dev-setup.sh --check # Verify prerequisites only ``` ## What it does 1. **Prerequisite checks** — Verifies git, node (18+), python (3.10+), npm, docker, docker compose. Reports missing tools with install links. Optional tools (Rust, Anchor) noted but not required. 2. **Environment** — Copies .env.example to .env if not exists. Preserves existing .env. 3. **Frontend** — Runs npm install in frontend/ 4. **Backend** — Creates Python venv, installs requirements.txt 5. **Docker** — Starts all services via docker compose up -d --build 6. **Health check** — Polls /health endpoint with retries to confirm services are ready 7. **Summary** — Prints service URLs and next steps ## Features - Color-coded output (✓ success, ⚠ warning, ✗ error) - Version validation (Node 18+, Python 3.10+) - Graceful fallback when Docker unavailable (--no-docker guide) - Idempotent — safe to re-run (skips existing venv, keeps .env) - Health check with 10 retries and 2s backoff Wallet: HZV6YPdTeJPjPujWjzsFLLKja91K2Ze78XeY8MeFhfK8
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new executable Bash script Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/dev-setup.sh`:
- Around line 55-69: The argument parsing loop for "for arg in \"$@\"; do ...
case \"$arg\" in" silently ignores unknown flags (so typos like --nodocker are
missed); update the case in scripts/dev-setup.sh to add a catch-all pattern (*)
that prints an error (using the existing error/log function or echo), shows
usage hint ("Run '$0 --help' for usage"), and exits non-zero, so unknown args
cause failure; reference the parsing block, the variables USE_DOCKER and
CHECK_ONLY, and add the fallback case to the case statement.
- Line 232: The script references BACKEND_PORT and FRONTEND_PORT (used to build
HEALTH_URL and frontend URLs) but never sources the generated .env, so those
vars always fall back to defaults; fix by adding logic near the top (before
HEALTH_URL and the frontend URL usage) to load .env when present and export its
variables (e.g., source .env with automatic export) so BACKEND_PORT and
FRONTEND_PORT are available to the script.
- Around line 137-146: The for-loop that detects optional tooling incorrectly
checks for a secondary binary by testing "${cmd}c" which is valid for rust ->
rustc but wrong for Anchor (it would look for "anchorc"); update the detection
logic in the loop that uses variables cmd and desc so it only checks the real
binary name (use just command -v "$cmd" &>/dev/null 2>&1) or map tool names to
their actual binaries before checking, then keep the existing success("$desc —
found") and info("$desc — not installed (not required for frontend/backend)")
calls unchanged.
- Around line 110-117: The Python version check only reads
sys.version_info.minor into PY_VERSION and compares it to 10, which misses the
major version; update the logic in scripts/dev-setup.sh so PY_VERSION captures
both major and minor (e.g., "MAJOR.MINOR"), split into PY_MAJOR and PY_MINOR,
and then perform a two-part check: fail if PY_MAJOR < 3, or if PY_MAJOR == 3 and
PY_MINOR < 10, then call error with the discovered version and increment ERRORS;
update the variables referenced (PY_VERSION, PY_MAJOR, PY_MINOR) and the
conditional that currently compares PY_VERSION to 10 accordingly.
- Line 186: The script currently truncates installer output by piping "npm
install --no-audit --no-fund 2>&1 | tail -3" (and similarly the "pip install"
line), which can hide important warnings; change these invocations to either use
installer quiet flags (e.g., add "--silent" to the npm call and "-q" where
applicable for pip) or capture full logs while showing a short summary (e.g.,
pipe through tee to a log file and tail the last few lines of that log) so full
output is retained for troubleshooting while keeping console output concise;
update the "npm install --no-audit --no-fund ..." and the corresponding "pip
install ..." lines accordingly.
- Around line 274-284: The summary always prints Docker commands even when
--no-docker is used; wrap the two Docker-specific echo lines so they only
display when the USE_DOCKER flag is true. Locate the summary block that prints
"Logs" and "Stop" (the echo -e lines showing "docker compose logs -f" and
"docker compose down") and move or guard them with a conditional that checks
USE_DOCKER (or the function/variable that represents Docker mode) so those lines
are only emitted when USE_DOCKER is truthy.
- Around line 77-92: The check_cmd function currently accepts min_version but
never uses it; update check_cmd to parse the detected version (the local
variable version) and compare it against the provided min_version parameter,
returning non-zero and incrementing ERRORS when the installed version is missing
or less than min_version, and only printing the success "$cmd found (v...)"
message when the version meets the minimum; ensure comparisons handle semantic
numeric versions (major.minor[.patch]) robustly (e.g., using a numeric-aware
comparator like sort -V or a split-and-compare routine) and keep the function
name check_cmd and ERRORS behavior intact.
- Around line 166-172: Add a guard before copying in the conditional that
creates .env: when .env does not exist and before the cp .env.example .env call,
check for existence of .env.example (using a test like [ ! -f .env.example ])
and if missing call error " .env.example not found — cannot create .env" and
exit 1; keep the existing info/success messages and only run cp .env.example
.env when the example file is present (functions referenced: info, success,
error and the cp invocation).
- Line 180: Add explicit existence checks before changing directories for the
frontend and backend steps: before the cd "$PROJECT_ROOT/frontend" and cd
"$PROJECT_ROOT/backend" commands verify the target directories exist and call
the script's error reporting (e.g., error) with a clear message and exit
non‑zero if they do not; update the blocks around those cd invocations so they
check [ -d "$PROJECT_ROOT/frontend" ] and [ -d "$PROJECT_ROOT/backend" ] (using
the existing error function) to provide a clear error message instead of letting
set -e produce an unclear failure.
- Around line 237-246: The current health check issues two curls and can race;
replace the dual-call pattern by performing a single curl into HEALTH (using
HEALTH=$(curl -sf "$HEALTH_URL" 2>/dev/null) && { ... }) and then derive STATUS
from HEALTH with the existing python3 JSON parsing, then call success "Health
check passed: $STATUS" or warn "Health check returned: $STATUS" and break as
before; update the block that references HEALTH_URL, HEALTH, STATUS, success and
warn to use the single-curl flow so only one network request is made and STATUS
is computed from that response.
- Around line 119-135: The script detects both Docker Compose v2 and legacy v1
but continues to hardcode "docker compose" later, causing failures when only
"docker-compose" exists; introduce a COMPOSE_CMD variable in the detection block
(when USE_DOCKER is true) and set it to either "docker compose" or
"docker-compose" depending on which check passes, and fall back to disabling
USE_DOCKER as before if neither exists; then replace all literal use of "docker
compose" in later commands (e.g., where the script calls compose to bring
services up or run compose commands) with "$COMPOSE_CMD" so the chosen binary is
used consistently.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 38270ac4-de52-4385-aa8d-4833adda78e8
📒 Files selected for processing (1)
scripts/dev-setup.sh
| info "node_modules exists — running npm install for updates..." | ||
| fi | ||
|
|
||
| npm install --no-audit --no-fund 2>&1 | tail -3 |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Output truncation with tail may hide important warnings or errors.
Lines 186 and 210 pipe npm install and pip install output through tail -3 / tail -2, discarding most output. While this keeps output clean, it can hide important deprecation warnings, version conflicts, or security advisories that don't cause command failure.
Consider using --quiet flags more consistently or logging full output to a file while showing a summary:
npm install --no-audit --no-fund --silent
# or
npm install --no-audit --no-fund 2>&1 | tee /tmp/npm-install.log | tail -3Also applies to: 210-210
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/dev-setup.sh` at line 186, The script currently truncates installer
output by piping "npm install --no-audit --no-fund 2>&1 | tail -3" (and
similarly the "pip install" line), which can hide important warnings; change
these invocations to either use installer quiet flags (e.g., add "--silent" to
the npm call and "-q" where applicable for pip) or capture full logs while
showing a short summary (e.g., pipe through tee to a log file and tail the last
few lines of that log) so full output is retained for troubleshooting while
keeping console output concise; update the "npm install --no-audit --no-fund
..." and the corresponding "pip install ..." lines accordingly.
There was a problem hiding this comment.
Acknowledged as nitpick — tail -3 / tail -2 is retained to keep output readable for typical installs. The full pip/npm output is still visible on failure since the script exits with a non-zero code.
- Add catch-all case for unknown CLI arguments (exit with error message) - Implement actual version comparison in check_cmd using major/minor split - Fix Python version check: validate both major AND minor version, not just minor (avoids false failures with Python 4.x) - Store detected compose command in COMPOSE_CMD; use it consistently throughout the script so legacy docker-compose also works - Fix Anchor CLI detection: check 'anchor' binary directly instead of looking for 'anchorc' (which doesn't exist) - Add guard for missing .env.example before cp - Source .env after creation so BACKEND_PORT/FRONTEND_PORT are available - Add existence checks for frontend/ and backend/ directories - Consolidate double curl call into single call to avoid race condition - Wrap docker-specific summary output in USE_DOCKER conditional - Pass $COMPOSE_CMD to docker commands and log hints
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/dev-setup.sh`:
- Around line 96-100: The script currently calls success "$cmd found
(v${version:-unknown})" before validating version constraints, causing success
then warning/error for the same tool; update the check around the variables cmd,
version, major, minor, min_major, min_minor, and min_version so that version
validation runs first and only prints success after the conditional verifies
major/minor >= min_major/min_minor, otherwise emit warn (or info) with the
recommendation and/or a fail/exit; in other words, move or conditionally gate
the success call so success is printed only when the version check passes (or
change the first success to an info when only existence is confirmed).
- Around line 278-290: The loop currently breaks on any successful curl, which
lets non-healthy responses (e.g., STATUS="degraded") stop retries; update the
logic in the health-check loop that reads HEALTH and computes STATUS so that it
only breaks when STATUS equals "healthy" (i.e., move the break inside the if [
"$STATUS" = "healthy" ] branch) and otherwise increment RETRIES and continue
retrying, or if you intended to accept any response, add a clarifying comment
above the loop explaining that a non-"healthy" status should still be considered
"up" and thus stops retries; refer to variables/commands HEALTH_URL, RETRIES,
MAX_RETRIES, HEALTH, STATUS, curl, success, and warn when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 00fc30f2-2109-4495-95db-661b81bfe7b2
📒 Files selected for processing (2)
backend/app/models/bounty_table.pyscripts/dev-setup.sh
|
CI failures in this PR are pre-existing repository issues unrelated to this change:
This PR's own changes have no test regressions. |
- check_cmd: move success message after version comparison so it only prints when the version requirement is actually met; version-mismatch tools now show only the warning (no confusing success → warning sequence) - health check loop: break only when status is 'healthy'; degraded/unknown responses now trigger a retry instead of exiting the loop, matching the stated intent of waiting until fully healthy
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/dev-setup.sh`:
- Around line 279-280: The health-check loop using curl in the while loop that
references RETRIES, MAX_RETRIES and HEALTH_URL can hang because curl has no
timeouts; update the curl invocation inside the loop (the command that sets
HEALTH) to include connection and total timeouts (e.g., --connect-timeout and
--max-time) so each attempt fails quickly on network stalls and the
RETRIES/MAX_RETRIES logic behaves deterministically, and keep existing -s -f
behavior so non-2xx responses still count as failures.
- Around line 201-206: The script currently uses "source .env" which executes
the file as shell code (risking command execution and failures); replace this
with a safe .env parser that reads .env line-by-line, ignores comments and blank
lines, extracts KEY=VALUE pairs (e.g., matching ^[A-Za-z_][A-Za-z0-9_]*=),
strips optional surrounding quotes, and exports only those variables (so
BACKEND_PORT and FRONTEND_PORT become available) instead of sourcing; update the
block that contains "source .env" and remove the shellcheck disable for SC1091,
ensuring the new parser handles spaces, quoted values, and skips any lines with
command characters to avoid executing arbitrary code.
- Around line 305-307: The manual backend start command hardcodes --port 8000
which can diverge from the env-driven BACKEND_PORT used in printed URLs; update
the uvicorn invocation in the manual-start block (the line calling "uvicorn
app.main:app --reload --port 8000") to use the same parameter expansion
${BACKEND_PORT:-8000} and likewise replace any other hardcoded 8000 occurrences
in that manual-start/printed-URLs section so the printed instructions and the
actual command stay consistent with the BACKEND_PORT environment variable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 575e7d73-43ee-424f-a790-4fe072c24571
📒 Files selected for processing (1)
scripts/dev-setup.sh
- Replace 'source .env' with safe line-by-line .env parser that reads
KEY=VALUE pairs, strips quotes, and exports variables without executing
arbitrary shell code (addresses CodeRabbit security concern)
- Add --connect-timeout 2 --max-time 5 to curl in health-check loop so
network stalls don't cause the RETRIES/MAX_RETRIES logic to hang
- Use ${BACKEND_PORT:-8000} in manual-start uvicorn command for consistency
with printed URLs in the summary section
|
Addressed the remaining CodeRabbit review feedback:
The CI failures are pre-existing repository issues unrelated to this PR. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
scripts/dev-setup.sh (1)
234-234: 🧹 Nitpick | 🔵 TrivialThe repeated
tailpiping still hides the diagnostics needed to debug bootstrap failures.Lines 234, 262, and 274 drop most of the
npm,pip, and Compose output. When dependency resolution or image builds fail, the last few lines are often not enough to identify the real root cause.Also applies to: 262-262, 274-274
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/dev-setup.sh` at line 234, The script currently pipes critical commands through "tail" (e.g., the "npm install --no-audit --no-fund 2>&1 | tail -3" invocation and the similar pip and Docker Compose invocations), which truncates useful diagnostics; remove the "| tail..." from those commands so their full stdout/stderr is shown (or replace the pipe with "tee /tmp/dev-setup.log" if you still want a saved log), updating the occurrences that match the npm install, pip install, and docker compose build/run commands so they no longer drop important output.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/dev-setup.sh`:
- Around line 110-115: The script's prerequisite checks omit curl, but the
health check loop in scripts/dev-setup.sh invokes curl (with stderr suppressed)
and silently times out if curl is missing; add a prerequisite check by calling
check_cmd "curl" with an appropriate minimum version/URL alongside the existing
check_cmd calls (near the git/node/python3/npm lines) so the script fails early
and reports the missing curl binary before the health check loop runs;
alternatively ensure the health check loop explicitly verifies curl exists and
logs a clear error via the same check_cmd/exit path if not found.
- Line 196: The .env parsing loop that uses read -r preserves trailing CR
characters (so variables like BACKEND_PORT keep a \r and produce malformed
URLs); after the code that strips surrounding quotes from the parsed value (the
variable named val in the read loop that processes .env.example) add a step to
remove any trailing carriage return from val (e.g., strip a trailing CR using
shell parameter expansion) so exported variables are clean before export and
downstream uses (health check URL construction and summary output) are not
corrupted.
- Around line 139-150: The script currently sets COMPOSE_CMD after CLI checks
(USE_DOCKER, command -v docker, docker compose version, docker-compose
--version) but later runs $COMPOSE_CMD up -d --build unconditionally and with
set -e will abort if the daemon is unavailable; update the logic so that before
running the full up you perform a safe daemon/connectivity test (e.g., run
`docker info` or a no-op compose command) using the chosen COMPOSE_CMD and check
its exit code, and if that test fails, log a warning and set USE_DOCKER=false
(or skip the compose step) so the script falls back to the manual setup block
instead of exiting; ensure this check references the same COMPOSE_CMD and
USE_DOCKER variables and that the actual $COMPOSE_CMD up -d --build is only
executed when that test succeeds or is guarded by conditional error handling.
---
Duplicate comments:
In `@scripts/dev-setup.sh`:
- Line 234: The script currently pipes critical commands through "tail" (e.g.,
the "npm install --no-audit --no-fund 2>&1 | tail -3" invocation and the similar
pip and Docker Compose invocations), which truncates useful diagnostics; remove
the "| tail..." from those commands so their full stdout/stderr is shown (or
replace the pipe with "tee /tmp/dev-setup.log" if you still want a saved log),
updating the occurrences that match the npm install, pip install, and docker
compose build/run commands so they no longer drop important output.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5c36cabd-552f-4c62-a0c7-8ecc62207d71
📒 Files selected for processing (1)
scripts/dev-setup.sh
|
Addressed the latest CodeRabbit review feedback (round 4):
The CI failures remain pre-existing infrastructure issues unrelated to this change. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/dev-setup.sh`:
- Around line 277-288: The docker compose invocation ($COMPOSE_CMD up -d
--build) is run without checking its exit status so compose failures still abort
the script; modify the block that runs $COMPOSE_CMD to capture its stdout/stderr
and exit code (e.g., store output in a variable or redirect to a temp file),
check the exit status right after running the command, and on non-zero exit set
USE_DOCKER=false, emit the captured output via warn/error (instead of piping
blindly to tail -5), and avoid exiting so the existing manual setup instructions
(the manual fallback code path) run; refer to the symbols USE_DOCKER,
COMPOSE_CMD and the success/warn logging calls to locate and update the logic.
- Around line 318-345: The final success banner is printed unconditionally even
when health checks timed out or the script fell back to manual setup; update the
control flow so the "🎉 SolFoundry dev environment is ready!" header and URL
block are only printed after a successful health check (i.e., move those
echo/header lines into the branch that runs when services are healthy) or
alternatively make the timeout branch (when RETRIES -eq MAX_RETRIES) and the
manual/fallback branch perform a non-zero exit (e.g., exit 1) after printing
their warnings; reference the RETRIES and MAX_RETRIES checks and the
banner/header string "🎉 SolFoundry dev environment is ready!" to locate where
to change control flow.
- Line 21: The script currently uses "set -euo pipefail" which causes the shell
to exit on the first failing return from check_cmd(), preventing aggregation
into ERRORS and the final summary for the --check flow; change the prerequisite
checks so failures are captured instead of terminating: replace direct calls to
check_cmd() (the sequential invocations) with a guarded form that tests the
return and increments ERRORS (e.g., if ! check_cmd foo; then
ERRORS=$((ERRORS+1)); fi), or append "|| true" and explicitly handle the
non-zero status to update ERRORS; keep set -euo pipefail for normal execution
but ensure the check_cmd invocation sites use conditional handling so the
summary block that reads ERRORS can run.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4be29cca-f231-4307-91c9-f8de38be51c5
📒 Files selected for processing (1)
scripts/dev-setup.sh
|
Verified the latest CodeRabbit review feedback (round 4) against the current code — all three actionable items are already addressed:
The repeated No code changes needed for this round. CI failures remain pre-existing. |
|
Addressed CodeRabbit round-4 major issues (commit a25d496):
|
|
Addressed all CodeRabbit round-4 major issues (commit a25d496):
The CI failures are pre-existing repository issues unrelated to this change. |
|
Responded to all outstanding CodeRabbit review comments (rounds 1–4). Summary of what's addressed in the current code:
The only remaining CI failures are pre-existing repository issues unrelated to this PR's changes. |
a25d496 to
8d84687
Compare
- Add || true to all check_cmd calls so set -e does not abort on first missing prerequisite; ERRORS counter still accumulates all failures - Add curl to prerequisite checks alongside git/node/python3/npm - Capture COMPOSE_OUTPUT and handle failures by falling back to manual setup instead of aborting with unhandled error - Introduce SERVICES_HEALTHY flag; success banner is only shown after health check confirms status == "healthy"; timeout and fallback paths exit cleanly without printing the ready banner
|
Addressed the remaining CodeRabbit review feedback (round 5):
|
… summary - Strip trailing carriage returns from .env values (fixes CRLF line endings from Windows editors corrupting BACKEND_PORT and URL construction) - Add Docker daemon preflight check (docker info) before compose startup so inaccessible daemon falls back gracefully rather than aborting - Replace subshell COMPOSE_OUTPUT capture with mktemp pattern for reliable output capture and error handling under set -euo pipefail - Remove exit 1 on health-check timeout; show informative summary instead - Remove exit 0 from manual-setup path; show URLs in summary instead - Add distinct summary banners: healthy / timed-out / manual-setup paths
|
Addressed the remaining CodeRabbit review feedback (latest round):
The CI failures remain pre-existing repository issues unrelated to this change. |
|
Verified all outstanding CodeRabbit review comments against current code — everything is already addressed:
The CI failures remain pre-existing repository issues unrelated to this PR. The implementation is complete and correct — ready for maintainer review. |
Closes #491
Adds
scripts/dev-setup.shfor one-command development setup.Usage
Steps
Features
Wallet:
HZV6YPdTeJPjPujWjzsFLLKja91K2Ze78XeY8MeFhfK8