Skip to content
Open
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
45 changes: 45 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Build artifacts
target/
**/target/
*.o
*.so
*.rlib
*.d

# Submodule build artifacts (we rebuild inside the image)
ivy_duckdb/build/
ivy_duckdb/third_party/duckdb/build/
ivy_duckdb/*.so
ivy_moonlink/target/
ivy_duckdb_mooncake/build/

# Cargo
.cargo/
**/.cargo/

# Editor / IDE
.vscode/
.idea/
.devcontainer/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Spec/plan/memory files (untracked, dev-local)
docs/

# Other
.git/
.github/
.gitignore
.gitmodules

# But keep .gitmodules — needed to know submodule layout? No, COPY explicitly
# names submodules; .gitmodules not needed at build time.

# Local test/log
*.log
/tmp/
107 changes: 107 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: docker

on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/ivy_mooncake
IVORYSQL_BASE: registry.highgo.com/ivorysql/ivorysql:5.3-ubi8

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch,suffix=-ubi8
type=ref,event=pr,suffix=-ubi8
type=semver,pattern={{version}},suffix=-ubi8
type=semver,pattern={{major}}.{{minor}},suffix=-ubi8
type=sha,prefix=sha-,suffix=-ubi8
type=raw,value=5.3-ubi8,enable={{is_default_branch}}
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push (amd64)
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
build-args: |
IVORYSQL_BASE=${{ env.IVORYSQL_BASE }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

smoke-test:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
needs: build
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Build image
run: |
docker build \
--build-arg IVORYSQL_BASE=${{ env.IVORYSQL_BASE }} \
-t ivy_mooncake:test .

- name: Run container
run: |
docker run -d --name test \
-e IVORYSQL_PASSWORD=password \
ivy_mooncake:test
for i in $(seq 1 60); do
docker exec test pg_isready -U ivorysql -d postgres 2>/dev/null && { echo "ready in ${i}s"; break; }
sleep 1
done

- name: Verify CREATE EXTENSION pg_mooncake CASCADE
run: |
docker exec test psql -U ivorysql -d postgres -c "
CREATE EXTENSION pg_mooncake CASCADE;
SELECT extname, extversion FROM pg_extension WHERE extname IN ('pg_duckdb','pg_mooncake');
"

- name: Verify mooncake.create_table E2E
run: |
docker exec test psql -U ivorysql -d postgres <<'SQL'
CREATE TABLE t (id int PRIMARY KEY, v text);
ALTER TABLE t REPLICA IDENTITY FULL;
INSERT INTO t VALUES (1,'a'),(2,'b');
CALL mooncake.create_table('t_mirror', 't');
SELECT count(*) FROM t_mirror;
SQL
143 changes: 143 additions & 0 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: regression

# Run pgrx regression tests on every PR + manual dispatch.
# Mirrors `make test` (which calls `cargo pgrx regress --resetdb`) inside
# the project's Docker build stage so we exercise the real IvorySQL pg_config,
# pg_duckdb install, and the bgworker codepath end-to-end.

on:
pull_request:
branches: [main]
workflow_dispatch:

env:
IVORYSQL_BASE: registry.highgo.com/ivorysql/ivorysql:5.3-ubi8
TEST_IMAGE: ivy_mooncake:regress-${{ github.run_id }}

jobs:
regress:
runs-on: ubuntu-latest
timeout-minutes: 90
permissions:
contents: read
steps:
- name: Checkout (with submodules)
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# Build the `build` stage of the project Dockerfile. That stage ends
# with:
# - /ivy_mooncake = source tree (incl. all 3 submodules)
# - /etc/pgconfig = absolute path to IvorySQL pg_config
# - pg_duckdb + libduckdb.so installed into IvorySQL libdir/sharedir
# - rust 1.91.1 + cargo-pgrx 0.16.1 + `cargo pgrx init --pg18=$PG_CONFIG` done
# Stopping at this stage means we can run `cargo pgrx regress` from the
# same container without re-paying any build cost.
- name: Build (Dockerfile target=build)
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
target: build
load: true
tags: ${{ env.TEST_IMAGE }}
build-args: |
IVORYSQL_BASE=${{ env.IVORYSQL_BASE }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Run cargo pgrx regress (pg18)
id: regress
run: |
mkdir -p _artifacts
set -o pipefail
docker run --rm \
-v "$PWD/_artifacts:/out" \
-w /ivy_mooncake \
-e RUST_BACKTRACE=1 \
-e CARGO_TERM_COLOR=always \
"${{ env.TEST_IMAGE }}" \
bash -c '
set -eux

# PG refuses to run as root, so spin up an unprivileged user
# (tester) and have it drive cargo pgrx regress.
useradd -m -u 2000 -s /bin/bash tester

# Share /root/.cargo and /root/.rustup with tester via chmod
# rather than cp -a / chown -R: on overlayfs chown forces a
# copy_up of every file (~1GB doubling), and a full chown of
# the build tree wastes minutes + GBs. chmod only flips
# metadata bits.
chmod o+rx /root
chmod -R o+rX /root/.cargo /root/.rustup

# target/ from the image build is root-owned + stale once
# cargo recompiles with different feature flags during regress,
# so wipe it instead of chown-recursing.
rm -rf /ivy_mooncake/target
chown -R tester:tester /ivy_mooncake

# /out is a host-mounted volume owned by the host user; tester
# would otherwise lack write perms.
chown tester:tester /out

PG_CONFIG="$(cat /etc/pgconfig)"
LIBDIR="$($PG_CONFIG --pkglibdir)"
SHAREDIR="$($PG_CONFIG --sharedir)"
chmod -R a+rwX "$LIBDIR" "$SHAREDIR/extension"

su - tester -c "
set -eux
# Share the root-owned cargo/rustup caches in place; per-user
# pgrx state still goes under tester home.
export CARGO_HOME=/root/.cargo
export RUSTUP_HOME=/root/.rustup
export PGRX_HOME=/home/tester/.pgrx
export PATH=/root/.cargo/bin:\$PATH

cargo pgrx init --pg18=\"$PG_CONFIG\"
cd /ivy_mooncake
# pg_duckdb refuses to load unless it is in
# shared_preload_libraries; the IvorySQL base also expects
# liboracle_parser/ivorysql_ora at preload time.
cargo pgrx regress --resetdb \
--postgresql-conf \"shared_preload_libraries=liboracle_parser,ivorysql_ora,pg_duckdb,pg_mooncake\" \
--postgresql-conf \"wal_level=logical\" \
--postgresql-conf \"duckdb.allow_community_extensions=true\" \
2>&1 | tee /out/regress.log
"
'

- name: Collect regression diffs on failure
if: failure() && steps.regress.outcome == 'failure'
run: |
docker run --rm \
-v "$PWD/_artifacts:/out" \
-w /ivy_mooncake \
"${{ env.TEST_IMAGE }}" \
bash -c '
set -eu
# Best-effort: regression diffs land somewhere under the source
# tree depending on pgrx version, so just grab everything that
# could be useful for triage.
find . -name regression.diffs -exec cp -v {} /out/ \; 2>/dev/null || true
find . -name regression.out -exec cp -v {} /out/ \; 2>/dev/null || true
find . -path "*/pg_regress/results/*" -exec cp -v {} /out/ \; 2>/dev/null || true
# cargo target log (if any)
find . -name "postmaster.log" -exec cp -v {} /out/ \; 2>/dev/null || true
ls -la /out/ || true
' || true

- name: Upload regression artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: regression-artifacts-${{ github.run_id }}
path: _artifacts/
if-no-files-found: ignore
retention-days: 14
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@
/tests/pg_regress/regression.diffs
/tests/pg_regress/regression.out
/tests/pg_regress/results/

# Local-only: developer notes, machine-specific helpers, alt-base image
docs/
Dockerfile.ivorysql-base
scripts/docker-relocate-data.sh
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pgrx = "0.16.1"
postgres.git = "https://github.com/Mooncake-Labs/rust-postgres.git"
postgres-native-tls.git = "https://github.com/Mooncake-Labs/rust-postgres.git"
regex = "1"
serde_json = "1"
tokio = "1.48"

[profile.release]
Expand Down
Loading