Skip to content

feat: add guided walkthrough with Codespaces support#286

Merged
AntTheLimey merged 17 commits intomainfrom
feature/walkthrough
Mar 11, 2026
Merged

feat: add guided walkthrough with Codespaces support#286
AntTheLimey merged 17 commits intomainfrom
feature/walkthrough

Conversation

@AntTheLimey
Copy link
Member

@AntTheLimey AntTheLimey commented Mar 6, 2026

Summary

Add a guided walkthrough that deploys a 3-node distributed PostgreSQL
database with active-active multi-master replication (and read replica
support) using the Spock extension, all orchestrated by pgEdge Control
Plane.

Three ways to experience the walkthrough

  • Docs sitedocs/walkthrough.md renders as a standard MkDocs
    page at docs.pgedge.com with admonitions, tips, and copyable code
    blocks
  • Interactive terminal guideexamples/walkthrough/guide.sh
    walks you through the same steps with branded UX, spinners, and
    press-Enter prompts
  • GitHub Codespaces — one-click environment with Docker-in-Docker
    pre-configured and walkthrough auto-opened via the Runme VS Code
    extension

All code blocks use direct psql connections (via configurable port
variables) rather than docker exec, keeping the experience consistent
across delivery modes.

What's included

  • docs/walkthrough.md — 4-step walkthrough (start CP, create DB,
    verify replication, resilience demo) with prerequisites section,
    cleanup instructions, and Explore Further commands
  • examples/walkthrough/guide.sh — interactive terminal guide
    with the same 4 steps, branded output, spinners, and idempotent
    re-run support
  • examples/walkthrough/setup.sh — prerequisites checker:
    validates docker/curl/jq/psql are installed, Docker daemon is
    accessible, and (on macOS) Docker Desktop host networking is enabled
  • examples/walkthrough/install.sh — curl-pipe bootstrap that
    downloads walkthrough files, runs setup, and presents a picker to
    choose between the interactive guide or self-paced walkthrough
  • examples/walkthrough/runner.sh — terminal UX framework with
    pgEdge brand colors, output dividers, spinners, and interactive
    prompts
  • .devcontainer/ — Codespaces devcontainers for both walkthrough
    and development workflows; walkthrough post-create installs psql from
    the pgEdge apt repository

Navigation changes

  • Moved Quickstart and Walkthrough into a new "Getting Started" nav
    section, separate from "Installing Control Plane" (which focuses on
    production deployment)

Cross-platform support (Linux + macOS)

  • setup.sh detects the OS and adjusts Docker diagnostics: systemctl
    on Linux, Docker Desktop guidance on macOS, generic fallback for
    non-systemd Linux
  • setup.sh validates Docker Desktop host networking on macOS by
    checking settings-store.json with step-by-step enable instructions
    if it fails
  • setup.sh provides platform-aware psql install hints (Homebrew on
    macOS, pgEdge Enterprise packages on Linux)
  • guide.sh uses ss for port detection on Linux, lsof on macOS
  • guide.sh uses --advertise-addr for Swarm init on Linux (handles
    multi-interface hosts), plain docker swarm init on macOS
  • walkthrough.md has an explicit Prerequisites section with macOS
    Docker Desktop host networking instructions and a tip for the Swarm
    multi-interface error

Test plan

Interactive guide (guide.sh)

  • Run on a Linux VM with Docker — full 4-step flow
  • Run on macOS with Docker Desktop — full 4-step flow
  • Verify setup.sh catches missing Docker Desktop host networking on macOS
  • Verify n2 recovery waits for Postgres readiness, not just container

Walkthrough markdown (walkthrough.md)

  • mkdocs serve — verify page renders with prerequisites, admonitions, and tips
  • Open in VS Code with Runme — execute each cell
  • Copy commands manually from docs site — verify they work

Bootstrap installer (install.sh)

  • curl -fsSL .../install.sh | bash — downloads files, runs setup
  • Picker option 1 launches guide.sh
  • Picker option 2 prints walkthrough.md path and exits
  • In Codespaces, exits early with "already set up" message

