diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8e7589..8791bd3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,10 @@ jobs: target: aarch64-apple-darwin artifact_name: database-replicator asset_name: database-replicator-macos-arm64-binary + - os: windows-latest + target: x86_64-pc-windows-msvc + artifact_name: database-replicator.exe + asset_name: database-replicator-windows-x64.exe steps: - name: Checkout code uses: actions/checkout@v4 @@ -51,11 +55,18 @@ jobs: if: matrix.os == 'macos-latest' run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }} - - name: Rename binary + - name: Rename binary (Unix) + if: matrix.os != 'windows-latest' run: | cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} ${{ matrix.asset_name }} chmod +x ${{ matrix.asset_name }} + - name: Rename binary (Windows) + if: matrix.os == 'windows-latest' + run: | + copy target\${{ matrix.target }}\release\${{ matrix.artifact_name }} ${{ matrix.asset_name }} + shell: cmd + - name: Upload artifact uses: actions/upload-artifact@v4 with: diff --git a/Dockerfile b/Dockerfile index aeadc75..b599ea6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,20 @@ # syntax=docker/dockerfile:1 -FROM rust:1.82-slim AS builder -WORKDIR /app +FROM debian:bookworm-slim AS downloader +ARG VERSION=latest +ENV BINARY_NAME=database-replicator-linux-x64-binary +ENV RELEASE_ROOT=https://github.com/serenorg/database-replicator/releases -# Install build dependencies for OpenSSL / libpq bindings -RUN apt-get update && \ - apt-get install -y --no-install-recommends pkg-config libssl-dev libpq-dev && \ - rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && rm -rf /var/lib/apt/lists/* -# Cache dependencies -COPY Cargo.toml Cargo.lock ./ -COPY src ./src -COPY README.md . -RUN cargo build --release --bin database-replicator +RUN set -eux; \ + if [ "$VERSION" = "latest" ]; then \ + URL="$RELEASE_ROOT/latest/download/$BINARY_NAME"; \ + else \ + URL="$RELEASE_ROOT/download/$VERSION/$BINARY_NAME"; \ + fi; \ + curl -fL "$URL" -o /tmp/database-replicator && \ + chmod +x /tmp/database-replicator FROM debian:bookworm-slim LABEL org.opencontainers.image.title="database-replicator" \ @@ -20,11 +22,11 @@ LABEL org.opencontainers.image.title="database-replicator" \ org.opencontainers.image.source="https://github.com/serenorg/database-replicator" RUN apt-get update && \ - apt-get install -y --no-install-recommends ca-certificates libssl3 libpq5 && \ + apt-get install -y --no-install-recommends ca-certificates libssl3 libpq5 postgresql-client && \ rm -rf /var/lib/apt/lists/* && \ useradd -m replicator -COPY --from=builder /app/target/release/database-replicator /usr/local/bin/database-replicator +COPY --from=downloader /tmp/database-replicator /usr/local/bin/database-replicator USER replicator ENTRYPOINT ["database-replicator"] CMD ["--help"] diff --git a/README.md b/README.md index e45a753..a4efce6 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Replicate any database to PostgreSQL with zero downtime. Supports PostgreSQL, SQ SerenAI provides managed PostgreSQL databases optimized for AI workloads. When replicating to SerenDB targets, this tool can run your replication jobs on SerenAI's cloud infrastructure - no local resources required. **Benefits of SerenAI Cloud Execution:** + - No local compute resources needed - Automatic retry and error handling - Job monitoring and logging @@ -32,8 +33,7 @@ With just your API key set, the tool will interactively guide you through select export SEREN_API_KEY="your-api-key" # Get from console.serendb.com database-replicator init \ - --source "postgresql://user:pass@source:5432/db" \ - --local + --source "postgresql://user:pass@source:5432/db" ``` The tool will: @@ -54,7 +54,7 @@ database-replicator init \ --target "postgresql://user:pass@your-db.serendb.com:5432/db" ``` -For local execution (non-SerenDB targets), use the `--local` flag. See [Remote Execution](#remote-execution-serendb-only) for details. +For local execution (non-SerenDB targets), use the `--local` flag. See [Remote Execution](#remote-execution-aws) for details. --- @@ -205,14 +205,21 @@ Download the latest release for your platform from [GitHub Releases](https://git - **Linux (x64)**: `database-replicator-linux-x64-binary` - **macOS (Intel)**: `database-replicator-macos-x64-binary` - **macOS (Apple Silicon)**: `database-replicator-macos-arm64-binary` +- **Windows (x64)**: `database-replicator-windows-x64.exe` -Make the binary executable: +Make the binary executable (Linux/macOS): ```bash chmod +x database-replicator-*-binary ./database-replicator-*-binary --help ``` +On Windows, run directly: + +```cmd +database-replicator-windows-x64.exe --help +``` + ### Install from crates.io ```bash @@ -233,18 +240,22 @@ The binary will be available at `target/release/database-replicator`. ### Docker Image -Build a container image with the latest source: +Build an image from the latest GitHub release (default) or a specific tag: ```bash +# latest release asset docker build -t serenorg/database-replicator:latest . + +# specific version +docker build --build-arg VERSION=v5.3.20 -t serenorg/database-replicator:v5.3.20 . ``` Run the CLI inside the container (pass connection strings via arguments or environment variables): ```bash -docker run --rm -it \ - serenorg/database-replicator:latest \ - validate --source "postgresql://user:pass@source/db" --target "postgresql://user:pass@target/db" +docker run --rm -it serenorg/database-replicator:latest \ + validate --source "postgresql://user:pass@source/db" \ + --target "postgresql://user:pass@target/db" ``` Mount local config files if needed: @@ -253,7 +264,7 @@ Mount local config files if needed: docker run --rm -it \ -v "$PWD:/work" \ serenorg/database-replicator:latest \ - init --source @/work/source.txt --target @/work/target.txt + init --source "$(cat /work/source.txt)" --target "$(cat /work/target.txt)" ``` ### Prerequisites diff --git a/src/main.rs b/src/main.rs index e468714..094ef65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -268,18 +268,23 @@ async fn main() -> anyhow::Result<()> { let mut state = database_replicator::state::load()?; let mut target = target.or(state.target_url); + // If no target and not forcing local execution, trigger interactive project selection + // This is the default behavior - remote execution with SerenDB target picker + if target.is_none() && !local { + target = Some(database_replicator::interactive::select_seren_database().await?); + } + + // If --seren flag explicitly set, validate target is SerenDB if seren { if let Some(t) = &target { if !database_replicator::utils::is_serendb_target(t) { anyhow::bail!("--seren flag is only compatible with SerenDB targets."); } - } else { - target = Some(database_replicator::interactive::select_seren_database().await?); } } let target = target.ok_or_else(|| { - anyhow::anyhow!("Target database URL not provided and not set in state. Use `--target` or `database-replicator target set`.") + anyhow::anyhow!("Target database URL not provided. Use `--target` to specify a target database, or remove `--local` to use interactive SerenDB project selection.") })?; // Check if CLI filter flags were provided (skip interactive if so)