Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Build and Development Commands

### Database Setup
- `make start-deps` - Start PostgreSQL in Docker
- `make start-deps` - Start PostgreSQL via nix process-compose (no Docker required)
- `make setup-db` - Run database migrations
- `make reset-deps` - Clean, start, and setup database

Expand Down
31 changes: 16 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
clean-deps:
docker compose down
NIX_DEPS_DIR := .nix-deps

.PHONY: start-deps clean-deps setup-db reset-deps sqlx-prepare check-code test-in-ci test-book test-chapter serve-book

start-deps:
@command -v docker >/dev/null 2>&1 && docker compose up -d || echo "Docker not found, skipping start-deps"
@mkdir -p $(NIX_DEPS_DIR)
nix run .#nix-deps-base -- up -D
nix run .#nix-deps-base -- project is-ready --wait

clean-deps:
-nix run .#nix-deps-base -- down
chmod -R u+w $(NIX_DEPS_DIR) 2>/dev/null || true
rm -rf $(NIX_DEPS_DIR)

setup-db:
@echo "Waiting for PostgreSQL and running migrations..."
@for i in 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; do \
cargo sqlx migrate run 2>/dev/null && echo "Migrations complete" && exit 0; \
echo "Attempt $$i: Database not ready, waiting..."; \
sleep 1; \
done; \
echo "Database failed to become ready after 30 attempts"; \
cargo sqlx migrate run

reset-deps: clean-deps start-deps setup-db

test-in-ci: start-deps setup-db
nix run .#setup-db-dev

reset-deps: clean-deps start-deps

test-in-ci: start-deps
rm -rf $${CARGO_TARGET_DIR:-./target}/mdbook-test
$(MAKE) test-book
cargo nextest run --workspace --verbose
Expand Down
15 changes: 0 additions & 15 deletions docker-compose.yml

This file was deleted.

16 changes: 16 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

174 changes: 154 additions & 20 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
flake = false;
};
crane.url = "github:ipetkov/crane";
process-compose-flake.url = "github:Platonic-Systems/process-compose-flake";
};
outputs = {
self,
Expand All @@ -23,6 +24,7 @@
rust-overlay,
advisory-db,
crane,
process-compose-flake,
}:
flake-utils.lib.eachDefaultSystem
(system: let
Expand Down Expand Up @@ -66,29 +68,157 @@
mdbook
bacon
postgresql
docker-compose
ytt
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think we still need ytt in the dev shell. ci/repipe still uses ytt, but after this change nix develop no longer includes the tool needed to update the Concourse pipeline

podman
podman-compose
process-compose
curl
];

pgPort = 5432;
pgUser = "user";
pgPassword = "password";
pgDatabase = "pg";

devEnvVars = rec {
PGDATABASE = "pg";
PGUSER = "user";
PGPASSWORD = "password";
PGDATABASE = pgDatabase;
PGUSER = pgUser;
PGPASSWORD = pgPassword;
PGHOST = "127.0.0.1";
DATABASE_URL = "postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:5432/pg?sslmode=disable";
PGPORT = toString pgPort;
DATABASE_URL = "postgres://${pgUser}:${pgPassword}@127.0.0.1:${toString pgPort}/${pgDatabase}?sslmode=disable";
PG_CON = "${DATABASE_URL}";
};

podman-runner = pkgs.callPackage ./nix/podman-runner.nix {};
# ── Postgres start helper ──────────────────────────────────────────
pg-start = pkgs.writeShellApplication {
name = "pg-start";
runtimeInputs = [pkgs.postgresql pkgs.coreutils];
text = ''
NAME="$1" PORT="$2" PGUSER="$3" DB="$4"
PGDATA="$PWD/.nix-deps/$NAME"

mkdir -p "$PWD/.nix-deps"

if [ ! -f "$PGDATA/PG_VERSION" ]; then
echo "[$NAME] Initializing data directory at $PGDATA..."
mkdir -p "$PGDATA"
initdb -D "$PGDATA" --username="$PGUSER" --auth=trust --no-locale -E UTF8
{
echo "port = $PORT"
echo "unix_socket_directories = '/tmp'"
echo "listen_addresses = '127.0.0.1'"
} >> "$PGDATA/postgresql.conf"
fi

if [ -f "$PGDATA/postmaster.pid" ]; then
pg_ctl -D "$PGDATA" stop -m immediate 2>/dev/null || rm -f "$PGDATA/postmaster.pid"
fi

postgres -D "$PGDATA" -p "$PORT" -k /tmp &
PG_PID=$!
trap 'kill $PG_PID 2>/dev/null; wait $PG_PID 2>/dev/null' EXIT

while ! pg_isready -p "$PORT" -U "$PGUSER" -h 127.0.0.1 -q 2>/dev/null; do
sleep 0.1
done

if [ "$DB" != "$PGUSER" ]; then
createdb -p "$PORT" -U "$PGUSER" -h 127.0.0.1 "$DB" 2>/dev/null || {
if psql -p "$PORT" -U "$PGUSER" -h 127.0.0.1 -lqt | cut -d \| -f 1 | grep -qw "$DB"; then
echo "[$NAME] Database '$DB' already exists"
else
echo "[$NAME] ERROR: Failed to create database '$DB'" >&2
exit 1
fi
}
fi

echo "[$NAME] Ready on port $PORT (database: $DB)"
wait $PG_PID
'';
};