Codespaces

  • Launch walkthrough devcontainer — verify post-create, walkthrough auto-opens
  • Launch dev devcontainer — verify Docker-in-Docker works

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a guided walkthrough: two devcontainer definitions (Go and Ubuntu), container post-create hooks, bash installer/runner/setup/guide scripts to deploy and verify a 3-node distributed PostgreSQL cluster via the pgEdge Control Plane, new walkthrough documentation, mkdocs navigation updates, and a small .gitignore addition.

Changes

Cohort / File(s) Summary
Devcontainer configs
.devcontainer/dev/devcontainer.json, .devcontainer/walkthrough/devcontainer.json
Adds two devcontainer definitions (Go and Ubuntu bases) enabling Docker-in-Docker, sets VS Code prefs (bash terminal, startup/editor behavior), runs postCreate/postAttach commands, and installs listed extensions.
Walkthrough post-create script
.devcontainer/walkthrough/post-create.sh
New post-create script: strict shell options, installs jq and pgEdge Postgres client, runs prerequisites check, and prints access guidance for the interactive guide and docs.
Walkthrough scripts
examples/walkthrough/install.sh, examples/walkthrough/guide.sh, examples/walkthrough/runner.sh, examples/walkthrough/setup.sh
Adds installer to fetch assets and launch setup, interactive guide automating deployment/verification (port detection, Docker Swarm, API polling, resilience demo), a runner UX library (colorized output, prompts, spinner), and a prerequisites checker with platform-specific Docker guidance.
Documentation & nav
docs/walkthrough.md, mkdocs.yml
Adds a comprehensive, executable walkthrough document for deploying and validating a 3-node distributed Postgres cluster and updates mkdocs navigation to include the walkthrough.
Repository metadata
.gitignore
Adds docs/plans to .gitignore.

Poem

