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
44 changes: 29 additions & 15 deletions .github/workflows/publish-ghcr-platform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,18 @@ jobs:
echo "build=false" >> "$GITHUB_OUTPUT"
fi

# @note reuse is decided once for the single flavor; a second flavor
# needs a per-flavor lookup and output here
- name: Resolve image names
# @note the build matrix is skipped as a whole, so reuse requires both
# component images for every flavor at the same source revision
- name: Resolve image prefix
if: steps.diff.outputs.build == 'true'
id: image
env:
FLAVOR: community
REPOSITORY_NAME: ${{ github.event.repository.name }}
REPOSITORY_OWNER: ${{ github.repository_owner }}
run: |
owner="${REPOSITORY_OWNER,,}"
repository="${REPOSITORY_NAME,,}"
stack="${REGISTRY}/${owner}/${repository}-${FLAVOR}"
echo "application=${stack}-app" >> "$GITHUB_OUTPUT"
echo "initializer=${stack}-init" >> "$GITHUB_OUTPUT"
echo "prefix=${REGISTRY}/${owner}/${repository}" >> "$GITHUB_OUTPUT"

- name: Set up Docker Buildx
if: steps.diff.outputs.build == 'true'
Expand All @@ -109,14 +106,15 @@ jobs:
# @note candidates are the pushed commit (a fast-forward or a re-run)
# and its parents (the promotion merge, whose second parent is the next
# head). A candidate counts only when its tree is byte-identical to the
# pushed tree and both component images carry its sha- tag, which only
# publish creates and only after verify passed
# pushed tree and every flavor's component images carry its sha- tag,
# which only publish creates and only after verify passed
- name: Find a published image of the same tree
if: steps.diff.outputs.build == 'true'
id: reuse
env:
APPLICATION_IMAGE: ${{ steps.image.outputs.application }}
INITIALIZER_IMAGE: ${{ steps.image.outputs.initializer }}
# @note keep this list in sync with the build and publish matrices
FLAVORS: community studio
IMAGE_PREFIX: ${{ steps.image.outputs.prefix }}
run: |
tree=$(git rev-parse "${GITHUB_SHA}^{tree}")

Expand All @@ -133,9 +131,18 @@ jobs:

short="${candidate:0:7}"

if docker buildx imagetools inspect "${APPLICATION_IMAGE}:sha-${short}" >/dev/null 2>&1 \
&& docker buildx imagetools inspect "${INITIALIZER_IMAGE}:sha-${short}" >/dev/null 2>&1
then
complete=true

for flavor in $FLAVORS; do
if ! docker buildx imagetools inspect "${IMAGE_PREFIX}-${flavor}-app:sha-${short}" >/dev/null 2>&1 \
|| ! docker buildx imagetools inspect "${IMAGE_PREFIX}-${flavor}-init:sha-${short}" >/dev/null 2>&1
then
complete=false
break
fi
done

if [ "$complete" = true ]; then
echo "Reusing images built from ${candidate}"
echo "reuse=${short}" >> "$GITHUB_OUTPUT"
exit 0
Expand Down Expand Up @@ -184,6 +191,11 @@ jobs:
- name: community
application_target: application
initializer_target: initializer
# @note studio starts with the same package selection as community;
# both share Docker targets until studio's implementation diverges
- name: studio
application_target: application
initializer_target: initializer
architecture:
- name: amd64
platform: linux/amd64
Expand Down Expand Up @@ -244,7 +256,7 @@ jobs:
file: docker/Dockerfile
target: ${{ matrix.flavor.application_target }}
platforms: ${{ matrix.architecture.platform }}
# @note community images embed full source maps on purpose - the
# @note distribution images embed full source maps on purpose - the
# source is public and self-hosted debugging needs them
build-args: |
BUILD_SOURCEMAPS=full
Expand Down Expand Up @@ -380,6 +392,8 @@ jobs:
# @note keep this list in sync with the build job's flavor matrix
- name: community
runner: ubuntu-latest-8-cores-amd64
- name: studio
runner: ubuntu-latest-8-cores-amd64

steps:
- uses: actions/checkout@v7
Expand Down
13 changes: 4 additions & 9 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,11 @@ ENV NODE_OPTIONS="--max-old-space-size=$NODE_HEAP_MB --require /app/platform/scr
ARG SITE_URL=http://cbk.localhost:3000
ENV SITE_URL=$SITE_URL

# @note apex host rewrites are generated at build time, so the image bakes
# `.localhost` names browsers resolve to loopback without DNS: space sites at
# `<slug>.cbk-space.localhost`, portals at `<slug>.cbk-portal.localhost`.
# The runtime environment must name the same apexes (the compose files do).
# @todo move the apex host rewrites out of next.config.d into a runtime proxy
# @note space and portal sites use their apexes at runtime through proxy.ts;
# the remaining apex rewrites are generated at build time, so their runtime
# values must match the build
# @todo move the remaining apex host rewrites into the runtime proxy
# so one image digest serves any domain without a rebuild
ARG SPACE_APEX=cbk-space.localhost
ENV SPACE_APEX=$SPACE_APEX
ARG PORTAL_APEX=cbk-portal.localhost
ENV PORTAL_APEX=$PORTAL_APEX
ARG APP_APEX=
ENV APP_APEX=$APP_APEX
ARG PARTNERS_APEX=
Expand Down
6 changes: 4 additions & 2 deletions docker/distro/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ docker compose -f oci://ghcr.io/chatbotkit/platform-<flavor>:latest up -d
Swap only what the flavor changes (e.g. a `postgres` service replacing the
SQLite volume); keep service names, healthchecks and the variable surface
consistent.
3. Add the flavor to the matrix in
3. Add the flavor to the build and publish matrices in
`.github/workflows/publish-ghcr-platform.yaml` with its application and
initializer targets. Everything downstream - images, smoke test, artifact
initializer targets, and to the `FLAVORS` list used by the image reuse
lookup. A build is reused only when every flavor has both component images
from the same revision. Everything downstream - images, smoke test, artifact
publish - is parameterized on `matrix.flavor` and needs no other change.
4. Verify before relying on CI: `docker compose -f
docker/distro/<flavor>/compose.yml config --quiet`, then publish to a
Expand Down
5 changes: 2 additions & 3 deletions docker/distro/community/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ services:
# needs an address it can reach instead (and TLS if the site has it)
RELAY_PORT: 3001
RELAY_URL: ${RELAY_URL:-http://cbk-relay.localhost:3001}
# @note deployment-issued subdomains; must match the apexes baked into
# the image (docker/Dockerfile). Browsers resolve `*.localhost` to
# loopback, so `acme.cbk-space.localhost:3000` works with no DNS setup
# @note space and portal subdomains read their apexes at server startup;
# recreate the container to change domains without rebuilding the image
SPACE_APEX: ${SPACE_APEX:-cbk-space.localhost}
PORTAL_APEX: ${PORTAL_APEX:-cbk-portal.localhost}
# @note the app shells, baked the same way: the main shell at
Expand Down
Loading