setupDbDev = pkgs.writeShellApplication {
name = "setup-db-dev";
runtimeInputs = [pkgs.sqlx-cli];
text = ''
export DATABASE_URL="${devEnvVars.DATABASE_URL}"
exec sqlx migrate run
'';
};

# ── process-compose: core-pg + setup-db ────────────────────────────
pcLib = import process-compose-flake.lib {inherit pkgs;};

mkPg = {
name,
port,
user,
db,
}: {
command = "${
pkgs.writeShellApplication {
name = "start-${name}";
runtimeInputs = [pg-start];
text = ''
exec pg-start ${name} ${toString port} ${user} ${db}
'';
}
}/bin/start-${name}";
readiness_probe = {
exec.command = "${
pkgs.writeShellApplication {
name = "ready-${name}";
runtimeInputs = [pkgs.postgresql];
text = ''
exec psql -p ${toString port} -U ${user} -h 127.0.0.1 -d ${db} -c 'SELECT 1' -t -q
'';
}
}/bin/ready-${name}";
initial_delay_seconds = 1;
period_seconds = 1;
failure_threshold = 60;
};
shutdown = {
signal = 2;
timeout_seconds = 10;
};
};

baseProcesses = {
core-pg = mkPg {
name = "core-pg";
port = pgPort;
user = pgUser;
db = pgDatabase;
};
setup-db = {
command = "${setupDbDev}/bin/setup-db-dev";
depends_on.core-pg.condition = "process_healthy";
availability.exit_on_end = false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think this makes DB migrations racy. This makes setup-db behave like a background process (i.e. not blocking until it is done), so project is-ready --wait may return once migrations have started rather than after they have finished. Then tests can start before the fresh DB schema is ready.

shutdown = {
signal = 2;
timeout_seconds = 10;
};
};
};

nix-deps-base = pcLib.makeProcessCompose {
name = "nix-deps-base";
modules = [
{
settings = {
log_level = "info";
log_location = ".nix-deps/process-compose.log";
processes = baseProcesses;
};
}
];
};

# ── CI test runner ────────────────────────────────────────────────
nextest-runner = pkgs.writeShellScriptBin "nextest-runner" ''
set -e

export PATH="${pkgs.lib.makeBinPath [
podman-runner.podman-compose-runner
pkgs.wait4x
pkgs.sqlx-cli
pkgs.cargo-nextest
pkgs.coreutils
Expand All @@ -104,22 +234,19 @@
export PGUSER="${devEnvVars.PGUSER}"
export PGPASSWORD="${devEnvVars.PGPASSWORD}"
export PGHOST="${devEnvVars.PGHOST}"
export PGPORT="${devEnvVars.PGPORT}"

cleanup() {
echo "Stopping deps..."
${podman-runner.podman-compose-runner}/bin/podman-compose-runner down || true
${nix-deps-base}/bin/nix-deps-base down 2>/dev/null || true
}

trap cleanup EXIT

echo "Starting PostgreSQL..."
${podman-runner.podman-compose-runner}/bin/podman-compose-runner up -d
mkdir -p .nix-deps

echo "Waiting for PostgreSQL to be ready..."
${pkgs.wait4x}/bin/wait4x postgresql "$DATABASE_URL" --timeout 120s

echo "Running database migrations..."
${pkgs.sqlx-cli}/bin/sqlx migrate run
echo "Starting PostgreSQL via process-compose..."
${nix-deps-base}/bin/nix-deps-base up -D
${nix-deps-base}/bin/nix-deps-base project is-ready --wait

echo "Running mdbook tests..."
rm -rf ''${CARGO_TARGET_DIR:-./target}/mdbook-test
Expand All @@ -141,6 +268,13 @@
with pkgs; {
packages = {
nextest = nextest-runner;
setup-db-dev = setupDbDev;
inherit nix-deps-base;
};

apps.setup-db-dev = flake-utils.lib.mkApp {
drv = setupDbDev;
name = "setup-db-dev";
};

checks = {
Expand Down
Loading
Loading