🐇 I nibble at scripts and hop through the trees,
Three tiny Postgres nodes dance on the breeze,
Swarm drums a rhythm, Control Plane hums along,
Replicas whisper softly in a replication song,
Follow the guide — hop in and sing along.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: adding a guided walkthrough for deploying distributed PostgreSQL with Codespaces support.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, detailed changes, test plan, and implementation details across all included files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/walkthrough

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AntTheLimey
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@AntTheLimey AntTheLimey force-pushed the feature/walkthrough branch from 76efa02 to fe7ad40 Compare March 6, 2026 20:11
@AntTheLimey AntTheLimey marked this pull request as ready for review March 6, 2026 21:35
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/walkthrough.md`:
- Around line 39-52: The docs currently imply install.sh only downloads files
but the bootstrap now launches examples/walkthrough/guide.sh, which is
confusing; update docs/walkthrough.md to state that running the curl | bash
command will run the installer which in turn launches the interactive guide
(install.sh) and add a note explaining how to rerun the interactive guide
manually from the repo root via bash examples/walkthrough/guide.sh so users
don’t try to start it twice.
- Around line 305-317: Replace the container-existence poll with an active
Postgres readiness check and a replication-sync check: instead of using docker
ps for n2, loop until a psql connection (PGPASSWORD=password psql -h localhost
-p 5433 -U admin example -c "SELECT 1") succeeds to ensure Postgres is accepting
connections, then loop until a replication verification query
(PGPASSWORD=password psql -h localhost -p 5433 -U admin example -tAc "SELECT 1
FROM example WHERE id = 3;") returns the expected row, sleeping between
attempts; update the echo messages accordingly to "Waiting for n2 to accept
connections..." and "Replication is synced." so readiness and replication are
both guaranteed before proceeding.

In `@examples/walkthrough/guide.sh`:
- Around line 8-11: The script defines CP_PORT and uses it for CP_URL but never
passes it into docker run, so the container (started with --network host) still
listens on 3000; update the docker run/startup steps that reference
CP_CONTAINER/CP_IMAGE to bind or set the control-plane port consistently by
exporting or injecting CP_PORT into the container startup (or hardcode 3000),
e.g., ensure the docker run command uses -p "${CP_PORT}:3000" or configures the
container to listen on "${CP_PORT}" so CP_URL and the container port match;
apply the same change to the other startup/health-check blocks mentioned (around
the other occurrences).
- Around line 238-239: The docker container/service resolution in the prompt_run
invocations (e.g., the line calling prompt_run "docker exec $(docker ps --filter
label=pgedge.node.name=n1 --format '{{.Names}}') ...") is too broad and can pick
other databases' nodes; update every docker ps and docker service ls selector
that currently filters only by pgedge.node.name (and where used,
pgedge.component) to also include --filter label=pgedge.database.id=${DB_ID} so
the lookups are scoped to this walkthrough's database; ensure all occurrences
(the prompt_run calls and any docker service ls lines referenced around the
ranges noted) add that extra filter and keep the same --format/command usage.

In `@examples/walkthrough/setup.sh`:
- Around line 62-84: When the script checks "if ! docker info &>/dev/null" avoid
unconditionally using systemctl/usermod recovery steps; first test for systemd
by using "command -v systemctl" before calling systemctl is-active and emitting
systemd-specific instructions. If systemctl is not available, capture the docker
info error output and call error/explain to report a generic "Docker socket is
unreachable" message including the captured docker info failure text and a
suggestion to check Docker in the current environment (e.g., start the daemon or
use containerdev features), rather than printing systemd-specific commands;
update the branch that currently uses systemctl is-active, error, and explain so
it first gates on command -v systemctl and uses the alternate generic messaging
when systemctl is absent, referencing the docker info check, systemctl
is-active, error, explain, and SCRIPT_DIR symbols to locate the changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b180121f-0e79-4b2c-8386-001e632716e5

📥 Commits

Reviewing files that changed from the base of the PR and between eec724e and fe7ad40.

📒 Files selected for processing (9)
  • .devcontainer/dev/devcontainer.json
  • .devcontainer/walkthrough/devcontainer.json
  • .devcontainer/walkthrough/post-create.sh
  • docs/walkthrough.md
  • examples/walkthrough/guide.sh
  • examples/walkthrough/install.sh
  • examples/walkthrough/runner.sh
  • examples/walkthrough/setup.sh
  • mkdocs.yml

@AntTheLimey AntTheLimey marked this pull request as draft March 6, 2026 21:47
@AntTheLimey AntTheLimey force-pushed the feature/walkthrough branch 3 times, most recently from 835ac10 to e74ffb1 Compare March 6, 2026 23:53
Add a guided walkthrough that deploys a 3-node distributed PostgreSQL
database with active-active multi-master replication using the Spock
extension, all orchestrated by pgEdge Control Plane.

Three ways to experience the walkthrough:

- Docs site — walkthrough.md renders as a standard MkDocs page
- Interactive terminal guide — guide.sh with branded UX and spinners
- GitHub Codespaces — one-click environment with Docker-in-Docker

Includes:
- docs/walkthrough.md — 4-step walkthrough with prerequisites,
  macOS Docker Desktop instructions, and cleanup
- examples/walkthrough/guide.sh — interactive terminal guide
- examples/walkthrough/setup.sh — cross-platform prerequisites
  checker (Linux + macOS)
- examples/walkthrough/install.sh — curl-pipe bootstrap with
  interactive picker
- examples/walkthrough/runner.sh — terminal UX framework
- .devcontainer/ — Codespaces devcontainers for walkthrough and dev
@AntTheLimey AntTheLimey force-pushed the feature/walkthrough branch from e74ffb1 to 9284d0a Compare March 7, 2026 00:26
@AntTheLimey AntTheLimey marked this pull request as ready for review March 7, 2026 00:27
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
examples/walkthrough/runner.sh (1)

59-82: Consider capturing the command's exit status for debugging.

The eval "$cmd" calls don't preserve the exit status, so command failures won't propagate. This is likely intentional for walkthrough UX (continue even if a step fails), but you may want to at least display the exit status for user awareness.

That said, the current behavior is reasonable for an interactive guide where output visibility is the primary concern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/walkthrough/runner.sh` around lines 59 - 82, The prompt_run function
currently uses eval "$cmd" (both in the slow and fast branches) without
capturing or displaying the command's exit status; modify prompt_run to capture
the exit code immediately after each eval (e.g., local exit_code=$?), then print
or log that exit code (and optionally a brief success/failure message) so users
can see failures for debugging; ensure you capture the exit code right after
eval in both the tmpfile branch (after eval "$cmd" > "$tmpfile" ...) and the
direct branch (after eval "$cmd" 2> ...), and preserve existing spinner/tmptfile
cleanup behavior in start_spinner/stop_spinner and rm -f "$tmpfile".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@examples/walkthrough/runner.sh`:
- Around line 59-82: The prompt_run function currently uses eval "$cmd" (both in
the slow and fast branches) without capturing or displaying the command's exit
status; modify prompt_run to capture the exit code immediately after each eval
(e.g., local exit_code=$?), then print or log that exit code (and optionally a
brief success/failure message) so users can see failures for debugging; ensure
you capture the exit code right after eval in both the tmpfile branch (after
eval "$cmd" > "$tmpfile" ...) and the direct branch (after eval "$cmd" 2> ...),
and preserve existing spinner/tmptfile cleanup behavior in
start_spinner/stop_spinner and rm -f "$tmpfile".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: de0f2cb5-4b88-42db-92e5-c7b247e5d119

📥 Commits

Reviewing files that changed from the base of the PR and between fe7ad40 and 9284d0a.

📒 Files selected for processing (10)
  • .devcontainer/dev/devcontainer.json
  • .devcontainer/walkthrough/devcontainer.json
  • .devcontainer/walkthrough/post-create.sh
  • .gitignore
  • docs/walkthrough.md
  • examples/walkthrough/guide.sh
  • examples/walkthrough/install.sh
  • examples/walkthrough/runner.sh
  • examples/walkthrough/setup.sh
  • mkdocs.yml
🚧 Files skipped from review as they are similar to previous changes (6)
  • examples/walkthrough/setup.sh
  • mkdocs.yml
  • .devcontainer/walkthrough/devcontainer.json
  • examples/walkthrough/install.sh
  • examples/walkthrough/guide.sh
  • .devcontainer/dev/devcontainer.json

@AntTheLimey AntTheLimey requested a review from mmols March 7, 2026 00:34
Copy link
Member

@mmols mmols left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks to be almost there. I've left comments mostly in the guide.sh portion - the same adjustments in language / tone should be applied to walkthrough.md

- Move Quickstart and Walkthrough into Getting Started nav section
- Introduce nodes as a concept, mention read replica support
- Use "Control Plane" instead of "CP" abbreviation throughout
- Switch from docker exec to direct psql connections
- Add psql to prerequisites, use port variables instead of hardcoded values
- Remove watch docker ps tips (not universally installed)
- De-emphasize image pulling in database creation messaging
- Simplify Docker Desktop host networking check to grep settings-store.json
- Replace "cluster" with "database" when referring to the distributed DB
- Remove bold formatting from tables per docs style guide
- Update Learn More link titles to match actual page titles
- Switch Codespaces post-create to install psql from pgEdge apt repo
  (pgedge-postgresql-client-18) instead of community postgresql-client
- Add platform-specific psql install hints in setup.sh (Homebrew for
  macOS, pgEdge Enterprise docs for Linux)
- Update walkthrough.md prerequisites to match
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/walkthrough.md`:
- Around line 80-82: The current snippet masks all failures from "docker swarm
init" by redirecting stderr and defaulting to "Swarm already active"; replace
this with a safe check that queries Docker's Swarm state using "docker info
--format '{{.Swarm.LocalNodeState}}'" and only print "Swarm already active" when
that check returns "active", otherwise run "docker swarm init" so real errors
(e.g., multi-interface/address issues) are surfaced; update the block containing
the "docker swarm init" command accordingly to perform the conditional check and
run init only when necessary.

