Skip to content
Merged
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
145 changes: 145 additions & 0 deletions .github/workflows/testdb-images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
name: Test database images

# Publishes ghcr.io/queryahub/querya-testdb-<db>:<version> (and :latest): the
# docker/<db> seeds baked into the official database images, for extension
# authors (no bind mounts). A database is built when docker/<db>/Dockerfile.testdb
# exists, so adding one appears here without editing this file.
#
# Pull requests only build and smoke-test. `workflow_run`, not `release`: the
# release is created with GITHUB_TOKEN, and events made by that token do not
# start other workflows.
on:
pull_request:
paths:
- docker/**
- .github/workflows/testdb-images.yml
workflow_run:
workflows: [Release]
types: [completed]
workflow_dispatch:
inputs:
version:
description: Querya Desktop release the images are tagged with (e.g. 0.4.19)
required: true
latest:
description: Also tag the images as latest
type: boolean
default: true

permissions:
contents: read
packages: write

jobs:
plan:
name: Plan
runs-on: ubuntu-latest
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
outputs:
databases: ${{ steps.dbs.outputs.databases }}
push: ${{ steps.v.outputs.push }}
version: ${{ steps.v.outputs.version }}
latest: ${{ steps.v.outputs.latest }}
steps:
- uses: actions/checkout@v4

- name: Databases with a Dockerfile.testdb
id: dbs
shell: bash
run: |
set -euo pipefail
list=$(for f in docker/*/Dockerfile.testdb; do basename "$(dirname "$f")"; done | jq -R . | jq -sc .)
echo "databases=$list" >> "$GITHUB_OUTPUT"

- name: Resolve the version
id: v
shell: bash
run: |
set -euo pipefail
case "${{ github.event_name }}" in
workflow_dispatch) VERSION="${{ inputs.version }}"; LATEST="${{ inputs.latest }}" ;;
workflow_run) VERSION="${{ github.event.workflow_run.head_branch }}"; LATEST=true ;;
*) VERSION=""; LATEST=false ;;
esac
VERSION="${VERSION#v}"
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "push=true" >> "$GITHUB_OUTPUT"
else
[ -z "$VERSION" ] || echo "::notice::'$VERSION' is not a release tag, images are only built"
echo "push=false" >> "$GITHUB_OUTPUT"
VERSION=dev
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "latest=$LATEST" >> "$GITHUB_OUTPUT"

image:
name: querya-testdb-${{ matrix.db }}
needs: plan
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
db: ${{ fromJson(needs.plan.outputs.databases) }}
env:
IMAGE: ghcr.io/queryahub/querya-testdb-${{ matrix.db }}
steps:
- uses: actions/checkout@v4

- uses: docker/setup-buildx-action@v3

- uses: docker/login-action@v3
if: needs.plan.outputs.push == 'true'
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build (loaded locally for the smoke test)
uses: docker/build-push-action@v6
with:
context: docker/${{ matrix.db }}
file: docker/${{ matrix.db }}/Dockerfile.testdb
load: true
tags: querya-testdb:test
cache-from: type=gha,scope=testdb-${{ matrix.db }}
cache-to: type=gha,mode=max,scope=testdb-${{ matrix.db }}

- name: Smoke test (seeds are in, no bind mounts)
shell: bash
run: |
set -euo pipefail
docker run -d --name testdb querya-testdb:test
for i in $(seq 1 60); do
s=$(docker inspect -f '{{.State.Health.Status}}' testdb)
[ "$s" = healthy ] && break
sleep 3
done
[ "$s" = healthy ] || { docker logs testdb; echo "::error::not healthy: $s"; exit 1; }

case "${{ matrix.db }}" in
postgres) out=$(docker exec testdb psql -U querya -d querya -Atc "SELECT count(*) FROM shop.customers") ;;
mysql) out=$(docker exec testdb mysql -uquerya -pquerya querya -Nse "SELECT count(*) FROM customers") ;;
mongo) out=$(docker exec testdb mongosh --quiet -u querya -p querya --authenticationDatabase admin querya --eval "db.users.countDocuments()") ;;
clickhouse) out=$(docker exec testdb clickhouse-client --user querya --password querya --query "SELECT count() FROM querya.customers") ;;
redis) out=$(docker exec testdb redis-cli GET querya:seed:marker) ;;
*) echo "::error::no smoke test for ${{ matrix.db }}"; exit 1 ;;
esac
echo "seed check: $out"
# A seeded table or key is a positive number; an empty database is 0 or empty.
[[ "$out" =~ ^[1-9][0-9]*$ ]] || { docker logs testdb; echo "::error::seed missing"; exit 1; }

