Skip to content

Commit b68c13a

Browse files
rustyconoverclaude
andcommitted
release: build & push vgi-fixtures container images to GHCR
Add a stdio fixture-worker image so the VGI DuckDB extension's container (oci://) transport can run the test fixtures with no local uv/Python install — the container IS the worker, piped over stdin/stdout at full subprocess fidelity (unlike HTTP). This unblocks running the extension's integration suite in CI without shipping its path-sensitive unittest binary around. - packages/vgi-fixtures/docker/Dockerfile: python:3.13-slim + the exact release wheels (vgi + vgi-fixtures, [duckdb]/[test-fixtures-writable] from PyPI). The worker is chosen by VGI_FIXTURE_WORKER, baked late (after the heavy install layer) via a build arg so per-worker tags share that layer. - docker-entrypoint.sh: takes the transport mode as argv[1] (the extension's `docker run -i … IMAGE stdio` contract), execs the selected vgi-fixture-* worker for stdio, rejects tcp/http (stdio-only image), and refuses to exec anything but a vgi-fixture-* console script. - release.yml: new build-docker-image job (needs: build), a 7-worker matrix (one per fixture the extension suite uses), max-parallel 1 + gha cache so the install layer builds once. Pushes ghcr.io/query-farm/vgi-fixtures:<ver>-<short> (+ :<ver> and :latest for the base worker) via GITHUB_TOKEN. Validated locally: image builds on slim, all deps resolve, entrypoint dispatch is correct, the base worker boots its VgiProtocol RPC server and the VGI_FIXTURE_WORKER override switches workers. linux/amd64 only for now. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d52b654 commit b68c13a

3 files changed

Lines changed: 159 additions & 0 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,80 @@ jobs:
5656
name: dist-fixtures
5757
path: dist-fixtures/
5858

59+
build-docker-image:
60+
name: Build & push vgi-fixtures image (${{ matrix.short }})
61+
needs: build
62+
runs-on: ubuntu-latest
63+
permissions:
64+
contents: read
65+
packages: write # push to GHCR
66+
# One image per fixture worker, selected via the VGI_FIXTURE_WORKER build arg.
67+
# The VGI extension's container transport uses plain `oci://…` string
68+
# LOCATIONs (no struct env), so the worker must be baked into the tag rather
69+
# than passed at runtime. Tags: ghcr.io/query-farm/vgi-fixtures:<ver>-<short>
70+
# (plus :<ver> and :latest for the base worker). max-parallel: 1 so the heavy
71+
# pip-install layer is built once and reused from the gha cache by the rest.
72+
strategy:
73+
fail-fast: false
74+
max-parallel: 1
75+
matrix:
76+
include:
77+
- { short: worker, worker: vgi-fixture-worker, latest: true }
78+
- { short: versioned, worker: vgi-fixture-versioned-worker }
79+
- { short: versioned-tables, worker: vgi-fixture-versioned-tables-worker }
80+
- { short: attach-options, worker: vgi-fixture-attach-options-worker }
81+
- { short: bad-protocol, worker: vgi-fixture-bad-protocol-worker }
82+
- { short: bad-enum, worker: vgi-fixture-bad-enum-worker }
83+
- { short: simple-writable, worker: vgi-fixture-simple-writable-worker }
84+
steps:
85+
- uses: actions/checkout@v7
86+
87+
# The image installs the exact wheels this release publishes.
88+
- name: Download vgi wheel
89+
uses: actions/download-artifact@v8
90+
with:
91+
name: dist-vgi
92+
path: dist
93+
- name: Download vgi-fixtures wheel
94+
uses: actions/download-artifact@v8
95+
with:
96+
name: dist-fixtures
97+
path: dist
98+
99+
- name: Compute image tags
100+
id: meta
101+
run: |
102+
ver="${{ github.event.release.tag_name }}"
103+
ver="${ver#v}" # normalize a leading v (v0.8.2 -> 0.8.2)
104+
img="ghcr.io/query-farm/vgi-fixtures"
105+
tags="$img:$ver-${{ matrix.short }}"
106+
if [ "${{ matrix.latest }}" = "true" ]; then
107+
tags="$tags,$img:$ver,$img:latest"
108+
fi
109+
echo "tags=$tags" >> "$GITHUB_OUTPUT"
110+
111+
- uses: docker/setup-buildx-action@v3
112+
113+
- name: Log in to GHCR
114+
uses: docker/login-action@v3
115+
with:
116+
registry: ghcr.io
117+
username: ${{ github.actor }}
118+
password: ${{ secrets.GITHUB_TOKEN }}
119+
120+
- name: Build & push
121+
uses: docker/build-push-action@v6
122+
with:
123+
context: .
124+
file: packages/vgi-fixtures/docker/Dockerfile
125+
platforms: linux/amd64
126+
build-args: |
127+
VGI_FIXTURE_WORKER=${{ matrix.worker }}
128+
tags: ${{ steps.meta.outputs.tags }}
129+
push: true
130+
cache-from: type=gha
131+
cache-to: type=gha,mode=max
132+
59133
publish-vgi:
60134
name: Publish vgi to PyPI
61135
needs: build
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# syntax=docker/dockerfile:1
2+
#
3+
# vgi-fixtures — example/test VGI worker images for the VGI DuckDB extension.
4+
#
5+
# Each worker speaks vgi-rpc over stdin/stdout; the extension's oci:// container
6+
# transport runs `docker run -i ... IMAGE stdio` and pipes the worker like a
7+
# subprocess (full fidelity — same semantics as the local subprocess transport,
8+
# unlike HTTP). Which worker runs is selected by VGI_FIXTURE_WORKER, baked per
9+
# image tag via the build arg below (overridable at runtime with `-e`).
10+
#
11+
# Built from the SAME wheels published to PyPI in the release (the release
12+
# workflow copies them into ./dist), so the image matches the released
13+
# vgi-fixtures exactly — no separate source path to drift.
14+
15+
FROM python:3.13-slim
16+
17+
# vgi-python (core) + vgi-fixtures (worker entry points + the vgi/_test_fixtures
18+
# sources the fixtures wheel force-includes). Installing both local wheels; the
19+
# extras the fixtures require ([duckdb], [test-fixtures-writable]) resolve from
20+
# PyPI. Kept as one heavy layer so the per-worker ARG below doesn't bust it.
21+
COPY dist/*.whl /tmp/wheels/
22+
RUN pip install --no-cache-dir /tmp/wheels/*.whl && rm -rf /tmp/wheels
23+
24+
# Worker selection — placed AFTER the install so the (expensive) layer above is
25+
# shared across every per-worker tag; only this cheap tail rebuilds per worker.
26+
ARG VGI_FIXTURE_WORKER=vgi-fixture-worker
27+
ENV VGI_FIXTURE_WORKER=${VGI_FIXTURE_WORKER}
28+
29+
COPY packages/vgi-fixtures/docker/docker-entrypoint.sh /usr/local/bin/vgi-fixtures-entrypoint
30+
RUN chmod +x /usr/local/bin/vgi-fixtures-entrypoint
31+
32+
LABEL org.opencontainers.image.source="https://github.com/Query-farm/vgi-python" \
33+
org.opencontainers.image.description="Example/test VGI worker (stdio) for the VGI DuckDB extension" \
34+
org.opencontainers.image.licenses="MIT"
35+
36+
# The extension passes the transport mode as argv[1]; stdio is the default + only
37+
# mode this image implements.
38+
ENTRYPOINT ["/usr/local/bin/vgi-fixtures-entrypoint"]
39+
CMD ["stdio"]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/sh
2+
# Entrypoint for the vgi-fixtures container image.
3+
#
4+
# The VGI DuckDB extension's container (oci://) transport invokes the image as
5+
# docker run -i ... IMAGE <mode>
6+
# where <mode> is the transport it wants: "stdio" (private per-process, piped over
7+
# stdin/stdout exactly like the subprocess transport) or "tcp"/"http" (a shared
8+
# server). This image implements *stdio only* — the fixture workers speak vgi-rpc
9+
# over stdin/stdout and advertise no farm.query.vgi.transports label, so the
10+
# extension stays on per-process stdio for it.
11+
#
12+
# Which fixture worker runs is chosen by $VGI_FIXTURE_WORKER. It is baked per image
13+
# tag via the Dockerfile build arg (e.g. the ":<ver>-versioned" tag bakes
14+
# vgi-fixture-versioned-worker) and can be overridden at runtime with
15+
# docker run -e VGI_FIXTURE_WORKER=vgi-fixture-bad-enum-worker ...
16+
set -eu
17+
18+
mode="${1:-stdio}"
19+
worker="${VGI_FIXTURE_WORKER:-vgi-fixture-worker}"
20+
21+
# Only ever exec a published vgi-fixture-* console script — never an arbitrary
22+
# command smuggled in through the env var.
23+
case "$worker" in
24+
vgi-fixture-*) : ;;
25+
*)
26+
echo "vgi-fixtures: refusing to run non-fixture command '$worker'" >&2
27+
exit 64
28+
;;
29+
esac
30+
31+
case "$mode" in
32+
stdio)
33+
# The worker serves vgi-rpc over stdin/stdout and runs until EOF.
34+
exec "$worker"
35+
;;
36+
tcp | http)
37+
echo "vgi-fixtures: transport '$mode' is not supported by this image (stdio only)." >&2
38+
echo " It advertises no farm.query.vgi.transports label, so the extension" >&2
39+
echo " uses per-process stdio; do not force connection=$mode for it." >&2
40+
exit 64
41+
;;
42+
*)
43+
echo "vgi-fixtures: unknown transport mode '$mode' (expected: stdio)" >&2
44+
exit 64
45+
;;
46+
esac

0 commit comments

Comments
 (0)