In `@examples/walkthrough/guide.sh`:
- Line 103: The call to detect_ports runs too early and may allocate new ports
before we know if this is a fresh run; move or defer the detect_ports invocation
until after the script determines whether the DB_ID (example) already exists (or
wrap detect_ports in a conditional that only runs on fresh setup), so that
existing databases keep their original 5432-5434 bindings and subsequent psql
calls target the correct ports.
- Around line 181-186: The current curl call to "${CP_URL}/v1/cluster/init"
collapses any transport error or non-2xx into the “already initialized” branch;
change it to capture curl's exit status and HTTP status code (use curl -sS -w
"%{http_code}" or similar), then: treat 200 (or 201) as success and 409 as
“already initialized”, but for network errors (non-zero curl exit) or unexpected
HTTP codes log an error with details (include status code and curl stderr) and
exit non-zero; update the logic around the existing CP_URL /v1/cluster/init call
and the info/error messages so they reflect these distinct cases.
- Around line 353-355: Replace the fixed 3-second sleep after the "Waiting for
replication to sync..." info message with an active poll that queries for the
replayed row (id = 3) until it appears or a sensible timeout is reached;
specifically, remove the sleep call and implement a loop that repeatedly runs
the same check used in docs/walkthrough.md (e.g., a psql/HTTP query that looks
for id=3), exit the loop when the row is found or fail after timeout, and keep
the original info log for context.