- name: Push
if: needs.plan.outputs.push == 'true'
uses: docker/build-push-action@v6
with:
context: docker/${{ matrix.db }}
file: docker/${{ matrix.db }}/Dockerfile.testdb
push: true
cache-from: type=gha,scope=testdb-${{ matrix.db }}
tags: |
${{ env.IMAGE }}:${{ needs.plan.outputs.version }}
${{ needs.plan.outputs.latest == 'true' && format('{0}:latest', env.IMAGE) || '' }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.description=Querya test database (${{ matrix.db }}) with the Querya seeds baked in
org.opencontainers.image.licenses=MIT
9 changes: 9 additions & 0 deletions docker/clickhouse/Dockerfile.testdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# querya-testdb-clickhouse: ClickHouse with the Querya seeds, no bind mounts.
FROM clickhouse/clickhouse-server:24.8
ENV CLICKHOUSE_DB=querya \

Check warning on line 3 in docker/clickhouse/Dockerfile.testdb

View workflow job for this annotation

GitHub Actions / querya-testdb-clickhouse

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "CLICKHOUSE_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
CLICKHOUSE_USER=querya \
CLICKHOUSE_PASSWORD=querya \
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
COPY init/ /docker-entrypoint-initdb.d/
HEALTHCHECK --interval=5s --timeout=5s --retries=20 --start-period=40s \
CMD clickhouse-client --user querya --password querya --query 'SELECT 1'
8 changes: 8 additions & 0 deletions docker/mongo/Dockerfile.testdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# querya-testdb-mongo: MongoDB with the Querya seeds, no bind mounts.
# Auth source is admin; the init script runs on the first start.
FROM mongo:7
ENV MONGO_INITDB_ROOT_USERNAME=querya \

Check warning on line 4 in docker/mongo/Dockerfile.testdb

View workflow job for this annotation

GitHub Actions / querya-testdb-mongo

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "MONGO_INITDB_ROOT_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
MONGO_INITDB_ROOT_PASSWORD=querya
COPY init/ /docker-entrypoint-initdb.d/
HEALTHCHECK --interval=5s --timeout=5s --retries=20 --start-period=30s \
CMD mongosh --quiet -u querya -p querya --authenticationDatabase admin --eval "db.adminCommand('ping').ok"
11 changes: 11 additions & 0 deletions docker/mysql/Dockerfile.testdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# querya-testdb-mysql: MySQL 8.0 with mysql_native_password (what CI runs), so
# a client without TLS can connect. The init scripts run on the first start.
FROM mysql:8.0
ENV MYSQL_ROOT_PASSWORD=querya \

Check warning on line 4 in docker/mysql/Dockerfile.testdb

View workflow job for this annotation

GitHub Actions / querya-testdb-mysql

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "MYSQL_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 4 in docker/mysql/Dockerfile.testdb

View workflow job for this annotation

GitHub Actions / querya-testdb-mysql

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "MYSQL_ROOT_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
MYSQL_DATABASE=querya \
MYSQL_USER=querya \
MYSQL_PASSWORD=querya
COPY init/ /docker-entrypoint-initdb.d/
CMD ["--default-authentication-plugin=mysql_native_password", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
HEALTHCHECK --interval=5s --timeout=5s --retries=20 --start-period=30s \
CMD mysqladmin ping -h 127.0.0.1 -uquerya -pquerya
9 changes: 9 additions & 0 deletions docker/postgres/Dockerfile.testdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# querya-testdb-postgres: PostgreSQL with the Querya seeds, no bind mounts.
# The init scripts run on the first start of an empty data directory.
FROM postgres:16-alpine
ENV POSTGRES_USER=querya \

Check warning on line 4 in docker/postgres/Dockerfile.testdb

View workflow job for this annotation

GitHub Actions / querya-testdb-postgres

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "POSTGRES_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
POSTGRES_PASSWORD=querya \
POSTGRES_DB=querya
COPY init/ /docker-entrypoint-initdb.d/
HEALTHCHECK --interval=5s --timeout=5s --retries=12 \
CMD pg_isready -U querya -d querya
10 changes: 10 additions & 0 deletions docker/redis/Dockerfile.testdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# querya-testdb-redis: Redis seeded with the Querya keys on every start.
# Redis has no init directory, so the entrypoint starts the server, runs
# seed.sh against it and then keeps serving.
FROM redis:7-alpine
COPY seed.sh /seed.sh
COPY testdb-entrypoint.sh /testdb-entrypoint.sh
RUN chmod +x /testdb-entrypoint.sh
ENTRYPOINT ["/testdb-entrypoint.sh"]
HEALTHCHECK --interval=5s --timeout=3s --retries=12 \
CMD redis-cli ping | grep -q PONG
12 changes: 12 additions & 0 deletions docker/redis/testdb-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh
# Starts redis-server, seeds it once it answers, then waits for the server so
# that a stop signal reaches it and the container exits with its status.
set -eu

redis-server --save "" --appendonly no "$@" &
SERVER=$!
trap 'kill -TERM "$SERVER" 2>/dev/null' TERM INT

REDIS_HOST=127.0.0.1 REDIS_PORT=6379 sh /seed.sh

wait "$SERVER"
Loading