diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 868d5aa..2495efa 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -18,13 +18,20 @@ COPY crates/parsers/src crates/parsers/src # Build with sccache (cache persisted between builds via Docker cache mount) RUN --mount=type=cache,target=/sccache \ - cargo build --release -p api + cargo build --release -p api && \ + cargo install sqlx-cli --no-default-features --features postgres --locked FROM debian:bookworm-slim -RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates wget unar poppler-utils locales && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates wget unar poppler-utils locales postgresql-client \ + && rm -rf /var/lib/apt/lists/* RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen ENV LANG=en_US.UTF-8 ENV LC_ALL=en_US.UTF-8 COPY --from=builder /app/target/release/api /usr/local/bin/api +COPY --from=builder /usr/local/cargo/bin/sqlx /usr/local/bin/sqlx +COPY infra/migrations /app/migrations +COPY apps/api/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh EXPOSE 7080 -CMD ["/usr/local/bin/api"] +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/apps/api/entrypoint.sh b/apps/api/entrypoint.sh new file mode 100644 index 0000000..f457d31 --- /dev/null +++ b/apps/api/entrypoint.sh @@ -0,0 +1,63 @@ +#!/bin/sh +set -e + +# psql requires "postgresql://" but Rust/sqlx accepts both "postgres://" and "postgresql://" +PSQL_URL=$(echo "$DATABASE_URL" | sed 's|^postgres://|postgresql://|') + +# Check 1: does the old schema exist (index_jobs table)? +HAS_OLD_TABLES=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name='index_jobs')::text" \ + 2>/dev/null || echo "false") + +# Check 2: is sqlx tracking present and non-empty? +HAS_SQLX_TABLE=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name='_sqlx_migrations')::text" \ + 2>/dev/null || echo "false") + +if [ "$HAS_SQLX_TABLE" = "true" ]; then + HAS_SQLX_ROWS=$(psql "$PSQL_URL" -tAc \ + "SELECT EXISTS(SELECT 1 FROM _sqlx_migrations LIMIT 1)::text" \ + 2>/dev/null || echo "false") +else + HAS_SQLX_ROWS="false" +fi + +echo "==> Migration check: old_tables=$HAS_OLD_TABLES sqlx_table=$HAS_SQLX_TABLE sqlx_rows=$HAS_SQLX_ROWS" + +if [ "$HAS_OLD_TABLES" = "true" ] && [ "$HAS_SQLX_ROWS" = "false" ]; then + echo "==> Upgrade from pre-sqlx migration system detected: creating baseline..." + + psql "$PSQL_URL" -c " + CREATE TABLE IF NOT EXISTS _sqlx_migrations ( + version BIGINT PRIMARY KEY, + description TEXT NOT NULL, + installed_on TIMESTAMPTZ NOT NULL DEFAULT NOW(), + success BOOLEAN NOT NULL, + checksum BYTEA NOT NULL, + execution_time BIGINT NOT NULL + ) + " + + for f in /app/migrations/*.sql; do + filename=$(basename "$f") + # Strip leading zeros to get the integer version (e.g. "0005" -> "5") + version=$(echo "$filename" | sed 's/^0*//' | cut -d'_' -f1) + description=$(echo "$filename" | sed 's/^[0-9]*_//' | sed 's/\.sql$//') + checksum=$(sha384sum "$f" | awk '{print $1}') + + psql "$PSQL_URL" -c " + INSERT INTO _sqlx_migrations (version, description, installed_on, success, checksum, execution_time) + VALUES ($version, '$description', NOW(), TRUE, decode('$checksum', 'hex'), 0) + ON CONFLICT (version) DO NOTHING + " + echo " baselined: $filename" + done + + echo "==> Baseline complete." +fi + +echo "==> Running migrations..." +sqlx migrate run --source /app/migrations + +echo "==> Starting API..." +exec /usr/local/bin/api diff --git a/docker-compose.yml b/docker-compose.yml index e7071a0..1fa73cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,24 +29,6 @@ services: timeout: 5s retries: 5 - migrate: - image: postgres:16-alpine - depends_on: - postgres: - condition: service_healthy - environment: - POSTGRES_USER: stripstream - POSTGRES_PASSWORD: stripstream - POSTGRES_DB: stripstream - volumes: - - ./infra/migrations:/migrations:ro - command: - [ - "sh", - "-c", - "export PGPASSWORD=$$POSTGRES_PASSWORD; for f in /migrations/*.sql; do echo \"Applying migration: $$f\"; psql -h postgres -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\" -f \"$$f\" || exit 1; done", - ] - api: build: context: . @@ -59,8 +41,6 @@ services: - ${LIBRARIES_HOST_PATH:-./libraries}:/libraries - ${THUMBNAILS_HOST_PATH:-./data/thumbnails}:/data/thumbnails depends_on: - migrate: - condition: service_completed_successfully postgres: condition: service_healthy meilisearch: @@ -83,8 +63,8 @@ services: - ${LIBRARIES_HOST_PATH:-./libraries}:/libraries - ${THUMBNAILS_HOST_PATH:-./data/thumbnails}:/data/thumbnails depends_on: - migrate: - condition: service_completed_successfully + api: + condition: service_healthy postgres: condition: service_healthy meilisearch: diff --git a/scripts/docker-push.sh b/scripts/docker-push.sh index 35f3de1..f9aadf7 100755 --- a/scripts/docker-push.sh +++ b/scripts/docker-push.sh @@ -17,17 +17,17 @@ echo "" for service in "${SERVICES[@]}"; do echo "Building $service..." docker build -f apps/$service/Dockerfile -t $service:latest . - + echo "Tagging $service..." docker tag $service:latest $REGISTRY/$OWNER/stripstream-$service:$VERSION docker tag $service:latest $REGISTRY/$OWNER/stripstream-$service:latest - + echo "Pushing stripstream-$service:$VERSION..." docker push $REGISTRY/$OWNER/stripstream-$service:$VERSION - + echo "Pushing stripstream-$service:latest..." docker push $REGISTRY/$OWNER/stripstream-$service:latest - + echo "✓ $service pushed successfully" echo "" done