In `@examples/walkthrough/setup.sh`:
- Around line 19-57: The setup script may report success even if the
platform-specific port probe tool is missing, causing guide.sh to wrongly
consider busy ports free; update REQUIRED_CMDS logic so it includes lsof when
"$OS" == "Darwin" and includes ss when "$OS" != "Darwin" (or add both
unconditionally), then keep the existing existence check loop that populates
MISSING so missing probes are warned and install hints shown; modify the
REQUIRED_CMDS array construction near the top (and reference the OS variable) so
REQUIRED_CMDS, MISSING, and the for cmd in "${REQUIRED_CMDS[@]}" loop will
detect and report missing lsof/ss appropriately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c080f8dc-43dd-4e59-99d3-412f690af601

📥 Commits

Reviewing files that changed from the base of the PR and between 9284d0a and a6b263d.

📒 Files selected for processing (5)
  • .devcontainer/walkthrough/post-create.sh
  • docs/walkthrough.md
  • examples/walkthrough/guide.sh
  • examples/walkthrough/setup.sh
  • mkdocs.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .devcontainer/walkthrough/post-create.sh

- walkthrough.md: check Swarm state before init instead of
  suppressing errors
- guide.sh: defer detect_ports until after CP is running; reuse
  existing DB ports on rerun
- guide.sh: distinguish real cluster/init failures from
  already-initialized (409)
- guide.sh: replace fixed sleep with active replication sync poll
- setup.sh: check for lsof (macOS) / ss (Linux) used by port
  detection
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (6)
examples/walkthrough/guide.sh (3)

53-70: Potential infinite loop if all ports above 5432 are in use.

While the guard at line 66 prevents iterating past port 65533, on a heavily loaded system this loop could take a very long time. Consider adding a more reasonable upper bound or a maximum iteration count.

This is a very unlikely edge case in practice, so this is a minor observation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/walkthrough/guide.sh` around lines 53 - 70, The loop in the port
discovery logic (variables start, p1/p2/p3 and the port_in_use checks that set
N1_PORT/N2_PORT/N3_PORT) can run for a very long time; add a hard cap to avoid
long hangs by introducing a maximum-tries or a reasonable upper-bound (e.g.,
MAX_TRIES or start_max) and break with an error if exceeded, so the while loop
exits deterministically instead of potentially scanning all ports up to 65533.

287-289: Silent table drop could mask connection issues.

The || true suppresses all errors including connection failures. If n1 isn't actually reachable at this point, the script continues silently and will fail later with a less obvious error.

Consider checking the exit status separately:

Suggested improvement
 # Clean up any leftover data from a previous run
-PGPASSWORD=password psql -h localhost -p "${N1_PORT}" -U admin "${DB_ID}" \
-  -c "DROP TABLE IF EXISTS example;" >/dev/null 2>&1 || true
+if ! PGPASSWORD=password psql -h localhost -p "${N1_PORT}" -U admin "${DB_ID}" \
+  -c "DROP TABLE IF EXISTS example;" >/dev/null 2>&1; then
+  warn "Could not clean up previous data (n1 may still be starting)."
+fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/walkthrough/guide.sh` around lines 287 - 289, The current cleanup
command uses "PGPASSWORD=... psql ... -c 'DROP TABLE IF EXISTS example;'
>/dev/null 2>&1 || true", which hides connection failures; remove the blanket
"|| true" and instead run the same psql command (using the N1_PORT and DB_ID
variables shown) while redirecting output as needed, then explicitly check the
psql exit status ($?); if psql failed (non-zero), log a clear error like "Failed
to connect to n1 or drop table" and exit non‑zero so connection problems are
surfaced rather than silently ignored. Ensure the check surrounds the exact
command invocation shown so only genuine failures trigger the error path.

27-33: The ss pattern may produce false positives.

The grep pattern :${1} (with trailing space) may not match all ss output formats. Official iproute2 documentation confirms ss output is padded for human readability, and port numbers appearing at the end of a line will not have trailing spaces. Additionally, IPv6 addresses use different formatting (e.g., :::22 for wildcard listeners). A more robust pattern would handle both cases.

More robust pattern
   else
-    ss -tln 2>/dev/null | grep -q ":${1} "
+    ss -tln 2>/dev/null | grep -qE ":${1}($| )"
   fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/walkthrough/guide.sh` around lines 27 - 33, In port_in_use(), the
ss-based check is brittle; update the else branch to reliably detect listeners
by extracting the local address:port field and comparing the port (e.g., use ss
-tnl piped to awk to strip the address portion and test equality against the
supplied $1) so it handles end-of-line ports and IPv6 forms like :::22 instead
of relying on the current grep ':${1} ' pattern.
docs/walkthrough.md (3)

58-74: Clarify the relationship between the bootstrap script and the interactive guide.

The description at lines 58-61 now explains that install.sh offers a choice, but the subsequent section "Prefer a guided terminal experience?" (lines 67-74) creates confusion. Since install.sh already prompts users to choose between the interactive guide and self-paced walkthrough, this section reads as if users need to manually start the guide separately.

Consider clarifying that the command at line 73 is for re-running the guide later:

Suggested documentation tweak
 ### Prefer a guided terminal experience?

-The interactive guide walks you through the same steps with prompts
-and spinners:
+If you want to re-run the interactive guide later (or chose to exit
+the bootstrap script), run:

 ```text
 bash examples/walkthrough/guide.sh
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/walkthrough.md around lines 58 - 74, The current text is ambiguous
about the relationship between install.sh and the interactive guide; update the
wording to state that install.sh will prompt users to choose the interactive
guide or a self-paced walkthrough, and make the "Prefer a guided terminal
experience?" section explicitly say that guide.sh is the same interactive guide
that install.sh can launch and can also be re-run later manually (reference
install.sh and examples/walkthrough/guide.sh by name) so readers understand they
do not need to run guide.sh if they already selected the interactive option
during install.sh, but can re-run guide.sh anytime to replay the guided
experience.


</details>

---

`370-379`: **Cleanup command may fail silently if no services exist.**

The cleanup block suppresses all errors from `docker service rm`, which is fine for idempotency, but the subshell `$(docker service ls ... -q)` will expand to empty if no services match, causing `docker service rm` to receive no arguments and print an error before `|| true` catches it. This isn't harmful but produces confusing output.

<details>
<summary>Suggested fix for cleaner output</summary>

```diff
 ```bash
 # Remove database services (stops Postgres containers)
-docker service rm $(docker service ls \
-  --filter label=pgedge.database.id=example -q) 2>/dev/null || true
+services=$(docker service ls --filter label=pgedge.database.id=example -q)
+[ -n "$services" ] && docker service rm $services || true

 # Remove the Control Plane container
 docker rm -f host-1 2>/dev/null || true

 echo "Cleanup complete."
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/walkthrough.md around lines 370 - 379, The cleanup step calls docker
service rm with a subshell that can expand to empty, producing an unnecessary
error; capture the list first (e.g., assign docker service ls --filter
label=pgedge.database.id=example -q to a variable like services), then only call
docker service rm when that variable is non-empty (use a test like [ -n
"$services" ] && docker service rm $services) and keep the existing docker rm -f
host-1 and || true behavior for idempotency and silent failures.


</details>

---

`63-65`: **Use `bash` instead of `text` for the code fence.**

While using `text` prevents syntax highlighting, it also prevents Runme from recognizing this as an executable block. Since the tip at lines 17-22 emphasizes that "every code block below is executable," this block should be consistent:

```diff
-```text
+```bash
 curl -fsSL https://raw.githubusercontent.com/pgEdge/control-plane/main/examples/walkthrough/install.sh | bash

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/walkthrough.md around lines 63 - 65, Replace the markdown code fence
that currently uses "text" with "bash" for the executable snippet containing
"curl -fsSL
https://raw.githubusercontent.com/pgEdge/control-plane/main/examples/walkthrough/install.sh
| bash" so Runme and syntax highlighting treat it as an executable block; locate
the triple-backtick fence around that curl line in docs/walkthrough.md and
change text to bash.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @docs/walkthrough.md:

  • Around line 140-143: The docs currently use curl -sf http://localhost:3000/v1/cluster/init which fails silently on non-2xx
    responses; replace that one-liner in the code block with a small bash snippet
    that captures the full response and HTTP status (e.g., store output in a
    response variable and the status in status), then branch on status to
    print "Cluster initialized." for 200/201, "Cluster already initialized." for
    409, and print an error and exit 1 for other status codes; update the code
    block in docs/walkthrough.md accordingly so users get clear feedback instead of
    always seeing "Cluster initialized."

In @examples/walkthrough/guide.sh:

  • Around line 193-197: The current port extraction using grep/sed for
    existing_db is fragile and uses the wrong JSON paths; replace the grep/sed
    pipeline that sets N1_PORT, N2_PORT, N3_PORT with jq queries that read ports
    from the API response field .instances[].connection_info.port (e.g., extract the
    first, second, third entries) so N1_PORT/N2_PORT/N3_PORT come from
    .instances[0].connection_info.port, .instances[1].connection_info.port,
    .instances[2].connection_info.port respectively; ensure the curl result
    (existing_db) is piped into jq and handle missing entries gracefully (fall back
    to empty) the same way the script currently allows empty values.

Nitpick comments:
In @docs/walkthrough.md:

  • Around line 58-74: The current text is ambiguous about the relationship
    between install.sh and the interactive guide; update the wording to state that
    install.sh will prompt users to choose the interactive guide or a self-paced
    walkthrough, and make the "Prefer a guided terminal experience?" section
    explicitly say that guide.sh is the same interactive guide that install.sh can
    launch and can also be re-run later manually (reference install.sh and
    examples/walkthrough/guide.sh by name) so readers understand they do not need to
    run guide.sh if they already selected the interactive option during install.sh,
    but can re-run guide.sh anytime to replay the guided experience.
  • Around line 370-379: The cleanup step calls docker service rm with a subshell
    that can expand to empty, producing an unnecessary error; capture the list first
    (e.g., assign docker service ls --filter label=pgedge.database.id=example -q to
    a variable like services), then only call docker service rm when that variable
    is non-empty (use a test like [ -n "$services" ] && docker service rm $services)
    and keep the existing docker rm -f host-1 and || true behavior for idempotency
    and silent failures.
  • Around line 63-65: Replace the markdown code fence that currently uses "text"
    with "bash" for the executable snippet containing "curl -fsSL
    https://raw.githubusercontent.com/pgEdge/control-plane/main/examples/walkthrough/install.sh
    | bash" so Runme and syntax highlighting treat it as an executable block; locate
    the triple-backtick fence around that curl line in docs/walkthrough.md and
    change text to bash.

In @examples/walkthrough/guide.sh:

  • Around line 53-70: The loop in the port discovery logic (variables start,
    p1/p2/p3 and the port_in_use checks that set N1_PORT/N2_PORT/N3_PORT) can run
    for a very long time; add a hard cap to avoid long hangs by introducing a
    maximum-tries or a reasonable upper-bound (e.g., MAX_TRIES or start_max) and
    break with an error if exceeded, so the while loop exits deterministically
    instead of potentially scanning all ports up to 65533.
  • Around line 287-289: The current cleanup command uses "PGPASSWORD=... psql ...
    -c 'DROP TABLE IF EXISTS example;' >/dev/null 2>&1 || true", which hides
    connection failures; remove the blanket "|| true" and instead run the same psql
    command (using the N1_PORT and DB_ID variables shown) while redirecting output
    as needed, then explicitly check the psql exit status ($?); if psql failed
    (non-zero), log a clear error like "Failed to connect to n1 or drop table" and
    exit non‑zero so connection problems are surfaced rather than silently ignored.
    Ensure the check surrounds the exact command invocation shown so only genuine
    failures trigger the error path.
  • Around line 27-33: In port_in_use(), the ss-based check is brittle; update the
    else branch to reliably detect listeners by extracting the local address:port
    field and comparing the port (e.g., use ss -tnl piped to awk to strip the
    address portion and test equality against the supplied $1) so it handles
    end-of-line ports and IPv6 forms like :::22 instead of relying on the current
    grep ':${1} ' pattern.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Organization UI

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `e8b69893-0b81-4437-9a93-12c63473609d`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a6b263deecac5a7e6229a7f8cbb17cf3d4c958d0 and 8d8929ef175aa473038f64b7b4a31f68364d14fe.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `docs/walkthrough.md`
* `examples/walkthrough/guide.sh`
* `examples/walkthrough/setup.sh`

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* examples/walkthrough/setup.sh

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

- walkthrough.md: add proper error handling for cluster/init endpoint
- guide.sh: use jq with correct API paths for port extraction
  (.instances[].connection_info.port) instead of fragile grep/sed
@AntTheLimey
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@docs/walkthrough.md`:
- Around line 374-388: The cleanup snippet leaves the temporary data directory
referenced by CP_DATA behind; update the cleanup block that removes services and
the Control Plane container to also remove CP_DATA by checking if the CP_DATA
variable is non-empty and then invoking sudo rm -rf on it (e.g., use a
conditional like [ -n "$CP_DATA" ] && sudo rm -rf "$CP_DATA"); ensure you
reference the CP_DATA variable name and place this removal immediately before
the final echo "Cleanup complete." so root-owned temp files created by guide.sh
are deleted.
- Around line 63-74: Update the two runnable code blocks in docs/walkthrough.md
currently fenced as ```text``` (the curl install command and the guided script
invocation) to use ```bash``` fences instead so Runme treats them as executable;
locate the blocks containing "curl -fsSL
https://raw.githubusercontent.com/pgEdge/control-plane/main/examples/walkthrough/install.sh
| bash" and "bash examples/walkthrough/guide.sh" and replace their opening fence
label from text to bash.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a1f0950-95f0-48ce-aff5-463e2904307a

📥 Commits

Reviewing files that changed from the base of the PR and between 8d8929e and b51649e.

📒 Files selected for processing (2)
  • docs/walkthrough.md
  • examples/walkthrough/guide.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/walkthrough/guide.sh

AntTheLimey and others added 5 commits March 10, 2026 10:35
Mirrors the structure of the Helm walkthrough README, covering
file overview, how users reach the walkthrough, and instructions
for running via curl-pipe, Codespaces, and cloned repo.
   Show the API response as formatted JSON and explain the async
   task model before polling. Replace the hidden spinner with
   visible state transitions so the user can follow progress.
   Remove Docker-centric language from the creation step.
   Align intro paragraph, step names, node explanation, and heading
   style between guide.sh and walkthrough.md. Rewrite node
   introduction to match Helm walkthrough style. Rename
   Initialize the cluster to Initialize the Control Plane.
  Remove 2-space indent padding from runner.sh so text and
  command output align consistently. Replace repetitive state
  polling output with a spinner that only prints on state
  transitions.
@AntTheLimey AntTheLimey merged commit 8589f84 into main Mar 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants